经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » Kubernetes » 查看文章
详细聊聊k8s deployment的滚动更新(二)
来源:cnblogs  作者:wilson排球  时间:2019/2/12 9:21:37  对本文有异议

一、知识准备

● 本文详细探索deployment在滚动更新时候的行为
● 相关的参数介绍:
??livenessProbe:存活性探测。判断pod是否已经停止
??readinessProbe:就绪性探测。判断pod是否能够提供正常服务
??maxSurge:在滚动更新过程中最多可以存在的pod数
??maxUnavailable:在滚动更新过程中最多不可用的pod数


二、环境准备

组件 版本
OS Ubuntu 18.04.1 LTS
docker 18.06.0-ce


三、准备镜像、yaml文件

首先准备2个不同版本的镜像,用于测试(已经在阿里云上创建好2个不同版本的nginx镜像)

  1. docker pull registry.cn-beijing.aliyuncs.com/mrvolleyball/nginx:v1
  2. docker pull registry.cn-beijing.aliyuncs.com/mrvolleyball/nginx:delay_v1

2个镜像都提供相同的服务,只不过nginx:delay_v1会延迟启动20才启动nginx

  1. root@k8s-master:~# docker run -d --rm -p 10080:80 nginx:v1
  2. e88097841c5feef92e4285a2448b943934ade5d86412946bc8d86e262f80a050
  3. root@k8s-master:~# curl http://127.0.0.1:10080
  4. ----------
  5. version: v1
  6. hostname: f5189a5d3ad3

yaml文件:

  1. root@k8s-master:~# more roll_update.yaml
  2. apiVersion: extensions/v1beta1
  3. kind: Deployment
  4. metadata:
  5. name: update-deployment
  6. spec:
  7. replicas: 3
  8. template:
  9. metadata:
  10. labels:
  11. app: roll-update
  12. spec:
  13. containers:
  14. - name: nginx
  15. image: registry.cn-beijing.aliyuncs.com/mrvolleyball/nginx:v1
  16. imagePullPolicy: Always
  17. ---
  18. apiVersion: v1
  19. kind: Service
  20. metadata:
  21. name: nginx-service
  22. spec:
  23. selector:
  24. app: roll-update
  25. ports:
  26. - protocol: TCP
  27. port: 10080
  28. targetPort: 80

四、livenessProbe与readinessProbe

livenessProbe:存活性探测,最主要是用来探测pod是否需要重启
readinessProbe:就绪性探测,用来探测pod是否已经能够提供服务

● 在滚动更新的过程中,pod会动态的被delete,然后又被create出来。存活性探测保证了始终有足够的pod存活提供服务,一旦出现pod数量不足,k8s会立即拉起新的pod
● 但是在pod启动的过程中,服务正在打开,并不可用,这时候如果有流量打过来,就会造成报错

下面来模拟一下这个场景:

首先apply上述的配置文件

  1. root@k8s-master:~# kubectl apply -f roll_update.yaml
  2. deployment.extensions "update-deployment" created
  3. service "nginx-service" created
  4. root@k8s-master:~# kubectl get pod -owide
  5. NAME READY STATUS RESTARTS AGE IP NODE
  6. update-deployment-7db77f7cc6-c4s2v 1/1 Running 0 28s 10.10.235.232 k8s-master
  7. update-deployment-7db77f7cc6-nfgtd 1/1 Running 0 28s 10.10.36.82 k8s-node1
  8. update-deployment-7db77f7cc6-tflfl 1/1 Running 0 28s 10.10.169.158 k8s-node2
  9. root@k8s-master:~# kubectl get svc
  10. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  11. nginx-service ClusterIP 10.254.254.199 <none> 10080/TCP 1m

重新打开终端,测试当前服务的可用性(每秒做一次循环去获取nginx的服务内容):

  1. root@k8s-master:~# while :; do curl http://10.254.254.199:10080; sleep 1; done
  2. ----------
  3. version: v1
  4. hostname: update-deployment-7db77f7cc6-nfgtd
  5. ----------
  6. version: v1
  7. hostname: update-deployment-7db77f7cc6-c4s2v
  8. ----------
  9. version: v1
  10. hostname: update-deployment-7db77f7cc6-tflfl
  11. ----------
  12. version: v1
  13. hostname: update-deployment-7db77f7cc6-nfgtd
  14. ...

这时候把镜像版本更新到nginx:delay_v1,这个镜像会延迟启动nginx,也就是说,会先sleep 20s,然后才去启动nginx服务。这就模拟了在服务启动过程中,虽然pod已经是存在的状态,但是并没有真正提供服务

  1. root@k8s-master:~# kubectl patch deployment update-deployment --patch '{"metadata":{"annotations":{"kubernetes.io/change-cause":"update version to v2"}} ,"spec": {"template": {"spec": {"containers": [{"name": "nginx","image":"registry.cn-beijing.aliyuncs.com/mrvolleyball/nginx:delay_v1"}]}}}}'
  2. deployment.extensions "update-deployment" patched
  1. ...
  2. ----------
  3. version: v1
  4. hostname: update-deployment-7db77f7cc6-h6hvt
  5. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  6. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  7. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  8. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  9. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  10. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  11. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  12. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  13. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  14. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  15. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  16. curl: (7) Failed to connect to 10.254.254.199 port 10080: Connection refused
  17. ----------
  18. version: delay_v1
  19. hostname: update-deployment-d788c7dc6-6th87
  20. ----------
  21. version: delay_v1
  22. hostname: update-deployment-d788c7dc6-n22vz
  23. ----------
  24. version: delay_v1
  25. hostname: update-deployment-d788c7dc6-njmpz
  26. ----------
  27. version: delay_v1
  28. hostname: update-deployment-d788c7dc6-6th87

可以看到,由于延迟启动,nginx并没有真正做好准备提供服务,此时流量已经发到后端,导致服务不可用的状态

所以,加入readinessProbe是非常必要的手段:

  1. apiVersion: extensions/v1beta1
  2. kind: Deployment
  3. metadata:
  4. name: update-deployment
  5. spec:
  6. replicas: 3
  7. template:
  8. metadata:
  9. labels:
  10. app: roll-update
  11. spec:
  12. containers:
  13. - name: nginx
  14. image: registry.cn-beijing.aliyuncs.com/mrvolleyball/nginx:v1
  15. imagePullPolicy: Always
  16. readinessProbe:
  17. tcpSocket:
  18. port: 80
  19. initialDelaySeconds: 5
  20. periodSeconds: 10
  21. ---
  22. apiVersion: v1
  23. kind: Service
  24. metadata:
  25. name: nginx-service
  26. spec:
  27. selector:
  28. app: roll-update
  29. ports:
  30. - protocol: TCP
  31. port: 10080
  32. targetPort: 80

重复上述步骤,先创建nginx:v1,然后patch到nginx:delay_v1

  1. root@k8s-master:~# kubectl apply -f roll_update.yaml
  2. deployment.extensions "update-deployment" created
  3. service "nginx-service" created
  4. root@k8s-master:~# kubectl patch deployment update-deployment --patch '{"metadata":{"annotations":{"kubernetes.io/change-cause":"update version to v2"}} ,"spec": {"template": {"spec": {"containers": [{"name": "nginx","image":"registry.cn-beijing.aliyuncs.com/mrvolleyball/nginx:delay_v1"}]}}}}'
  5. deployment.extensions "update-deployment" patched
  1. root@k8s-master:~# kubectl get pod -owide
  2. NAME READY STATUS RESTARTS AGE IP NODE
  3. busybox 1/1 Running 0 45d 10.10.235.255 k8s-master
  4. lifecycle-demo 1/1 Running 0 32d 10.10.169.186 k8s-node2
  5. private-reg 1/1 Running 0 92d 10.10.235.209 k8s-master
  6. update-deployment-54d497b7dc-4mlqc 0/1 Running 0 13s 10.10.169.178 k8s-node2
  7. update-deployment-54d497b7dc-pk4tb 0/1 Running 0 13s 10.10.36.98 k8s-node1
  8. update-deployment-6d5d7c9947-l7dkb 1/1 Terminating 0 1m 10.10.169.177 k8s-node2
  9. update-deployment-6d5d7c9947-pbzmf 1/1 Running 0 1m 10.10.36.97 k8s-node1
  10. update-deployment-6d5d7c9947-zwt4z 1/1 Running 0 1m 10.10.235.246 k8s-master

● 由于设置了readinessProbe,虽然pod已经启动起来了,但是并不会立即投入使用,所以出现了 READY: 0/1 的情况
● 并且有pod出现了一直持续Terminating状态,因为滚动更新的限制,至少要保证有pod可用

再查看curl的状态,image的版本平滑更新到了nginx:delay_v1,没有出现报错的状况

  1. root@k8s-master:~# while :; do curl http://10.254.66.136:10080; sleep 1; done
  2. ...
  3. version: v1
  4. hostname: update-deployment-6d5d7c9947-pbzmf
  5. ----------
  6. version: v1
  7. hostname: update-deployment-6d5d7c9947-zwt4z
  8. ----------
  9. version: v1
  10. hostname: update-deployment-6d5d7c9947-pbzmf
  11. ----------
  12. version: v1
  13. hostname: update-deployment-6d5d7c9947-zwt4z
  14. ----------
  15. version: delay_v1
  16. hostname: update-deployment-54d497b7dc-pk4tb
  17. ----------
  18. version: delay_v1
  19. hostname: update-deployment-54d497b7dc-4mlqc
  20. ----------
  21. version: delay_v1
  22. hostname: update-deployment-54d497b7dc-pk4tb
  23. ----------
  24. version: delay_v1
  25. hostname: update-deployment-54d497b7dc-4mlqc
  26. ...

五、maxSurge与maxUnavailable

● 在滚动更新中,有几种更新方案:先删除老的pod,然后添加新的pod;先添加新的pod,然后删除老的pod。在这个过程中,服务必须是可用的(也就是livenessProbe与readiness必须检测通过)
● 在具体的实施中,由maxSurge与maxUnavailable来控制究竟是先删老的还是先加新的以及粒度
● 若指定的副本数为3:
??maxSurge=1 maxUnavailable=0:最多允许存在4个(3+1)pod,必须有3个pod(3-0)同时提供服务。先创建一个新的pod,可用之后删除老的pod,直至全部更新完毕
??maxSurge=0 maxUnavailable=1:最多允许存在3个(3+0)pod,必须有2个pod(3-1)同时提供服务。先删除一个老的pod,然后创建新的pod,直至全部更新完毕
● 归根结底,必须满足maxSurge与maxUnavailable的条件,如果maxSurge与maxUnavailable同时为0,那就没法更新了,因为又不让删除,也不让添加,这种条件是无法满足的

六、小结

● 本文介绍了deployment滚动更新过程中,maxSurge、maxUnavailable、liveness、readiness等参数的使用
● 在滚动更新过程中,还有留有一个问题。比如在一个大型的系统中,某个业务的pod数很多(100个),执行一次滚动更新时,势必会造成pod版本不一致(有些pod是老版本,有些pod是新版本),用户访问很有可能会造成多次结果不一致的现象,直至版本更新完毕。关于这个问题待之后慢慢讨论



至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

原文链接:http://www.cnblogs.com/MrVolleyball/p/10360860.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号