目前,原生容器发布基本都是使用 deployment,通过给 deployment 和 service 灵活配置 labels ,可以实现一种基于服务版本的灰度发布。
由于原生 Ingress 对象描述能力的限制,一些常见 Ingress controller 的灰度发布功能也大打折扣,很难满足用户灰度发布的实际需求。
博云基于原生Ingress,做了大量增强,基于请求特征的灰度发布是其中一个重要特性。
通过配置 pod labels 和 service label selector,Kubernetes 原生支持灰度发布。假设我们部署了 echo-demo 服务的两个版本的 deployment:
name: echo-demo-v1
replicas: 3
…
labels:
app: echo-demo
track: stable
…
image: deploy.bocloud/ingress/echo-demo:1.0.0
> echo-demo-v2.yaml
name: echo-demo-v2
replicas: 2
…
labels:
app: echo-demo
track: canary
…
image: deploy.bocloud/ingress/echo-demo:2.0.0
以及一个 echo-demo service:
kind: Service
metadata:
name: echo-demo
spec:
ports:
– port: 80
protocol: TCP
targetPort: 8080
selector:
app: echo-demo
上述配置中,echo-demo service 聚合了 echo-demo-v1 和 echo-demo-v2 两个版本的服务,两个版本分别有 3 个和 2 个实例。此时我们访问 echo-demo service,请求将根据实例数量的占比按 3:2 的比例分布到 v1 和 v2 两个服务中。这样就实现了基于权重的灰度发布。
然而这种灰度发布却自有其限制和问题。首先,如果我们给服务加上自动水平伸缩(HPA),那么两个版本的服务将完全根据各自的负载情况独立调整 pod 实例数量,这样一来两个版本的实例数量和比例就会发生变化,打破我们一开始设置的灰度比例。其次,如果我们只想配置很小比例的请求到灰度版本,比如 100:1,那么在最少提供一个灰度版本 pod 的前提下,需要配置最少 100 个旧版本实例,很不灵活。第三,除了按比例的灰度策略,有时可能还需要根据请求特征来辨别用户并分配灰度服务到其中的一小部分。由于deployment有着上述的缺陷,导致其很少被当做灰度使用的原因。所以在实际应用当中,灰度发布基本上 由ingress来做。而这几个问题,都可以通过使用 Ingress 灰度发布方案来解决。
kind: Ingress
metadata:
name: echo-demo
labels:
app: echo-demo
annotations:
kubernetes.io/ingress.class: nginx
namespace: default
spec:
rules:
– host: test.domain.com
http:
paths:
– backend:
serviceName: echo-demo-v1
servicePort: 80
path: /echo
– backend:
serviceName: hello-world
servicePort: 8080
path: /hello
由 Ingress API 可以看到,一个域名下可以定义多个访问路径,然而一个路径却只能定义一个 service。于是,在使用 Ingress 对象来描述灰度发布的情形下,要实现一个访问端点与多个服务版本的映射,仍然只能采用上述一个 kubernetes service 聚合多个版本的 deployment 的方式,这种方案的种种问题上文已经分析过了。社区版 Nginx Ingress Controller 受限于 Ingress API 的描述能力,对灰度发布的支持完全是不可用的状态。有没有一种办法,既兼容 Ingress API,又能做到一个访问端点映射到多个 service 呢?
博云基于 Nginx Ingress Controller 开发的 Ingress 控制器 BeyondELB,设计了一种 Ingress 组合模型,在兼容 Ingress API 的基础上,用 labels 给 Ingress 对象分类,并将多个不同类别的 Ingress 对象组合成一个逻辑 Ingress,从而实现了一个访问端点到多个 service 的映射。这种组合模型为实现另一种灰度发布方案提供了可能。
实施基于权重的灰度发布
采用了 Ingress 组合模型的 BeyondELB 支持上述权重灰度发布策略。可以为某个 Ingress 访问路径定义一个或多个服务版本,然后为不同服务版本设定灰度权重,请求将按照灰度权重分配到不同版本的服务中。
上图中,选择开启基于权重的灰度发布,定义了一个灰度服务并设定 20 的权重,如果主版本服务的权重设定为 80(图中未给出主服务版本定义),则请求将按照 4:1 的比例分配到主版本服务和灰度版本服务。下面对配置了 80/20 权重的服务连续请求 100 次,可见流量按设定的比例分配到 v1 和 v2 服务中。
78 “1.0.0”
22 “2.0.0”
实施基于请求特征的版本级灰度发布
上图中,我们添加了一个灰度服务版本,并且设定灰度策略为“基于请求特征”。当请求附有名为 “canary” 值为 “true” 的请求 Header 时,将由该灰度服务版本响应;而其它未匹配该灰度条件的请求则由主服务版本响应(图中未给出主服务版本定义)。
我们通过以下两个脚本测试基于 Header 的灰度效果。
请求携带名为 canary 且其值为 “true” 的 Header:
100 “1.0.0”
请求不携带名为 “canary” 的 Header:
100 “2.0.0”