kubernetes雲原生紀元:領悟 Ingress Nginx(下)

kubernetes雲原生紀元:領悟 Ingress Nginx(下)

續領悟Ingress Nginx(中)


解決https 證書問題

ingress-nginx 配置證書

  1. 生產證書

    首先生成一個證書gen-secret.sh腳步生成證書,輸出一個key 一個密鑰

注意這裏我生成完後直接在kubernetes 創建了secret

kubectl create secret tls mooc-tls --key mooc.key --cert mooc.crt

gen-secret.sh

#!/bin/bash

openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout mooc.key -out mooc.crt -subj "/CN=*.mooc.com/O=*.mooc.com"

kubectl create secret tls mooc-tls --key mooc.key --cert mooc.crt

生成證書

[root@master-001 ~]# sh gen-secret.sh
Generating a 2048 bit RSA private key
.........+++
..........................+++
writing new private key to 'mooc.key'
-----
secret/mooc-tls created

我們查看 ,tls.crt是kubernetes 的規範

[root@master-001 ~]# kubectl get secret mooc-tls -o yaml
apiVersion: v1
data:
  tls.crt: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURKekNDQWcrZ0F3SUJBZ0lKQUlCTGUrTEVEcEJSTUEwR0NTcUdTSWIzRFFFQkN3VUFNQ...
  tls.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2QUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktZd2dnU2lBZ0VBQW9JQkF.....
kind: Secret
metadata:
  creationTimestamp: "2020-01-28T13:48:54Z"
  name: mooc-tls
  namespace: dev
  resourceVersion: "334008"
  selfLink: /api/v1/namespaces/dev/secrets/mooc-tls
  uid: d12f095c-a79b-4765-a06f-62d32d731eeb
type: kubernetes.io/tls
  1. 證書掛載到ingress-controller

修改nginx-ingress-controller,在配置中增加==–default-ssl-certifcate=default/mooc-tls==,意思是指定default命名空間下的mooc-tls

[root@master-001 ~]# vi nginx-ingress-controller.yaml
apiVersion: apps/v1
kind: DaemonSet 
metadata:
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  name: nginx-ingress-controller
  namespace: ingress-nginx
spec:
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  updateStrategy:
    rollingUpdate:
      maxUnavailable: 1
    type: RollingUpdate
  template:
    metadata:
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
      creationTimestamp: null
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
    spec:
      containers:
      - args:
        - /nginx-ingress-controller
        - --configmap=$(POD_NAMESPACE)/nginx-configuration
        - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
        - --udp-services-configmap=$(POD_NAMESPACE)/udp-services
        - --publish-service=$(POD_NAMESPACE)/ingress-nginx
        - --annotations-prefix=nginx.ingress.kubernetes.io
        - --default-ssl-certifcate=default/mooc-tls #看這裏
        # 增加數據卷掛載,
        volumeMounts:
          - mountPath: /etc/nginx/template
            name: nginx-template
            readOnly: true
            # end
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.namespace
        image: siriuszg/nginx-ingress-controller:latest
        imagePullPolicy: Always
        lifecycle:
          preStop:
            exec:
              command:
              - /wait-shutdown
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          initialDelaySeconds: 10
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 10
        name: nginx-ingress-controller
        ports:
        - containerPort: 80
          hostPort: 80
          name: http
          protocol: TCP
        - containerPort: 443
          hostPort: 443
          name: https
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /healthz
            port: 10254
            scheme: HTTP
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 10
        resources: {}
        securityContext:
          allowPrivilegeEscalation: true
          capabilities:
            add:
            - NET_BIND_SERVICE
            drop:
            - ALL
          runAsUser: 33
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      hostNetwork: true 
      nodeSelector:
        kubernetes.io/os: linux
        app: ingress 
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: nginx-ingress-serviceaccount
      serviceAccountName: nginx-ingress-serviceaccount
      terminationGracePeriodSeconds: 300
       # 通過configmap指定我們上面創建的nginx.tmpl
      volumes:
        - name: nginx-template-volume
          configMap:
            name: nginx-template
            items:
            - key: nginx.tmpl
              path: nginx.tmpl

更新一下

[root@master-001 ~]# kubectl apply -f nginx-ingress-controller.yaml
daemonset.apps/nginx-ingress-controller configured

