Ingress

使用支援協議的配置機制來提供 HTTP(或 HTTPS)網路服務,該機制理解 URI、主機名、路徑等 Web 概念。Ingress 概念允許你根據透過 Kubernetes API 定義的規則,將流量對映到不同的後端。

特性狀態: Kubernetes v1.19 [stable]

一個 API 物件,用於管理叢集中服務的外部訪問,通常是 HTTP。

Ingress 可以提供負載均衡、SSL 終止和基於名稱的虛擬主機。

術語

為清楚起見,本指南定義以下術語

  • 節點:Kubernetes 中的工作機器,叢集的一部分。
  • 叢集:一組執行由 Kubernetes 管理的容器化應用程式的節點。在此示例中,以及在大多數常見的 Kubernetes 部署中,叢集中的節點不屬於公共網際網路。
  • 邊緣路由器:為叢集實施防火牆策略的路由器。這可以是雲提供商管理的閘道器,也可以是物理硬體。
  • 叢集網路:根據 Kubernetes 網路模型 促進叢集內部通訊的一組邏輯或物理鏈路。
  • Service:一個 Kubernetes Service,它使用 標籤 選擇器識別一組 Pod。除非另有說明,否則假定 Service 具有僅在叢集網路內可路由的虛擬 IP。

什麼是 Ingress?

Ingress 將叢集外部的 HTTP 和 HTTPS 路由公開到叢集內部的服務。流量路由由 Ingress 資源上定義的規則控制。

這裡有一個簡單的例子,一個 Ingress 將所有流量傳送到一個 Service

ingress-diagram

圖:Ingress

Ingress 可以配置為向 Service 提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS 並提供基於名稱的虛擬主機。一個 Ingress 控制器 負責實現 Ingress,通常使用負載均衡器,但它也可以配置你的邊緣路由器或額外的前端來幫助處理流量。

Ingress 不會暴露任意埠或協議。將 HTTP 和 HTTPS 之外的服務暴露給網際網路通常使用 Service.Type=NodePortService.Type=LoadBalancer 型別的服務。

先決條件

你必須有一個 Ingress 控制器 才能滿足 Ingress 的要求。僅僅建立一個 Ingress 資源是沒有任何作用的。

你可能需要部署一個 Ingress 控制器,例如 ingress-nginx。你可以從多個 Ingress 控制器 中進行選擇。

理想情況下,所有 Ingress 控制器都應符合參考規範。但實際上,各種 Ingress 控制器的操作方式略有不同。

Ingress 資源

最小 Ingress 資源示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: minimal-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx-example
  rules:
  - http:
      paths:
      - path: /testpath
        pathType: Prefix
        backend:
          service:
            name: test
            port:
              number: 80

Ingress 需要 apiVersionkindmetadataspec 欄位。Ingress 物件的名稱必須是有效的 DNS 子域名。有關使用配置檔案的一般資訊,請參閱部署應用配置容器管理資源。Ingress 經常使用註解來配置一些選項,具體取決於 Ingress 控制器,例如 rewrite-target 註解。不同的 Ingress 控制器 支援不同的註解。請查閱你選擇的 Ingress 控制器的文件,以瞭解支援哪些註解。

Ingress 規約 包含配置負載均衡器或代理伺服器所需的所有資訊。最重要的是,它包含一個與所有傳入請求匹配的規則列表。Ingress 資源只支援用於引導 HTTP(S) 流量的規則。

如果省略 ingressClassName,則應定義一個 預設 Ingress 類

有一些 ingress 控制器,即使沒有定義預設的 IngressClass 也能工作。例如,Ingress-NGINX 控制器可以透過一個 標誌 --watch-ingress-without-class 進行配置。但是,建議 指定預設的 IngressClass,如下所示

Ingress 規則

