【K8s教程】Nginx Ingress 控制器 Ingress 配置示例介紹

參考:
https://kubernetes.github.io/ingress-nginx/examples/
https://github.com/kubernetes/ingress-nginx/tree/main/docs/examples
https://cloud.tencent.com/developer/article/1761376html

Ingress示例介紹

先決條件

TLS證書

除非另有說明,在示例中使用的TLS祕密是2048位RSA密鑰/證書對與任意選擇的主機名,建立以下:node

$ 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簽署服務器證書nginx

客戶端證書認證

CA認證也被稱爲相互身份驗證容許服務器和客戶端經過一個共同的CA.驗證對方的身份git

咱們有一個一般從證書頒發機構得到的 CA 證書,並使用它來簽署咱們的服務器證書和客戶端證書。 那麼每次咱們要訪問咱們的後端時,都必須經過客戶端證書。github

這些說明基於如下博客(https://medium.com/@awkwardferny/configuring-certificate-based-mutual-authentication-with-kubernetes-ingress-nginx-20e7e38fdfca)json

生成 CA 密鑰和證書:後端

openssl req -x509 -sha256 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 356 -nodes -subj '/CN=My Cert Authority'

生成服務器密鑰和證書並使用 CA 證書籤名:api

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

一樣咱們更新 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 應用中。

相關文章
相關標籤/搜索