WEBKT

Kubernetes 灰度发布(Canary Deployment)实战:原理、步骤与最佳实践

2 0 0 0

什么是灰度发布?

为什么需要灰度发布?

Kubernetes 如何实现灰度发布?

1. 使用 Deployment 和 Service (基于副本数)

2. 使用 Ingress (基于流量权重)

3. 使用 Service Mesh (例如 Istio, Linkerd)

灰度发布的最佳实践

总结

大家好,我是你们的码农朋友,小K。

今天咱们聊聊 Kubernetes 中的一个非常重要的发布策略:灰度发布(Canary Deployment,也叫金丝雀发布)。在软件开发领域,快速迭代和持续交付是常态,但每次新版本发布都伴随着潜在的风险。如何平滑地将新版本应用部署到生产环境,同时最大限度地降低风险?灰度发布就是解决这个问题的一把利器。

什么是灰度发布?

想象一下,矿工在下井之前,会带上一只金丝雀。因为金丝雀对有毒气体非常敏感,如果金丝雀出现异常,矿工就知道井下环境有危险。灰度发布借鉴了这个思路,它的核心思想是:逐步将新版本的应用部署到生产环境,先让一小部分用户使用新版本,观察其稳定性、性能等指标,确认没问题后再逐步扩大新版本的用户范围,直到所有用户都切换到新版本。

在 Kubernetes 中,灰度发布通常涉及以下几个关键概念:

  • 旧版本 (Stable/Current Version): 当前稳定运行的版本,服务大部分用户。
  • 新版本 (Canary Version): 要发布的新版本,先只服务一小部分用户。
  • 流量控制 (Traffic Control): 将用户流量按比例或特定规则分配给旧版本和新版本。
  • 监控 (Monitoring): 密切监控新版本和旧版本的各项指标,如错误率、延迟、资源利用率等。
  • 回滚 (Rollback): 如果新版本出现问题,能够快速将流量切换回旧版本,最大限度减少影响。

为什么需要灰度发布?

灰度发布的主要优势在于:

  • 降低风险: 新版本只影响一小部分用户,即使出现问题,影响范围也有限,可以快速回滚。
  • 真实环境测试: 在生产环境中测试新版本,可以发现测试环境中难以发现的问题。
  • 用户反馈: 收集早期用户的反馈,及时发现并修复问题,改进产品。
  • 平滑过渡: 逐步切换流量,避免一次性全量发布带来的冲击。
  • A/B 测试: 可以同时部署多个新版本,对比不同版本的表现,选择最佳方案。

Kubernetes 如何实现灰度发布?

Kubernetes 提供了多种机制来实现灰度发布,下面介绍几种常用的方法,并详细讲解具体的操作步骤。

1. 使用 Deployment 和 Service (基于副本数)

这是最基本的一种方式,通过调整 Deployment 的副本数来实现流量的切换。

原理:

  • 创建一个用于旧版本的 Deployment (例如 my-app-stable) 和一个 Service (例如 my-app)。
  • 创建一个用于新版本的 Deployment (例如 my-app-canary)。
  • my-app Service 通过 label selector 同时选择 my-app-stablemy-app-canary 的 Pod。
  • 通过调整 my-app-canary 的副本数来控制新版本的流量比例。

步骤:

  1. 创建旧版本 Deployment 和 Service:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-app-stable
    spec:
    replicas: 3
    selector:
    matchLabels:
    app: my-app
    version: stable
    template:
    metadata:
    labels:
    app: my-app
    version: stable
    spec:
    containers:
    - name: my-app
    image: my-app:v1
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: my-app
    spec:
    selector:
    app: my-app
    ports:
    - protocol: TCP
    port: 80
    targetPort: 8080
  2. 创建新版本 Deployment:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-app-canary
    spec:
    replicas: 1 # 初始副本数为 1
    selector:
    matchLabels:
    app: my-app
    version: canary
    template:
    metadata:
    labels:
    app: my-app
    version: canary
    spec:
    containers:
    - name: my-app
    image: my-app:v2 # 新版本镜像
  3. 调整新版本副本数:
    逐渐增加 my-app-canary 的副本数,例如从 1 增加到 2、3...,同时减少my-app-stable的副本数。观察新版本的表现。

  4. 完成发布或回滚:

    • 如果新版本稳定,将 my-app-canary 的副本数增加到与原 my-app-stable 副本数一致, 并将 my-app-stable 副本数缩减为0。
    • 如果新版本出现问题,将 my-app-canary 的副本数减少到 0,将流量全部切换回旧版本。

优点:

  • 简单易用,无需额外组件。

缺点:

  • 流量控制粒度粗,只能按副本数比例分配流量。
  • 无法根据请求内容、Header 等信息进行流量控制。
  • 需要手动调整副本数,不够自动化。

2. 使用 Ingress (基于流量权重)

Ingress 是 Kubernetes 集群中负责处理外部流量的 API 对象,可以通过 Ingress Controller (例如 Nginx Ingress Controller, Traefik) 来实现更精细的流量控制。

原理:

  • 部署两个 Service,分别对应旧版本和新版本。
  • 配置 Ingress 规则,根据权重将流量分配给不同的 Service。

步骤(以 Nginx Ingress Controller 为例):

  1. 安装 Nginx Ingress Controller:

    具体安装步骤请参考官方文档:https://kubernetes.github.io/ingress-nginx/deploy/

  2. 创建旧版本和新版本的 Deployment 和 Service:

    # 旧版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-app-stable
    spec:
    replicas: 3
    selector:
    matchLabels:
    app: my-app-stable
    template:
    metadata:
    labels:
    app: my-app-stable
    spec:
    containers:
    - name: my-app
    image: my-app:v1
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: my-app-stable
    spec:
    selector:
    app: my-app-stable
    ports:
    - protocol: TCP
    port: 80
    targetPort: 8080
    # 新版本
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: my-app-canary
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: my-app-canary
    template:
    metadata:
    labels:
    app: my-app-canary
    spec:
    containers:
    - name: my-app
    image: my-app:v2
    ---
    apiVersion: v1
    kind: Service
    metadata:
    name: my-app-canary
    spec:
    selector:
    app: my-app-canary
    ports:
    - protocol: TCP
    port: 80
    targetPort: 8080
  3. 创建 Ingress 规则:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
    name: my-app-ingress
    annotations:
    nginx.ingress.kubernetes.io/canary: "true" # 启用 canary
    nginx.ingress.kubernetes.io/canary-weight: "20" # 新版本流量权重为 20%
    spec:
    rules:
    - host: myapp.example.com
    http:
    paths:
    - path: /
    pathType: Prefix
    backend:
    service:
    name: my-app-stable # 默认流量到旧版本
    port:
    number: 80
    - path: /
    pathType: Prefix
    backend:
    service:
    name: my-app-canary
    port:
    number: 80
  4. 调整流量权重:

    修改 nginx.ingress.kubernetes.io/canary-weight 的值,逐步增加新版本的流量比例。

  5. 完成发布或回滚:

    • 如果新版本稳定, 删除 nginx.ingress.kubernetes.io/canary: "true"nginx.ingress.kubernetes.io/canary-weight 注解,并将所有对 myapp.example.com 的请求都路由到 my-app-canary 对应的Service。最后将原先的 my-app-stable 删除。
    • 如果新版本出现问题,将 nginx.ingress.kubernetes.io/canary-weight 设置为 0,或者直接删除 nginx.ingress.kubernetes.io/canarynginx.ingress.kubernetes.io/canary-weight 注解, 将流量全部切换回旧版本。

优点:

  • 流量控制粒度更细,可以按权重分配流量。
  • 支持基于 Header、Cookie 等信息的流量控制 (通过 Ingress Controller 的配置)。

缺点:

  • 需要安装和配置 Ingress Controller。
  • 配置相对复杂。

3. 使用 Service Mesh (例如 Istio, Linkerd)