3 . 指定域名使用創建的tls

然後具體給哪個服務指定一下域名使用哪個tls ,我們給你web-demo 服務指定一下

測試的機器上必須有web-demo這個服務

web-ingress.yaml

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web-demo
  namespace: dev
spec:
  rules:
  - host: web-dev.mooc.com
    http:
      paths:
      - backend:
          serviceName: web-demo
          servicePort: 80
        path: /
  tls:
    - hosts:
      - web-dev.mooc.com
      secretName: mooc-tls #指定我們剛創建的tls

創建一下

[root@master-001 ~]# kubectl apply -f web-ingress.yaml
ingress.extensions/web-demo configured

否則沒有他就不會創建一個web-dev.mooc.comhttps的服務

  1. 訪問測試

直接在瀏覽器訪問https://web-dev.mooc.com 就可以看到他返回了,表示我們這裏配置證書成功

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-UyEMmyjS-1580869872957)(/Users/zck/Library/Application Support/typora-user-images/image-20200128225447406.png)]

解決問題訪問控制

ingress-nginx session保持

web服務需要會話保持的,需要訪問同一個後端

環境:

有一個service ,有兩個後端一個是web版本一個spring-boot版本,service 輪訓訪問這個兩個後端

配置信息在領悟 Ingress Nginx(上)環境部分有,這裏不展示

Web 版本訪問

image-20200201103846635

spring-boot版本訪問

image-20200201103927662

我們直接修改ingress的配置增加session保持就可以實現只是訪問一個後端

ingress-session.yaml

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/affinity: cookie # cookine保存
    nginx.ingress.kubernetes.io/session-cookie-hash: sha1 # session 算法
    nginx.ingress.kubernetes.io/session-cookie-name: route # 隨便起的一個名字 ,cookie 名字
  name: spring-boot-demo
 # namespace: dev
spec:
  rules:
  - host: spring-boot.demo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: spring-boot-demo
          servicePort: 80

創建下

[root@master-001 ~]# kubectl apply -f ingress-session.yaml
ingress.extensions/spring-boot-demo created

這樣他就一直保持一個後端訪問了

image-20200201094447019

ingress+ 金絲雀模式 流量控制

小流量 剛上線不知道服務有沒有問題先把流量切到剛上線的服務切10%,沒有問題開20%,50%,100%。

流量控制基於金絲雀模式

ingress-nginx 從 0.21.0 開始支持金絲雀(canary)模式

金絲雀annotations使Ingress規範可以作爲路由到請求的替代服務

 annotations:
   nginx.ingress.kubernetes.io/canary: "true"
   nginx.ingress.kubernetes.io/canary-by-header: "version"
   nginx.ingress.kubernetes.io/canary-by-header-value: "canary"
   nginx.ingress.kubernetes.io/canary-by-cookie: "canary-cookie"
   nginx.ingress.kubernetes.io/canary-weight: <weight>

nginx.ingress.kubernetes.io/canary-by-header用於通知Ingress將請求路由到Canary Ingress中指定的服務的標頭。當請求標頭設置always時,它將被路由到金絲雀。當標頭設置never爲時,它將永遠不會被路由到金絲雀。對於任何其他值,將忽略標頭,並通過優先級將請求與其他金絲雀規則進行比較。nginx.ingress.kubernetes.io/canary-by-header-value: 要匹配的標頭值,用於通知Ingress將請求路由到Canary Ingress中指定的服務。當請求標頭設置爲此值時,它將被路由到金絲雀。對於任何其他標頭值,標頭將被忽略,並且請求與其他金絲雀規則的優先級進行比較。此註釋必須與nginx.ingress.kubernetes.io/canary-by-header一起使用。nginx.ingress.kubernetes.io/canary-by-header允許自定義標頭值而不是使用硬編碼值的擴展。如果nginx.ingress.kubernetes.io/canary-by-header未定義註釋,則沒有任何效果。

nginx.ingress.kubernetes.io/canary-by-cookie: 用於通知Ingress將請求路由到Canary Ingress中指定的服務的cookie。當cookie值設置always時,它將被路由到金絲雀。當cookie被設置never時,它將永遠不會被路由到金絲雀。對於任何其他值,將忽略cookie並將請求與其他金絲雀規則進行優先比較。

nginx.ingress.kubernetes.io/canary-weight: 該路由到金絲雀Ingress中指定的服務的隨機請求的整數(0 – 100)百分比。權重爲0意味着該金絲雀規則不會向Canary入口中的服務發送任何請求。權重爲100意味着所有請求都將被髮送到Ingress中指定的替代服務。

優先順序如下: canary-by-header -> canary-by-cookie -> canary-weight
已知限制目前,每個Ingress規則最多可以應用一個金絲雀入口。

場景:我現在有兩個服務分別是web-canary-aweb-canary-b同時都有service,然後有一個ingress名字是web-canary-a,他只訪問 web-canary-a的服務,這時候我們要上線web-canary-b

web-canary-a.yaml

#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-canary-a
  namespace: canary
spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  selector:
    matchLabels:
      app: web-canary-a
  replicas: 1
  template:
    metadata:
      labels:
        app: web-canary-a
    spec:
      containers:
      - name: web-canary-a
        image: hub.zhang.com/kubernetes/spring-boot-demo:v1 #版本不一樣
        ports:
        - containerPort: 8080
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 10
          failureThreshold: 3
          successThreshold: 1
          timeoutSeconds: 5
        readinessProbe:
          httpGet:
            path: /
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 20
          periodSeconds: 10
          failureThreshold: 1
          successThreshold: 1
          timeoutSeconds: 5
---
#service
apiVersion: v1
kind: Service
metadata:
  name: web-canary-a
  namespace: canary
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: web-canary-a
  type: ClusterIP

web-canary-b.yaml

#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-canary-b
  namespace: canary
spec:
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  selector:
    matchLabels:
      app: web-canary-b
  replicas: 1
  template:
    metadata:
      labels:
        app: web-canary-b
    spec:
      containers:
      - name: web-canary-b
        image: hub.zhang.com/kubernetes/spring-boot-demo:v2 #版本不一樣
        ports:
        - containerPort: 8080
        livenessProbe:
          tcpSocket:
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 10
          failureThreshold: 3
          successThreshold: 1
          timeoutSeconds: 5
        readinessProbe:
          httpGet:
            path: /
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 20
          periodSeconds: 10
          failureThreshold: 1
          successThreshold: 1
          timeoutSeconds: 5
---
#service
apiVersion: v1
kind: Service
metadata:
  name: web-canary-b
  namespace: canary
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: web-canary-b
  type: ClusterIP


ingress-common.yaml

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
 name: web-canary-a  
 namespace: canary
spec:
 rules:
 - host: canary.demo.com
   http:
     paths:
     - path: /
       backend:
         serviceName: web-canary-a #只是指定web-canary-a的service
         servicePort: 80

全部創建一下:

[root@master-001 ~]# kubectl apply -f web-canary-a.yaml
deployment.apps/web-canary-a created
service/web-canary-a created
[root@master-001 ~]# kubectl apply -f web-canary-b.yaml
deployment.apps/web-canary-b created
service/web-canary-b created
[root@master-001 ~]# kubectl apply -f ingress-common.yaml
ingress.extensions/web-canary-a created

這個時候我們只能訪問web-canary-a的服務

image-20200201102223544

ingress + 金絲雀模式 流量定向訪問

還是跟上面的流量控制一樣都依賴金絲雀模式實現

這個時候我們要上線web-canary-b而且流量只是給web-canary-b 10%

主要使用 金絲雀模式的 nginx.ingress.kubernetes.io/canary-weight:

image-20200201102705535

同一個域名服務canary.demo.com

nginx.ingress.kubernetes.io/canary: “true” # 開啓金絲雀
nginx.ingress.kubernetes.io/canary-weight: “10” # 流量權重分配爲10

nginx.ingress.kubernetes.io/canary-weight: 該路由到金絲雀Ingress中指定的服務的隨機請求的整數(0 – 100)百分比。權重爲0意味着該金絲雀規則不會向Canary入口中的服務發送任何請求。權重爲100意味着所有請求都將被髮送到Ingress中指定的替代服務。

ingress-weight.yaml

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web-canary-b
  namespace: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 開啓金絲雀
    nginx.ingress.kubernetes.io/canary-weight: "10" # 流量權重分配爲10
spec:
  rules:
  - host: canary.demo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web-canary-b
          servicePort: 80

創建下

