k8s-部署策略

Kubernetes中有幾種不一樣的方式發佈應用,因此爲了讓應用在升級期間依然平穩提供服務,選擇一個正確的發佈策略就很是重要了。git

選擇正確的部署策略是要依賴於咱們的業務需求的,下面咱們列出了一些可能會使用到的策略:github

  • 重建(recreate):中止舊版本部署新版本shell

  • 滾動更新(rolling-update):一個接一個地以滾動更新方式發佈新版本api

  • 藍綠(blue/green):新版本與舊版本一塊兒存在,而後切換流量bash

  • 金絲雀(canary):將新版本面向一部分用戶發佈,而後繼續全量發佈cookie

  • A/B測(a/b testing):以精確的方式(HTTP 頭、cookie、權重等)向部分用戶發佈新版本。A/B測其實是一種基於數據統計作出業務決策的技術。在 Kubernetes 中並不原生支持,須要額外的一些高級組件來完成改設置(好比Istio、Linkerd、Traefik、或者自定義 Nginx/Haproxy 等)。app

你能夠在Kubernetes集羣上來對上面的這些策略進行測試,下面的倉庫中有須要使用到的資源清單:https://github.com/ContainerSolutions/k8s-deployment-strategies負載均衡

接下來咱們來介紹下每種策略,看看在什麼場景下面適合哪一種策略。curl

重建(Recreate) - 最好在開發環境

策略定義爲RecreateDeployment,會終止全部正在運行的實例,而後用較新的版原本從新建立它們。分佈式

 
 
spec:
  replicas: 3
  strategy:
    type: Recreate
 

RecreateRecreate

從新建立策略是一個虛擬部署,包括關閉版本A,而後在關閉版本A後部署版本B. 此技術意味着服務的停機時間取決於應用程序的關閉和啓動持續時間。

咱們這裏建立兩個相關的資源清單文件,app-v1.yaml:

apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: my-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v1.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          periodSeconds: 5

 

app-v2.yaml 文件內容以下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 3
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v2.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          periodSeconds: 5

 

上面兩個資源清單文件中的 Deployment 定義幾乎是一直的,惟一不一樣的是定義的環境變量VERSION值不一樣,接下來按照下面的步驟來驗證Recreate策略:

  1. 版本1提供服務
  2. 刪除版本1
  3. 部署版本2
  4. 等待全部副本準備就緒

首先部署第一個應用:

$ kubectl apply -f app-v1.yaml
service "my-app" created
deployment.apps "my-app" created

 

 

測試版本1是否部署成功:

$ kubectl get pods -l app=my-app
NAME                      READY     STATUS    RESTARTS   AGE
my-app-7b4874cd75-m5kct   1/1       Running   0          19m
my-app-7b4874cd75-pc444   1/1       Running   0          19m
my-app-7b4874cd75-tlctl   1/1       Running   0          19m
$ kubectl get svc my-app
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
my-app    NodePort   10.108.238.76   <none>        80:32532/TCP   5m
$ curl http://127.0.0.1:32532
Host: my-app-7b4874cd75-pc444, Version: v1.0.0

 

 

能夠看到版本1的應用正常運行了。爲了查看部署的運行狀況,打開一個新終端並運行如下命令:

$ watch kubectl get po -l app=my-app

而後部署版本2的應用:

$ kubectl apply -f app-v2.yaml

這個時候能夠觀察上面新開的終端中的 Pod 列表的變化,能夠看到以前的3個 Pod 都會先處於Terminating狀態,而且3個 Pod 都被刪除後纔開始建立新的 Pod。

而後測試第二個版本應用的部署進度:

$ while sleep 0.1; do curl http://127.0.0.1:32532; done
curl: (7) Failed connect to 127.0.0.1:32532; Connection refused
curl: (7) Failed connect to 127.0.0.1:32532; Connection refused
......
Host: my-app-f885c8d45-sp44p, Version: v2.0.0
Host: my-app-f885c8d45-t8g7g, Version: v2.0.0
Host: my-app-f885c8d45-sp44p, Version: v2.0.0

能夠看到最開始的階段服務都是處於不可訪問的狀態,而後到第二個版本的應用部署成功後才正常訪問,能夠看到如今訪問的數據是版本2了。

最後,能夠執行下面的命令來清空上面的資源對象:

$ kubectl delete all -l app=my-app

