上篇文章介绍了RS,RS可以保证维持一定数量的副本,多了剔除,少了自动拉起,可以方便的扩缩容,可以替换镜像更新升级,替换之后只对新的Pod有效。但是官方建议我们不应该直接使用RS来控制副本,而是使用Deployment来间接控制副本。
Deployment可以更好的解决服务编排的问题,在1.2版本开始引入,这种控制器是通过控制RS来间接控制Pod,所以具备RS的所有功能,并且对RS的更新升级做了优化
在RS中镜像更新升级只有当我们删除原来的Pod,自动拉起新的Pod时才生效,那么这个删除原来Pod的动作能不能自动运行,每次按批量的删除Pod达到一个滚动升级的效果,或者删除部分Pod停止,等待一段时间再继续达到一个灰度发布的效果。更新完后上一次的版本能否做版本保留,以便随时回退。
带着上面的问题我们看Deployment是否可以解决
通过上面介绍,我们知道RS具备的功能还是挺多的,只是不太自动化,比如更新升级需要删除原来的Pod,这个动作是手动的,我们希望是能够自动的升级,于是Deployment就出现了,它在RS之上做个扩展,跟我们写框架一样,最开始提供出来的都是原始的api,然后在这之上做一个二次封装,以便更好的使用。
Deployment可以持有多个RS,这样我们就能随时切换版本,所以她还支持回退的功能
deploy的工作机制如下图所示
apiVersion: apps/v1
kind: Deployment # Deployment类型
metadata:
name: # Deployment名称
namespace:
labels:
spec:
replicas: # 副本数量默认为1
revisionHistoryLimit: # 保留历史版本数量也是就RS,默认是10个
paused: # 暂停部署,默认是false
progressDeadlineSeconds: # 部署超时时间(s),默认是600
strategy: # 更新策略
type: # 更新策略 Recreate(先删除所有,再创建)与RollingUpdate(滚动 默认)
rollingUpdate: # 滚动更新
maxSurge: # 可以额外多出的Pod数,可以为百分比,也可以为整数
maxUnavaliable: # 可以忍受多少个Pod不可用,可以为百分比,也可以为整数
selector: # 与RS一样通过它指定该控制器管理哪些pod
matchLabels:
matchExpressions:
template: # 与Pod定义一样
metadata:
spec:
创建一个具有三个副本的deployment
编写 deployment.yaml 内容如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 3
revisionHistoryLimit: 5 # 保留五个版本
strategy:
type: Recreate # 更新策略 先删除所有,再创建
selector:
matchExpressions:
- {key: app, operator: In,values: [nginx]}
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19.1
创建deployment,观察deploy,rs,pod详情,既然Pod通过管理rs来控制Pod,那么也会创建出一个rs
# 创建deploy
[root@master deploy]# kubectl create -f deployment.yaml
deployment.apps/deployment created
# 查看deploy,rs,pod
[root@master deploy]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 3/3 3 3 14s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-78ff8d9ff6 3 3 3 14s
NAME READY STATUS RESTARTS AGE
pod/deployment-78ff8d9ff6-9xkjl 1/1 Running 0 14s
pod/deployment-78ff8d9ff6-c4jgz 1/1 Running 0 14s
pod/deployment-78ff8d9ff6-c7r65 1/1 Running 0 14s
通过上面结果显示,可以知道,创建deploy同时也会创建出一个rs,rs得名字再deploy的基础上加上一串字符串如78ff8d9ff6,Pod的命名又是在rs的基础上加上一串字符串如9xkjl
扩缩容实际上是RS的功能,所以使用方式也是一样的,会有编辑文件与命令行两种方式
编辑文件方式
# 修改文件如下部分将副本扩到5
#spec:
# replicas: 5
[root@master deploy]# kubectl edit deploy deployment
deployment.apps/deployment edited
# 查看详情,此时已经有五个副本
[root@master deploy]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 5/5 5 5 97s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-78ff8d9ff6 5 5 5 97s
NAME READY STATUS RESTARTS AGE
pod/deployment-78ff8d9ff6-9xkjl 1/1 Running 0 97s
pod/deployment-78ff8d9ff6-c4jgz 1/1 Running 0 97s
pod/deployment-78ff8d9ff6-c7r65 1/1 Running 0 97s
pod/deployment-78ff8d9ff6-xvg6w 1/1 Running 0 3s
pod/deployment-78ff8d9ff6-zj878 1/1 Running 0 3s
通过命令行方式
# 使用命令进行缩容,将副本数改为3
[root@master deploy]# kubectl scale deploy deployment --replicas=3
deployment.apps/deployment scaled
# 查看详情,此时只有三个副本
[root@master deploy]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 3/3 3 3 2m21s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-78ff8d9ff6 3 3 3 2m21s
NAME READY STATUS RESTARTS AGE
pod/deployment-78ff8d9ff6-9xkjl 1/1 Running 0 2m21s
pod/deployment-78ff8d9ff6-c4jgz 1/1 Running 0 2m21s
pod/deployment-78ff8d9ff6-zj878 1/1 Running 0 47s
上面我们创建的yaml其更新方式为 Recreate–先删除所有Pod,再创建新的Pod
为了更好的观察更新过程,新打开一个窗口监控Pod的变化
# -w 观察Pod的变化,有变动会自动打印出日志
[root@master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
deployment-78ff8d9ff6-9xkjl 1/1 Running 0 3m40s
deployment-78ff8d9ff6-c4jgz 1/1 Running 0 3m40s
deployment-78ff8d9ff6-zj878 1/1 Running 0 2m6s
通过命令方式更新镜像
# 将镜像版本改为1.17.1
[root@master deploy]# kubectl set image deploy deployment nginx=nginx:1.17.1
deployment.apps/deployment image updated
# 查看详情
[root@master ~]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 3/3 3 3 4m7s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-74cdbf844b 3 3 3 5s
replicaset.apps/deployment-78ff8d9ff6 0 0 0 4m7s
NAME READY STATUS RESTARTS AGE
pod/deployment-74cdbf844b-bbn47 1/1 Running 0 5s
pod/deployment-74cdbf844b-dzgl8 1/1 Running 0 5s
pod/deployment-74cdbf844b-jccdz 1/1 Running 0 5s
通过上面数据看出,原先的RS deployment-78ff8d9ff6已经没有Pod在运行,新的deployment-74cdbf844b运行中,观察Pod的名称也与之前的不一样了,说明Pod都是新创建的。
观察Pod的更新详情(更新之前先打开一个新窗口监控)
[root@master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
deployment-78ff8d9ff6-9xkjl 1/1 Running 0 3m40s
deployment-78ff8d9ff6-c4jgz 1/1 Running 0 3m40s
deployment-78ff8d9ff6-zj878 1/1 Running 0 2m6s
deployment-78ff8d9ff6-zj878 1/1 Terminating 0 2m27s
deployment-78ff8d9ff6-c4jgz 1/1 Terminating 0 4m1s
deployment-78ff8d9ff6-9xkjl 1/1 Terminating 0 4m1s
deployment-78ff8d9ff6-c4jgz 0/1 Terminating 0 4m1s
deployment-78ff8d9ff6-c4jgz 0/1 Terminating 0 4m1s
deployment-78ff8d9ff6-c4jgz 0/1 Terminating 0 4m1s
deployment-78ff8d9ff6-9xkjl 0/1 Terminating 0 4m2s
deployment-78ff8d9ff6-9xkjl 0/1 Terminating 0 4m2s
deployment-78ff8d9ff6-9xkjl 0/1 Terminating 0 4m2s
deployment-78ff8d9ff6-zj878 0/1 Terminating 0 2m28s
deployment-78ff8d9ff6-zj878 0/1 Terminating 0 2m28s
deployment-78ff8d9ff6-zj878 0/1 Terminating 0 2m28s
deployment-74cdbf844b-bbn47 0/1 Pending 0 0s
deployment-74cdbf844b-jccdz 0/1 Pending 0 0s
deployment-74cdbf844b-dzgl8 0/1 Pending 0 0s
deployment-74cdbf844b-bbn47 0/1 Pending 0 0s
deployment-74cdbf844b-jccdz 0/1 Pending 0 0s
deployment-74cdbf844b-dzgl8 0/1 Pending 0 0s
deployment-74cdbf844b-bbn47 0/1 ContainerCreating 0 0s
deployment-74cdbf844b-jccdz 0/1 ContainerCreating 0 0s
deployment-74cdbf844b-dzgl8 0/1 ContainerCreating 0 1s
deployment-74cdbf844b-bbn47 1/1 Running 0 1s
deployment-74cdbf844b-dzgl8 1/1 Running 0 2s
deployment-74cdbf844b-jccdz 1/1 Running 0 2s
从上面的更新过程可以看出,先是停掉原来的Pod,所有Pod都停止后才创建新的Pod,这其实是deploy的一种更新策略Recreate,先删再建,还有一种更新策略便是滚动更新 RollingUpdate,默认也是滚动更新
滚动更新有两个参数可以设置
maxSurge: 25% # 可以额外多出的Pod数,默认为百分比25%,也可以为整数
maxUnavailable: 25% # 可以忍受多少个Pod不可用,默认为百分比25%,也可以为整数
修改deployment.yaml 内容如下
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment
spec:
replicas: 3
revisionHistoryLimit: 5 # 保留五个版本
strategy: # 更新策略
type: RollingUpdate
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
selector:
matchExpressions:
- {key: app, operator: In,values: [nginx]}
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.19.1
删除原来的deploy重新创建
# 删除
[root@master deploy]# kubectl delete -f deployment.yaml
deployment.apps "deployment" deleted
# 创建
[root@master deploy]# kubectl create -f deployment.yaml --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/deployment created
# 查看
[root@master deploy]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 3/3 3 3 11s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-78ff8d9ff6 3 3 3 11s
NAME READY STATUS RESTARTS AGE
pod/deployment-78ff8d9ff6-7wfx9 1/1 Running 0 11s
pod/deployment-78ff8d9ff6-gvztv 1/1 Running 0 11s
pod/deployment-78ff8d9ff6-mrndc 1/1 Running 0 11s
在更新升级之前同样的新打开一个窗口监控Pod的变化 kubectl get pod -w
将镜像版本修改为1.17.1
# 修改镜像版本
[root@master deploy]# kubectl set image deploy deployment nginx=nginx:1.17.1
deployment.apps/deployment image updated
# 观察 此时两个RS都有正在运行的Pod
[root@master deploy]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 3/3 2 3 42s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-74cdbf844b 2 2 1 2s
replicaset.apps/deployment-78ff8d9ff6 2 2 2 42s
NAME READY STATUS RESTARTS AGE
pod/deployment-74cdbf844b-hc2jh 0/1 ContainerCreating 0 1s
pod/deployment-74cdbf844b-qhmzs 1/1 Running 0 2s
pod/deployment-78ff8d9ff6-7wfx9 1/1 Running 0 42s
pod/deployment-78ff8d9ff6-mrndc 1/1 Running 0 42s
#############################################################################
# 在此观察78ff8d9ff6已经没有Pod运行,所有存活Pod均在新的RS 74cdbf844b
[root@master deploy]# kubectl get deploy,rs,pod
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/deployment 3/3 3 3 104s
NAME DESIRED CURRENT READY AGE
replicaset.apps/deployment-74cdbf844b 3 3 3 64s
replicaset.apps/deployment-78ff8d9ff6 0 0 0 104s
NAME READY STATUS RESTARTS AGE
pod/deployment-74cdbf844b-2mfqh 1/1 Running 0 61s
pod/deployment-74cdbf844b-hc2jh 1/1 Running 0 63s
pod/deployment-74cdbf844b-qhmzs 1/1 Running 0 64s
从上面的结果可以看出会有两个RS同时有存活的Pod,并不是先删除完所有的Pod再创建新的。
观察Pod的更新详情(更新之前先打开一个新窗口监控)
[root@master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
deployment-78ff8d9ff6-7wfx9 1/1 Running 0 27s
deployment-78ff8d9ff6-gvztv 1/1 Running 0 27s
deployment-78ff8d9ff6-mrndc 1/1 Running 0 27s
deployment-74cdbf844b-qhmzs 0/1 Pending 0 0s
deployment-74cdbf844b-qhmzs 0/1 Pending 0 0s
deployment-74cdbf844b-qhmzs 0/1 ContainerCreating 0 0s
deployment-74cdbf844b-qhmzs 1/1 Running 0 1s
deployment-78ff8d9ff6-gvztv 1/1 Terminating 0 41s
deployment-74cdbf844b-hc2jh 0/1 Pending 0 0s
deployment-74cdbf844b-hc2jh 0/1 Pending 0 0s
deployment-74cdbf844b-hc2jh 0/1 ContainerCreating 0 0s
deployment-78ff8d9ff6-gvztv 0/1 Terminating 0 42s
deployment-78ff8d9ff6-gvztv 0/1 Terminating 0 42s
deployment-78ff8d9ff6-gvztv 0/1 Terminating 0 42s
deployment-74cdbf844b-hc2jh 1/1 Running 0 2s
deployment-78ff8d9ff6-7wfx9 1/1 Terminating 0 43s
deployment-74cdbf844b-2mfqh 0/1 Pending 0 0s
deployment-74cdbf844b-2mfqh 0/1 Pending 0 0s
deployment-74cdbf844b-2mfqh 0/1 ContainerCreating 0 0s
deployment-78ff8d9ff6-7wfx9 0/1 Terminating 0 43s
deployment-78ff8d9ff6-7wfx9 0/1 Terminating 0 43s
deployment-78ff8d9ff6-7wfx9 0/1 Terminating 0 43s
deployment-74cdbf844b-2mfqh 1/1 Running 0 1s
deployment-78ff8d9ff6-mrndc 1/1 Terminating 0 44s
deployment-78ff8d9ff6-mrndc 0/1 Terminating 0 45s
deployment-78ff8d9ff6-mrndc 0/1 Terminating 0 45s
deployment-78ff8d9ff6-mrndc 0/1 Terminating 0 45s
从更新的流程来看先是创建qhmzs,然后终止gvztv,创建hc2jh,终止7wfx9,创建2mfqh,终止mrndc,这正是滚动更新的效果。
不止可以监控pod,rs也可以监控,下面是rs的监控过程,同样可以反应出滚动更新的效果,78ff8d9ff6由三个副本慢慢变为0,74cdbf844b由0慢慢变为3
[root@node02 ~]# kubectl get rs -w
NAME DESIRED CURRENT READY AGE
deployment-78ff8d9ff6 3 3 3 49s
deployment-74cdbf844b 1 0 0 0s
deployment-74cdbf844b 1 0 0 0s
deployment-74cdbf844b 1 1 0 0s
deployment-74cdbf844b 1 1 1 1s
deployment-78ff8d9ff6 2 3 3 53s
deployment-74cdbf844b 2 1 1 1s
deployment-78ff8d9ff6 2 3 3 53s
deployment-78ff8d9ff6 2 2 2 53s
deployment-74cdbf844b 2 1 1 1s
deployment-74cdbf844b 2 2 1 1s
deployment-74cdbf844b 2 2 2 3s
deployment-78ff8d9ff6 1 2 2 55s
deployment-78ff8d9ff6 1 2 2 55s
deployment-74cdbf844b 3 2 2 3s
deployment-78ff8d9ff6 1 1 1 55s
deployment-74cdbf844b 3 2 2 3s
deployment-74cdbf844b 3 3 2 3s
deployment-74cdbf844b 3 3 3 4s
deployment-78ff8d9ff6 0 1 1 56s
deployment-78ff8d9ff6 0 1 1 56s
deployment-78ff8d9ff6 0 0 0 56s
补充:校验Pod是否使用了更新后的镜像
# 进入容器查看nginx版本
[root@master deploy]# kubectl exec deployment-74cdbf844b-2dlst -- nginx -V
nginx version: nginx/1.17.1
# 查看deploy的状态
[root@master deploy]# kubectl rollout status deploy deployment
deployment "deployment" successfully rolled out
# 每次更新应用k8s都会保留当前的配置并且记录一个版本
# 现在坐了一次更新,所以会有两个不同版本存在,有了版本保留之后,我们就能轻松的做应用回退
[root@master deploy]# kubectl rollout history deploy deployment
deployment.apps/deployment
REVISION CHANGE-CAUSE
1 kubectl create --filename=deployment.yaml --record=true
2 kubectl create --filename=deployment.yaml --record=true
# 通过指定版本号回退到指定的版本
[root@master deploy]# kubectl rollout undo deploy deployment --to-revision=1
deployment.apps/deployment rolled back
# 查看rs已经是使用原来的rs了
[root@master deploy]# kubectl get rs
NAME DESIRED CURRENT READY AGE
deployment-74cdbf844b 0 0 0 17m
deployment-78ff8d9ff6 3 3 3 18m
# Pod也是重新创建的
[root@master deploy]# kubectl get pod
NAME READY STATUS RESTARTS AGE
deployment-78ff8d9ff6-g4hx5 1/1 Running 0 10m
deployment-78ff8d9ff6-rw46x 1/1 Running 0 10m
deployment-78ff8d9ff6-ttq5j 1/1 Running 0 10m
# 查看deploy信息,总共更新了三次,当前使用的版本号是 3 使用的镜像是nginx:1.19.1
[root@master deploy]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment 3/3 3 3 19m nginx nginx:1.19.1 app in (nginx)
# 查看版本列表
[root@master deploy]# kubectl rollout history deploy deployment
deployment.apps/deployment
REVISION CHANGE-CAUSE
2 kubectl create --filename=deployment.yaml --record=true
3 kubectl create --filename=deployment.yaml --record=true
# 验证是否回滚成功
[root@master deploy]# kubectl exec deployment-78ff8d9ff6-m5jsk -- nginx -V
nginx version: nginx/1.19.1
灰度发布其实是在滚动升级的基础上做的,假如我们升级的时候可以暂停,那么就会存在一部分实例已经更新了,一部分还没更新,正是金丝雀发布的场景
# 由于案例升级太快,执行的命令也要走够快才行,讲两个操作写到一起模拟
[root@master deploy]# kubectl set image deploy deployment nginx=nginx:1.17.1 && kubectl rollout pause deploy deployment
deployment.apps/deployment image updated
deployment.apps/deployment paused
# 查看deploy已经有四个pod运行
[root@master deploy]# kubectl get deploy -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
deployment 4/3 1 4 28m nginx nginx:1.17.1 app in (nginx)
# 查看rs,两个不同版本是并存着
[root@master deploy]# kubectl get rs -o wide
NAME DESIRED CURRENT READY AGE CONTAINERS IMAGES SELECTOR
deployment-74cdbf844b 1 1 1 27m nginx nginx:1.17.1 app in (nginx),pod-template-hash=74cdbf844b
deployment-78ff8d9ff6 3 3 3 28m nginx nginx:1.19.1 app in (nginx),pod-template-hash=78ff8d9ff6
# 四个Pod正常运行
[root@master deploy]# kubectl get pods
NAME READY STATUS RESTARTS AGE
deployment-74cdbf844b-sc9pc 1/1 Running 0 58s
deployment-78ff8d9ff6-g4hx5 1/1 Running 0 20m
deployment-78ff8d9ff6-rw46x 1/1 Running 0 20m
deployment-78ff8d9ff6-ttq5j 1/1 Running 0 20m
# 查看更新动作,正在等待更新完成,已经更新完成一个实例
[root@master deploy]# kubectl rollout status deploy deployment
Waiting for deployment "deployment" rollout to finish: 1 out of 3 new replicas have been updated...
# 恢复升级动作 在恢复之前先打开一个窗口监控升级 kubectl rollout status deploy deployment
[root@master ~]# kubectl rollout resume deploy deployment
deployment.apps/deployment resumed
# 查看升级状态,出现successfully表示升级完成
[root@master deploy]# kubectl rollout status deploy deployment
Waiting for deployment "deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment spec update to be observed...
Waiting for deployment spec update to be observed...
Waiting for deployment "deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "deployment" rollout to finish: 1 old replicas are pending termination...
deployment "deployment" successfully rolled out
# 再次查看rs,只有一个版本运行着
[root@master deploy]# kubectl get rs
NAME DESIRED CURRENT READY AGE
deployment-74cdbf844b 3 3 3 15m
deployment-78ff8d9ff6 0 0 0 16m
好了,k8s的deploy操作就记录到这里,后面会持续发布其它的学习笔记
欢迎关注,学习不迷路!