每個 HTTP 規則包含以下資訊:

  • 一個可選的主機。在此示例中,未指定主機,因此該規則適用於透過指定 IP 地址的所有入站 HTTP 流量。如果提供了主機(例如,foo.bar.com),則規則適用於該主機。
  • 路徑列表(例如,/testpath),每個路徑都有一個關聯的後端,該後端透過 service.nameservice.port.nameservice.port.number 定義。主機和路徑都必須與傳入請求的內容匹配,負載均衡器才會將流量引導到引用的 Service。
  • 後端是 Service 和埠名稱的組合,如 Service 文件 中所述,或者透過 CRD 實現的自定義資源後端。匹配規則主機和路徑的 HTTP(和 HTTPS)請求將傳送到列出的後端。

defaultBackend 通常在 Ingress 控制器中配置,用於處理與規約中任何路徑都不匹配的請求。

預設後端

沒有規則的 Ingress 將所有流量傳送到單個預設後端,在這種情況下,.spec.defaultBackend 是應該處理請求的後端。defaultBackend 通常是 Ingress 控制器 的配置選項,不會在 Ingress 資源中指定。如果未指定 .spec.rules,則必須指定 .spec.defaultBackend。如果未設定 defaultBackend,則不匹配任何規則的請求的處理將由 Ingress 控制器決定(請查閱你的 Ingress 控制器文件,瞭解它如何處理這種情況)。

如果 Ingress 物件中的任何主機或路徑都不匹配 HTTP 請求,則流量將路由到你的預設後端。

資源後端

Resource 後端是同一名稱空間(與 Ingress 物件相同)中另一個 Kubernetes 資源的 ObjectRef。Resource 是與 Service 互斥的設定,如果同時指定兩者,則驗證將失敗。Resource 後端的一個常見用法是將資料入站到具有靜態資產的物件儲存後端。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-resource-backend
spec:
  defaultBackend:
    resource:
      apiGroup: k8s.example.com
      kind: StorageBucket
      name: static-assets
  rules:
    - http:
        paths:
          - path: /icons
            pathType: ImplementationSpecific
            backend:
              resource:
                apiGroup: k8s.example.com
                kind: StorageBucket
                name: icon-assets

建立上述 Ingress 後,你可以使用以下命令檢視它

kubectl describe ingress ingress-resource-backend
Name:             ingress-resource-backend
Namespace:        default
Address:
Default backend:  APIGroup: k8s.example.com, Kind: StorageBucket, Name: static-assets
Rules:
  Host        Path  Backends
  ----        ----  --------
  *
              /icons   APIGroup: k8s.example.com, Kind: StorageBucket, Name: icon-assets
Annotations:  <none>
Events:       <none>

路徑型別

Ingress 中的每個路徑都必須具有相應的路徑型別。未包含顯式 pathType 的路徑將無法透過驗證。支援三種路徑型別:

  • ImplementationSpecific:使用此路徑型別,匹配由 IngressClass 決定。實現可以將其視為單獨的 pathType,也可以將其視為與 PrefixExact 路徑型別相同。

  • Exact:精確匹配 URL 路徑,區分大小寫。

  • Prefix:根據按 / 分隔的 URL 路徑字首進行匹配。匹配區分大小寫,並逐個路徑元素進行。路徑元素是指路徑中按 / 分隔的標籤列表。如果請求路徑的每個 p 都是 p 的元素字首,則請求與路徑 p 匹配。

示例

種類路徑請求路徑匹配?
字首/(所有路徑)
精確/foo/foo
精確/foo/bar
精確/foo/foo/
精確/foo//foo
字首/foo/foo, /foo/
字首/foo//foo, /foo/
字首/aaa/bb/aaa/bbb
字首/aaa/bbb/aaa/bbb
字首/aaa/bbb//aaa/bbb是,忽略尾部斜槓
字首/aaa/bbb/aaa/bbb/是,匹配尾部斜槓
字首/aaa/bbb/aaa/bbb/ccc是,匹配子路徑
字首/aaa/bbb/aaa/bbbxyz否,不匹配字串字首
字首/, /aaa/aaa/ccc是,匹配 /aaa 字首
字首/, /aaa, /aaa/bbb/aaa/bbb是,匹配 /aaa/bbb 字首
字首/, /aaa, /aaa/bbb/ccc是,匹配 / 字首
字首/aaa/ccc否,使用預設後端
混合/foo (字首), /foo (精確)/foo是,優先選擇精確匹配

