滚动更新
服务不会停止,但是整个pod会有新旧并存的情况。
重新创建
先停止旧的pod,然后再创建新的pod,这个过程服务是会间断的。
蓝绿
**无需停机,风险较小**
01-部署v1的应用(一开始的状态) 所有外部请求的流量都打到这个版本上.
02-部署版本2的应用 版本2的代码与版本1不同(新功能、Bug修复等).
03-将流量从版本1切换到版本2。
04-如版本2测试正常,就删除版本1正在使用的资源(例如实例),从此正式用版本2。
金丝雀
maxSurge:指定升级期间存在的总
Pod
对象数量最多可超出期望值的个数,其值可以是0
或正整数,也可以是一个期望值的百分比;例如,如果期望值为3
,当前的属性值为1
,则表示Pod
对象的总数不能超过4
个。maxUnavailable:升级期间正常可用的
Pod
副本数(包括新旧版本)最多不能低于期望值的个数,其值可以是0
或正整数,也可以是期望值的百分比;默认值为1
,该值意味着如果期望值是3
,则升级期间至少要有两个Pod
对象处于正常提供服务的状态。
#rollingupdate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: rollingupdate
spec:
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector:
matchLabels:
app: rollingupdate
replicas: 4
template:
metadata:
labels:
app: rollingupdate
spec:
containers:
- name: rollingupdate
image: registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: rollingupdate
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: rollingupdate
type: ClusterIP
#执行
kubectl apply -f rollingupdate.yaml
kubectl get pods
kubectl get svc
curl cluster-ip/dockerfile
修改rollingupdate.yaml文件,将镜像修改成v2.0
# 在w1上,不断地访问观察输出
while sleep 0.2;do curl cluster-ip/dockerfile;echo "";done
# 在w2上,监控
pod kubectl get pods -w
# 使得更改生效
kubectl apply -f rollingupdate.yaml
kubectl get pods
conclusion :发现新旧pod是会共存的,并且可以访问测试看一下
kubectl get pods -w
kubectl get svc
可以发现,新老版本的确会共存
recreate.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: recreate
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: recreate
replicas: 4
template:
metadata:
labels:
app: recreate
spec:
containers:
- name: recreate
image: registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
ports:
- containerPort: 8080
livenessProbe:
tcpSocket:
port: 8080
修改recreate.yaml文件
kubectl apply -f recreate.yaml
kubectl get pods
conclusion :发现pod是先停止,然后再创建新的
#停止
NAME READY STATUS RESTARTS AGE
recreate-655d4868d8-5dqcz 0/1 Terminating 0 2m31s
recreate-655d4868d8-sb688 0/1 Terminating 0
#创建
NAME READY STATUS RESTARTS AGE
recreate-6f74f4686d-4xkgl 1/1 Running 0 13s
recreate-6f74f4686d-blrt7 1/1 Running 0 13s
Have a try
kubectl rollout pause deploy rollingupdate
kubectl rollout resume deploy rollingupdate
kubectl rollout undo deploy rollingupdate
# 回到上一个版本
bluegreen.yaml
#deploy
apiVersion: apps/v1
kind: Deployment
metadata:
name: blue
spec:
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
selector:
matchLabels:
app: bluegreen
replicas: 4
template:
metadata:
labels:
app: bluegreen
version: v1.0
spec:
containers:
- name: bluegreen
image: registry.cn-hangzhou.aliyuncs.com/itcrazy2016/test-docker-image:v1.0
ports:
- containerPort: 8080
#执行
kubectl apply -f bluegreen.yaml
kubectl get pods
bluegreen-service.yaml
#service
apiVersion: v1
kind: Service
metadata:
name: bluegreen
spec:
ports:
- port: 80
protocol: TCP
targetPort: 8080
selector:
app: bluegreen
version: v1.0
type: ClusterIP
#执行service.yaml
kubectl apply -f bluegreen-service.yaml
kubectl get svc
# 在w1上不断访问观察
while sleep 0.3;do curl cluster-ip/dockerfile;echo "";done
修改bluegreen.yaml
#修改三处
01-deployment-name:blue ---> green
02-image:v1.0---> v2.0
03-version:v1.0 ---> v2.0
#重新执行
kubectl apply -f bluegreen.yaml
kubectl get pods
# 同时观察刚才访问的地址有没有变化 可以发现,两个版本就共存了,并且之前访问的地址没有变化
修改bluegreen-service.yaml
# 也就是把流量切到2.0的版本中
selector:
app: bluegreen
version: v2.0
#修改完执行
kubectl apply -f bluegreen-service.yaml
kubectl get svc
# 同时观察刚才访问的地址有没有变化 发现流量已经完全切到了v2.0的版本上
好事之者:istio、spinnaker
selector:
app: bluegreen
version: v2.0
# 把version删除掉,只是根据bluegreen进行选择
kubectl apply -f bluegreen-service.yaml
# 同时观察刚才访问的地址有没有变化,istio中就更方便咯
此时新旧版本能够同时被访问到,AB测试,新功能部署少一些的实例
基于ambassador实现K8S灰度发布
推荐:K8S基于ingress-nginx实现灰度发布
Ingress-Nginx 是一个K8S ingress工具,支持配置 Ingress Annotations 来实现不同场景下的灰度发布和测试。 Nginx Annotations 支持以下 4 种 Canary 规则:
nginx.ingress.kubernetes.io/canary-by-header
:基于 Request Header 的流量切分,适用于灰度发布以及 A/B 测试。当 Request Header 设置为 always
时,请求将会被一直发送到 Canary 版本;当 Request Header 设置为 never
时,请求不会被发送到 Canary 入口;对于任何其他 Header 值,将忽略 Header,并通过优先级将请求与其他金丝雀规则进行优先级的比较。nginx.ingress.kubernetes.io/canary-by-header-value
:要匹配的 Request Header 的值,用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务。当 Request Header 设置为此值时,它将被路由到 Canary 入口。该规则允许用户自定义 Request Header 的值,必须与上一个 annotation (即:canary-by-header)一起使用。nginx.ingress.kubernetes.io/canary-weight
:基于服务权重的流量切分,适用于蓝绿部署,权重范围 0 - 100 按百分比将请求路由到 Canary Ingress 中指定的服务。权重为 0 意味着该金丝雀规则不会向 Canary 入口的服务发送任何请求。权重为 100 意味着所有请求都将被发送到 Canary 入口。nginx.ingress.kubernetes.io/canary-by-cookie
:基于 Cookie 的流量切分,适用于灰度发布与 A/B 测试。用于通知 Ingress 将请求路由到 Canary Ingress 中指定的服务的cookie。当 cookie 值设置为 always
时,它将被路由到 Canary 入口;当 cookie 值设置为 never
时,请求不会被发送到 Canary 入口;对于任何其他值,将忽略 cookie 并将请求与其他金丝雀规则进行优先级的比较。注意:金丝雀规则按优先顺序进行如下排序:
canary-by-header - > canary-by-cookie - > canary-weight
我们可以把以上的四个 annotation 规则可以总体划分为以下两类:
正常服务的:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: springboot-rest-demo
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: springboot-rest.jadepeng.com
http:
paths:
- backend:
serviceName: springboot-rest-demo
servicePort: 80
canary 的:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: springboot-rest-demo-gray
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: "true"
spec:
rules:
- host: springboot-rest.jadepeng.com
http:
paths:
- backend:
serviceName: springboot-rest-demo-gray
servicePort: 80
使用Nginx实现灰度发布
nginx+lua+redis 灰度发布实现方案)
Nacos+gateway实现灰度发布
SpringCloudGateway实现灰度发布,结合nacos支持不同服务配置不同灰度版本及灰度权重(概率)
k8s+istio:流量控制之灰度发布
k8s容器灰度发布实践(基于spinnaker)【附源码】