You need to enable JavaScript to run this app.
导航
使用 Annotation 实现容器服务应用的蓝绿发布和灰度发布
最近更新时间:2024.12.04 16:05:46首次发布时间:2024.06.19 10:13:18

API 网关深度集成火山引擎容器服务 VKE,可实时动态获取 VKE 集群中部署的 K8S Service 信息,作为 K8S Service 对外提供服务的流量入口。同时,API 网关提供 Upstream 和流量权重能力,方便用户进行服务的灰度发布,实现敏捷迭代、平滑升级。本文为您介绍如何通过 API 网关实现容器服务中应用的蓝绿部署和灰度发布。

应用场景

为了保证服务稳定地对外提供服务,各企业都十分重视发布策略的选择。目前被业界广泛采用的服务发布策略有蓝绿部署和灰度发布,请根据实际情况选择适合的发布策略。

  • 蓝绿部署:同时运行两个版本的应用。蓝绿部署期间,旧版本保持对外提供服务,等新版本运行起来后,再将流量全部切换至新版本。一般新版本与旧版本的资源规格保持一致,相当于该服务有两套完全相同的部署环境。新版本对外提供服务后,旧版本会作为热备。如果新版本上线后出现问题,可以迅速将流量切回旧版本,极大缩短故障恢复时间。
  • 灰度发布:也称为金丝雀发布,是一种从旧版本平滑过渡到新版本的发布策略。该策略先上线一个新版本,从旧版本中切分一小部分线上流量到新版本,检验新版本在生产环境中的实际表现。新版本在环境中表现满足预期后,逐步加大流量分配比例,直至完全替代旧版本。

背景信息

本文通过配置 2 个服务,为您演示容器服务集群中应用的蓝绿部署和灰度发布。该服务已提供一个查询当前版本的接口,请求路径为/version。用户发送请求后,API 网关可将请求按照 Header 或权重转发至不同的服务,实现应用的多版本流量管理。
alt

前提条件

基于 Header 实现灰度发布

步骤一:部署旧版本应用

  1. 使用如下 YAML 配置,在容器服务集群中部署 v1 版本应用和服务。

    apiVersion: v1
    kind: Service
    metadata:
      name:  service-old
      namespace: default
    spec:
      ports:
      - name: port
        port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: old
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: app-old
      namespace: default 
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: old
      template:
        metadata:
          labels:
            app: old
        spec:
          containers:
          - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v1
            name: demo
            ports:
            - containerPort: 80
    
  2. 使用如下 YAML 配置,在集群中创建 Ingress。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-old
      namespace: default
    spec:
      ingressClassName: apig
      rules:
        - host: apig-example.com
          http:
            paths:
              - backend:
                  service:
                    name: service-old
                    port:
                      number: 80
                path: /version
                pathType: Exact
    
  3. 执行以下命令,进行 10 次访问测试。

    for i in {1..10}; do curl apig-example.com/version;echo;done
    

    预期结果如下,所有请求均成功转发至 v1 版本应用。

    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    

步骤二:灰度发布新版本服务

  1. 使用如下 YAML 配置,在容器服务集群中部署 v2 版本应用和服务。

    注意

    使用 API 网关实例发布容器服务集群中的应用,支持同集群部署和跨集群部署。

    • 同集群部署时,应用需部署在同一集群同一命名空间下。
    • 跨集群部署时,应用需部署在跨集群的同名命名空间下。
    apiVersion: v1
    kind: Service
    metadata:
      name: service-new
      namespace: default
    spec:
      ports:
      - name: port
        port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: new
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: app-new
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: new
      template:
        metadata:
          labels:
            app: new
        spec:
          containers:
          - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v2
            name: demo
            ports:
            - containerPort: 80
    
  2. 使用如下 YAML 配置,在集群中为新版本服务创建 Ingress。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/canary: 'true'
        # 开启灰度发布
        nginx.ingress.kubernetes.io/canary-by-header: 'foo'
        nginx.ingress.kubernetes.io/canary-by-header-value: 'bar'
        # headers 中包含 foo=bar 时,转发至 v2 版本的服务。不带此 header 时,转发至 v1 版本的服务
      name: ingress-new
      namespace: default
    spec:
      ingressClassName: apig
      rules:
        - host: apig-example.com
          http:
            paths:
              - backend:
                  service:
                    name: service-new
                    port:
                      number: 80
                path: /version
                pathType: Exact
    
  3. 执行以下命令,不带 Header 进行 10 次访问测试。

    for i in {1..10}; do curl apig-example.com/version;echo;done
    

    预期结果如下,所有请求均成功转发至 v1 版本应用。

    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    
  4. 执行以下命令,带 Header 进行 10 次访问测试。

    for i in {1..10}; do curl -H "foo:bar" ${网关服务域名}/version;echo;done
    

    预期结果如下,所有请求均成功转发至 v2 版本应用。

    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v2"}
    

综上结果可以发现,两条路由都通过 apig-example.com/version 访问,如果带 Header(foo=bar),则转发至 v2 版本服务;否则转发至 v1 版本服务。实现了基于 Header 的灰度发布。

注意

在真实业务场景中,新版本验证完毕后,便可继续调大访问新版本的流量权重。期间注意对新版本扩容,按需对旧版本缩容。

基于权重实现灰度发布

步骤一:部署旧版本应用

  1. 使用如下 YAML 配置,在容器服务集群中部署 v1 版本应用和服务。

    apiVersion: v1
    kind: Service
    metadata:
      name:  service-old
      namespace: default
    spec:
      ports:
      - name: port
        port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: old
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: app-old
      namespace: default 
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: old
      template:
        metadata:
          labels:
            app: old
        spec:
          containers:
          - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v1
            name: demo
            ports:
            - containerPort: 80
    
  2. 使用如下 YAML 配置,在集群中创建 Ingress。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: ingress-old
      namespace: default
    spec:
      ingressClassName: apig
      rules:
        - host: apig-example.com
          http:
            paths:
              - backend:
                  service:
                    name: service-old
                    port:
                      number: 80
                path: /version
                pathType: Exact
    
  3. 执行以下命令,进行 10 次访问测试。

    for i in {1..10}; do curl apig-example.com/version;echo;done
    

    预期结果如下,所有请求均成功转发至 v1 版本应用。

    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    

步骤二:灰度发布新版本服务

  1. 使用如下 YAML 配置,在容器服务集群中部署 v2 版本应用和服务。

    注意

    使用 API 网关实例发布容器服务集群中的应用,支持同集群部署和跨集群部署。

    • 同集群部署时,应用需部署在同一集群同一命名空间下。
    • 跨集群部署时,应用需部署在跨集群的同名命名空间下。
    apiVersion: v1
    kind: Service
    metadata:
      name: service-new
      namespace: default
    spec:
      ports:
      - name: port
        port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: new
      type: ClusterIP
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: app-new
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: new
      template:
        metadata:
          labels:
            app: new
        spec:
          containers:
          - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v2
            name: demo
            ports:
            - containerPort: 80
    
  2. 使用如下 YAML 配置,在集群中为新版本服务创建 Ingress。

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/canary: 'true'
        # 开启灰度发布
        nginx.ingress.kubernetes.io/canary-weight: '30'
        # 配置流量权重,将 30% 的流量转发至 v2 服务,70% 的流量转发至 v1 服务
      name: ingress-new
      namespace: default
    spec:
      ingressClassName: apig
      rules:
        - host: apig-example.com
          http:
            paths:
              - backend:
                  service:
                    name: service-new
                    port:
                      number: 80
                path: /version
                pathType: Exact
    
  3. 执行以下命令,进行 10 次访问测试。

    for i in {1..10}; do curl apig-example.com/version;echo;done
    

    预期结果如下,10 个请求中有 3 个请求转发至新版本 v2,流量比符合预期。

    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v1"}
    {"code": 200, "message": "version: v2"}
    {"code": 200, "message": "version: v1"}
    

    注意

    在真实业务场景中,新版本验证完毕后,便可继续调大访问新版本的流量权重。期间注意对新版本扩容,按需对旧版本缩容。