多重匹配

在某些情況下,Ingress 中的多個路徑將匹配一個請求。在這些情況下,優先順序將首先給予最長匹配路徑。如果兩個路徑仍然等長匹配,則優先順序將給予具有精確路徑型別而非字首路徑型別的路徑。

主機名萬用字元

主機可以是精確匹配(例如 “foo.bar.com”)或萬用字元(例如 “*.foo.com”)。精確匹配要求 HTTP host 頭與 host 欄位匹配。萬用字元匹配要求 HTTP host 頭等於萬用字元規則的字尾。

主機主機頭匹配?
*.foo.combar.foo.com基於共享字尾匹配
*.foo.combaz.bar.foo.com不匹配,萬用字元只覆蓋一個 DNS 標籤
*.foo.comfoo.com不匹配,萬用字元只覆蓋一個 DNS 標籤
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-wildcard-host
spec:
  rules:
  - host: "foo.bar.com"
    http:
      paths:
      - pathType: Prefix
        path: "/bar"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: "*.foo.com"
    http:
      paths:
      - pathType: Prefix
        path: "/foo"
        backend:
          service:
            name: service2
            port:
              number: 80

Ingress 類

Ingress 可以由不同的控制器實現,通常具有不同的配置。每個 Ingress 都應指定一個類,該類是對 IngressClass 資源的引用,其中包含附加配置,包括應實現該類的控制器的名稱。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb
spec:
  controller: example.com/ingress-controller
  parameters:
    apiGroup: k8s.example.com
    kind: IngressParameters
    name: external-lb

IngressClass 的 .spec.parameters 欄位允許你引用另一個提供與該 IngressClass 相關的配置的資源。

要使用的引數的具體型別取決於你在 IngressClass 的 .spec.controller 欄位中指定的 ingress 控制器。

IngressClass 範圍

根據你的 ingress 控制器,你可能可以使用叢集範圍的引數,或者僅用於一個名稱空間的引數。

IngressClass 引數的預設範圍是叢集範圍。

如果你設定了 .spec.parameters 欄位但沒有設定 .spec.parameters.scope,或者你將 .spec.parameters.scope 設定為 Cluster,那麼 IngressClass 將引用叢集範圍的資源。引數的 kind(與 apiGroup 結合)引用叢集範圍的 API(可能是一個自定義資源),引數的 name 標識該 API 的特定叢集範圍資源。

例如

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-1
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in a
    # ClusterIngressParameter (API group k8s.example.net) named
    # "external-config-1". This definition tells Kubernetes to
    # look for a cluster-scoped parameter resource.
    scope: Cluster
    apiGroup: k8s.example.net
    kind: ClusterIngressParameter
    name: external-config-1

特性狀態: Kubernetes v1.23 [stable]

如果你設定了 .spec.parameters 欄位並將 .spec.parameters.scope 設定為 Namespace,那麼 IngressClass 將引用名稱空間範圍的資源。你還必須將 .spec.parameters 中的 namespace 欄位設定為包含要使用的引數的名稱空間。

引數的 kind(與 apiGroup 結合)引用名稱空間 API(例如:ConfigMap),引數的 name 標識你在 namespace 中指定的名稱空間中的特定資源。

名稱空間範圍的引數有助於叢集操作員委託對工作負載所用配置(例如:負載均衡器設定、API 閘道器定義)的控制。如果你使用叢集範圍的引數,則:

  • 每次應用新的配置更改時,叢集操作員團隊都需要批准不同團隊的更改。
  • 叢集操作員必須定義特定的訪問控制,例如 RBAC 角色和繫結,以允許應用程式團隊更改叢集範圍的引數資源。

IngressClass API 本身始終是叢集範圍的。

這是一個引用名稱空間引數的 IngressClass 示例

---
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: external-lb-2
spec:
  controller: example.com/ingress-controller
  parameters:
    # The parameters for this IngressClass are specified in an
    # IngressParameter (API group k8s.example.com) named "external-config",
    # that's in the "external-configuration" namespace.
    scope: Namespace
    apiGroup: k8s.example.com
    kind: IngressParameter
    namespace: external-configuration
    name: external-config

已棄用的註解

在 Kubernetes 1.18 中新增 IngressClass 資源和 ingressClassName 欄位之前,Ingress 類是透過 Ingress 上的 kubernetes.io/ingress.class 註解指定的。此註解從未正式定義,但受到 Ingress 控制器的廣泛支援。

Ingress 上較新的 ingressClassName 欄位取代了該註解,但並非直接等效。雖然該註解通常用於引用應實現 Ingress 的 Ingress 控制器的名稱,但該欄位是對 IngressClass 資源的引用,其中包含附加的 Ingress 配置,包括 Ingress 控制器的名稱。

預設 IngressClass

你可以將某個 IngressClass 標記為叢集的預設 IngressClass。在 IngressClass 資源上將 ingressclass.kubernetes.io/is-default-class 註解設定為 true 將確保沒有指定 ingressClassName 欄位的新 Ingress 將被分配此預設 IngressClass。

有一些 Ingress 控制器即使沒有定義預設的 IngressClass 也能工作。例如,Ingress-NGINX 控制器可以使用 標誌 --watch-ingress-without-class 進行配置。但是,建議 指定預設的 IngressClass

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  labels:
    app.kubernetes.io/component: controller
  name: nginx-example
  annotations:
    ingressclass.kubernetes.io/is-default-class: "true"
spec:
  controller: k8s.io/ingress-nginx

Ingress 的型別

由單個服務支援的 Ingress

現有 Kubernetes 概念允許你暴露單個 Service(請參閱替代方案)。你也可以透過 Ingress 來實現,方法是指定一個沒有規則的 預設後端

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  defaultBackend:
    service:
      name: test
      port:
        number: 80

如果你使用 kubectl apply -f 建立它,你應該能夠檢視你新增的 Ingress 的狀態。

kubectl get ingress test-ingress
NAME           CLASS         HOSTS   ADDRESS         PORTS   AGE
test-ingress   external-lb   *       203.0.113.123   80      59s

其中 203.0.113.123 是 Ingress 控制器為滿足此 Ingress 而分配的 IP。

簡單扇出

扇出配置根據請求的 HTTP URI,將流量從單個 IP 地址路由到多個 Service。Ingress 允許你將負載均衡器數量降至最低。例如,一個像這樣的設定:

ingress-fanout-diagram

圖。Ingress 扇出

它將需要一個 Ingress,例如:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: simple-fanout-example
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 4200
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: service2
            port:
              number: 8080

當你使用 kubectl apply -f 建立 Ingress 時:

kubectl describe ingress simple-fanout-example
Name:             simple-fanout-example
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:4200 (10.8.0.90:4200)
               /bar   service2:8080 (10.8.0.91:8080)
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     22s                loadbalancer-controller  default/test

只要 Service (service1, service2) 存在,Ingress 控制器就會配置一個特定於實現的負載均衡器來滿足 Ingress。完成此操作後,你可以在 Address 欄位中看到負載均衡器的地址。

基於名稱的虛擬主機

基於名稱的虛擬主機支援將 HTTP 流量路由到相同 IP 地址上的多個主機名。

ingress-namebase-diagram

圖。Ingress 基於名稱的虛擬主機

以下 Ingress 指示後端負載均衡器根據 Host header 路由請求。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress
spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: bar.foo.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80

如果你建立了一個 Ingress 資源,但在規則中沒有定義任何主機,那麼任何指向 Ingress 控制器 IP 地址的 Web 流量都可以在不需要基於名稱的虛擬主機的情況下進行匹配。

例如,以下 Ingress 將請求 first.bar.com 的流量路由到 service1,將請求 second.bar.com 的流量路由到 service2,並將請求主機頭不匹配 first.bar.comsecond.bar.com 的任何流量路由到 service3

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: name-virtual-host-ingress-no-third-host
spec:
  rules:
  - host: first.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service1
            port:
              number: 80
  - host: second.bar.com
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service2
            port:
              number: 80
  - http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: service3
            port:
              number: 80

TLS

你可以透過指定一個包含 TLS 私鑰和證書的 Secret 來保護 Ingress。Ingress 資源只支援單個 TLS 埠 443,並假定在 Ingress 入口點進行 TLS 終止(到 Service 及其 Pod 的流量是明文的)。如果 Ingress 中的 TLS 配置部分指定了不同的主機,它們將根據 SNI TLS 擴充套件指定的主機名在同一埠上進行多路複用(前提是 Ingress 控制器支援 SNI)。TLS Secret 必須包含名為 tls.crttls.key 的鍵,它們包含用於 TLS 的證書和私鑰。例如:

apiVersion: v1
kind: Secret
metadata:
  name: testsecret-tls
  namespace: default
data:
  tls.crt: base64 encoded cert
  tls.key: base64 encoded key
type: kubernetes.io/tls

在 Ingress 中引用此 Secret 會告訴 Ingress 控制器使用 TLS 保護從客戶端到負載均衡器的通道。你需要確保你建立的 TLS Secret 來自包含 https-example.foo.com 的通用名稱 (CN)(也稱為完全限定域名 (FQDN))的證書。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-example-ingress
spec:
  tls:
  - hosts:
      - https-example.foo.com
    secretName: testsecret-tls
  rules:
  - host: https-example.foo.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: service1
            port:
              number: 80

負載均衡

Ingress 控制器透過一些負載均衡策略設定進行引導,這些設定適用於所有 Ingress,例如負載均衡演算法、後端權重方案等。更高階的負載均衡概念(例如持久會話、動態權重)尚未透過 Ingress 公開。你可以透過用於 Service 的負載均衡器來獲取這些功能。

還值得注意的是,儘管健康檢查沒有直接透過 Ingress 公開,但在 Kubernetes 中存在並行概念,例如 readiness probes,它們允許你實現相同的最終結果。請檢視特定於控制器的文件,瞭解它們如何處理健康檢查(例如:nginxGCE)。

更新 Ingress

要更新現有 Ingress 以新增新的 Host,你可以透過編輯資源來更新它

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     35s                loadbalancer-controller  default/test
kubectl edit ingress test

這將彈出一個以 YAML 格式顯示現有配置的編輯器。修改它以包含新的 Host。

spec:
  rules:
  - host: foo.bar.com
    http:
      paths:
      - backend:
          service:
            name: service1
            port:
              number: 80
        path: /foo
        pathType: Prefix
  - host: bar.baz.com
    http:
      paths:
      - backend:
          service:
            name: service2
            port:
              number: 80
        path: /foo
        pathType: Prefix
..

儲存更改後,kubectl 會更新 API 伺服器中的資源,這會告訴 Ingress 控制器重新配置負載均衡器。

驗證這一點

kubectl describe ingress test
Name:             test
Namespace:        default
Address:          178.91.123.132
Default backend:  default-http-backend:80 (10.8.2.3:8080)
Rules:
  Host         Path  Backends
  ----         ----  --------
  foo.bar.com
               /foo   service1:80 (10.8.0.90:80)
  bar.baz.com
               /foo   service2:80 (10.8.0.91:80)
Annotations:
  nginx.ingress.kubernetes.io/rewrite-target:  /
Events:
  Type     Reason  Age                From                     Message
  ----     ------  ----               ----                     -------
  Normal   ADD     45s                loadbalancer-controller  default/test

你也可以透過對修改後的 Ingress YAML 檔案呼叫 kubectl replace -f 來實現相同的效果。

跨可用區故障

在不同的雲提供商之間,跨故障域分散流量的技術有所不同。請查閱相關 Ingress 控制器 的文件以獲取詳細資訊。

替代方案

你可以透過多種方式暴露 Service,這些方式不直接涉及 Ingress 資源:

下一步

上次修改時間:2024 年 9 月 13 日太平洋標準時間上午 9:33:修復 markdown 檔案中的一些超連結 (e6855623c7)