目录
- 总结
介绍
金丝雀发布:又叫灰度发布,控制产品从A版本平滑的过度到B版本
ingress-nginx:k8s ingress工具,支持金丝雀发布,可以实现基于权重、请求头、请求头的值、cookie转发流量。
ingress-nginx canary官方说明:https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md#canary
软件 | 版本 |
kubernetes | v1.23.1 |
nginx-ingress-controller | v1.0.0 |
部署ingress
apiVersion v1
kind Namespace
metadata
name ingress-nginx
labels
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
---
# Source: ingress-nginx/templates/controller-serviceaccount.yaml
apiVersion v1
kind ServiceAccount
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name ingress-nginx
namespace ingress-nginx
automountServiceAccountTokentrue
---
# Source: ingress-nginx/templates/controller-configmap.yaml
apiVersion v1
kind ConfigMap
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name ingress-nginx-controller
namespace ingress-nginx
data
---
# Source: ingress-nginx/templates/clusterrole.yaml
apiVersion rbac.authorization.k8s.io/v1
kind ClusterRole
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
name ingress-nginx
rules
apiGroups
''
resources
configmaps
endpoints
nodes
pods
secrets
verbs
list
watch
apiGroups
''
resources
nodes
verbs
get
apiGroups
''
resources
services
verbs
get
list
watch
apiGroups
networking.k8s.io
resources
ingresses
verbs
get
list
watch
apiGroups
''
resources
events
verbs
create
patch
apiGroups
networking.k8s.io
resources
ingresses/status
verbs
update
apiGroups
networking.k8s.io
resources
ingressclasses
verbs
get
list
watch
---
# Source: ingress-nginx/templates/clusterrolebinding.yaml
apiVersion rbac.authorization.k8s.io/v1
kind ClusterRoleBinding
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
name ingress-nginx
roleRef
apiGroup rbac.authorization.k8s.io
kind ClusterRole
name ingress-nginx
subjects
kind ServiceAccount
name ingress-nginx
namespace ingress-nginx
---
# Source: ingress-nginx/templates/controller-role.yaml
apiVersion rbac.authorization.k8s.io/v1
kind Role
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name ingress-nginx
namespace ingress-nginx
rules
apiGroups
''
resources
namespaces
verbs
get
apiGroups
''
resources
configmaps
pods
secrets
endpoints
verbs
get
list
watch
apiGroups
''
resources
services
verbs
get
list
watch
apiGroups
networking.k8s.io
resources
ingresses
verbs
get
list
watch
apiGroups
networking.k8s.io
resources
ingresses/status
verbs
update
apiGroups
networking.k8s.io
resources
ingressclasses
verbs
get
list
watch
apiGroups
''
resources
configmaps
resourceNames
ingress-controller-leader
verbs
get
update
apiGroups
''
resources
configmaps
verbs
create
apiGroups
''
resources
events
verbs
create
patch
---
# Source: ingress-nginx/templates/controller-rolebinding.yaml
apiVersion rbac.authorization.k8s.io/v1
kind RoleBinding
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name ingress-nginx
namespace ingress-nginx
roleRef
apiGroup rbac.authorization.k8s.io
kind Role
name ingress-nginx
subjects
kind ServiceAccount
name ingress-nginx
namespace ingress-nginx
---
# Source: ingress-nginx/templates/controller-service-webhook.yaml
apiVersion v1
kind Service
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name ingress-nginx-controller-admission
namespace ingress-nginx
spec
type ClusterIP
ports
name https-webhook
port443
targetPort webhook
appProtocol https
selector
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/component controller
---
# Source: ingress-nginx/templates/controller-deployment.yaml
apiVersion apps/v1
kind DaemonSet
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name ingress-nginx-controller
namespace ingress-nginx
spec
selector
matchLabels
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/component controller
revisionHistoryLimit10
minReadySeconds0
template
metadata
labels
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/component controller
spec
hostNetworktrue
dnsPolicy ClusterFirst
containers
name controller
image registry.cn-beijing.aliyuncs.com/kole_chang/controller v1.0.0
imagePullPolicy IfNotPresent
lifecycle
preStop
exec
command
/wait-shutdown
args
/nginx-ingress-controller
--election-id=ingress-controller-leader
--controller-class=k8s.io/ingress-nginx
--configmap=$(POD_NAMESPACE)/ingress-nginx-controller
--validating-webhook=:8443
--validating-webhook-certificate=/usr/local/certificates/cert
--validating-webhook-key=/usr/local/certificates/key
--watch-ingress-without-class=true
securityContext
capabilities
drop
ALL
add
NET_BIND_SERVICE
runAsUser101
allowPrivilegeEscalationtrue
env
name POD_NAME
valueFrom
fieldRef
fieldPath metadata.name
name POD_NAMESPACE
valueFrom
fieldRef
fieldPath metadata.namespace
name LD_PRELOAD
value /usr/local/lib/libmimalloc.so
livenessProbe
failureThreshold5
httpGet
path /healthz
port10254
scheme HTTP
initialDelaySeconds10
periodSeconds10
successThreshold1
timeoutSeconds1
readinessProbe
failureThreshold3
httpGet
path /healthz
port10254
scheme HTTP
initialDelaySeconds10
periodSeconds10
successThreshold1
timeoutSeconds1
ports
name http
containerPort80
protocol TCP
name https
containerPort443
protocol TCP
name webhook
containerPort8443
protocol TCP
volumeMounts
name webhook-cert
mountPath /usr/local/certificates/
readOnlytrue
resources
requests
cpu 100m
memory 90Mi
nodeSelector
kubernetes.io/os linux
serviceAccountName ingress-nginx
terminationGracePeriodSeconds300
volumes
name webhook-cert
secret
secretName ingress-nginx-admission
---
# Source: ingress-nginx/templates/controller-ingressclass.yaml
# We don't support namespaced ingressClass yet
# So a ClusterRole and a ClusterRoleBinding is required
apiVersion networking.k8s.io/v1
kind IngressClass
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component controller
name nginx
namespace ingress-nginx
spec
controller k8s.io/ingress-nginx
---
# Source: ingress-nginx/templates/admission-webhooks/validating-webhook.yaml
# before changing this value, check the required kubernetes version
# https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#prerequisites
apiVersion admissionregistration.k8s.io/v1
kind ValidatingWebhookConfiguration
metadata
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
name ingress-nginx-admission
webhooks
name validate.nginx.ingress.kubernetes.io
matchPolicy Equivalent
rules
apiGroups
networking.k8s.io
apiVersions
v1
operations
CREATE
UPDATE
resources
ingresses
failurePolicy Fail
sideEffects None
admissionReviewVersions
v1
clientConfig
service
namespace ingress-nginx
name ingress-nginx-controller-admission
path /networking/v1/ingresses
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/serviceaccount.yaml
apiVersion v1
kind ServiceAccount
metadata
name ingress-nginx-admission
namespace ingress-nginx
annotations
helm.sh/hook pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/clusterrole.yaml
apiVersion rbac.authorization.k8s.io/v1
kind ClusterRole
metadata
name ingress-nginx-admission
annotations
helm.sh/hook pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
rules
apiGroups
admissionregistration.k8s.io
resources
validatingwebhookconfigurations
verbs
get
update
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/clusterrolebinding.yaml
apiVersion rbac.authorization.k8s.io/v1
kind ClusterRoleBinding
metadata
name ingress-nginx-admission
annotations
helm.sh/hook pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
roleRef
apiGroup rbac.authorization.k8s.io
kind ClusterRole
name ingress-nginx-admission
subjects
kind ServiceAccount
name ingress-nginx-admission
namespace ingress-nginx
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/role.yaml
apiVersion rbac.authorization.k8s.io/v1
kind Role
metadata
name ingress-nginx-admission
namespace ingress-nginx
annotations
helm.sh/hook pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
rules
apiGroups
''
resources
secrets
verbs
get
create
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/rolebinding.yaml
apiVersion rbac.authorization.k8s.io/v1
kind RoleBinding
metadata
name ingress-nginx-admission
namespace ingress-nginx
annotations
helm.sh/hook pre-install,pre-upgrade,post-install,post-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
roleRef
apiGroup rbac.authorization.k8s.io
kind Role
name ingress-nginx-admission
subjects
kind ServiceAccount
name ingress-nginx-admission
namespace ingress-nginx
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-createSecret.yaml
apiVersion batch/v1
kind Job
metadata
name ingress-nginx-admission-create
namespace ingress-nginx
annotations
helm.sh/hook pre-install,pre-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
spec
template
metadata
name ingress-nginx-admission-create
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
spec
containers
name create
image registry.cn-beijing.aliyuncs.com/kole_chang/kube-webhook-certgen v1.0
imagePullPolicy IfNotPresent
args
create
--host=ingress-nginx-controller-admission,ingress-nginx-controller-admission.$(POD_NAMESPACE).svc
--namespace=$(POD_NAMESPACE)
--secret-name=ingress-nginx-admission
env
name POD_NAMESPACE
valueFrom
fieldRef
fieldPath metadata.namespace
restartPolicy OnFailure
serviceAccountName ingress-nginx-admission
nodeSelector
kubernetes.io/os linux
securityContext
runAsNonRoottrue
runAsUser2000
---
# Source: ingress-nginx/templates/admission-webhooks/job-patch/job-patchWebhook.yaml
apiVersion batch/v1
kind Job
metadata
name ingress-nginx-admission-patch
namespace ingress-nginx
annotations
helm.sh/hook post-install,post-upgrade
helm.sh/hook-delete-policy before-hook-creation,hook-succeeded
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
spec
template
metadata
name ingress-nginx-admission-patch
labels
helm.sh/chart ingress-nginx-4.0.1
app.kubernetes.io/name ingress-nginx
app.kubernetes.io/instance ingress-nginx
app.kubernetes.io/version1.0.0
app.kubernetes.io/managed-by Helm
app.kubernetes.io/component admission-webhook
spec
containers
name patch
image registry.cn-beijing.aliyuncs.com/kole_chang/kube-webhook-certgen v1.0
imagePullPolicy IfNotPresent
args
patch
--webhook-name=ingress-nginx-admission
--namespace=$(POD_NAMESPACE)
--patch-mutating=false
--secret-name=ingress-nginx-admission
--patch-failure-policy=Fail
env
name POD_NAMESPACE
valueFrom
fieldRef
fieldPath metadata.namespace
restartPolicy OnFailure
serviceAccountName ingress-nginx-admission
nodeSelector
kubernetes.io/os linux
securityContext
runAsNonRoottrue
runAsUser2000
创建试验基础环境
apiVersion apps/v1
kind Deployment
metadata
name appv1
labels
app v1
spec
replicas1
selector
matchLabels
app v1
template
metadata
labels
app v1
spec
containers
name nginx
image zerchin/canary v1
ports
containerPort80
---
apiVersion v1
kind Service
metadata
name appv1
spec
selector
app v1
ports
protocol TCP
port80
targetPort80
---
apiVersion apps/v1
kind Deployment
metadata
name appv2
labels
app v2
spec
replicas1
selector
matchLabels
app v2
template
metadata
labels
app v2
spec
containers
name nginx
image zerchin/canary v2
ports
containerPort80
---
apiVersion v1
kind Service
metadata
name appv2
spec
selector
app v2
ports
protocol TCP
port80
targetPort80
# 创建出两个pod
appv1-5567d54695-9j44d 1/1 Running 0 24h 10.0.135.177 k8s-node03 <none> <none>
appv2-5cf679bc57-pfg2q 1/1 Running 0 24h 10.0.135.178 k8s-node03 <none> <none>
root@k8s-node01 ~ # curl 10.0.135.177
v1
root@k8s-node01 ~ # curl 10.0.135.178
canary-v2
创建一个ingress可以路由到appv1
apiVersion networking.k8s.io/v1
kind Ingress
metadata
name app
namespace default
spec
rules
host nginx.zerchin.xyz
http
paths
pathType Prefix
path"/"
backend
service
name appv1
port
number80
# 执行命令可以看到,已经正常访问到appv1了
root@k8s-master01 canary # curl -H'host nginx.zerchin.xyz' http://172.16.2.7
v1
基于权重转发流量
nginx.ingress.kubernetes.io/canary-weight
:随机整数请求的整数百分比(0-100),应将其路由到canary Ingress中指定的服务。权重0表示此Canary规则不会在Canary入口中将任何请求发送到服务。权重为100表示所有请求都将发送到Ingress中指定的替代服务。
apiVersion networking.k8s.io/v1
kind Ingress
metadata
annotations
kubernetes.io/ingress.class nginx
nginx.ingress.kubernetes.io/canary"true"
nginx.ingress.kubernetes.io/canary-weight"30"
name app-canary
namespace default
spec
rules
host nginx.zerchin.xyz
http
paths
pathType Prefix
path"/"
backend
service
name appv2
port
number80
kubectl查看ingress
root@k8s-master01 canary # kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
app <none> nginx.zerchin.xyz 172.16.2.7,172.16.2.8,172.16.2.9 80 20h
app-canary <none> nginx.zerchin.xyz 172.16.2.7,172.16.2.8,172.16.2.9 80 4h44m
这时候再访问nginx.zerchin.xyz,会发现其中30%的流量会路由到v2版本上
# for i in `seq 1 10`;do curl nginx.zerchin.xyz;done
canary-v2
canary-v2
v1
v1
canary-v2
v1
v1
v1
v1
v1
基于请求头转发流量
nginx.ingress.kubernetes.io/canary-by-header
:用于通知Ingress将请求路由到Canary Ingress中指定的服务的标头。当请求标头设置always为时,它将被路由到Canary。当标头设置never为时,它将永远不会路由到金丝雀。对于任何其他值,标头将被忽略,并且按优先级将请求与其他金丝雀规则进行比较。
修改app-canary的ingress配置,修改annotation,如下:
annotations
kubernetes.io/ingress.class nginx
nginx.ingress.kubernetes.io/canary"true"
nginx.ingress.kubernetes.io/canary-by-header"canary"
测试结果
root@k8s-master01 canary # curl nginx.zerchin.xyz
v1
root@k8s-master01 canary # curl -H'canary:always' nginx.zerchin.xyz
canary-v2
基于请求头和请求头的值转发流量
nginx.ingress.kubernetes.io/canary-by-header-value:匹配的报头值,用于通知Ingress将请求路由到Canary Ingress中指定的服务。当请求标头设置为此值时,它将被路由到Canary。对于任何其他标头值,标头将被忽略,并按优先级将请求与其他金丝雀规则进行比较。此注释必须与nginx.ingress.kubernetes.io/canary-by-header一起使用。
修改app-canary的ingress配置,修改annotation,如下:
annotations
kubernetes.io/ingress.class nginx
nginx.ingress.kubernetes.io/canary"true"
nginx.ingress.kubernetes.io/canary-by-header"canary"
nginx.ingress.kubernetes.io/canary-by-header-value"haha"
测试结果
root@k8s-master01 canary # curl nginx.zerchin.xyz
v1
root@k8s-master01 canary # curl -H'canary:always' nginx.zerchin.xyz
v1
root@k8s-master01 canary # curl -H "canary:haha" nginx.zerchin.xyz
canary-v2
基于cookie转发流量
nginx.ingress.kubernetes.io/canary-by-cookie:用于通知Ingress将请求路由到Canary Ingress中指定的服务的cookie。当cookie值设置always为时,它将被路由到canary。当cookie设置never为时,它将永远不会路由到Canary。对于任何其他值,将忽略cookie,并按优先级将请求与其他canary规则进行比较。
annotations
kubernetes.io/ingress.class nginx
nginx.ingress.kubernetes.io/canary"true"
nginx.ingress.kubernetes.io/canary-by-cookie"test"
测试结果
"test=always" nginx.zerchin.xyzroot@k8s-master01 canary # curl -b
canary-v2
root@k8s-master01 canary # curl -b "test=never" nginx.zerchin.xyz
v1
root@k8s-master01 canary # curl -b "test=1" nginx.zerchin.xyz
v1
总结
- 金丝雀发布规则优先级:canary-by-header -> canary-by-cookie -> canary-weight
- 目前,每个ingress规则最多可以应用一个canary ingress