[root@master-001 ~]# kubectl apply -f ingress-weight.yaml
ingress.extensions/web-canary-b created

我們偶爾可以看到web-canary-b,大部分都web-canary-b

image-20200201103846635

image-20200201103927662

沒問題就把 nginx.ingress.kubernetes.io/canary-weight: 改成90這樣全部百分90都是web-canary-b

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web-canary-b
  namespace: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 開啓金絲雀
    nginx.ingress.kubernetes.io/canary-weight: "90" # 流量權重分配爲90
spec:
  rules:
  - host: canary.demo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web-canary-b
          servicePort: 80


[root@master-001 ~]# kubectl apply -f ingress-weight.yaml
ingress.extensions/web-canary-b configured

還有一種場景就是我不讓用戶去訪問我們要上線的服務,讓測試人員去訪問,測試完成我在走上線流程。

nginx.ingress.kubernetes.io/canary-by-cookie: 用於通知Ingress將請求路由到Canary Ingress中指定的服務的cookie。當cookie值設置always時,它將被路由到金絲雀。當cookie被設置never時,它將永遠不會被路由到金絲雀。對於任何其他值,將忽略cookie並將請求與其他金絲雀規則進行優先比較

主要使用 金絲雀模式的 nginx.ingress.kubernetes.io/canary-by-cookie:

ingress-cookie.yaml

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web-canary-b
  namespace: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-cookie: "web-canary" # 設置金絲雀cookie 名字
spec:
  rules:
  - host: canary.demo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web-canary-b
          servicePort: 80

創建下

[root@master-001 ~]# kubectl apply -f ingress-cookie.yaml
ingress.extensions/web-canary-b configured

我們訪問下發現全是web-canary-a版本

image-20200201105718769

這個時候怎麼訪問web-canary-b 呢需要添加一個cookie名字上面我們在配置中寫的是web-canary,cookie值是always

注意:發現只有火狐瀏覽器可以添加cookie

image-20200201110327810

image-20200201110435624

這裏可以實現一個流量的定向訪問了,這種手動加cookie只是測試,

但是我們真實中舉個例子:

我們新上線的服務只是讓女性訪問,看下女性的反饋,男性還是訪問之前的,這樣我們就可以根據登錄用戶性別做出判斷,在程序設置cookie 值=always了。

除了 nginx.ingress.kubernetes.io/canary-by-cookie: 進行定向流量之外還可以通過header實現:nginx.ingress.kubernetes.io/canary-by-header:

主要使用 金絲雀模式的 nginx.ingress.kubernetes.io/canary-by-header:

還是通過web-canary-b測試

ingress-header.yaml

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web-canary-b
  namespace: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "web-canary"
spec:
  rules:
  - host: canary.demo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web-canary-b
          servicePort: 80

創建下

[root@master-001 ~]# kubectl apply -f ingress-header.yaml
ingress.extensions/web-canary-b configured

這時候瀏覽器已經只是訪問web-canary-a了,

image-20200201111800481

我們做測試可以用curl方便測試,我們看大加上header web-canary 值等於always 就訪問到web-canary-a

➜  ~ curl -H 'web-canary: always' http://canary.demo.com/
😄😂我有變了啦啦......%

nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "version"
nginx.ingress.kubernetes.io/canary-by-header-value: "canary"
nginx.ingress.kubernetes.io/canary-by-cookie: "canary-cookie"
nginx.ingress.kubernetes.io/canary-weight: <weight>

組合使用

優先級順序canary-by-header -> canary-by-cookie -> canary-weight

如果header就按他來,沒有就按 cookie,沒有cookie就按權重weight分配流量。

#ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: web-canary-b
  namespace: canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-by-header: "web-canary"
    nginx.ingress.kubernetes.io/canary-by-cookie: "web-canary"
    nginx.ingress.kubernetes.io/canary-weight: "90"
spec:
  rules:
  - host: canary.demo.com
    http:
      paths:
      - path: /
        backend:
          serviceName: web-canary-b
          servicePort: 80

創建下

[root@master-001 ~]# kubectl apply -f ingress-compose.yaml
ingress.extensions/web-canary-b configured

之前我們也講過金絲雀但是沒有配合ingress,ingress+金絲雀模式能把流量控制的很精準。

發佈了33 篇原創文章 · 獲贊 20 · 訪問量 2908
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章