結論:

  • 應用狀態所有更新

  • 停機時間取決於應用程序的關閉和啓動消耗的時間

滾動更新(rolling-update)

滾動更新經過逐個替換實例來逐步部署新版本的應用,直到全部實例都被替換完成爲止。它一般遵循如下過程:在負載均衡器後面使用版本 A 的實例池,而後部署版本 B 的一個實例,當服務準備好接收流量時(Readiness Probe 正常),將該實例添加到實例池中,而後從實例池中刪除一個版本 A 的實例並關閉,以下圖所示:

rampedramped

下圖是滾動更新過程應用接收流量的示意圖:

rolling-update requestsrolling-update requests

下面是 Kubernetes 中經過 Deployment 來進行滾動更新的關鍵參數:

spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2        # 一次能夠添加多少個Pod
      maxUnavailable: 1  # 滾動更新期間最大多少個Pod不可用

 

如今仍然使用上面的 app-v1.yaml 這個資源清單文件,新建一個定義滾動更新的資源清單文件 app-v2-rolling-update.yaml,文件內容以下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  replicas: 10
  # maxUnavailable設置爲0能夠徹底確保在滾動更新期間服務不受影響,還可使用百分比的值來進行設置。
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v2.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          # 初始延遲設置高點能夠更好地觀察滾動更新過程
          initialDelaySeconds: 15
          periodSeconds: 5

 

上面的資源清單中咱們在環境變量中定義了版本2,而後經過設置strategy.type=RollingUpdate來定義該 Deployment 使用滾動更新的策略來更新應用,接下來咱們按下面的步驟來驗證滾動更新策略:

  1. 版本1提供服務
  2. 部署版本2
  3. 等待直到全部副本都被版本2替換完成

一樣,首先部署版本1應用:

$ kubectl apply -f app-v1.yaml
service "my-app" created
deployment.apps "my-app" created

測試版本1是否部署成功:

$ kubectl get pods -l app=my-app
NAME                      READY     STATUS    RESTARTS   AGE
my-app-7b4874cd75-h8c4d   1/1       Running   0          47s
my-app-7b4874cd75-p4l8f   1/1       Running   0          47s
my-app-7b4874cd75-qnt7p   1/1       Running   0          47s
$ kubectl get svc my-app
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
my-app    NodePort   10.109.99.184   <none>        80:30486/TCP   1m
$ curl http://127.0.0.1:30486
Host: my-app-7b4874cd75-qnt7p, Version: v1.0.0

 

一樣,在一個新終端中執行下面命令觀察 Pod 變化:

$ watch kubectl get pod -l app=my-app

而後部署滾動更新版本2應用:

$ kubectl apply -f app-v2-rolling-update.yaml
deployment.apps "my-app" configured

 

這個時候在上面的 watch 終端中能夠看到多了不少 Pod,還在建立當中,並無一開始就刪除以前的 Pod,一樣,這個時候執行下面命令,測試應用狀態:

$ while sleep 0.1; do curl http://127.0.0.1:30486; done
Host: my-app-7b4874cd75-vrlj7, Version: v1.0.0
......
Host: my-app-7b4874cd75-vrlj7, Version: v1.0.0
Host: my-app-6b5479d97f-2fk24, Version: v2.0.0
Host: my-app-7b4874cd75-p4l8f, Version: v1.0.0
......
Host: my-app-6b5479d97f-s5ctz, Version: v2.0.0
Host: my-app-7b4874cd75-5ldqx, Version: v1.0.0
......
Host: my-app-6b5479d97f-5z6ww, Version: v2.0.0

 

咱們能夠看到上面的應用並無出現不可用的狀況,最開始訪問到的都是版本1的應用,而後偶爾會出現版本2的應用,直到最後全都變成了版本2的應用,而這個時候看上面 watch 終端中 Pod 已經所有變成10個版本2的應用了,咱們能夠看到這就是一個逐步替換的過程。

若是在滾動更新過程當中發現新版本應用有問題,咱們能夠經過下面的命令來進行一鍵回滾:

$ kubectl rollout undo deploy my-app
deployment.apps "my-app"

 

若是你想保持兩個版本的應用都存在,那麼咱們也能夠執行 pause 命令來暫停更新:

$ kubectl rollout pause deploy my-app
deployment.apps "my-app" paused
 

這個時候咱們再去循環訪問咱們的應用就能夠看到偶爾會出現版本1的應用信息了。

若是新版本應用程序沒問題了,也能夠繼續恢復更新:

$ kubectl rollout resume deploy my-app
deployment.apps "my-app" resumed

 

最後,能夠執行下面的命令來清空上面的資源對象:

$ kubectl delete all -l app=my-app

結論:

  • 版本在實例之間緩慢替換
  • rollout/rollback 可能須要必定時間
  • 沒法控制流量

藍/綠(blue/green) - 最好用來驗證 API 版本問題

藍/綠髮布是版本2 與版本1 一塊兒發佈,而後流量切換到版本2,也稱爲紅/黑部署。藍/綠髮布與滾動更新不一樣,版本2() 與版本1()一塊兒部署,在測試新版本知足要求後,而後更新更新 Kubernetes 中扮演負載均衡器角色的 Service 對象,經過替換 label selector 中的版本標籤來將流量發送到新版本,以下圖所示:

blug/greenblug/green

下面是藍綠髮布策略下應用方法的示例圖:

blue/green requestblue/green request

在 Kubernetes 中,咱們能夠用兩種方法來實現藍綠髮布,經過單個 Service 對象或者 Ingress 控制器來實現藍綠髮布,實際操做都是相似的,都是經過 label 標籤去控制。

實現藍綠髮布的關鍵點就在於 Service 對象中 label selector 標籤的匹配方法,好比咱們從新定義版本1 的資源清單文件 app-v1-single-svc.yaml,文件內容以下:

apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  # 注意這裏咱們匹配 app 和 version 標籤,當要切換流量的時候,咱們更新 version 標籤的值,好比:v2.0.0
  selector:
    app: my-app
    version: v1.0.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v1
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: v1.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v1.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          periodSeconds: 5

上面定義的資源對象中,最重要的就是 Service 中 label selector 的定義:

selector:
  app: my-app
  version: v1.0.0

版本2 的應用定義和之前同樣,新建文件 app-v2-single-svc.yaml,文件內容以下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v2
  labels:
    app: my-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
      version: v2.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v2.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          periodSeconds: 5

而後按照下面的步驟來驗證使用單個 Service 對象實現藍/綠部署的策略:

  1. 版本1 應用提供服務
  2. 部署版本2 應用
  3. 等到版本2 應用所有部署完成
  4. 切換入口流量從版本1 到版本2
  5. 關閉版本1 應用

首先,部署版本1 應用:

$ kubectl apply -f app-v1-single-svc.yaml
service "my-app" created
deployment.apps "my-app-v1" created

測試版本1 應用是否部署成功:

$ kubectl get pods -l app=my-app
NAME                         READY     STATUS    RESTARTS   AGE
my-app-v1-7b4874cd75-7xh6s   1/1       Running   0          41s
my-app-v1-7b4874cd75-dmq8f   1/1       Running   0          41s
my-app-v1-7b4874cd75-t64z7   1/1       Running   0          41s
$ kubectl get svc -l app=my-app
NAME      TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
my-app    NodePort   10.106.184.144   <none>        80:31539/TCP   50s
$ curl http://127.0.0.1:31539
Host: my-app-v1-7b4874cd75-7xh6s, Version: v1.0.0

 

一樣,新開一個終端,執行以下命令觀察 Pod 變化:

$ watch kubectl get pod -l app=my-app

而後部署版本2 應用:

$ kubectl apply -f app-v2-single-svc.yaml
deployment.apps "my-app-v2" created

而後在上面 watch 終端中能夠看到會多3個my-app-v2開頭的 Pod,待這些 Pod 部署成功後,咱們再去訪問當前的應用:

$ while sleep 0.1; do curl http://127.0.0.1:31539; done
Host: my-app-v1-7b4874cd75-dmq8f, Version: v1.0.0
Host: my-app-v1-7b4874cd75-dmq8f, Version: v1.0.0
......

 

咱們會發現訪問到的都是版本1 的應用,和咱們剛剛部署的版本2 沒有任何關係,這是由於咱們 Service 對象中經過 label selector 匹配的是version=v1.0.0這個標籤,咱們能夠經過修改 Service 對象的匹配標籤,將流量路由到標籤version=v2.0.0的 Pod 去:

$ kubectl patch service my-app -p '{"spec":{"selector":{"version":"v2.0.0"}}}'
service "my-app" patched

 

而後再去訪問應用,能夠發現如今都是版本2 的信息了:

$ while sleep 0.1; do curl http://127.0.0.1:31539; done
Host: my-app-v2-f885c8d45-r5m6z, Version: v2.0.0
Host: my-app-v2-f885c8d45-r5m6z, Version: v2.0.0
......

若是你須要回滾到版本1,一樣只須要更改 Service 的匹配標籤便可:

$ kubectl patch service my-app -p '{"spec":{"selector":{"version":"v1.0.0"}}}'

 

若是新版本已經徹底符合咱們的需求了,就能夠刪除版本1 的應用了:

$ kubectl delete deploy my-app-v1

最後,一樣,執行以下命令清理上述資源對象:

 
 
$ kubectl delete all -l app=my-app

結論:

  • 實時部署/回滾

  • 避免版本問題,由於一次更改是整個應用的改變

  • 須要兩倍的資源

  • 在發佈到生產以前,應該對整個應用進行適當的測試

金絲雀(Canary) - 讓部分用戶參與測試

金絲雀部署是讓部分用戶訪問到新版本應用,在 Kubernetes 中,可使用兩個具備相同 Pod 標籤的 Deployment 來實現金絲雀部署。新版本的副本和舊版本的一塊兒發佈。在一段時間後若是沒有檢測到錯誤,則能夠擴展新版本的副本數量並刪除舊版本的應用。

若是須要按照具體的百分比來進行金絲雀發佈,須要儘量的啓動多的 Pod 副本,這樣計算流量百分比的時候才方便,好比,若是你想將 1% 的流量發送到版本 B,那麼咱們就須要有一個運行版本 B 的 Pod 和 99 個運行版本 A 的 Pod,固然若是你對具體的控制策略不在乎的話也就無所謂了,若是你須要更精確的控制策略,建議使用服務網格(如 Istio),它們能夠更好地控制流量。

CanaryCanary

在下面的例子中,咱們使用 Kubernetes 原生特性來實現一個窮人版的金絲雀發佈,若是你想要對流量進行更加細粒度的控制,請使用豪華版本的 Istio。下面是金絲雀發佈的應用請求示意圖:

canary requestscanary requests

接下來咱們按照下面的步驟來驗證金絲雀策略:

  1. 10個副本的版本1 應用提供服務
  2. 版本2 應用部署1個副本(意味着小於10%的流量)
  3. 等待足夠的時間來確認版本2 應用足夠穩定沒有任何錯誤信息
  4. 將版本2 應用擴容到10個副本
  5. 等待全部實例完成
  6. 關閉版本1 應用

首先,建立版本1 的應用資源清單,app-v1-canary.yaml,內容以下:

apiVersion: v1
kind: Service
metadata:
  name: my-app
  labels:
    app: my-app
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: http
  selector:
    app: my-app
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v1
  labels:
    app: my-app
spec:
  replicas: 10
  selector:
    matchLabels:
      app: my-app
      version: v1.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v1.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v1.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          periodSeconds: 5

 

 

其中核心的部分也是 Service 對象中的 label selector 標籤,不在具備版本相關的標籤了,而後定義版本2 的資源清單文件,app-v2-canary.yaml,文件內容以下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app-v2
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
      version: v2.0.0
  template:
    metadata:
      labels:
        app: my-app
        version: v2.0.0
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9101"
    spec:
      containers:
      - name: my-app
        image: containersol/k8s-deployment-strategies
        ports:
        - name: http
          containerPort: 8080
        - name: probe
          containerPort: 8086
        env:
        - name: VERSION
          value: v2.0.0
        livenessProbe:
          httpGet:
            path: /live
            port: probe
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:
          httpGet:
            path: /ready
            port: probe
          periodSeconds: 5

 

版本1 和版本2 的 Pod 都具備一個共同的標籤app=my-app,因此對應的 Service 會匹配兩個版本的 Pod。

首先,部署版本1 應用:

$ kubectl apply -f app-v1-canary.yaml
service "my-app" created
deployment.apps "my-app-v1" created

 

而後測試版本1 應用是否正確部署了:

$ kubectl get svc -l app=my-app
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
my-app        NodePort    10.105.133.213   <none>        80:30760/TCP   47s
$ curl http://127.0.0.1:30760
Host: my-app-v1-7b4874cd75-tsh2s, Version: v1.0.0

 

一樣,新開一個終端,查看 Pod 的變化:

$ watch kubectl get pod

而後部署版本2 應用:

$ kubectl apply -f app-v2-canary.yaml
deployment.apps "my-app-v2" created

而後在 watch 終端頁面能夠看到多了一個 Pod,如今一共 11 個 Pod,其中只有1 個 Pod 運行新版本應用,而後一樣能夠循環訪問該應用,查看是否會有版本2 的應用信息:

$ while sleep 0.1; do curl http://127.0.0.1:30760; done
Host: my-app-v1-7b4874cd75-bhxbp, Version: v1.0.0
Host: my-app-v1-7b4874cd75-wmcqc, Version: v1.0.0
Host: my-app-v1-7b4874cd75-tsh2s, Version: v1.0.0
Host: my-app-v1-7b4874cd75-ml58j, Version: v1.0.0
Host: my-app-v1-7b4874cd75-spsdv, Version: v1.0.0
Host: my-app-v2-f885c8d45-mc2fx, Version: v2.0.0
......

 

正常狀況下能夠看到大部分都是返回的版本1 的應用信息,偶爾會出現版本2 的應用信息,這就證實咱們的金絲雀發佈成功了,待確認了版本2 的這個應用沒有任何問題後,能夠將版本2 應用擴容到10 個副本:

$ kubectl scale --replicas=10 deploy my-app-v2
deployment.extensions "my-app-v2" scaled

其實這個時候訪問應用的話新版本和舊版本的流量分配是1:1了,確認了版本2 正常後,就能夠刪除版本1 的應用了:

$ kubectl delete deploy my-app-v1
deployment.extensions "my-app-v1" deleted

最終留下的是 10 個新版本的 Pod 了,到這裏咱們的整個金絲雀發佈就完成了。

一樣,最後,執行下面的命令刪除上面的資源對象:

$ kubectl delete all -l app=my-app

結論:

  • 部分用戶獲取新版本
  • 方便錯誤和性能監控
  • 快速回滾
  • 發佈較慢
  • 流量精準控制很浪費(99%A / 1%B = 99 Pod A,1 Pod B)

若是你對新功能的發佈沒有信心,建議使用金絲雀發佈的策略。

A/B測試(A/B testing) - 最適合部分用戶的功能測試

A/B 測試其實是一種基於統計信息而非部署策略來制定業務決策的技術,與業務結合很是緊密。可是它們也是相關的,也可使用金絲雀發佈來實現。

除了基於權重在版本之間進行流量控制以外,A/B 測試還能夠基於一些其餘參數(好比 Cookie、User Agent、地區等等)來精肯定位給定的用戶羣,該技術普遍用於測試一些功能特性的效果,而後按照效果來進行肯定。

咱們常常能夠在今日頭條的客戶端中就會發現有大量的 A/B 測試,同一個地區的用戶看到的客戶端有很大不一樣。

要使用這些細粒度的控制,仍然仍是建議使用 Istio,能夠根據權重或 HTTP 頭等來動態請求路由控制流量轉發。

ab testab test

下面是使用 Istio 進行規則設置的示例,由於 Istio 還不太穩定,如下示例規則未來可能會更改:

route:
- tags:
  version: v1.0.0
  weight: 90
- tags:
  version: v2.0.0
  weight: 10

關於在 Istio 中具體如何作 A/B 測試,咱們這裏就再也不詳細介紹了,咱們在istio-book文檔中有相關的介紹。

ab test requestab test request

結論:

  • 幾個版本並行運行
  • 徹底控制流量分配
  • 特定的一個訪問錯誤難以排查,須要分佈式跟蹤
  • Kubernetes 沒有直接的支持,須要其餘額外的工具

總結

發佈應用有許多種方法,當發佈到開發/測試環境的時候,重建或者滾動更新一般是一個不錯的選擇。在生產環境,滾動更新或者藍綠髮布比較合適,可是新版本的提早測試是很是有必要的。若是你對新版本的應用不是頗有信心的話,那應該使用金絲雀發佈,將用戶的影響降到最低。最後,若是你的公司須要在特定的用戶羣體中進行新功能的測試,例如,移動端用戶請求路由到版本 A,桌面端用戶請求路由到版本 B,那麼你就看使用A/B 測試,經過使用 Kubernetes 服務網關的配置,能夠根據某些請求參數來肯定用戶應路由的服務。

相關文章
相關標籤/搜索