API 网关深度集成火山引擎容器服务 VKE,可实时动态获取 VKE 集群中部署的 K8S Service 信息,作为 K8S Service 对外提供服务的流量入口。同时,API 网关提供 Upstream 流量分配,方便用户进行服务的灰度发布,实现敏捷迭代、平滑升级。
本文为您介绍如何通过 API 网关实现 K8S 蓝绿部署和灰度发布。
为了保证服务稳定地对外提供服务,各企业都十分重视发布策略的选择。目前被业界广泛采用的服务发布策略有蓝绿部署和灰度发布,请根据实际情况选择适合的发布策略。
蓝绿部署:同时运行两个版本的应用。蓝绿部署期间,旧版本保持对外提供服务,等新版本运行起来后,再将流量全部切换至新版本。一般新版本与旧版本的资源规格保持一致,相当于该服务有两套完全相同的部署环境。新版本对外提供服务后,旧版本会作为热备。如果新版本上线后出现问题,可以迅速将流量切回旧版本,极大缩短故障恢复时间。
灰度发布:也称为金丝雀发布,是一种从旧版本平滑过渡到新版本的发布策略。该策略先上线一个新版本,从旧版本中切分一小部分线上流量到新版本,检验新版本在生产环境中的实际表现。新版本在环境中表现满足预期后,逐步加大流量分配比例,直至完全替代旧版本。
本文通过一个 http-server 服务,为您演示 K8S 蓝绿部署和灰度发布。该服务已提供一个查询当前版本的接口:请求路径为/version
。API 网关将该 http-server 服务抽象为一个 Upstream,并通过 Pod 标签来标识旧版本 v1 和新版本 v2。用户发送请求后,API 网关便可将请求按照设置的权重转发至新旧版本,实现应用的多版本流量管理。
部署 v1 应用,并通过 API 网关对外提供服务。
使用以下 YAML 样例,在容器服务控制台目标集群的 default 命名空间下部署一个 http-server 服务。具体操作可参见 创建无状态负载 和 集群内访问(ClusterIP)。
apiVersion: apps/v1 kind: Deployment metadata: name: http-server-v1 namespace: default spec: replicas: 2 selector: matchLabels: app: http-server-v1 template: metadata: labels: app: http-server-v1 version: v1 spec: containers: - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v1 imagePullPolicy: IfNotPresent name: http-server-v1 ports: - containerPort: 80 --- apiVersion: v1 kind: Service metadata: name: http-server namespace: default spec: ports: - name: http-server port: 80 protocol: TCP selector: app: http-server sessionAffinity: None type: ClusterIP
将当前 v1 应用所在 VKE 集群导入 API 网关。具体操作可参见 创建 Upstream 来源。
将该 VKE 集群中 default 命名空间下的 http-server 服务抽象为一个 Upstream。其中,协议选择 HTTP 1.1,TLS 设置选择 关闭 TLS,具体操作请参见 创建 VKE 类型 Upstream。
为该 Upstream 添加 version: v1
版本标识。该标识对应 K8S Pod 的标签spec.template.metadata.labels
,用于区分应用的不同版本。具体操作可参见 添加 Upstream 版本。 添加完成后, v1 应用即对应当前 Upstream 的 version1。
创建一条路由规则,将 http-server 暴露给外部用户。具体操作可参见 创建路由。 请求路径为/version
,目标 Upstream 为 http-server version1,权重为 100%。
执行以下测试请求命令:
for i in seq 1 10;do curl ${您的网关服务访问域名}/version;echo;done
响应结果:
{"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"}
可以发现,所有请求均转发至 v1,符合预期。
允许引流一小部分流量到服务新版本,待验证通过后,逐步调大流量,直至切流完毕,期间可伴随着新版本的扩容,旧版本的缩容操作,达到资源利用率最大化。
使用以下 YAML 样例,在容器服务控制台目标集群的 default 命名空间下部署 http-server 服务的新版本 v2。灰度发布策略中,新版本的副本数无需与原始保持一致,仅需保持资源始终满足灰度流量,故将副本数调为 1。
注意
v2 应用支持同集群部署和跨集群部署。
同集群部署时,需部署在同一集群同一命名空间下。
跨集群部署时,需部署在跨集群的同名命名空间下。
apiVersion: apps/v1 kind: Deployment metadata: name: http-server-v2 spec: replicas: 1 selector: matchLabels: app: http-server-v2 template: metadata: labels: app: http-server-v2 version: v2 spec: containers: - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v2 imagePullPolicy: IfNotPresent name: http-server-v2 ports: - containerPort: 80
(可选)如果 v2 应用跨集群部署,需将 v2 应用所在 VKE 集群导入同一 API 网关实例。导入成功后,之前创建的 Upstream 将同时监听这两个集群的 default 命名空间下的 http-server 服务。具体操作可参见 创建 Upstream 来源。
为之前创建的 Upstream 添加 version: v2
版本标识。具体操作可参见 添加 Upstream 版本。添加完成后, v1 应用对应当前 Upstream 的 version1,v2 应用对应当前 Upstream 的 version2。
修改之前创建的路由规则,将流量按所需权重转发至新旧版本。具体操作可参见 管理路由。 本示例设置 v1 应用权重为 80%,v2 应用权重为 20%。
将 http-server version1 的权重修改为 80%。
目标 Upstream 新增 http-server version2,并将 version2 的权重配置为 20%。
执行以下测试请求命令:
for i in seq 1 10;do curl ${您的网关服务访问域名}/version;echo;done
响应结果:
for i in seq 1 10 ;do curl sch51h4dt82rcefali1qg.apigateway-cn-beijing.volceapi.com/version;echo;done {"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: v1"} {"code": 200, "message": "version: v1"}
可以发现,10 个请求中有 2 个请求转发至新版本 v2,流量比符合期望比例。
注意
在真实业务场景中,新版本验证完毕后,便可继续调大访问新版本的流量权重。期间注意对新版本扩容,按需对旧版本缩容。
部署应用,并通过 API 网关对外提供服务。
使用以下 YAML 样例,在容器服务控制台目标集群的 default 命名空间下部署一个 http-server1 服务。具体操作可参见 创建无状态负载 和 集群内访问(ClusterIP)。
apiVersion: v1 kind: Service metadata: name: http-server1 namespace: default spec: ports: - name: http-server1 port: 80 protocol: TCP selector: app: http-server1 sessionAffinity: None type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: http-server1 namespace: default spec: replicas: 2 selector: matchLabels: app: http-server1 template: metadata: labels: app: http-server1 version: v1 spec: containers: - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v1 imagePullPolicy: IfNotPresent name: http-server1 ports: - containerPort: 80
将当前应用所在 VKE 集群导入 API 网关。具体操作可参见 创建 Upstream 来源。
将该 VKE 集群中 default 命名空间下的 http-server1 服务抽象为一个 Upstream。其中,协议选择 HTTP 1.1,TLS 设置选择 关闭 TLS,具体操作请参见 创建 VKE 类型 Upstream。
创建一条路由规则,将 http-server1 暴露给外部用户。具体操作可参见 创建路由。 请求路径为/version
,目标 Upstream 为 http-server1,权重为 100%。
执行以下测试请求命令:
for i in seq 1 10;do curl ${您的网关服务访问域名}/version;echo;done
响应结果:
{"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"}
可以发现,所有请求均转发至 v1,符合预期。
允许引流一小部分流量到新服务,待验证通过后,逐步调大流量,直至切流完毕,期间可伴随着新服务的扩容,旧服务的缩容操作,达到资源利用率最大化。
使用以下 YAML 样例,在容器服务控制台目标集群的 default 命名空间下部署 http-server2 新服务。灰度发布策略中,新服务的副本数无需与原始保持一致,仅需保持资源始终满足灰度流量,故将副本数调为 1。
注意
http-server2 应用支持同集群部署和跨集群部署。
同集群部署时,需部署在同一集群同一命名空间下。
跨集群部署时,需部署在跨集群的同名命名空间下。
apiVersion: v1 kind: Service metadata: name: http-server2 namespace: default spec: ports: - name: http-server2 port: 80 protocol: TCP selector: app: http-server2 sessionAffinity: None type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: http-server2 spec: replicas: 1 selector: matchLabels: app: http-server2 template: metadata: labels: app: http-server2 version: v2 spec: containers: - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v2 imagePullPolicy: IfNotPresent name: http-server2 ports: - containerPort: 80
(可选)如果 http-server2 应用跨集群部署,需将 http-server2 应用所在 VKE 集群导入同一 API 网关实例。导入成功后,之前创建的 Upstream 将同时监听这两个集群的 default 命名空间下的 http-server 服务。具体操作可参见 创建 Upstream 来源。
修改之前创建的路由规则,将流量按所需权重转发至新服务。具体操作可参见 管理路由。 本示例设置 http-server1 应用权重为 80%,http-server2 应用权重为 20%。
将 http-server1 的权重修改为 80%。
目标 Upstream 新增 http-server2,并将 http-server2 的权重配置为 20%。
执行以下测试请求命令:
for i in seq 1 10;do curl ${您的网关服务访问域名}/version;echo;done
响应结果:
for i in seq 1 10 ;do curl sch51h4dt82rcefali1qg.apigateway-cn-beijing.volceapi.com/version;echo;done {"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: v1"} {"code": 200, "message": "version: v1"}
可以发现,10 个请求中有 2 个请求转发至新服务,流量比符合期望比例。
注意
在真实业务场景中,新服务验证完毕后,便可继续调大访问新服务的流量权重。期间注意对新服务扩容,按需对旧服务缩容。
部署应用,并通过 API 网关对外提供服务。
使用以下 YAML 样例,在容器服务控制台目标集群的 default 命名空间下部署一个 http-server1 服务。具体操作可参见 创建无状态负载 和 集群内访问(ClusterIP)。
apiVersion: v1 kind: Service metadata: name: http-server1 namespace: default spec: ports: - name: http-server1 port: 80 protocol: TCP selector: app: http-server1 sessionAffinity: None type: ClusterIP --- apiVersion: apps/v1 kind: Deployment metadata: name: http-server1 namespace: default spec: replicas: 2 selector: matchLabels: app: http-server1 template: metadata: labels: app: http-server1 version: v1 spec: containers: - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v1 imagePullPolicy: IfNotPresent name: http-server1 ports: - containerPort: 80
将当前应用所在 VKE 集群导入 API 网关。具体操作可参见 创建 Upstream 来源。
将该 VKE 集群中 default 命名空间下的 http-server1 服务抽象为一个 Upstream。其中,协议选择 HTTP 1.1,TLS 设置选择 关闭 TLS,具体操作请参见 创建 VKE 类型 Upstream。
创建一条路由规则,将 http-server1 暴露给外部用户。具体操作可参见 创建路由。
请求路径为/version
,目标 Upstream 为 http-server1,权重为 100%。
执行以下测试请求命令:
for i in seq 1 10;do curl ${您的网关服务访问域名}/version;echo;done
响应结果:
{"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"}
可以发现,所有请求均转发至 v1,符合预期。
允许引流一小部分流量到新服务,待验证通过后,逐步调大流量,直至切流完毕,期间可伴随着新服务的扩容,旧服务的缩容操作,达到资源利用率最大化。
使用以下 YAML 样例,在容器服务控制台目标集群的 default 命名空间下部署 http-server2 新服务。灰度发布策略中,新服务的副本数无需与原始保持一致,仅需保持资源始终满足灰度流量,故将副本数调为 1。
注意
http-server2 应用支持同集群部署和跨集群部署。
同集群部署时,需部署在同一集群同一命名空间下。
跨集群部署时,需部署在跨集群的同名命名空间下。
apiVersion: apps/v1 kind: Deployment metadata: name: http-server2 spec: replicas: 1 selector: matchLabels: app: http-server2 template: metadata: labels: app: http-server2 version: v2 spec: containers: - image: cr-apig-cn-beijing.cr.volces.com/apig-demo/http-server:v2 imagePullPolicy: IfNotPresent name: http-server2 ports: - containerPort: 80
(可选)如果 http-server2 应用跨集群部署,需将 http-server2 应用所在 VKE 集群导入同一 API 网关实例。导入成功后,之前创建的 Upstream 将同时监听这两个集群的 default 命名空间下的 http-server 服务。具体操作可参见 创建 Upstream 来源。
创建另一个路由规则,将 http-server2 暴露给外部用户。具体操作可参见 管理路由。
配置请求头 Header,当 Header 中 foo 精准匹配 bar 时路由匹配。
目标 Upstream 新增 http-server2。
查看路由访问情况。
执行以下测试请求命令:
for i in seq 1 10;do curl ${您的网关服务访问域名}/version;echo;done
响应结果:
for i in seq 1 10 ;do curl sch51h4dt82rcefali1qg.apigateway-cn-beijing.volceapi.com/version;echo;done {"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"}
执行以下测试请求命令:
for i in seq 1 10;do curl -H "foo:bar" ${您的网关服务访问域名}/version;echo;done
响应结果:
for i in seq 1 10 ;do curl -H "foo:bar" sch51h4dt82rcefali1qg.apigateway-cn-beijing.volceapi.com/version;echo;done {"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"}
可以发现,两条路由都通过 www.example.com/
version 访问,如果带 Header(foo=bar),那就分流到 http-server-v2 上;否则分流到 http-server-v1 上,符合期望比例。
注意
在真实业务场景中,新服务验证完毕后,便可继续调大访问新服务的流量权重。期间注意对新服务扩容,按需对旧服务缩容。