灰度发布
灰度发布是一种通过逐渐增加流向新版本的流量来推出新版本的策略。这种策略可以帮助用真实流量测试新版本,以便在全面推出之前识别并修复任何问题。

本指南将引导你完成使用 traffic-split 插件在 APISIX 中配置灰度发布的过程。
配置灰度发布
你将使用 httpbin.org 和 mock.api7.ai 作为旧服务和新服务。
首先,将所有流量引导到你的旧服务。为此,创建一个具有以下配置的路由:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "canary-deployment",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
// Annotate 1
"httpbin.org:443":1
}
},
// Annotate 1
"weight": 100
},
{
// Annotate 2
"weight": 0
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
// Annotate 2
"mock.api7.ai:443":1
}
}
}'
❶ 100% 的请求应路由到 httpbin.org。
❷ 0% 的请求应路由到 mock.api7.ai。
routes:
- uris:
- /headers
name: canary-deployment
plugins:
traffic-split:
rules:
- weighted_upstreams:
// Annotate 1
- weight: 100
upstream:
type: roundrobin
pass_host: node
nodes:
// Annotate 1
httpbin.org:443: 1
scheme: https
// Annotate 2
- weight: 0
upstream:
type: roundrobin
pass_host: node
nodes:
// Annotate 2
mock.api7.ai:443: 1
scheme: https
❶ 100% 的请求应路由到 httpbin.org。
❷ 0% 的请求应路由到 mock.api7.ai。
将配置同步到 APISIX:
adc sync -f apisix.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
plugins:
- name: traffic-split
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
// Annotate 1
httpbin.org:443: 1
// Annotate 1
weight: 100
// Annotate 2
- weight: 0
---
apiVersion: v1
kind: Service
metadata:
namespace: ingress-apisix
name: mockapi7-external-domain
spec:
type: ExternalName
// Annotate 2
externalName: mock.api7.ai
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: ingress-apisix
name: passhost-node
spec:
targetRefs:
- name: mockapi7-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: ingress-apisix
name: canary-deployment
spec:
parentRefs:
- name: apisix
rules:
- matches:
- path:
type: Exact
value: /headers
filters:
- type: ExtensionRef
extensionRef:
group: apisix.apache.org
kind: PluginConfig
name: traffic-split-plugin-config
backendRefs:
- name: mockapi7-external-domain
port: 443
weight: 1
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: mockapi7-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
// Annotate 2
name: mock.api7.ai
weight: 1
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixPluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
ingressClassName: apisix
plugins:
- name: traffic-split
enable: true
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
// Annotate 1
httpbin.org:443: 1
// Annotate 1
weight: 100
// Annotate 2
- weight: 0
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: canary-deployment
spec:
ingressClassName: apisix
http:
- name: canary-deployment
match:
paths:
- /headers
plugin_config_name: traffic-split-plugin-config
upstreams:
- name: mockapi7-external-domain
❶ 100% 的请求应路由到 httpbin.org。
❷ 0% 的请求应路由到 mock.api7.ai。
将配置应用到你的集群:
kubectl apply -f canary-deployment.yaml
因此,如果你发送 100 个请求,APISIX 会将它们全部定向到 httpbin.org:
resp=$(seq 100 | xargs -I{} curl "http://127.0.0.1:9080/headers" -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
你将得到以下响应:
httpbin.org: 100, mock.api7.ai: 0
接下来,更新配置以将 5% 的请求定向到新服务:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "canary-deployment",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
},
"weight": 95
},
{
"weight": 5
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
routes:
- uris:
- /headers
name: canary-deployment
plugins:
traffic-split:
rules:
- weighted_upstreams:
- weight: 95
upstream:
type: roundrobin
pass_host: node
nodes:
httpbin.org:443: 1
scheme: https
- weight: 5
upstream:
type: roundrobin
pass_host: node
nodes:
mock.api7.ai:443: 1
scheme: https
将配置同步到 APISIX:
adc sync -f apisix.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
plugins:
- name: traffic-split
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
httpbin.org:443: 1
weight: 95
- weight: 5
apiVersion: apisix.apache.org/v2
kind: ApisixPluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
ingressClassName: apisix
plugins:
- name: traffic-split
enable: true
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
httpbin.org:443: 1
weight: 95
- weight: 5
将配置应用到你的集群:
kubectl apply -f canary-deployment.yaml
现在,如果你发送 100 个请求,其中 5 个将被定向到 mock.api7.ai:
resp=$(seq 100 | xargs -I{} curl "http://127.0.0.1:9080/headers" -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
响应将如下所示:
httpbin.org: 95, mock.api7.ai: 5
灰度发布背后的想法是通过一小部分请求测试新版本,以最大程度地减少任何问题的影响。一旦此版本经过测试,请逐渐增加发送到新版本的请求百分比,直到所有请求都路由到它:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "canary-deployment",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
},
"weight": 0
},
{
"weight": 100
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}'
routes:
- uris:
- /headers
name: canary-deployment
plugins:
traffic-split:
rules:
- weighted_upstreams:
- weight: 0
upstream:
type: roundrobin
pass_host: node
nodes:
httpbin.org:443: 1
scheme: https
- weight: 100
upstream:
type: roundrobin
pass_host: node
nodes:
mock.api7.ai:443: 1
scheme: https
将配置同步到 APISIX:
adc sync -f apisix.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
plugins:
- name: traffic-split
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
httpbin.org:443: 1
weight: 0
- weight: 100
apiVersion: apisix.apache.org/v2
kind: ApisixPluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
ingressClassName: apisix
plugins:
- name: traffic-split
enable: true
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
httpbin.org:443: 1
weight: 0
- weight: 100
将配置应用到你的集群:
kubectl apply -f canary-deployment.yaml
现在,所有请求都将定向到 mock.api7.ai:
resp=$(seq 100 | xargs -I{} curl "http://127.0.0.1:9080/headers" -sL) && \
count_httpbin=$(echo "$resp" | grep "httpbin.org" | wc -l) && \
count_mockapi7=$(echo "$resp" | grep "mock.api7.ai" | wc -l) && \
echo httpbin.org: $count_httpbin, mock.api7.ai: $count_mockapi7
从响应中可以看出这一点:
httpbin.org: 0, mock.api7.ai: 100
如果新版本有问题,请通过更新配置回滚到旧服务,直到问题解决。
配置高级灰度发布
你还可以使用 traffic-split 插件以更细粒度的方式部署你的版本。下面的示例展示了如何基于标头路由请求。
当你希望让你的客户端更多地控制他们访问哪个版本时,这很有用。客户端也可以通过修改/删除标头轻松回退到旧版本。
如下所示在路由中配置此项:
- Admin API
- ADC
- Ingress Controller
curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"uri": "/headers",
"id": "canary-deployment",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["http_release","==","new"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"mock.api7.ai:443":1
}
}
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"scheme": "https",
"pass_host": "node",
"nodes": {
"httpbin.org:443":1
}
}
}'
routes:
- uris:
- /headers
name: canary-deployment
plugins:
traffic-split:
rules:
- match:
- vars:
- - http_release
- ==
- new
weighted_upstreams:
- weight: 1
upstream:
type: roundrobin
pass_host: node
nodes:
mock.api7.ai:443: 1
scheme: https
upstream:
type: roundrobin
pass_host: node
nodes:
httpbin.org:443: 1
scheme: https
将配置同步到 APISIX:
adc sync -f apisix.yaml
- Gateway API
- APISIX CRD
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
plugins:
- name: traffic-split
config:
rules:
- match:
- vars:
- ["http_release","==","new"]
weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
mock.api7.ai:443: 1
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: ingress-apisix
name: httpbin-external-domain
spec:
ingressClassName: apisix
scheme: https
passHost: node
externalNodes:
- type: Domain
name: httpbin.org
weight: 1
port: 443
---
apiVersion: apisix.apache.org/v2
kind: ApisixPluginConfig
metadata:
namespace: ingress-apisix
name: traffic-split-plugin-config
spec:
ingressClassName: apisix
plugins:
- name: traffic-split
enable: true
config:
rules:
- match:
- vars:
- ["http_release","==","new"]
weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
mock.api7.ai:443: 1
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: ingress-apisix
name: canary-deployment
spec:
ingressClassName: apisix
http:
- name: canary-deployment
match:
paths:
- /headers
plugin_config_name: traffic-split-plugin-config
upstreams:
- name: httpbin-external-domain
将配置应用到你的集群:
kubectl apply -f canary-deployment.yaml
现在,当你发送带有 release 标头的请求时:
curl "http://127.0.0.1:9080/headers" -H 'release: new'
你将看到来自 mock.api7.ai 的响应:
{
"headers": {
"accept": "*/*",
"host": "mock.api7.ai",
...
}
}
如果你不指定 release 标头:
curl "http://127.0.0.1:9080/headers"
APISIX 将回退到 httpbin.org 上游:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
...
}
}
请参阅 traffic-split 插件文档以了解更多信息。