Service Mesh 是一种专门用于处理服务间通信的基础设施层,提供了更高级的流量管理、安全、可观察性等功能。Istio 和 Linkerd 是目前比较流行的 Service Mesh 实现。

原理:

  • Service Mesh 会在每个 Pod 中注入一个 sidecar proxy,拦截所有进出 Pod 的流量。
  • 通过配置 VirtualService、DestinationRule 等资源,可以实现复杂的流量控制策略,如按权重、Header、Cookie 等进行流量切分。

步骤 (以 Istio 为例):

  1. 安装 Istio:

    具体安装步骤请参考官方文档:https://istio.io/latest/docs/setup/getting-started/

  2. 创建旧版本和新版本的 Deployment 和 Service:
    (同 Ingress 例子)

  3. 创建 VirtualService 和 DestinationRule:

    apiVersion: networking.istio.io/v1alpha3
    kind: VirtualService
    metadata:
    name: my-app
    spec:
    hosts:
    - myapp.example.com
    http:
    - route:
    - destination:
    host: my-app-stable
    subset: v1
    weight: 80
    - destination:
    host: my-app-canary
    subset: v2
    weight: 20
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
    name: my-app
    spec:
    host: my-app-stable
    subsets:
    - name: v1
    labels:
    version: stable
    ---
    apiVersion: networking.istio.io/v1alpha3
    kind: DestinationRule
    metadata:
    name: my-app
    spec:
    host: my-app-canary
    subsets:
    - name: v2
    labels:
    version: canary
  4. 调整流量权重:

    修改 VirtualService 中的 weight 值,逐步增加新版本的流量比例。

  5. 完成发布或回滚:

    • 如果新版本稳定, 修改 VirtualService 配置, 将所有流量都导向my-app-canary
    • 如果新版本出现问题,修改 VirtualService 配置, 将流量全部切换回 my-app-stable

优点:

  • 功能强大,支持各种复杂的流量控制策略。
  • 提供丰富的可观察性工具,方便监控和排错。
  • 支持熔断、重试等高级功能,提高系统稳定性。

缺点:

  • 学习曲线陡峭,配置复杂。
  • 会增加系统的复杂度和资源消耗。

灰度发布的最佳实践

  • 自动化: 将灰度发布流程集成到 CI/CD 流水线中,实现自动化部署、流量控制、监控和回滚。
  • 监控: 建立完善的监控体系,实时监控新版本和旧版本的各项指标,及时发现问题。
  • 逐步放量: 从小流量开始,逐步增加新版本的流量比例,避免一次性全量发布带来的风险。
  • 快速回滚: 建立快速回滚机制,一旦新版本出现问题,能够立即将流量切换回旧版本。
  • 灰度发布策略的选择: 根据业务需求和技术能力选择合适的灰度发布策略, 如果业务简单, 可以选择副本数控制; 如果需要更细粒度的流量控制, 可以选择 Ingress; 如果对可靠性和可观察性有更高要求, 可以选择 Service Mesh。
  • 用户分组: 按照用户 ID、地理位置、设备类型等维度对用户进行分组, 可以更精准地控制灰度发布的范围, 并且可以进行 A/B 测试。
  • 灰度发布时间: 灰度发布的时间要足够长, 以便充分观察新版本的表现。
  • 灰度发布前的测试: 灰度发布前必须进行充分的测试,包括单元测试、集成测试、性能测试等。

总结

灰度发布是 Kubernetes 中一种非常重要的发布策略,可以帮助我们平滑地将新版本应用部署到生产环境,同时最大限度地降低风险。 通过这篇文章,相信你已经对 Kubernetes 灰度发布的原理、实现方法和最佳实践有了一定的了解。希望这些知识能帮助你在实际工作中更好地应用灰度发布,提高应用发布的效率和可靠性。如果你有任何问题,欢迎留言讨论!

小K Kubernetes灰度发布Canary Deployment

评论点评

打赏赞助
sponsor

感谢您的支持让我们更好的前行

分享

QRcode

https://www.webkt.com/article/8179