在基本的 K8S 中,没有提供方便细粒度的流量分配策略。但借助 K8S 的 selector 机制,仍然可以实现简单的灰度和蓝绿发布。

应用部署

应用版本 1

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ng-v1
spec:
  replicas: 4
  selector:
    matchLabels:
      app: ng
  template:
    metadata:
      labels:
        app: ng
        version: v1
    spec:
      containers:
        - name: ng
          image: nginx:1.22

应用版本 2

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ng-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: ng
  template:
    metadata:
      labels:
        app: ng
        version: v2
    spec:
      containers:
        - name: ng
          image: kong/httpbin
  • 为了演示版本不同,分别部署了 2 个完全不同的应用作为演示。
  • 这俩应用有着相同的 label: app 以及不同的 label: version

灰度发布

首先创建一个 service,这个 service 对外暴露服务使用了 app=ng 作为选择器。

apiVersion: v1
kind: Service
metadata:
  name: ng
spec:
  ports:
    - port: 80
  selector:
    app: ng

由于 service 本身是按照 RR 的策略进行轮询的,所有对应的 pod endpoint 得到的流量会保持一致。

所以上述代码中,流量会按照 pod 数量分配,此示例中 v1:v2 流量比例为 4:1。通过改变 pod 的数量就可以实现粗糙的灰度了。

启动一个 pod 测试一下:

kubectl run -it --rm test --image=nginx:1.22 --restart=Never -- sh

在终端中重复执行多次 curl,查看会发现流量按照 4:1 的比例分配了。

curl ng

这个 bash 代码模拟了每隔 5 秒逐步增加 V2 的流量,通过 4 次改变 pod 数量,最终将流量完全切换到 v2。

#!/bin/bash
v1count=5
v2count=0
for i in {1..5}
do
  v1count=$((v1count-1))
  v2count=$((v2count+1))
  kubectl scale deployment ng-v1 --replicas $v1count
  kubectl scale deployment ng-v2 --replicas $v2count
  sleep 5
done

这个方法不适合如下情况:

  • pod数量只有一两个的
  • 需按一定规则灰度

蓝绿发布

需要修改 service,增加一个版本的 selector,让 service 固定在特定版本:

当应用是版本 v1 的时候:

apiVersion: v1
kind: Service
metadata:
  name: ng
spec:
  ports:
    - port: 80
  selector:
    app: ng
    version: v1

实际生产中,先部署好 v2 版本,当验证无误后,可以通过修改 service 的 version 为 v2 。

现在测试一下:

先将 2 个版本部署成等量 pod。

kubectl scale deployment ng-v1 --replicas 1

kubectl scale deployment ng-v2 --replicas 1

初始的 service 为版本 v1:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
  name: ng
spec:
  ports:
    - port: 80
  selector:
    app: ng
    version: v1
EOF

现在切换到 v2 版本,如下:

kubectl patch svc ng -p '{"spec":{"selector": {"app": "ng", "version": "v2"}}}'

A/B test 发布

A/B test 意味着需要按照一定逻辑进行流量分发。

😭,臣妾做不到。

但可以借助 nginx 等产品完成。

事实上,一些第三方的 ingress 产品,以及 Service Mesh 就都可以解决这些问题的。

如果对延迟不敏感,可以考虑直接上 Istio 或 Linkerd 等 Service Mesh 产品。