配置金丝雀流量转移
金丝雀流量转移(Canary traffic shifting)能够通过将少量流量逐渐路由到新的上游(upstreams),同时将大部分流量保持在稳定的默认上游,从而安全地测试新的上游。这种增量方法通过将潜在问题控制在有限的用户范围内来降低风险,让你能够在不影响更广泛用户群的情况下识别并解决问题。
金丝雀流量转移与金丝雀发布不同,因为 API/服务版本是不变的。金丝雀发布是指同一 API/服务的两个版本的并发运行和可用。
先决条件
- 安装 API7 企业版。
- 创建一个路由 到
/headers。
按权重转移流量
在这个示例中,你将把 10% 的流量引导到一个新的上游。其余 90% 的流量将继续转发到默认上游。
在测试完新上游后,考虑用新值重写默认上游配置,并删除插件以终止金丝雀过程。
- Dashboard
- ADC
- Ingress Controller
- 从侧边导航栏选择你网关组的 已发布服务,然后点击你要修改的服务,例如版本为
1.0.0的httpbin。 - 在该服务下,从侧边导航栏选择 上游。
- 在 连接配置 模块中,点击 编辑,在 连接配置 模块中,选择
node,然后点击 保存。注意:由于
mock.api7.ai强制使用 HTTPS 访问,上游需要配置为对 HTTPS 端点使用443端口。pass_host参数必须更改为 node,以确保成功与上游握手。请根据你的实际情况进行调整。 - 点击 新增上游。
- 在对话框中,执行以下操作:
- 在 名称 字段中,输入
new upstream。 - 点击 新增节点 来调整节点的主机,使其指向新的后端。例如,使用
mock.api7.ai作为主机,443作为端口。 - 点击 新增。
- 在 名称 字段中,输入
- 在上游标题处(在 操作 按钮下方)点击 查看 ID 并复制以供使用。
- 在已发布的服务下,从侧边导航栏选择 插件。
- 点击 新增插件。
- 搜索
traffic-split插件,然后点击 新增。 - 在对话框中,执行以下操作:
-
将以下配置添加到 JSON 编辑器:
{
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": "new_upstream_id", // 使用 upstream id, 而不是 upstream name
"weight": 1
},
{
"weight": 9
}
]
}
]
} -
点击 新增。
验证
通过发送 10 个请求来验证金丝雀规则:
for i in {1..10}; do "curl 127.0.0.1:9080/headers"; done
9 个请求将被发送到默认上游地址 httpbin.org,你将收到以下响应:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6650ab7e-32c90eba787abbeb4e3dbb0c",
"X-Forwarded-Host": "127.0.0.1"
}
}
有 1 个请求将被发送到新上游地址 mock.api7.ai:
{
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, br",
"cf-connecting-ip": "159.89.160.194",
"cf-ipcountry": "IN",
"cf-ray": "888e28733f9604aa",
"cf-visitor": "{\"scheme\":\"https\"}",
"connection": "Keep-Alive",
"content-type": "application/json",
"host": "mock.api7.ai",
"user-agent": "curl/7.74.0",
"x-application-owner": "API7.ai",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "9080",
"x-forwarded-proto": "https",
"x-real-ip": "159.89.160.194",
"X-Application-Owner": "API7.ai",
"Content-Type": "application/json"
}
}
下面是此用例的交互式演示。点击并按照此演示中的步骤操作,你将更好地了解如何在 API7 企业版中使用它。
更新你的 ADC 配置文件(adc.yaml)以包含新的上游。完整配置如下:
services:
- name: httpbin
upstream:
name: Test Group
scheme: https
nodes:
- host: httpbin.org
port: 443
weight: 100
upstreams:
- name: newupstream
nodes:
- host: mock.api7.ai
port: 443
weight: 100
scheme: https
routes:
- uris:
- /headers
name: getting-started-headers
methods:
- GET
plugins:
traffic-split:
rules:
- weighted_upstreams:
- upstream_id: new_upstream_id # 使用 upstream id, 而不是 upstream name
weight: 1
- weight: 9
将配置同步到 API7 企业版:
adc sync -f adc.yaml
验证
通过发送 10 个请求来验证金丝雀规则:
for i in {1..10}; do curl "127.0.0.1:9080/headers"; done
9 个请求将被发送到 httpbin.org,你将收到以下响应:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6650ab7e-32c90eba787abbeb4e3dbb0c",
"X-Forwarded-Host": "127.0.0.1"
}
}
有 1 个请求将被发送到 mock.api7.ai:
{
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, br",
"cf-connecting-ip": "159.89.160.194",
"cf-ipcountry": "IN",
"cf-ray": "888e28733f9604aa",
"cf-visitor": "{\"scheme\":\"https\"}",
"connection": "Keep-Alive",
"content-type": "application/json",
"host": "mock.api7.ai",
"user-agent": "curl/7.74.0",
"x-application-owner": "API7.ai",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "9080",
"x-forwarded-proto": "https",
"x-real-ip": "159.89.160.194",
"X-Application-Owner": "API7.ai",
"Content-Type": "application/json"
}
}
现在,将权重更新为 50:50,以允许一半的流量被路由到新上游:
services:
- name: httpbin
upstream:
name: Test Group
scheme: https
nodes:
- host: httpbin.org
port: 443
weight: 100
plugins:
api7-traffic-split:
rules:
- canary_upstreams:
- upstream_name: newupstream
weight: 50
- weight: 50
upstreams:
- name: newupstream
nodes:
- host: mock.api7.ai
port: 443
weight: 100
scheme: https
routes:
- uris:
- /headers
name: getting-started-headers
methods:
- GET
发送更多请求以测试新上游。最后,更新默认上游以完成金丝雀流量转移:
services:
- name: httpbin
upstream:
name: Test Group
scheme: https
nodes:
- host: mock.api7.ai
port: 443
weight: 100
routes:
- uris:
- /headers
name: getting-started-headers
methods:
- GET
请注意,API7 Ingress Controller 不支持在 traffic-split 插件中使用 upstream_id。
- Gateway API
- APISIX CRD
创建一个路由(同时创建一个服务)的 Kubernetes 清单文件,在该服务中启用了 traffic-split 以实现 10%/90% 的流量拆分:
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: api7
name: traffic-split-plugin-config
spec:
plugins:
- name: traffic-split
config:
rules:
- weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
mock.api7.ai:443: 1
weight: 1
- weight: 9
---
apiVersion: v1
kind: Service
metadata:
namespace: api7
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: api7
name: passhost-node
spec:
targetRefs:
- name: httpbin-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: api7
name: getting-started-ip
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: httpbin-external-domain
port: 443
weight: 1
创建一个路由(同时创建一个服务)的 Kubernetes 清单文件,在该服务中启用了 traffic-split 以实现 10%/90% 的流量拆分:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: api7
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: api7
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:
mock.api7.ai:443: 1
weight: 1
- weight: 9
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: api7
name: getting-started-headers
spec:
ingressClassName: apisix
http:
- name: getting-started-headers
match:
paths:
- /headers
plugin_config_name: traffic-split-plugin-config
upstreams:
- name: httpbin-external-domain
或者,你也可以不使用 traffic-split 插件,直接为上游服务分配 weight。
将配置应用到你的集群:
kubectl apply -f traffic-split.yaml
请注意,如果你使用的是 Gateway API,该插件将出现在服务级别 。如果你使用的是 APISIX CRD,该插件将出现在路由级别。
按条件转移流量:请求头
在此示例中,你将把带有 version = test 请求头的请求引导到新上游,而其余流量将继续发送到默认上游。该金丝雀规则适用于服务中的所有路由,并且不能应用于单个路由。
- Dashboard
- ADC
- Ingress Controller
- 从侧边导航栏选择你网关组的 已发布服务,然后点击你要修改的服务,例如版本为
1.0.0的httpbin。 - 在该服务下,从侧边导航栏选择 上游。
- 点击 新增上游。
- 在对话框中,执行以下操作:
- 在 名称 字段中,输入
new upstream。 - 点击 新增节点 来调整节点的主机,使其指向新的后端。例如,使用
mock.api7.ai作为主机,443作为端口。 - 点击 Add。
- 在 名称 字段中,输入
- 在上游标题处(在 操作 按钮下方)点击 查看 ID 并复制以供使用。
- 在已发布的服务下,从侧边导航栏选择 插件。
- 点击 新增插件。
- 搜索
traffic-split插件,然后点击 新增。 - 在对话框中,执行以下操作:
-
将以下配置添加到 JSON 编辑器:
{
"rules": [
{
"match": [
{
"vars": [
[
"version",
"==",
"test"
]
]
}
],
"weighted_upstreams": [
{
"upstream_id": "new_upstream_id", // 使用 upstream id, 而不是 upstream name
"weight": 1
},
{
"weight": 9
}
]
}
]
} -
点击 Add。
验证
通过发送请求来验证金丝雀规则:
-
发送一个带有
version:test请求头的请求:curl 127.0.0.1:9080/headers -H "version:test"你将收到来自新上游的以下响应:
{
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, br",
"cf-connecting-ip": "159.89.160.194",
"cf-ipcountry": "IN",
"cf-ray": "888e28733f9604aa",
"cf-visitor": "{\"scheme\":\"https\"}",
"connection": "Keep-Alive",
"content-type": "application/json",
"host": "mock.api7.ai",
"user-agent": "curl/7.74.0",
"x-application-owner": "API7.ai",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "9080",
"x-forwarded-proto": "https",
"x-real-ip": "159.89.160.194",
"X-Application-Owner": "API7.ai",
"Content-Type": "application/json"
}
} -
发送一个带有错误请求头的请求:
curl 127.0.0.1:9080/headers -H "version:new"你将收到来自默认上游的以下响应:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6650ab7e-32c90eba787abbeb4e3dbb0c",
"X-Forwarded-Host": "127.0.0.1"
}
} -
发送一个没有请求头的请求:
curl 127.0.0.1:9080/headers -
你将收到来自默认上游的以下响应:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6650ab7e-32c90eba787abbeb4e3dbb0c",
"X-Forwarded-Host": "127.0.0.1"
}
} -
发送更多请求以测试新上游,直到它符合你的期望。
更新你的 ADC 配置文件(adc.yaml)以包含新的上游。完整配置如下:
services:
- name: httpbin
upstream:
name: default
scheme: https
nodes:
- host: httpbin.org
port: 443
weight: 100
upstreams:
- name: newupstream
nodes:
- host: mock.api7.ai
port: 443
weight: 100
scheme: https
routes:
- uris:
- /headers
name: getting-started-headers
methods:
- GET
plugins:
traffic-split:
rules:
- match:
- vars:
- - version
- "=="
- test
weighted_upstreams:
- upstream_id: new_upstream_id # 使用 upstream id, 而不是 upstream name
weight: 1
- weight: 9
将配置同步到 API7 网关:
adc sync -f adc.yaml
通过发送带有 version:test 请求头的请求来验证金丝雀规则:
curl 127.0.0.1:9080/headers -H "version:test"
你将收到来自新上游的响应:
{
"headers": {
"accept": "*/*",
"accept-encoding": "gzip, br",
"cf-connecting-ip": "159.89.160.194",
"cf-ipcountry": "IN",
"cf-ray": "888e28733f9604aa",
"cf-visitor": "{\"scheme\":\"https\"}",
"connection": "Keep-Alive",
"content-type": "application/json",
"host": "mock.api7.ai",
"user-agent": "curl/7.74.0",
"x-application-owner": "API7.ai",
"x-forwarded-for": "127.0.0.1",
"x-forwarded-host": "127.0.0.1",
"x-forwarded-port": "9080",
"x-forwarded-proto": "https",
"x-real-ip": "159.89.160.194",
"X-Application-Owner": "API7.ai",
"Content-Type": "application/json"
}
}
发送带有错误请求头的请求:
curl 127.0.0.1:9080/headers -H "version:new"
你将收到来自默认上游的以下响应:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6650ab7e-32c90eba787abbeb4e3dbb0c",
"X-Forwarded-Host": "127.0.0.1"
}
}
发送没有请求头的请求:
curl 127.0.0.1:9080/headers
你将收到来自默认上游的以下响应:
{
"headers": {
"Accept": "*/*",
"Host": "httpbin.org",
"User-Agent": "curl/7.74.0",
"X-Amzn-Trace-Id": "Root=1-6650ab7e-32c90eba787abbeb4e3dbb0c",
"X-Forwarded-Host": "127.0.0.1"
}
}
使用新上游的值更新默认上游以完成金丝雀流量转移:
services:
- name: httpbin
upstream:
name: Test Group
scheme: https
nodes:
- host: mock.api7.ai
port: 443
weight: 100
routes:
- uris:
- /headers
name: getting-started-headers
methods:
- GET
你将学习如何使用 traffic-split 插件按权重和按条件转移流量。
- Gateway API
- APISIX CRD
创建一个路由(同时创建一个服务)的 Kubernetes 清单文件,在该服务中启用了 traffic-split:
apiVersion: apisix.apache.org/v1alpha1
kind: PluginConfig
metadata:
namespace: api7
name: traffic-split-plugin-config
spec:
plugins:
- name: traffic-split
config:
rules:
- match:
- vars:
- - version
- "=="
- test
weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
mock.api7.ai:443: 1
weight: 1
- weight: 9
---
apiVersion: v1
kind: Service
metadata:
namespace: api7
name: httpbin-external-domain
spec:
type: ExternalName
externalName: httpbin.org
---
apiVersion: apisix.apache.org/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: api7
name: passhost-node
spec:
targetRefs:
- name: httpbin-external-domain
kind: Service
group: ""
passHost: node
scheme: https
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: api7
name: getting-started-ip
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: httpbin-external-domain
port: 443
weight: 1
创建一个路由(同时创建一个服务)的 Kubernetes 清单文件,在该服务中像这样配置了 traffic-split:
apiVersion: apisix.apache.org/v2
kind: ApisixUpstream
metadata:
namespace: api7
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: api7
name: traffic-split-plugin-config
spec:
ingressClassName: apisix
plugins:
- name: traffic-split
enable: true
config:
rules:
- match:
- vars:
- - version
- "=="
- test
weighted_upstreams:
- upstream:
scheme: https
pass_host: node
nodes:
mock.api7.ai:443: 1
weight: 1
- weight: 9
---
apiVersion: apisix.apache.org/v2
kind: ApisixRoute
metadata:
namespace: api7
name: getting-started-headers
spec:
ingressClassName: apisix
http:
- name: getting-started-headers
match:
paths:
- /headers
plugin_config_name: traffic-split-plugin-config
upstreams:
- name: httpbin-external-domain
将配置应用到你的集群:
kubectl apply -f traffic-split.yaml
请注意,如果你使用的是 Gateway API,该插件将出现在服务级别。如果你使用的是 APISIX CRD,该插件将出现在路由级别。
附加资源
- 核心概念
- 插件中心