应用灰度发布

灰度发布是一种渐进式发布策略,可将新版本应用逐步引入一小部分用户或流量中。这种增量式发布方式使团队能够监控系统行为、收集指标,并在全面部署前确保系统稳定性。尤其是在生产环境中,这种方式可以显著降低风险。 Alauda Container Platform Progressive Delivery 使用 Argo Rollouts,这是上游 Kubernetes 原生的渐进式发布控制器。它支持高级部署策略,并通过灰度发布、蓝绿部署、分析运行、实验和自动回滚等功能扩展 Kubernetes 的能力。它可与可观测性技术栈集成,以执行基于指标的健康检查,并提供基于 CLI 和监控面板的应用交付控制。

关键概念:

  • Rollout:Kubernetes 中的一种自定义资源定义(CRD),用于替代标准 Deployment 资源,从而实现蓝绿部署、灰度发布等高级部署控制。
  • 灰度步骤:一系列增量式流量切换操作,例如先将 25% 的流量、再将 50% 的流量导向新版本。
  • 暂停步骤:在进入下一灰度步骤前引入等待间隔,以便执行手动或自动验证。

灰度发布的优势

  • 降低风险:通过先将变更部署到一小部分服务器,您可以在全面发布前发现并解决问题,从而最大限度地降低对用户的影响。
  • 渐进式发布:这种方式可以逐步开放新功能,有助于您有效监控性能并收集用户反馈。
  • 实时反馈:灰度发布可以在真实环境中即时了解新版本的性能和稳定性。
  • 灵活性:您可以根据性能指标调整部署流程,从而实现动态发布,并根据需要暂停或回滚发布。
  • 经济高效:与蓝绿部署不同,灰度发布不需要单独的环境,因此可以更高效地利用资源。

使用 Alauda Container Platform Progressive Delivery 进行灰度发布

Alauda Container Platform Progressive Delivery 使用 Argo Rollouts 支持灰度发布策略,并通过 Gateway API Plugin 控制流量。在 ACP 中,您可以使用 ALB 作为 Gateway API Provider 来实现流量控制。

前提条件

  1. 集群中已安装 Argo Rollouts 和 Gateway API plugin。
  2. Argo Rollouts kubectl plugin(从此处安装)。
  3. 一个用于创建命名空间的项目。
  4. 集群中已部署 ALB,并已将其分配给项目。
  5. 集群中有一个用于部署应用的命名空间。

操作步骤

创建 Deployment

首先,定义应用的“stable”版本,即用户当前访问的版本。创建 Kubernetes Deployment,并设置适当的副本数、容器镜像版本(例如 hello:1.23.1)以及 app=web 等适当的标签。

使用以下 YAML:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: hello:1.23.1
          ports:
            - containerPort: 80

YAML 字段说明:

  • apiVersion:用于创建资源的 Kubernetes API 版本。
  • kind:指定这是一个 Deployment 资源。
  • metadata.name:Deployment 的名称。
  • spec.replicas:所需的 Pod 副本数。
  • spec.selector.matchLabels:定义 Deployment 如何查找要管理的 Pod。
  • template.metadata.labels:应用于 Pod 的标签,供 Service 用于选择 Pod。
  • spec.containers:要在每个 Pod 中运行的容器。
  • containers.name:容器的名称。
  • containers.image:要运行的容器镜像。
  • containers.ports.containerPort:容器公开的端口。

使用 kubectl 应用配置:

kubectl apply -f deployment.yaml

这样即可设置生产环境。

或者,您也可以使用 Helm Chart 创建 Deployment 和 Service。

创建 Stable Service

创建一个 Kubernetes Service,用于公开 stable Deployment。此 Service 将根据匹配的标签把流量转发到 stable 版本的 Pod。初始时,Service selector 会选择带有 app=web 标签的 Pod。

apiVersion: v1
kind: Service
metadata:
  name: web-stable
spec:
  selector:
    app: web
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

