參考:
https://kubernetes.github.io/ingress-nginx/examples/
https://github.com/kubernetes/ingress-nginx/tree/main/docs/examples
https://cloud.tencent.com/developer/article/1761376
Ingress示例介紹

先決條件
TLS證書
除非另有說明,在示例中使用的TLS秘密是2048位RSA密鑰/證書對與任意選擇的主機名,創建如下:
$ openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
Generating a 2048 bit RSA private key
................+++
................+++
writing new private key to 'tls.key'
-----
$ kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret "tls-secret" created
注意:如果使用CA認證,如下所述,您將需要與CA簽署服務器證書
客戶端證書認證
CA認證也被稱為相互身份驗證允許服務器和客戶端通過一個共同的CA.驗證對方的身份
我們有一個通常從證書頒發機構獲得的 CA 證書,並使用它來簽署我們的服務器證書和客戶端證書。 那么每次我們要訪問我們的后端時,都必須通過客戶端證書。
生成 CA 密鑰和證書:
openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=My Cert Authority'
生成服務器密鑰和證書並使用 CA 證書簽名:
openssl req -new -newkey rsa:4096 -keyout server.key -out server.csr -nodes -subj '/CN=mydomain.com'
openssl x509 -req -sha256 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt
生成客戶端密鑰和證書並使用 CA 證書簽名:
openssl req -new -newkey rsa:4096 -keyout client.key -out client.csr -nodes -subj '/CN=My Client'
openssl x509 -req -sha256 -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt
完成后,您可以繼續按照此處(https://kubernetes.github.io/ingress-nginx/examples/auth/client-certs/#creating-certificate-secrets)的說明進行操作。
測試 HTTP 服務
所有需要測試 HTTP 服務的示例都使用標准的 http-svc pod,您可以按如下方式部署:
$ kubectl create -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/docs/examples/http-svc.yaml
service "http-svc" created
replicationcontroller "http-svc" created
$ kubectl get po
NAME READY STATUS RESTARTS AGE
http-svc-p1t3t 1/1 Running 0 1d
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-svc 10.0.122.116 <pending> 80:30301/TCP 1d
您可以通過暫時公開它來測試 HTTP 服務是否有效:
$ kubectl patch svc http-svc -p '{"spec":{"type": "LoadBalancer"}}'
"http-svc" patched
$ kubectl get svc http-svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
http-svc 10.0.122.116 <pending> 80:30301/TCP 1d
$ kubectl describe svc http-svc
Name: http-svc
Namespace: default
Labels: app=http-svc
Selector: app=http-svc
Type: LoadBalancer
IP: 10.0.122.116
LoadBalancer Ingress: 108.59.87.136
Port: http 80/TCP
NodePort: http 30301/TCP
Endpoints: 10.180.1.6:8080
Session Affinity: None
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {service-controller } Normal Type ClusterIP -> LoadBalancer
1m 1m 1 {service-controller } Normal CreatingLoadBalancer Creating load balancer
16s 16s 1 {service-controller } Normal CreatedLoadBalancer Created load balancer
$ curl 108.59.87.136
CLIENT VALUES:
client_address=10.240.0.3
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://108.59.87.136:8080/
SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001
HEADERS RECEIVED:
accept=*/*
host=108.59.87.136
user-agent=curl/7.46.0
BODY:
-no body in request-
$ kubectl patch svc http-svc -p '{"spec":{"type": "NodePort"}}'
"http-svc" patched
粘性會話
示例:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-test
annotations:
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "route"
nginx.ingress.kubernetes.io/session-cookie-expires: "172800"
nginx.ingress.kubernetes.io/session-cookie-max-age: "172800"
spec:
rules:
- host: stickyingress.example.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
驗證:
$ kubectl describe ing nginx-test
Name: nginx-test
Namespace: default
Address:
Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
Rules:
Host Path Backends
---- ---- --------
stickyingress.example.com
/ nginx-service:80 (<none>)
Annotations:
affinity: cookie
session-cookie-name: INGRESSCOOKIE
session-cookie-expires: 172800
session-cookie-max-age: 172800
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test
$ curl -I http://stickyingress.example.com
HTTP/1.1 200 OK
Server: nginx/1.11.9
Date: Fri, 10 Feb 2017 14:11:12 GMT
Content-Type: text/html
Content-Length: 612
Connection: keep-alive
Set-Cookie: INGRESSCOOKIE=a9907b79b248140b56bb13723f72b67697baac3d; Expires=Sun, 12-Feb-17 14:11:12 GMT; Max-Age=172800; Path=/; HttpOnly
Last-Modified: Tue, 24 Jan 2017 14:02:19 GMT
ETag: "58875e6b-264"
Accept-Ranges: bytes
基本認證
$ htpasswd -c auth foo
New password: <bar>
New password:
Re-type new password:
Adding password for user foo
$ kubectl create secret generic basic-auth --from-file=auth
secret "basic-auth" created
$ kubectl get secret basic-auth -o yaml
apiVersion: v1
data:
auth: Zm9vOiRhcHIxJE9GRzNYeWJwJGNrTDBGSERBa29YWUlsSDkuY3lzVDAK
kind: Secret
metadata:
name: basic-auth
namespace: default
type: Opaque
echo "
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-with-auth
annotations:
# type of authentication
nginx.ingress.kubernetes.io/auth-type: basic
# name of the secret that contains the user/password definitions
nginx.ingress.kubernetes.io/auth-secret: basic-auth
# message to display with an appropriate context why the authentication is required
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - foo'
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /
backend:
serviceName: http-svc
servicePort: 80
" | kubectl create -f -
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com'
* Trying 10.2.29.4...
* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
> GET / HTTP/1.1
> Host: foo.bar.com
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Server: nginx/1.10.0
< Date: Wed, 11 May 2016 05:27:23 GMT
< Content-Type: text/html
< Content-Length: 195
< Connection: keep-alive
< WWW-Authenticate: Basic realm="Authentication Required - foo"
<
<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.10.0</center>
</body>
</html>
* Connection #0 to host 10.2.29.4 left intact
$ curl -v http://10.2.29.4/ -H 'Host: foo.bar.com' -u 'foo:bar'
* Trying 10.2.29.4...
* Connected to 10.2.29.4 (10.2.29.4) port 80 (#0)
* Server auth using Basic with user 'foo'
> GET / HTTP/1.1
> Host: foo.bar.com
> Authorization: Basic Zm9vOmJhcg==
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.10.0
< Date: Wed, 11 May 2016 06:05:26 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
<
CLIENT VALUES:
client_address=10.2.29.4
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://foo.bar.com:8080/
SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001
HEADERS RECEIVED:
accept=*/*
connection=close
host=foo.bar.com
user-agent=curl/7.43.0
x-request-id=e426c7829ef9f3b18d40730857c3eddb
x-forwarded-for=10.2.29.1
x-forwarded-host=foo.bar.com
x-forwarded-port=80
x-forwarded-proto=http
x-real-ip=10.2.29.1
x-scheme=http
BODY:
* Connection #0 to host 10.2.29.4 left intact
-no body in request-
客戶端證書認證
kubectl create secret generic ca-secret --from-file=ca.crt=ca.crt
kubectl create secret generic tls-secret --from-file=tls.crt=server.crt --from-file=tls.key=server.key
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
# Enable client certificate authentication
nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
# Create the secret containing the trusted ca certificates
nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
# Specify the verification depth in the client certificates chain
nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
# Specify an error page to be redirected to verification errors
nginx.ingress.kubernetes.io/auth-tls-error-page: "http://www.mysite.com/error-cert.html"
# Specify if certificates are passed to upstream server
nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
name: nginx-test
namespace: default
spec:
rules:
- host: mydomain.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
tls:
- hosts:
- mydomain.com
secretName: tls-secret
外部基本認證
$ kubectl create -f ingress.yaml
ingress "external-auth" created
$ kubectl get ing external-auth
NAME HOSTS ADDRESS PORTS AGE
external-auth external-auth-01.sample.com 172.17.4.99 80 13s
$ kubectl get ing external-auth -o yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-url: https://httpbin.org/basic-auth/user/passwd
creationTimestamp: 2016-10-03T13:50:35Z
generation: 1
name: external-auth
namespace: default
resourceVersion: "2068378"
selfLink: /apis/networking/v1beta1/namespaces/default/ingresses/external-auth
uid: 5c388f1d-8970-11e6-9004-080027d2dc94
spec:
rules:
- host: external-auth-01.sample.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
status:
loadBalancer:
ingress:
- ip: 172.17.4.99
$
外部 OAUTH 認證
...
metadata:
name: application
annotations:
nginx.ingress.kubernetes.io/auth-url: "https://$host/oauth2/auth"
nginx.ingress.kubernetes.io/auth-signin: "https://$host/oauth2/start?rd=$escaped_request_uri"
...
自定義headers(configuration-snippet)
適用於特定Ingress:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Request-Id: $req_id";
spec:
rules:
- host: custom.configuration.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
使用於所有Ingress:
apiVersion: v1
data:
X-Different-Name: "true"
X-Request-Start: t=${msec}
X-Using-Nginx-Controller: "true"
kind: ConfigMap
metadata:
name: custom-headers
namespace: ingress-nginx
apiVersion: v1
data:
proxy-set-headers: "ingress-nginx/custom-headers"
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
自定義配置
使用 ConfigMap 可以自定義 NGINX 配置。
例如,如果我們想更改超時,我們需要創建一個 ConfigMap:
$ cat configmap.yaml
apiVersion: v1
data:
proxy-connect-timeout: "10"
proxy-read-timeout: "120"
proxy-send-timeout: "120"
kind: ConfigMap
metadata:
name: ingress-nginx-controller
如果 Configmap 更新,NGINX 將使用新配置重新加載。
Sysctl 調優
調優參數:
net.core.somaxconn = 32768
net.ipv4.ip_local_port_range 1024 65000
此示例旨在演示使用 Init Container 來調整 sysctl 默認值 kubectl patch
kubectl patch deployment -n ingress-nginx nginx-ingress-controller \
--patch="$(curl https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/docs/examples/customization/sysctl/patch.json)"
變化:
- 積壓隊列設置 net.core.somaxconn從 128至 32768
- 臨時端口設置 net.ipv4.ip_local_port_range從 32768 60999至 1024 65000
在 NGINX 博客的一篇文章中(https://www.nginx.com/blog/tuning-nginx/),可以看到對這些變化的解釋。
重寫
部署
可以使用以下注釋控制重寫:

例子
重寫目標
從版本 0.22.0 開始,使用注解的入口定義 nginx.ingress.kubernetes.io/rewrite-target不向后兼容以前的版本。 在版本 0.22.0 及更高版本中,請求 URI 中需要傳遞到重寫路徑的任何子字符串都必須在 明確定義 捕獲組中 。
捕獲的組 按時間順序保存在編號的占位符中,格式為 $1, $2 ... $n. 這些占位符可以用作參數 rewrite-target注解。
創建帶有重寫注釋的 Ingress 規則:
$ echo '
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
' | kubectl create -f -
在這個入口定義中,任何被捕獲的字符 (.*)將分配給占位符 $2,然后將其用作參數 rewrite-target注解。
例如,上面的入口定義將導致以下重寫:
- rewrite.bar.com/something 改寫為 rewrite.bar.com/
- rewrite.bar.com/something/ 改寫為 rewrite.bar.com/
- rewrite.bar.com/something/new 改寫為 rewrite.bar.com/new
應用程序根
創建帶有 app-root 注釋的 Ingress 規則:
$ echo "
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/app-root: /app1
name: approot
namespace: default
spec:
rules:
- host: approot.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
" | kubectl create -f -
檢查重寫是否有效
$ curl -I -k http://approot.bar.com/
HTTP/1.1 302 Moved Temporarily
Server: nginx/1.11.10
Date: Mon, 13 Mar 2017 14:57:15 GMT
Content-Type: text/html
Content-Length: 162
Location: http://stickyingress.example.com/app1
Connection: keep-alive
一個完整示例
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: todo
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/app-root: /app/
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/configuration-snippet: | ## 借助 ingress-nginx 中的 configuration-snippet 來對靜態資源做一次跳轉
rewrite ^(/app)$ $1/ redirect; ## 應用在最后添加一個 / 這樣的 slash
rewrite ^/stylesheets/(.*)$ /app/stylesheets/$1 redirect;
rewrite ^/images/(.*)$ /app/images/$1 redirect;
spec:
rules:
- host: todo.example.com
http:
paths:
- backend:
serviceName: todo
servicePort: 3000
path: /app(/|$)(.*)
TLS 終止
部署
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: nginx-test
spec:
tls:
- hosts:
- foo.bar.com
# This assumes tls-secret exists and the SSL
# certificate contains a CN for foo.bar.com
secretName: tls-secret
rules:
- host: foo.bar.com
http:
paths:
- path: /
backend:
# This assumes http-svc exists and routes to healthy endpoints
serviceName: http-svc
servicePort: 80
驗證
$ kubectl describe ing nginx-test
Name: nginx-test
Namespace: default
Address: 104.198.183.6
Default backend: default-http-backend:80 (10.180.0.4:8080,10.240.0.2:8080)
TLS:
tls-secret terminates
Rules:
Host Path Backends
---- ---- --------
*
http-svc:80 (<none>)
Annotations:
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
7s 7s 1 {nginx-ingress-controller } Normal CREATE default/nginx-test
7s 7s 1 {nginx-ingress-controller } Normal UPDATE default/nginx-test
7s 7s 1 {nginx-ingress-controller } Normal CREATE ip: 104.198.183.6
7s 7s 1 {nginx-ingress-controller } Warning MAPPING Ingress rule 'default/nginx-test' contains no path definition. Assuming /
$ curl 104.198.183.6 -L
curl: (60) SSL certificate problem: self signed certificate
More details here: http://curl.haxx.se/docs/sslcerts.html
$ curl 104.198.183.6 -Lk
CLIENT VALUES:
client_address=10.240.0.4
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://35.186.221.137:8080/
SERVER VALUES:
server_version=nginx: 1.9.11 - lua: 10001
HEADERS RECEIVED:
accept=*/*
connection=Keep-Alive
host=35.186.221.137
user-agent=curl/7.46.0
via=1.1 google
x-cloud-trace-context=f708ea7e369d4514fc90d51d7e27e91d/13322322294276298106
x-forwarded-for=104.132.0.80, 35.186.221.137
x-forwarded-proto=https
BODY:
Pod 安全策略 (PSP)
在今天的大多數集群中,默認情況下,所有資源(例如 Deployments 和 ReplicatSets)都具有創建 pod 的權限。 然而,Kubernetes 提供了一種更細粒度的授權策略,稱為 Pod 安全策略 (PSP) 。
PSP 允許集群所有者定義每個對象的權限,例如創建 pod。 如果您在集群上啟用了 PSP,並且您部署了 ingress-nginx,您將需要為 Deployment 提供創建 pod 的權限。
在應用任何對象之前,首先通過運行來應用 PSP 權限:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/docs/examples/psp/psp.yaml
注意:必須在創建 Deployment 和 ReplicaSet 之前授予 PSP 權限。
灰度發布
在日常工作中我們經常需要對服務進行版本更新升級,所以我們經常會使用到滾動升級、藍綠發布、灰度發布等不同的發布操作。而 ingress-nginx 支持通過 Annotations 配置來實現不同場景下的灰度發布和測試,可以滿足金絲雀發布、藍綠部署與 A/B 測試等業務場景。ingress-nginx 的 Annotations 支持以下 4 種 Canary 規則:
-
nginx.ingress.kubernetes.io/canary-by-header:基於 Request Header 的流量切分,適用於灰度發布以及 A/B 測試。當 Request Header 設置為 always 時,請求將會被一直發送到 Canary 版本;當 Request Header 設置為 never時,請求不會被發送到 Canary 入口;對於任何其他 Header 值,將忽略 Header,並通過優先級將請求與其他金絲雀規則進行優先級的比較。
-
nginx.ingress.kubernetes.io/canary-by-header-value:要匹配的 Request Header 的值,用於通知 Ingress 將請求路由到 Canary Ingress 中指定的服務。當 Request Header 設置為此值時,它將被路由到 Canary 入口。該規則允許用戶自定義 Request Header 的值,必須與上一個 annotation (即:canary-by-header) 一起使用。
-
nginx.ingress.kubernetes.io/canary-weight:基於服務權重的流量切分,適用於藍綠部署,權重范圍 0 - 100 按百分比將請求路由到 Canary Ingress 中指定的服務。權重為 0 意味着該金絲雀規則不會向 Canary 入口的服務發送任何請求,權重為 100 意味着所有請求都將被發送到 Canary 入口。
-
nginx.ingress.kubernetes.io/canary-by-cookie:基於 cookie 的流量切分,適用於灰度發布與 A/B 測試。用於通知 Ingress 將請求路由到 Canary Ingress 中指定的服務的cookie。當 cookie 值設置為 always 時,它將被路由到 Canary 入口;當 cookie 值設置為 never 時,請求不會被發送到 Canary 入口;對於任何其他值,將忽略 cookie 並將請求與其他金絲雀規則進行優先級的比較。
需要注意的是金絲雀規則按優先順序進行排序:canary-by-header - > canary-by-cookie - > canary-weight
總的來說可以把以上的四個 annotation 規則划分為以下兩類:
- 基於權重的 Canary 規則

- 基於用戶請求的 Canary 規則

示例
創建一個用於 production 環境訪問的 Ingress 資源對象:
# production-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: production
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: echo.example.com
http:
paths:
- backend:
serviceName: production
servicePort: 80
命令行訪問應用:
curl echo.example.com
1.基於權重:基於權重的流量切分的典型應用場景就是藍綠部署,可通過將權重設置為 0 或 100 來實現。例如,可將 Green 版本設置為主要部分,並將 Blue 版本的入口配置為 Canary。最初,將權重設置為 0,因此不會將流量代理到 Blue 版本。一旦新版本測試和驗證都成功后,即可將 Blue 版本的權重設置為 100,即所有流量從 Green 版本轉向 Blue。
創建一個基於權重的 Canary 版本的應用路由 Ingress 對象。
# canary-ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: canary
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
nginx.ingress.kubernetes.io/canary-weight: "30" # 分配30%流量到當前Canary版本
spec:
rules:
- host: echo.example.com
http:
paths:
- backend:
serviceName: canary
servicePort: 80
命令行訪問應用:
curl -s echo.example.com
2.基於 Request Header: 基於 Request Header 進行流量切分的典型應用場景即灰度發布或 A/B 測試場景。
在上面的 Canary 版本的 Ingress 對象中新增一條 annotation 配置 nginx.ingress.kubernetes.io/canary-by-header: canary(這里的 value 可以是任意值),使當前的 Ingress 實現基於 Request Header 進行流量切分,由於 canary-by-header 的優先級大於 canary-weight,所以會忽略原有的 canary-weight 的規則。
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
nginx.ingress.kubernetes.io/canary-by-header: canary # 基於header的流量切分
nginx.ingress.kubernetes.io/canary-weight: "30" # 會被忽略,因為配置了 canary-by-header Canary版本
注意:當 Request Header 設置為 never 或 always 時,請求將不會或一直被發送到 Canary 版本,對於任何其他 Header 值,將忽略 Header,並通過優先級將請求與其他 Canary 規則進行優先級的比較。
命令行訪問應用:
curl -s -H "canary: never" echo.example.com
curl -s -H "canary: always" echo.example.com
curl -s -H "canary: other-value" echo.example.com
當我們請求設置的 Header 值為 canary: other-value 時,ingress-nginx 會通過優先級將請求與其他 Canary 規則進行優先級的比較,我們這里也就會進入 canary-weight: "30" 這個規則去。
這個時候我們可以在上一個 annotation (即 canary-by-header)的基礎上添加一條 nginx.ingress.kubernetes.io/canary-by-header-value: user-value 這樣的規則,就可以將請求路由到 Canary Ingress 中指定的服務了。
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
nginx.ingress.kubernetes.io/canary-by-header-value: user-value
nginx.ingress.kubernetes.io/canary-by-header: canary # 基於header的流量切分
nginx.ingress.kubernetes.io/canary-weight: "30" # 分配30%流量到當前Canary版本
同樣更新 Ingress 對象后,重新訪問應用,當 Request Header 滿足 canary: user-value 時,所有請求就會被路由到 Canary 版本。
curl -s -H "canary: user-value" echo.example.com
3.基於 Cookie:與基於 Request Header 的 annotation 用法規則類似。例如在 A/B 測試場景下,需要讓地域為北京的用戶訪問 Canary 版本。那么當 cookie 的 annotation 設置為 nginx.ingress.kubernetes.io/canary-by-cookie: "users_from_Beijing",此時后台可對登錄的用戶請求進行檢查,如果該用戶訪問源來自北京則設置 cookie users_from_Beijing 的值為 always,這樣就可以確保北京的用戶僅訪問 Canary 版本。
同樣我們更新 Canary 版本的 Ingress 資源對象,采用基於 Cookie 來進行流量切分:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: "true" # 要開啟灰度發布機制,首先需要啟用 Canary
nginx.ingress.kubernetes.io/canary-by-cookie: "users_from_Beijing" # 基於 cookie
nginx.ingress.kubernetes.io/canary-weight: "30" # 會被忽略,因為配置了 canary-by-cookie
更新上面的 Ingress 資源對象后,我們在請求中設置一個 users_from_Beijing=always 的 Cookie 值,再次訪問應用的域名:
curl -s -b "users_from_Beijing=always" echo.example.com
可以看到應用都被路由到了 Canary 版本的應用中去了,如果我們將這個 Cookie 值設置為 never,則不會路由到 Canary 應用中。
