Ingress
Kubernetes v1.19 [stable]
一個 API 物件,用於管理叢集中服務的外部訪問,通常是 HTTP。
Ingress 可以提供負載均衡、SSL 終止和基於名稱的虛擬主機。
注意
Ingress 已凍結。新功能正在新增到 Gateway API 中。術語
為清楚起見,本指南定義以下術語
- 節點:Kubernetes 中的工作機器,叢集的一部分。
- 叢集:一組執行由 Kubernetes 管理的容器化應用程式的節點。在此示例中,以及在大多數常見的 Kubernetes 部署中,叢集中的節點不屬於公共網際網路。
- 邊緣路由器:為叢集實施防火牆策略的路由器。這可以是雲提供商管理的閘道器,也可以是物理硬體。
- 叢集網路:根據 Kubernetes 網路模型 促進叢集內部通訊的一組邏輯或物理鏈路。
- Service:一個 Kubernetes Service,它使用 標籤 選擇器識別一組 Pod。除非另有說明,否則假定 Service 具有僅在叢集網路內可路由的虛擬 IP。
什麼是 Ingress?
Ingress 將叢集外部的 HTTP 和 HTTPS 路由公開到叢集內部的服務。流量路由由 Ingress 資源上定義的規則控制。
這裡有一個簡單的例子,一個 Ingress 將所有流量傳送到一個 Service
圖:Ingress
Ingress 可以配置為向 Service 提供外部可訪問的 URL、負載均衡流量、終止 SSL/TLS 並提供基於名稱的虛擬主機。一個 Ingress 控制器 負責實現 Ingress,通常使用負載均衡器,但它也可以配置你的邊緣路由器或額外的前端來幫助處理流量。
Ingress 不會暴露任意埠或協議。將 HTTP 和 HTTPS 之外的服務暴露給網際網路通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 型別的服務。
先決條件
你必須有一個 Ingress 控制器 才能滿足 Ingress 的要求。僅僅建立一個 Ingress 資源是沒有任何作用的。
你可能需要部署一個 Ingress 控制器,例如 ingress-nginx。你可以從多個 Ingress 控制器 中進行選擇。
理想情況下,所有 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 需要 apiVersion
、kind
、metadata
和 spec
欄位。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.name
和service.port.name
或service.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
,也可以將其視為與Prefix
或Exact
路徑型別相同。Exact
:精確匹配 URL 路徑,區分大小寫。Prefix
:根據按/
分隔的 URL 路徑字首進行匹配。匹配區分大小寫,並逐個路徑元素進行。路徑元素是指路徑中按/
分隔的標籤列表。如果請求路徑的每個 p 都是 p 的元素字首,則請求與路徑 p 匹配。注意
如果路徑的最後一個元素是請求路徑中最後一個元素的子字串,則不匹配(例如:/foo/bar
匹配/foo/bar/baz
,但不匹配/foo/barbaz
)。
示例
種類 | 路徑 | 請求路徑 | 匹配? |
---|---|---|---|
字首 | / | (所有路徑) | 是 |
精確 | /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.com | bar.foo.com | 基於共享字尾匹配 |
*.foo.com | baz.bar.foo.com | 不匹配,萬用字元只覆蓋一個 DNS 標籤 |
*.foo.com | foo.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。
注意
如果你的叢集中有多個 IngressClass 被標記為預設,准入控制器將阻止建立未指定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。
注意
Ingress 控制器和負載均衡器可能需要一兩分鐘才能分配 IP 地址。在此之前,你通常會看到地址顯示為<pending>
。簡單扇出
扇出配置根據請求的 HTTP URI,將流量從單個 IP 地址路由到多個 Service。Ingress 允許你將負載均衡器數量降至最低。例如,一個像這樣的設定:
圖。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 基於名稱的虛擬主機
以下 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.com
和 second.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.crt
和 tls.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))的證書。
注意
請記住,TLS 不適用於預設規則,因為證書必須頒發給所有可能的子域。因此,tls
部分中的 hosts
需要與 rules
部分中的 host
顯式匹配。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,它們允許你實現相同的最終結果。請檢視特定於控制器的文件,瞭解它們如何處理健康檢查(例如:nginx 或 GCE)。
更新 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 資源: