基于 Nginx Ingress + 云效 AppStack 实现灰度发布

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
简介: 本文将演示结合云效 AppStack,来看下如何在阿里云 ACK 集群上进行应用的 Ingress 灰度发布。


1. 场景简介


灰度发布是降低生产部署风险,提升线上服务稳定性的重要手段,这在当前快速迭代的软件研发中尤为重要。相对于 K8s 默认的滚动部署或者简单的 Pod 分批,基于流量特征的灰度发布验证更精准,风险更低。


在云原生场景下,基于 Nginx Ingress 的灰度发布是被广泛使用的方案之一。该方案通过在流量入口侧进行灰度和正常流量的路由调配,将灰度流量导入到灰度的服务版本,从而可以在全量部署到生产环境前,对新版本进行验证,当验证不通过时,可以及时回退,将风险控制在较低的范围内。而整个发布和验证,能做到对终端用户服务的不间断和体验一致。


2. 基本原理


对于常见的 web 服务,Ingress 灰度发布的基本逻辑是:将指向同一入口(HOST)的访问请求,根据特征或流量比例,将一部分流量路由到灰度服务中,通过对灰度流量的监控和验证,判断灰度服务是否符合上线标准。


按照流量的路径,我们可以画出 Ingress 流量灰度在 K8s 上的简单架构(如下图)。

image.png

流量从入口的 HOST 进来后,会根据 Nginx-Ingress 的流量标识(定义在 Ingress 的 annotation 中),将符合灰度标识的请求路由到灰度环境的 service 中,进而进入背后的工作负载 Pod。对于每个环境内部的 service 和 deployment,它们并不主动感知灰度标识,也就是说,通常情况下,内部的 rpc 流量并不携带灰度标识。因此,这种架构主要解决的是外部流量灰度的问题,适合服务数量不太多,服务间调用比较简单的场景。


3. 具体实践


接下来,我们结合云效 AppStack,来看下如何在阿里云 ACK 集群上进行应用的 Ingress 灰度发布。


我们首先导入 ACK 集群并创建应用。

image.png


3.1 定义和管理灰度环境

定义环境

在应用中,我们分别定义灰度环境与生产环境,两个环境共享同一个 K8s 集群,我们将灰度环境命名为 grey,生产环境命名为 ack-prod。

image.png

定义部署编排

我们打开应用设置,编排配置来定义部署编排。灰度发布生效的关键是 Ingress 中的 canary 注解,需要查看你的 nginx-ingress-controller 版本,以确定可以支持的注解。我测试的集群上 nginx-ingress-controller 的版本是 0.30,采用 header 来标识灰度流量。

image.png

为了做到只在灰度环境中开启灰度的路由配置,我们使用了编排模板的条件语句,见下面的编排示例:


---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
 name: {{ .AppStack.appName }}-{{ .AppStack.envName }}
  namespace: {{ .Values.namespace }}
{{ if eq .AppStack.envName "grey" }}
  annotations:
    # 开启Canary。
    nginx.ingress.kubernetes.io/canary: "true"
    # 请求头为_env。
    nginx.ingress.kubernetes.io/canary-by-header: "_env"
    # 请求头_env的值为grey时,请求才会被路由到新版本服务中。
    nginx.ingress.kubernetes.io/canary-by-header-value: "grey"
{{ end }}
spec:
  rules:
  - host: {{ .Values.host }}
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: {{ .AppStack.appName }}-{{ .AppStack.envName }}
            port:
              number: 80


可以看到在 Ingress 的编排中,仅名称为 “grey” 的环境,会开启 canary 的 annotaion,并且将灰度标识设置为通过 _env: grey 的 header 标签。


同时在 Ingress 的 rules 配置中,通过变量 host 来指定路由关联的 HOST,这里 ACK 灰度环境和 ACK 生产环境分别关联灰度环境变量组和生产环境变量组,这两个变量组的 host 变量采用相同的值。


示例:

image.png


#
namespace = demo-pre
#
host = go.demo.prod


#
namespace = demo-prod
#
host = go.demo.prod


除了 Ingress 外,还需要配置对应的 service 和 deployment。


---
apiVersion: v1
kind: Service
metadata:
 name: {{ .AppStack.appName }}-{{ .AppStack.envName }}
  namespace: {{ .Values.namespace }}
spec:
  selector:
    run: {{ .AppStack.appName }}-{{ .AppStack.envName }}
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080


---
apiVersion: apps/v1
kind: Deployment
metadata:
 name: {{ .AppStack.appName }}-{{ .AppStack.envName }}
  labels:
    run: {{ .AppStack.appName }}-{{ .AppStack.envName }}
  namespace: {{ .Values.namespace }}
spec:
  replicas: {{ .Values.replicas }}
  selector:
    matchLabels:
      run: {{ .AppStack.appName }}-{{ .AppStack.envName }}
  template:
    metadata:
      labels:
        run: {{ .AppStack.appName }}-{{ .AppStack.envName }}
    spec:
      containers:
        - name: main
          image: {{ .AppStack.image.backend }}
          ports:
            - containerPort: 8080
          resources:
            limits:
              cpu: {{ .Values.cpuLimit }}
              memory: {{ .Values.memoryLimit }}
            requests:
              cpu: {{ .Values.cpuRequest }}
              memory: {{ .Values.memoryRequest }}


3.2 准备示例代码并关联到应用中

可从 atomgit 上下载实例代码,路径为:链接


将代码导入到云效代码管理 Codeup,然后关联到应用中。

image.png

3.3 定义灰度发布的流程

接下来,我们通过云效 AppStack 的研发流程,定义灰度发布的整个过程,见下图:

image.png

在该流程中,每次执行,我们都会从 master 分支拉取代码进行镜像构建,构建完成后会转交运维进行审批,审批通过后即开始部署过程。


部署过程包含灰度部署、灰度验证、生产部署和灰度清理四个步骤。


  • 灰度部署步骤会将前面构建出来的镜像更新到 ACK 灰度环境,此时通过在请求中携带 _env:grey 的 header 就可进行灰度验证。
  • 灰度验证是一个人工卡点,用于对灰度环境的观测和验证,如果验证通过即自动进行生产环境的部署,如果验证失败,则跳过生产部署,执行灰度清理
  • 生产部署步骤会将镜像更新到 ACK 生产环境,此时新的服务版本将对普通用户可见。注意,这里为了降低风险,生产部署的策略被设置为了分批,且首批暂停的模式,保证线上仍然是逐步放量的,且有机会快速回退。
  • 灰度清理步骤主要是清理灰度环境的资源,一方面节约资源,另一方面避免灰度验证不通过时对线上的影响。


在云效 AppStack 上相关应用的设置中,进行研发流程设置(如果仅是体验灰度发布,可仅配置生产阶段)。

image.png

上述流程可以参考下面的流水线 yaml 来定义,请注意将其中的 acr_docker_build_step 步骤的镜像地址和服务连接修改为正确的值,并把 grey_validate 和 ops_validate 包含的 userId 替换为自己的阿里云的账号 ID。


---
stages:
 build:
    name: "构建"
    jobs:
      go_build:
        name: "Go 镜像构建"
        steps:
          golang_build_step:
            name: "Golang 构建"
            step: "GolangBuild"
            with:
              goVersion: "1.20.x"
              run: |
                export GOPROXY=https://goproxy.cn
                make build
          upload_step:
            step: "ArtifactUpload"
            name: "构建物上传"
            with:
              serviceConnection: "wtdbdh89rrfdsod6"
              repo: "flow_generic_repo"
              artifact: "demo-go-echo"
              version: "prod-${CI_COMMIT_ID}.${DATETIME}"
              filePath:
              - "demo-go-echo"
              - "deploy.sh"
          acr_docker_build_step:
            name: "镜像构建并推送至阿里云镜像仓库个人版"
            step: "ACRDockerBuild"
            with:
              artifact: "image"
              dockerfilePath: "Dockerfile"
              dockerRegistry: "registry.cn-zhangjiakou.aliyuncs.com/docker007/demo-go-echo"
              dockerTag: "prod-${CI_COMMIT_ID}.${DATETIME}"
              region: "cn-zhangjiakou"
              serviceConnection: "<connectionId>"
  approve:
    name: "部署审核"
    jobs:
      ops_validate:
        name: "运维审批"
        component: "ManualValidate"
        with:
          validatorType: "users"
          validators:
          - <userId>
  grey:
    name: "灰度验证"
    jobs:
      grey_deploy_job:
        name: "ACK灰度部署"
        component: "AppStackFlowDeploy"
        with:
          application: "demo-go-echo"
          environment: "grey"
          artifacts:
          - label: "backend"
            value: "$[stages.build.go_build.acr_docker_build_step.artifacts.image.dockerUrl]"
          autoDeploy: true
      grey_validate:
        name: "灰度验证"
        component: "ManualValidate"
        needs:
        - "grey_deploy_job"
        with:
          validatorType: "users"
          validators:
          - <userId>
  deploy:
    name: "部署"
    jobs:
      ack_deploy_job:
        name: "ACK生产部署"
        component: "AppStackFlowDeploy"
        condition: |
          succeed('grey.grey_validate')
        with:
          application: "demo-go-echo"
          environment: "ack-prod"
          artifacts:
          - label: "backend"
            value: "$[stages.build.go_build.acr_docker_build_step.artifacts.image.dockerUrl]"
          autoDeploy: true
  cleanup:
    name: "清理环境"
    jobs:
      cleanup_grey_env_job:
        name: "清理灰度环境"
        component: "AppStackCleanEnv"
        needs:
        - "grey.grey_validate"
        - "deploy.ack_deploy_job"
        condition: |
          failed('grey.grey_validate') || succeed('deploy.ack_deploy_job')
        with:
          application: "demo-go-echo"
          environment: "grey"
          deleteEnv: "cleanEnv"


3.4 验证灰度发布流程

我们假设研发流程仅包含生产阶段,先运行一次生产阶段,将应用部署到灰度和生产环境中,注意:环境第一次部署可能需要手动创建部署单。


修改代码,将 routes.go 里面的版本号修改为新的值,再次执行生产阶段,直到灰度验证步骤,此时生产环境与灰度环境运行不同的版本。


通过 kubectl get ing -A 获取 ingress 的出口 IP,在本地 /etc/hosts 中将其绑定到 go.demo.prod 中,如:


127.0.0.1 go.demo.prod  # 将127.0.0.1修改为正确的出口IP


打开终端,通过 httpie 或者 curl 请求/version 接口,以 httpie 为例,请求命令为:


http -v http://go.demo.prod/version # 请求正式环境
http -v http://go.demo.prod/version _env:grey    # 请求灰度环境


4. 常见问题


4.1 有了灰度环境,生产环境部署的时候还需要分批吗?

建议在生产环境部署的时候仍然开启分批,因为灰度环境虽然验证通过了,但受到数据量等影响,生产仍然不建议全量一起上,通过分批,可以把风险控制在小范围内,避免大的故障的发生。


4.2 如何在研发流程上整合配置变更和数据变更?

可以将配置变更和数据变更作为研发阶段的步骤,编排到研发流程的流水线 yaml 中,通常建议在应用部署前执行数据变更,部署后执行配置变更。同时,对应于 K8s 上的灰度环境,如果采用了类似 Nacos 这样的配置中心,也应当由对应的灰度 namespace,从而避免直接修改生产配置。


4.3 灰度环境包含多个应用,如何保证其内部服务间调用也是走的灰度环境?

完整的方案建议参考 MSE 等产品。


如果应用数量比较少,链路比较简单,且接受基于 K8s 的简单方案,可以为每个应用都定义一个灰度环境,共享同一个集群和 namespace,应用间通过 service 进行调用。此时,由于 namespace 的隔离,灰度环境内的应用互相调用只会调用同 namespace 下的其它应用的灰度版本。


这种方案需要保证各应用灰度环境的长期可用,因此研发流程最后的清理环境步骤需要被移除。


4.4 如何在流程中关联其它类型的发布如函数计算?

可以在函数计算的相关步骤编排到研发流程的流水线 yaml 中,从而实现双方的联动。


点击此处,手把手带你体验云效应用交付 AppStack,还可抽取漫步者蓝牙耳机、护眼台灯等丰厚礼品。

5. 参考文档

[1] 如何通过 Nginx Ingress Controller 实现应用服务的灰度发布_容器服务 Kubernetes 版 ACK(ACK)

[2] Canary Deployments - Ingress-Nginx Controller


作者:子丑

相关实践学习
通过workbench远程登录ECS,快速搭建Docker环境
本教程指导用户体验通过workbench远程登录ECS,完成搭建Docker环境的快速搭建,并使用Docker部署一个Nginx服务。
深入解析Docker容器化技术
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。Docker是世界领先的软件容器平台。开发人员利用Docker可以消除协作编码时“在我的机器上可正常工作”的问题。运维人员利用Docker可以在隔离容器中并行运行和管理应用,获得更好的计算密度。企业利用Docker可以构建敏捷的软件交付管道,以更快的速度、更高的安全性和可靠的信誉为Linux和Windows Server应用发布新功能。 在本套课程中,我们将全面的讲解Docker技术栈,从环境安装到容器、镜像操作以及生产环境如何部署开发的微服务应用。本课程由黑马程序员提供。 &nbsp; &nbsp; 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
1月前
|
敏捷开发 测试技术 持续交付
云效产品使用常见问题之AppStack支持kustomize方式失败如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
12天前
|
弹性计算 人工智能 Kubernetes
基于云效 AppStack,5 分钟搞定一个 AI 应用的开发和部署
区别于传统的流水线工具,本实验将带你体验云效应用交付平台 AppStack,从应用视角,完成一个 AI 聊天应用的高效交付。
55270 16
|
22天前
|
弹性计算 人工智能 Kubernetes
基于云效 AppStack,5分钟搞定一个 AI 应用的开发和部署
实验介绍了如何使用云效应用交付平台AppStack快速初始化和部署AI聊天应用.
807 3
|
1月前
|
JSON 运维 Kubernetes
云效产品使用报错问题之流水线中配置了AppStack,构建时下载的制品内容为json字符串,如何解决
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
|
1月前
|
敏捷开发 运维 Kubernetes
云效产品使用常见问题之流水线的AppStack部署自动创建发布单让更新了编排配置后也自动创建失败如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
1月前
|
敏捷开发 Serverless 测试技术
云效产品使用常见问题之appstack部署单拿不到最新的镜像如何解决
云效作为一款全面覆盖研发全生命周期管理的云端效能平台,致力于帮助企业实现高效协同、敏捷研发和持续交付。本合集收集整理了用户在使用云效过程中遇到的常见问题,问题涉及项目创建与管理、需求规划与迭代、代码托管与版本控制、自动化测试、持续集成与发布等方面。
|
1月前
|
Cloud Native 测试技术 Nacos
云效 AppStack + 阿里云 MSE 实现应用服务全链路灰度
本文介绍了如何通过阿里云 MSE 微服务引擎和云效应用交付平台 AppStack 实现灰度发布。
91105 4
|
1月前
|
Kubernetes JavaScript API
云效常见问题之appstack连接自定义k8s连不上如何解决
云效(CloudEfficiency)是阿里云提供的一套软件研发效能平台,旨在通过工程效能、项目管理、质量保障等工具与服务,帮助企业提高软件研发的效率和质量。本合集是云效使用中可能遇到的一些常见问题及其答案的汇总。
294 1
|
1月前
|
Cloud Native 测试技术 Nacos
云效AppStack+阿里云MSE实现应用服务全链路灰度
在应用开发测试验证通过后、进行生产发布前,为了降低新版本发布带来的风险,期望能够先部署到灰度环境,用小部分业务流量进行全链路灰度验证,验证通过后再全量发布生产。本文主要介绍如何通过阿里云MSE 微服务引擎和云效应用交付平台AppStack 实现灰度发布。
121475 3
|
1月前
|
Kubernetes 应用服务中间件 网络安全
kubernetes中Ingress Nginx 常用规则使用
kubernetes中Ingress Nginx 常用规则使用
42 0