通过给 Ingress 资源指定 Nginx Ingress 所支持的 annotation 可实现金丝雀发布。
需给服务创建2个 Ingress,其中1个常规 Ingress,另1个为带 nginx.ingress.kubernetes.io/canary: "true"
固定的 annotation 的 Ingress,称为 Canary Ingress。
Canary Ingress 一般代表新版本的服务,结合另外针对流量切分策略的 annotation 一起配置即可实现多种场景的金丝雀发布。
以下为相关 annotation 的详细介绍:
nginx.ingress.kubernetes.io/canary-by-header
表示如果请求头中包含指定的 header 名称,并且值为always
,就将该请求转发给该 Ingress 定义的对应后端服务。如果值为never
则不转发,可以用于回滚到旧版。如果为其他值则忽略该 annotation。nginx.ingress.kubernetes.io/canary-by-header-value
该 annotation 可以作为canary-by-header
的补充,可指定请求头为自定义值,包含但不限于always
或never
。当请求头的值命中指定的自定义值时,请求将会转发给该 Ingress 定义的对应后端服务,如果是其它值则忽略该 annotation。nginx.ingress.kubernetes.io/canary-by-header-pattern
与canary-by-header-value
类似,区别为该 annotation 用正则表达式匹配请求头的值,而不是只固定某一个值。如果该 annotation 与canary-by-header-value
同时存在,该 annotation 将被忽略。nginx.ingress.kubernetes.io/canary-by-cookie
与canary-by-header
类似,该 annotation 用于 cookie,仅支持always
和never
。nginx.ingress.kubernetes.io/canary-weight
表示 Canary Ingress 所分配流量的比例的百分比,取值范围 [0-100]。例如,设置为10,则表示分配10%的流量给 Canary Ingress 对应的后端服务。- 金丝雀规则按优先顺序进行如下排序:canary-by-header - > canary-by-cookie - > canary-weight
基于不同的场景,灰度发布有四种:
//第一种,所有的请求都会被转发到灰度(Canary)版本
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "always"
//第二种,所有的请求都不会被转发到灰度(Canary)版本
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "never"
//第三种,如果请求的header头包含"user-id: user_1",该请求会被转发到灰度(Canary)版本
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "user_id"
nginx.ingress.kubernetes.io/canary-by-header-value: "user_1"
//第四种,如果请求的header头包含"user-id: user_2"或"user-id: user-3"或"user-id: user4",该请求会被转发到灰度(Canary)版
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: "user_id" #在networking.k8s.io/v1中,canary-by-header的值尽量不用使用下划线“_”。如果使用了,请求头中要使用中横线“-”代替。
nginx.ingress.kubernetes.io/canary-by-header-pattern: "user_2|user-3|user4"
一、部署蓝环境版本服务
1、ConfigMap
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-blue-config
data:
nginx.conf: |-
worker_processes 1;
events {
accept_mutex on;
multi_accept on;
use epoll;
worker_connections 1024;
}
http {
ignore_invalid_headers off;
server {
listen 80;
location / {
access_by_lua '
local header_str = ngx.say("blue")
';
}
}
}
2、Deployment
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-blue
labels:
dce.daocloud.io/app: nginx-blue
annotations:
dce.daocloud.io/last-replicas: '1'
deployment.kubernetes.io/revision: '3'
kubernetes.io/change-cause: update YAML
spec:
replicas: 1
selector:
matchLabels:
dce.daocloud.io/component: nginx-blue
template:
metadata:
name: nginx-blue
labels:
dce.daocloud.io/app: nginx-blue
dce.daocloud.io/component: nginx-blue
annotations:
dce.daocloud.io/parcel.egress.burst: '0'
dce.daocloud.io/parcel.egress.rate: '0'
dce.daocloud.io/parcel.ingress.burst: '0'
dce.daocloud.io/parcel.ingress.rate: '0'
dce.daocloud.io/parcel.net.type: calico
spec:
volumes:
- name: nginx-blue-config
configMap:
name: nginx-blue-config
defaultMode: 420
containers:
- name: nginx-blue
image: 'x.x.x.x/library/openresty:1.19.9.1-sw-r4'
resources:
limits:
cpu: 500m
memory: '314572800'
requests:
cpu: 200m
memory: '314572800'
volumeMounts:
- name: nginx-blue-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
3、Service
kind: Service
apiVersion: v1
metadata:
name: nginx-blue-default
labels:
dce.daocloud.io/app: nginx-blue
annotations:
io.daocloud.dce.serviceSelectorType: service
spec:
ports:
- name: nginx-nginx-default-80680-80
protocol: TCP
port: 80
targetPort: 80
nodePort: 31046
selector:
dce.daocloud.io/component: nginx-blue
clusterIP: 172.31.69.137
type: NodePort
sessionAffinity: None
externalTrafficPolicy: Cluster
4、修改pod内容
cd /usr/local/openresty/nginx/html/
ls
50x.html index.html
echo "Hello Blue" > index.html
cat index.html
Hello Blue
二、部署绿环境版本服务
1、ConfigMap
kind: ConfigMap
apiVersion: v1
metadata:
name: nginx-green-config
data:
nginx.conf: |-
worker_processes 1;
events {
accept_mutex on;
multi_accept on;
use epoll;
worker_connections 1024;
}
http {
ignore_invalid_headers off;
server {
listen 80;
location / {
access_by_lua '
local header_str = ngx.say("green")
';
}
}
}
2、Deployment
kind: Deployment
apiVersion: apps/v1
metadata:
name: nginx-green
labels:
dce.daocloud.io/app: nginx-green
annotations:
deployment.kubernetes.io/revision: '5'
kubernetes.io/change-cause: update YAML
spec:
replicas: 1
selector:
matchLabels:
dce.daocloud.io/component: nginx-green
template:
metadata:
name: nginx-green
labels:
dce.daocloud.io/app: nginx-green
dce.daocloud.io/component: nginx-green
env: green
annotations:
dce.daocloud.io/parcel.egress.burst: '0'
dce.daocloud.io/parcel.egress.rate: '0'
dce.daocloud.io/parcel.ingress.burst: '0'
dce.daocloud.io/parcel.ingress.rate: '0'
dce.daocloud.io/parcel.net.type: calico
dce.daocloud.io/parcel.net.value: default-ipv4-ippool
spec:
volumes:
- name: nginx-green-config
configMap:
name: nginx-green-config
defaultMode: 420
containers:
- name: nginx-green
image: 'x.x.x.x/library/openresty:1.19.9.1-sw-r4'
resources:
limits:
cpu: 500m
memory: '314572800'
requests:
cpu: 200m
memory: '314572800'
volumeMounts:
- name: nginx-green-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
3、Service
kind: Service
apiVersion: v1
metadata:
name: nginx-green-default
labels:
dce.daocloud.io/app: nginx-green
annotations:
io.daocloud.dce.serviceSelectorType: service
spec:
ports:
- name: nginx-nginx-default-15833-80
protocol: TCP
port: 80
targetPort: 80
nodePort: 35218
selector:
dce.daocloud.io/component: nginx-green
clusterIP: 172.31.207.22
type: NodePort
sessionAffinity: None
externalTrafficPolicy: Cluster
4、修改pod内容
cd /usr/local/openresty/nginx/html/
ls
50x.html index.html
echo "Hello Green" > index.html
cat index.html
Hello Green
三、设置Ingress
1、blue环境Ingress
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: nginx-blue-ingress
labels:
dce.daocloud.io/app: nginx-blue
annotations:
nginx.ingress.kubernetes.io/use-port-in-redirects: 'true'
spec:
rules:
- host: nginx.ms-sit.xxxxxx.net
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: nginx-blue-default
servicePort: 80
2、green环境Ingress
案例1:
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: nginx-green-ingress
labels:
dce.daocloud.io/app: nginx-green
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-by-header: env
nginx.ingress.kubernetes.io/canary-by-header-pattern: green
spec:
rules:
- host: nginx.ms-sit.xxxxxx.net
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: nginx-green-default
servicePort: 80
案例2:
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: nginx-green-ingress
ingress
labels:
dce.daocloud.io/app: nginx-green
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/canary: 'true'
nginx.ingress.kubernetes.io/canary-by-header: Cookie
nginx.ingress.kubernetes.io/canary-by-header-pattern: bu=xxxcn|bu=xxxsg
spec:
rules:
- host: nginx.ms-sit.aswatson.net
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
serviceName: nginx-green-default
servicePort: 80
四、测试
案例1:
案例2: