查看原文
其他

Kubernetes 滚动发布和回滚入门实战

字符串拼接工程师 Go开发大全 2021-07-19

(给Go开发大全加星标)

【导读】k8s的滚动发布和回滚是如何实现的?如何使用?本文介绍了这些技术细节、带你实战滚动发布与回滚。

近年来在生产环境使用Kubernetes非常多,使用k8s的声明式API可以有非常多种容器调度解决方案。Kubernetes在执行滚动发布和回滚方面能力尤其出色。


预备知识

Deployment

Deployment是kubernetes管理工作负载(workload)的机制之一。Deployment是被Deployment controller管理的。

工作负载(workload)概念见官方文档:https://kubernetes.io/docs/concepts/workloads/controllers/

k8s中,控制器是监控着集群状态的,在需要的时候发生变更或请求变更。每个controller的目标是让集群状态更加接近用户需要的状态。

对于一个deployment来说,“用户需要的状态”是对于pod而言的。k8s中一切都是声明式定义的,结果状态定义在Deployment配置文件的spec。

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

如果任何pod实例要失败或者更新(这两个都是变更的状态),k8s系统会针对变更之间的spec配置的diff做出更正操作,结果就是让deploymeng和最新的spec定义保持一致。

Deployment的底层实现

Deployment是ReplicaSet上的一层抽象,实际上是Deployment创建了一个ReplicaSet、创建过程中会在我们的集群上创建pod。ReplicaSet的功能如其名,就是用来管理我们的pod的副本的。

总之就是Controller会读取Deployment配置的spec,把pod的配置发给ReplicaSet,ReplicaSet负责选合适的副本创建pod。

Deployment > ReplicaSet > Pods:

滚动发布

kubernetes保证服务可用,其中保证了可用性的一个非常有用的功能点就是滚动发布。k8s在发布过程中,使用滚动发布可以保证要到达pod的流量不被中断。

回滚

回滚的意思是让当前的deployment回到之前部署的deployment的实例版本上去。

实战

让我们通过实战演练学习deployment的逻辑策略和执行逻辑吧!

安装KinD

首先要在本机用Kind(kubernetes in Docker)工具装一个单节点K8s集群,确保Docker已经在运行。

安装KinD https://kind.sigs.k8s.io/docs/user/quick-start/

用下面的命令创建一个K8s集群:

$ kind create cluster

用这个集群就可以部署Deployment了。这篇教程中不会用YAML做任何定义,只通过调用kubectl命令行工具操作。

创建Deployment

用nginx镜像创建第一个Deployment:

$ kubectl create deployment test-nginx --image=nginx:1.18-alpine

如之前所讲,一个Deployment会创建一个有Pod的ReplicaSet。通过下面的命令检查新创建的资源:

$ kubectl get deploy,rs,po -l app=test-nginx

新创建的Deployment,ReplicaSet,Pod列表

用下面的命令检查Deployment有没有创建Replicaset:

$ kubectl describe rs <replica-set-name>

检查Deployment创建的ReplicaSet

检查Pod创建情况:

$ kubectl describe po <pod-name> 

扩容Deployment

把nginx pod数量扩容到3个:

$ kubectl scale deploy test-nginx --replicas=3

创建3副本nginx pod

现在集群上已经有了一定数量pod了,那我们来试试deployment策略。

实战:滚动发布deployment

比如现在你的系统里nginx的v18版本有些问题,v19版本修复了,现在你需要滚动升级pod里的nginx镜像版本。升级当前pod的镜像会触发状态变更,kubernetes就会滚动发布一个新deployment。

$ kubectl set image deploy test-nginx nginx=nginx:1.19-alpine

设置了新镜像后,可以看到旧pod被关闭、新pod被启动。

滚动发布,新pod替换旧pod:


kubernetes会保证pod被合理维护。最后一个旧版本镜像的pod不会被停止得很快,要等到整个replica的新pod都创建好才能杀掉。旧pod都会有一个比较长和完整的实际等待pod停止,目的是保证pod承载的流量一段时间内不会断开。直到请求可以安全打到新pod上旧pod才会被删掉。

成功升级所有pod,使用nginx v19版本镜像,查看命令:

$ kubectl describe deploy test-nginx

升级到nginx v19的pod:

实战:回滚deployment

假设新nginx版本比老版本问题还多,现在必须回退到上一个版本,要如何操作?

你可能注意到现在有两个ReplicaSet,这是因为我们更新了Deployment,此时会创建一个新replicaSet、创建了新pod。kubernetes默认保留10个历史ReplicaSet,可以修改deployment文件中的revisionHistoryLimit参数修改这个值。

这些历史叫rollout,只有最新的rollout处于活动状态。

到这里,我们就对test-nginx这个deployment做了两次变更了,查看变更历史能看到两个记录:

$ kubectl get rs 
$ kubectl rollout history deploy test-nginx
$ kubectl rollout history deploy test-nginx --revision=1

test-nginx deployment滚动发布历史:

好,那立马回滚到前一个发布版本。要回滚到的版本是用nginx v18的版本,就是滚动发布到Revision 1

$ kubectl rollout undo deploy test-nginx --to-revision=1

取消滚动发布的pod的状态:

和滚动发布deployment类似,rollback deployment会关掉当前pod,把pod替换包含Revision 1中spec 的pod。

再次查看滚动发布历史,可以看到Revision 1已经被拿去创建最新的pod了,tag是Revision 3。相同spec之间不需要维护多个版本,kubernetes就删掉了Revision 1,因为它有和Revision 3同样的spec。

reversion历史:

这样就回退到了nginx v18版本,通过下面的命令查看:

$ kubectl describe deploy test-nginx

检查回滚后的nginx版本:

总结

kubernetes的这些策略让管理应用的deployment非常方便,本文梳理了一遍滚动发布和回滚操作,是一篇入门文章。在实际工作中,这些步骤可能会把上面这些步骤都集成到CICD中,比如集成到ArgoCD就不需要手动执行了。

感谢阅读,希望本文让能帮你理解滚动发布和回滚在k8s中如何使用。


 - EOF -

推荐阅读(点击标题可打开)

1、GO 语言之反射 Reflect

2、Go语言Interface源码级解读

3、Go pprof 性能分析


Go 开发大全

参与维护一个非常全面的Go开源技术资源库。日常分享 Go, 云原生、k8s、Docker和微服务方面的技术文章和行业动态。

关注后获取

回复 Go 获取6万star的Go资源库



分享、点赞和在看

支持我们分享更多好文章,谢谢!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存