在现代微服务架构中,Canary 发布(金丝雀发布)是一种流行的部署策略。它通过将新版本逐步推广到一小部分用户,观察其表现并降低风险,最终实现平稳过渡。本文将详细讲解如何利用 NGINX Ingress Controller 在 Kubernetes 中配置 Canary 发布。
Canary 发布是一种渐进式部署方式,其核心思想是将新版本的服务首先部署到生产环境中的一小部分用户(称为“金丝雀”),通过监控其性能和用户反馈来验证稳定性。如果一切正常,再逐步将流量切换到新版本;如果发现问题,则可以快速回滚。这种策略在减少部署风险的同时,保证了用户体验。
NGINX Ingress Controller 通过一系列注解(annotations)提供了灵活的 Canary 发布支持。这些注解允许开发者控制流量在不同服务版本之间的分配方式。常见的注解包括:
nginx.ingress.kubernetes.io/canary
:设为 "true"
以启用 Canary 功能。nginx.ingress.kubernetes.io/canary-weight
:基于权重的流量分配,值为 0-100,表示 Canary 版本接收的流量百分比。nginx.ingress.kubernetes.io/canary-by-header
:基于请求头的流量分配,指定检查的请求头名称。nginx.ingress.kubernetes.io/canary-by-header-value
:与 canary-by-header
配合使用,指定触发 Canary 的请求头值。nginx.ingress.kubernetes.io/canary-by-cookie
:基于 Cookie 的流量分配,指定检查的 Cookie 名称。在本文中,我们将以基于 Cookie 的 Canary 发布为例,展示具体的配置过程。
假设我们有一个主服务 nginx
和一个 Canary 服务 nginx-hello-world
,目标是根据用户请求中的 Cookie 值,将部分流量路由到 Canary 版本。以下是完整的配置步骤和代码。
首先,创建一个 ConfigMap,用于存储 Canary 版本的自定义页面 index.html
:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-index
data:
index.html: |
Hello World
Hello, World!
这个 ConfigMap 将提供一个简单的“Hello, World!”页面,作为 Canary 版本的响应内容。
接下来,部署 Canary 版本的 NGINX 服务,并挂载上述 ConfigMap 中的 index.html
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-hello-world
labels:
app: nginx-hello-world
spec:
replicas: 1
selector:
matchLabels:
app: nginx-hello-world
template:
metadata:
labels:
app: nginx-hello-world
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
volumeMounts:
- name: nginx-config
mountPath: /usr/share/nginx/html/index.html
subPath: index.html
volumes:
- name: nginx-config
configMap:
name: nginx-index
为 Canary 版本创建一个 Service:
apiVersion: v1
kind: Service
metadata:
name: nginx-hello-world
spec:
selector:
app: nginx-hello-world
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
部署主版本的 NGINX 服务,这里我们使用一个自定义镜像 nextvirus/nginx:cookie
(假设它包含主版本的逻辑):
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nextvirus/nginx:cookie
ports:
- containerPort: 80
为主版本创建一个 Service:
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP
最后,配置两个 Ingress 资源,分别定义主版本和 Canary 版本的路由规则:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
ingressClassName: nginx
rules:
- host: n.com # 替换为你的域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx
port:
number: 80
在配置完成后需要先访问下页面设置下 cookie。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress-hello-world
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-cookie: "testCookie"
spec:
ingressClassName: nginx
rules:
- host: n.com # 替换为你的域名
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-hello-world
port:
number: 80
在上述配置中:
nginx-ingress
):默认将流量路由到主服务 nginx
。nginx-ingress-hello-world
):通过注解启用 Canary 功能,并使用 canary-by-cookie: "testCookie"
指定基于 Cookie 的路由规则。testCookie
的 Cookie 且其值满足条件(例如值为 true
),流量将被路由到 Canary 服务 nginx-hello-world
;否则,流量将路由到主服务 nginx
。部署完成后,可以通过以下方式测试:
不带 Cookie 的请求:
curl http://n.com
结果将返回主服务的响应。
带特定 Cookie 的请求:
curl -b "testCookie=true" http://n.com
结果将返回 Canary 服务的响应,cookie设置页面。
除了基于 Cookie 的方式,NGINX Ingress Controller 还支持以下策略:
通过注解 nginx.ingress.kubernetes.io/canary-weight
设置流量百分比。例如:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
这表示 20% 的流量将被路由到 Canary 服务。
通过注解 nginx.ingress.kubernetes.io/canary-by-header
和 nginx.ingress.kubernetes.io/canary-by-header-value
指定。例如:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "X-Canary"
nginx.ingress.kubernetes.io/canary-by-header-value: "true"
当请求头 X-Canary
的值为 true
时,流量将被路由到 Canary 服务。
通过 NGINX Ingress Controller,我们可以轻松实现 Canary 发布,支持基于 Cookie、权重和请求头等多种流量分配策略。上述示例展示了基于 Cookie 的配置方法,帮助团队在生产环境中逐步验证新版本,确保部署过程安全可靠。如果您需要更复杂的流量控制,可以结合其他注解灵活调整策略。