Deployment的使用
前面我们学习了Replication Controller和Replica Set两种资源对象,RC和RS的功能基本上是差不多的,唯一的区别就是RS支持集合的selector。我们也学习到了用RC / RS来控制Pod副本的数量,也实现了滚动升级Pod的功能。现在看上去似乎一切都比较完美的运行着,但是我们上节课最后也提到了现在我们推荐使用Deployment这种控制器了,而不是我们之前的RC或者RS,这是为什么呢?
我们来对比下二者之间的功能吧,首先RC是Kubernetes的一个核心概念,当我们把应用部署到集群之后,需要保证应用能够持续稳定的运行,RC就是这个保证的关键,主要功能如下:
- 确保Pod数量:它会确保Kubernetes中有指定数量的Pod在运行,如果少于指定数量的Pod,RC就会创建新的,反之这会删除多余的,保证Pod的副本数量不变。确保Pod健康:当Pod不健康,比如运行出错了,总之无法提供正常服务时,RC也会杀死不健康的Pod,重新创建新的。
- 弹性伸缩:在业务高峰或者低峰的时候,可以通过RC来动态的调整Pod数量来提高资源的利用率,当然我们也提到过如果使用HPA这种资源对象的话可以做到自动伸缩。
- 滚动升级:滚动升级是一种平滑的升级方式,通过逐步替换的策略,保证整体系统的稳定性。
Deployment同样也是Kubernetes系统的一个核心概念,主要职责和RC一样的都是保证Pod的数量和健康,二者大部分功能都是完全一致的,我们可以看成是一个升级版的RC控制器,那Deployment又具备那些新特性呢?
- RC的全部功能:Deployment具备上面描述的RC的全部功能
- 事件和状态查看:可以查看Deployment的升级详细进度和状态
- 回滚:当升级Pod的时候如果出现问z,可以使用回滚操作回滚到之前的任一版本
- 版本记录:每一次对Deployment的操作,都能够保存下来,这也是保证可以回滚到任一版本的基础
- 暂停和启动:对于每一次升级都能够随时暂停和启动
作为对比,我们知道Deployment作为新一代的RC,不仅在功能上更为丰富了,同时我们也说过现在官方也都是推荐使用Deployment来管理Pod的,比如一些官方组件kube- dns、kube-proxy也都是使用的Deployment来管理的,所以大家也最好使用Deployment来管理Pod。
创建
可以看出一个Deployment拥有多个Replica Set,而一个Replica Set拥有一个或多个Pod。一个Deployment控制多个rs主要是为了支持回滚机制,每当Deployment操作时,Kubernetes会重新生成一个Replica Set并保留,以后有需要的话就可以回滚至之前的状态。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQC03xXe-1628070701797)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20210301170525867.png)]
下面创建一个Deployment,它创建了一个Replica Set来启动3个nginx pod。
编写 nginx-deployment.yaml
[root@k8s-master ~]# vim nginx-deployment.yaml
[root@k8s-master ~]# cat nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment #类型为Deployment
metadata:
name: nginx-deploy #Deployment的名称
labels:
k8s-app: nginx-demo #标签
spec:
replicas: 3 #3副本数量
selector: #标签选择器
matchLabels:
app: nginx #pod的标签
template: #模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
创建yaml文件
[root@k8s-master ~]# kubectl create -f nginx-deployment.yaml
deployment.apps/nginx-deploy created
然后执行一下命令查看刚刚创建的Deployment:
[root@k8s-master ~]# kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deploy 3/3 3 3 4m33s
我们可以看到Deployment已经创建了1个Replica Set了,执行下面的命令查看rs和pod:
[root@k8s-master ~]# kubectl get rs,pod #先查看rs再查看pod
NAME DESIRED CURRENT READY AGE
replicaset.apps/nginx-deploy-5bf87f5f59 3 3 3 5m41s
#可以查看到都创建成功了副本为3
NAME READY STATUS RESTARTS AGE
pod/nginx-deploy-5bf87f5f59-4n7nx 1/1 Running 0 5m41s
pod/nginx-deploy-5bf87f5f59-fjp6s 1/1 Running 0 5m41s
pod/nginx-deploy-5bf87f5f59-kzpg7 1/1 Running 0 5m41s
滚动更新
#修改配置文件
[root@k8s-master ~]# vim nginx-deployment.yaml
18 - name: nginx
19 image: nginx #将nginx更新为最新版本
运行生效配置
[root@k8s-master ~]# kubectl apply -f nginx-deployment.yaml && kubectl get pod -w
#生效配置文件后执行get pod -w 进行动态查看并更新,会看到运行一个新版本的终止一个老版本的
[root@k8s-master ~]# kubectl get rs #rs=ReplicaSet 的缩写
NAME DESIRED CURRENT READY AGE
nginx-deploy-558fc78868 3 3 3 3m40s
nginx-deploy-5bf87f5f59 0 0 0 18m
#可以查看到老版本的已经没有资源在运行了,全部更新为新版本的在运行
上面的Deployment的yaml文件中的replicas:3将会保证我们始终有3个POD在运行。由于Deployment和RC的功能大部分都一样的,下面演示下Deployment的滚动升级和回滚功能。
滚动升级
现在将yaml文件中的nginx镜像修改为nginx:1.13.3,然后在spec下面添加滚动升级策略:
修改配置文件
[root@k8s-master ~]# vim nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
k8s-app: nginx-demo
spec:
replicas: 3
minReadySeconds: 5 #添加:升级过程中,容器运行起来5秒后进行更新
strategy: #添加:更新策略
type: RollingUpdate #添加:更新类型:滚动更新
rollingUpdate: #添加:滚动更新的配置
maxSurge: 1 #添加:升级过程中比原有期望数量多出的pod数量
maxUnavailable: 1 #添加:最多几个pod不可用
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
参数解释
-
minReadySeconds:
- Kubernetes在等待设置的时间后才进行升级
- 如果没有设置该值,Kubernetes会假设该容器启动起来后就提供服务了
- 如果没有设置该值,在某些极端情况下可能会造成服务不正常运行
-
maxSurge:
- 升级过程中最多可以比原先设置多出的POD数量
- 例如:maxSurage=1,replicas=5,则表示Kubernetes会先启动1一个新的Pod后才删掉一个旧的POD,整个升级过程中最多会有5+1个POD。
-
maxUnavaible:
- 升级过程中最多有多少个POD处于无法提供服务的状态
- 当maxSurge不为0时,该值也不能为0
- 例如:maxUnavaible=1,则表示Kubernetes整个升级过程中最多会有1个POD处于无法服务的状态。
然后执行命令:
[root@k8s-master ~]# kubectl apply -f nginx-deployment.yaml
deployment.apps/nginx-deploy configured
然后我们可以使用rollout命令:
- 查看状态
[root@k8s-master ~]# kubectl rollout status deployment nginx-deploy
#滚动更新成功
deployment "nginx-deploy" successfully rolled out
- 暂停升级
[root@k8s-master ~]# kubectl rollout pause deployment nginx-deploy
- 继续升级
[root@k8s-master ~]# kubectl rollout resume deployment nginx-deploy
升级结束后,继续查看rs的状态:
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deploy-558fc78868 3 3 3 49m
nginx-deploy-5bf87f5f59 0 0 0 63m
根据AGE我们可以看到离我们最近的当前状态是:3,和我们的yaml文件是一致的,证明升级成功了。用describe命令可
以查看升级的全部信息:
[root@k8s-master ~]# kubectl describe deployments.apps nginx-deploy
回滚Deployment
我们已经能够滚动平滑的升级我们的Deployment,但是如果升级后的POD出了问题该怎么办?最好最快的方式当然是回退到上一次能够提供正常工作的版本,Deployment就为我们提供了回滚机制。
首先,查看Deployment的升级历史:
[root@k8s-master ~]# kubectl rollout history deployment nginx-deploy
deployment.apps/nginx-deploy
REVISION CHANGE-CAUSE
1 <none>
2 <none>
#当前一共为两个版本
[root@k8s-master ~]# kubectl apply -f nginx-deployment.yaml --record=true
deployment.apps/nginx-deploy configured
从上面的结果可以看出在执行Deployment升级的时候最好带上record参数,便于我们查看历史版本信息。
默认情况下,所有通过kubectl xxxx --record都会被kubernetes记录到etcd进行持久化,这无疑会占用资源,最重要的是,时间久了,当你kubectl get rs时,会有成百上千的垃圾RS返回给你,那就不是我们想要的效果。
上生产时,我们最好通过设置Deployment的.spec.revisionHistoryLimit来限制最大保留的revision number,比如15个版本,回滚的时候一般只会回滚到最近的几个版本就足够了。
其实rollout history中记录的revision都和ReplicaSets一一对应。如果手动delete某个ReplicaSet,对应的rollout history就会被删除,也就是还说你无法回滚到这个revison了。
rollout history和ReplicaSet的对应关系,可以在kubectl describe rs $RSNAME返回的revision字段中得到,这里的revision就对应着rollout history返回的revison。
同样我们可以使用下面的命令查看单个revison的信息:
[root@k8s-master ~]# kubectl rollout history deployment nginx-deploy --revision=2
#查看第二个版本的信息
假如现在要直接回退到当前版本的前一个版本
[root@k8s-master ~]# kubectl rollout undo deployment nginx-deploy
deployment.apps/nginx-deploy rolled back
当然也可以用revision回退到指定的版本
[root@k8s-master ~]# kubectl rollout undo deployment nginx-deploy --to-revision=3
deployment.apps/nginx-deploy rolled back
现在可以用命令查看Deployment现在的状态了。
Deployment总结:
扩容/缩容
[root@k8s-master ~]# kubectl scale deployment nginx-deploy --replicas=4
deployment.apps/nginx-deploy scaled
[root@k8s-master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 2 3h13m
nginx-deploy-5bf87f5f59-mf5rt 1/1 Running 0 98s
nginx-deploy-5bf87f5f59-ps6hc 1/1 Running 0 11s
nginx-deploy-5bf87f5f59-rnj4b 1/1 Running 0 91s
nginx-deploy-5bf87f5f59-z97zn 1/1 Running 0 98s
[root@k8s-master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deploy-558fc78868 0 0 0 58m
nginx-deploy-5bf87f5f59 4 4 4 73m
# 注意:扩容前后rs的名称没有变动
更新镜像的方法
方法一: set
#kubectl get deploy,pods
# 格式
#kubectl set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1
#kubectl set image -f nginx-deployment.yaml nginx=nginx:1.13.3
#kubectl get rs 6
# 触发 rs 创建
方法二: edit
# kubectl get deploy,pods
# kubectl edit deployments.apps nginx-deploy
# kubectl get rs
方法三: 编辑 yaml 文件 apply
# kubectl apply -f deployment.yaml