YAML 字段说明:

  • apiVersion:用于创建 Service 的 Kubernetes API 版本。
  • kind:指定此资源为 Service。
  • metadata.name:Service 的名称。
  • spec.selector:根据标签标识要将流量路由到的 Pod。
  • ports.protocol:使用的协议(TCP)。
  • ports.port:Service 公开的端口。
  • ports.targetPort:流量转发到的容器端口。

使用以下命令应用:

kubectl apply -f web-stable-service.yaml

这样即可从外部访问 stable Deployment。

创建 Canary Service

创建一个 Kubernetes Service,用于公开 canary Deployment。此 Service 将根据匹配的标签把流量转发到 canary 版本的 Pod。初始时,Service selector 会选择带有 app=web 标签的 Pod。

apiVersion: v1
kind: Service
metadata:
  name: web-canary
spec:
  selector:
    app: web
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

YAML 字段说明:

  • apiVersion:用于创建 Service 的 Kubernetes API 版本。
  • kind:指定此资源为 Service。
  • metadata.name:Service 的名称。
  • spec.selector:根据标签标识要将流量路由到的 Pod。
  • ports.protocol:使用的协议(TCP)。
  • ports.port:Service 公开的端口。
  • ports.targetPort:流量转发到的容器端口。

使用以下命令应用:

kubectl apply -f web-canary-service.yaml

这样即可从外部访问 canary Deployment。

创建 Gateway

使用 example.com 作为访问服务的域名,创建 Gateway,以通过该域名公开服务:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: default
spec:
  gatewayClassName: exclusive-gateway
  listeners:
  - allowedRoutes:
      namespaces:
        from: All
    name: gateway-metric
    port: 11782
    protocol: TCP
  - allowedRoutes:
      namespaces:
        from: All
    hostname: example.com
    name: web
    port: 80
    protocol: HTTP

使用以下命令:

kubectl apply -f gateway.yaml

Gateway 将分配到一个外部 IP 地址。请从 Gateway 资源中类型为 IPAddress 的 status.addresses 获取该 IP 地址。

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: default
...
status:
  addresses:
  - type: IPAddress
    value: 192.168.134.30

DNS 配置

在 DNS 服务器中配置域名,使其解析到 Gateway 的 IP 地址。使用以下命令验证 DNS 解析结果:

nslookup example.com
Server:         192.168.16.19
Address:        192.168.16.19#53

Non-authoritative answer:
Name:   example.com
Address: 192.168.134.30

返回结果应为 Gateway 的地址。

创建 HTTPRoute

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: web
spec:
  hostnames:
  - example.com
  parentRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: default
    namespace: default
    sectionName: web
  rules:
  - backendRefs:
    - group: ""
      kind: Service
      name: web-canary
      namespace: default
      port: 80
      weight: 0
    - group: ""
      kind: Service
      name: web-stable
      namespace: default
      port: 80
      weight: 100
    matches:
    - path:
        type: PathPrefix
        value: /

使用以下命令:

kubectl apply -f httproute.yaml

访问 Stable Service

在集群外部,使用以下命令通过域名访问服务:

curl http://example.com

或者,您也可以在浏览器中访问 http://example.com。

创建 Rollout

接下来,使用 Canary 策略创建 Argo Rollouts 的 Rollout 资源。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: rollout-canary
spec:
  minReadySeconds: 30
  replicas: 2
  revisionHistoryLimit: 3
  selector:
    matchLabels:
      app: web
  strategy:
    canary:
      canaryService: web-canary
      maxSurge: 25%
      maxUnavailable: 0
      stableService: web-stable
      steps:
      - setWeight: 50
      - pause: {}
      - setWeight: 100
      trafficRouting:
        plugins:
          argoproj-labs/gatewayAPI:
            httpRoute: web
            namespace: default
  workloadRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
    scaleDown: onsuccess

YAML 字段说明:

  • spec.selector:Pod 的标签选择器。此选择器选中的现有 ReplicaSet 将受到此 Rollout 的影响。它必须与 Pod 模板的标签匹配。

  • workloadRef:指定工作负载引用以及应用 Rollout 时使用的缩容策略。

  • scaleDown:指定迁移到 Rollout 后是否缩减工作负载(Deployment)。可选值包括:

    • "never":不缩减 Deployment。
    • "onsuccess":Rollout 状态变为健康后缩减 Deployment。
    • "progressively":随着 Rollout 扩容,逐步缩减 Deployment。如果 Rollout 失败,则会重新扩容 Deployment。
  • strategy:Rollout 策略,支持 BlueGreen 和 Canary 策略。

  • canary:Canary Rollout 策略定义。

    • canaryService:对 Service 的引用,控制器会更新该 Service,使其选择 canary Pod。流量路由必需。
    • stableService:对 Service 的引用,控制器会更新该 Service,使其选择 stable Pod。流量路由必需。
    • steps:定义更新 canary 期间要执行的一系列步骤。首次部署 Rollout 时会跳过这些步骤。
      • setWeight:设置 canary ReplicaSet 的比例。
      • pause:无限期暂停 Rollout,或暂停指定时长。支持的单位:s、m、h。{} 表示无限期暂停。
      • plugin:执行已配置的插件;此处配置的是 gatewayAPI 插件。

使用以下命令应用:

kubectl apply -f rollout.yaml

这样即可为 Deployment 设置 Canary 策略的 Rollout。初始权重将设为 50,并等待晋级。50% 的流量将转发到 canary Service。Rollout 晋级后,权重将设为 100,所有流量都将转发到 canary Service。最后,canary Service 将成为 stable Service。

验证 Rollout

创建 Rollout 后,Argo Rollouts 将使用与 Deployment 相同的模板创建新的 ReplicaSet。新 ReplicaSet 的 Pod 健康后,Deployment 将缩容至 0。

使用以下命令确保 Pod 正常运行:

kubectl argo rollouts get rollout rollout-canary
Name:            rollout-canary
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
Step:          9/9
SetWeight:     100
ActualWeight:  100
Images:          hello:1.23.1 (stable)
Replicas:
Desired:       2
Current:       2
Updated:       2
Ready:         2
Available:     2

NAME                                      KIND        STATUS     AGE  INFO
⟳ rollout-canary                            Rollout     ✔ Healthy  32s
└──# revision:1
  └──⧉ rollout-canary-5c9d79697b           ReplicaSet  ✔ Healthy  32s  stable
    ├──□ rollout-canary-5c9d79697b-fh78d  Pod         ✔ Running  32s  ready:1/1
    └──□ rollout-canary-5c9d79697b-rrbtj  Pod         ✔ Running  32s  ready:1/1

准备灰度发布

接下来,将应用的新版本作为 green Deployment 进行准备。使用新镜像版本(例如 hello:1.23.2)更新 Deployment web。使用以下命令:

kubectl patch deployment web -p '{"spec":{"template":{"spec":{"containers":[{"name":"web","image":"hello:1.23.2"}]}}}}'

这样即可准备好新版本应用以供测试。

Rollout 将创建新的 ReplicaSet 来管理 canary Pod,50% 的流量将转发到 canary Pod。使用以下命令进行验证:

kubectl argo rollouts get rollout rollout-canary
Name:            rollout-canary
Namespace:       default
Status:          ॥ Paused
Message:         CanaryPauseStep
Strategy:        Canary
Step:          1/3
SetWeight:     50
ActualWeight:  50
Images:          hello:1.23.1 (stable)
                hello:1.23.2 (canary)
Replicas:
Desired:       2
Current:       3
Updated:       1
Ready:         3
Available:     3

NAME                                      KIND        STATUS     AGE  INFO
⟳ rollout-canary                            Rollout     ॥ Paused   95s
├──# revision:2
│  └──⧉ rollout-canary-5898765588           ReplicaSet  ✔ Healthy  46s  canary
│     └──□ rollout-canary-5898765588-ls5jk  Pod         ✔ Running  45s  ready:1/1
└──# revision:1
  └──⧉ rollout-canary-5c9d79697b           ReplicaSet  ✔ Healthy  95s  stable
    ├──□ rollout-canary-5c9d79697b-fk269  Pod         ✔ Running  94s  ready:1/1
    └──□ rollout-canary-5c9d79697b-wkmcn  Pod         ✔ Running  94s  ready:1/1

当前共有 3 个 Pod 正在运行,分别使用 stable 和 canary 版本。权重为 50,因此 50% 的流量将转发到 canary Service。Rollout 流程已暂停,等待晋级。

如果您使用 Helm Chart 部署应用,请使用 Helm 工具将应用升级到 canary 版本。

访问 http://example.com 时,50% 的流量将转发到 canary Service。您应该会从 URL 收到不同的响应。

晋级 Rollout

canary 版本测试通过后,您可以晋级 Rollout,将所有流量切换到 canary Pod。使用以下命令:

kubectl argo rollouts promote rollout-canary

使用以下命令验证 Rollout 是否已完成:

kubectl argo rollouts get rollout rollout-canary
Name:            rollout-canary
Namespace:       default
Status:          ✔ Healthy
Strategy:        Canary
Step:          3/3
SetWeight:     100
ActualWeight:  100
Images:          hello:1.23.2 (stable)
Replicas:
Desired:       2
Current:       2
Updated:       2
Ready:         2
Available:     2

NAME                                      KIND        STATUS         AGE    INFO
⟳ rollout-canary                            Rollout     ✔ Healthy      8m42s
├──# revision:2
│  └──⧉ rollout-canary-5898765588           ReplicaSet  ✔ Healthy      7m53s  stable
│     ├──□ rollout-canary-5898765588-ls5jk  Pod         ✔ Running      7m52s  ready:1/1
│     └──□ rollout-canary-5898765588-dkfwg  Pod         ✔ Running      68s    ready:1/1
└──# revision:1
  └──⧉ rollout-canary-5c9d79697b           ReplicaSet  • ScaledDown   8m42s
    ├──□ rollout-canary-5c9d79697b-fk269  Pod         ◌ Terminating  8m41s  ready:1/1
    └──□ rollout-canary-5c9d79697b-wkmcn  Pod         ◌ Terminating  8m41s  ready:1/1

如果 stable Images 已更新为 hello:1.23.2,且 revision 1 的 ReplicaSet 已缩容至 0,则表示 Rollout 已完成。

访问 http://example.com 时,所有流量都将转发到 canary Service。

中止 Rollout(可选)

如果在 Rollout 过程中发现 canary 版本存在问题,可以中止流程,将所有流量切换到 stable Service。使用以下命令:

kubectl argo rollouts abort rollout-canary

使用以下命令验证结果:

kubectl argo rollouts get rollout rollout-canary
Name:            rollout-demo
Namespace:       default
Status:          ✖ Degraded
Message:         RolloutAborted: Rollout aborted update to revision 3
Strategy:        Canary
Step:          0/3
SetWeight:     0
ActualWeight:  0
Images:          hello:1.23.1 (stable)
Replicas:
Desired:       2
Current:       2
Updated:       0
Ready:         2
Available:     2

NAME                                      KIND        STATUS        AGE  INFO
⟳ rollout-canary                            Rollout     ✖ Degraded    18m
├──# revision:3
│  └──⧉ rollout-canary-5c9d79697b           ReplicaSet  • ScaledDown  18m  canary,delay:passed
└──# revision:2
  └──⧉ rollout-canary-5898765588           ReplicaSet  ✔ Healthy     17m  stable
    ├──□ rollout-canary-5898765588-ls5jk  Pod         ✔ Running     17m  ready:1/1
    └──□ rollout-canary-5898765588-dkfwg  Pod         ✔ Running     10m  ready:1/1

访问 http://example.com 时,所有流量都将转发到 stable Service。

由 Alauda 于 2026-10-21 修改。

Argo® 是 LF Projects, LLC 的注册商标。

Alauda 是独立供应商。本产品与 LF Projects, LLC 无关联,也未获得其认可或赞助。所有商标均归其各自所有者所有,在此仅用于标识目的。