kubernetes-Deployment部署无状态服务的原理详解(七)
引言
k8s部署无状态应用后,若需要更新应用时,可以通过使用ReplicationController或ReplicaSet实现升级,主要有两种方式:
- 直接删除所有现有的pod,然后创建新的pod;
- 先创建新的pod,再删除旧pod。这里面也有两种方式,一种是先等所有新pod都运行成功后,应用切换到新pod访问,一次性删除所有旧pod;另一种是滚动升级方式逐步新建pod代替旧pod。
下面我们将先看一下常用的相关术语,然后看一下升级pod的演进方式。
其他相关术语
Pod:每个Pod是一个或一组紧密相关的容器,每个Pod就像是一个独立的逻辑机器,拥有自己的IP、主机名、进程等,运行一个独立的应用程序,是K8S调度的基本单位。
ReplicationController:简称RC,旨在创建和管理一个Pod的多个副本(replicas)。当Pod副本数少于指定数目,RC就会启动运行新的Pod副本;多于指定数目,RC就会杀死多余的Pod副本。
ReplicaSet:是新一代的RC,其相比于RC,Pod选择器的表达能力更强,其选择器可匹配缺少某个标签或特定标签名的Pod。
删旧pod,建新pod
假设ReplicationController管理一组v1版本的pod,直接通过将pod模板修改为v2版本的镜像,删除旧的pod实例,RC检测到当前没有pod匹配标签选择器,就会创建新的实例。
- 阶段1:原v1版本的RC有3个副本pod-v1。
- 阶段2:pod模板发生修改,由初始的v1版本修改为v2版本。
- 阶段3:pod-v1被手动删除。
- 阶段4:RC检测到当前没有pod匹配标签选择器,根据模板创建新的pod-v2。在阶段3过渡到阶段4期间,服务会出现短暂的不可用。
建新pod,删旧pod
如果客户不能接受升级更新期间出现短暂的不可用的服务,那就需要先创建新的pod,再删除旧pod,这需要更多的硬件资源来支撑新旧pod同时存在的场景。
创建所有新pod,删除所有旧pod
pod一般是通过Service来暴露服务的,在运行新版本pod前,Service都是访问的旧版本pod,当新版本pod创建且正常运行后,修改服务标签选择器切换Service流量至新pod,切换完毕后,删除旧RC,就可以删除所有旧pod。这种方式就是所谓的蓝绿部署
。
- 阶段1:原v1版本的RC有3个副本pod-v1。
- 阶段2:新建v2版本的RC,并且RC-v2自动创建了新的v2版本的pod。
- 阶段3:Service的流量切换到pod-v2,正常运行起来。
- 阶段4:删除RC-v1,从而自动删除pod-v1。
滚动新建和删除pod
除了一次性创建新pod再一次性删除旧pod,我们还可以逐步递进的对旧版本pod进行删除,对新版本pod进行创建。这个可以通过对旧版本RC逐步缩容,同时对新版本RC进行扩容来实现。
- 阶段1:v1版本的RC副本数为3,有3个pod-v1。
- 阶段2:RC-v1副本数降为2,自动删除一个pod-v1,此时,创建一个v2版本的RC,且pod副本数为1,会自动新建一个v2版本的pod。
- 阶段3:RC-v1副本数降为1,自动再删除一个pod-v1,RC-v2的副本数为2,再自动新建一个pod-v2。
- 阶段4:RC-v1副本数降为0,并且删掉RC-v1,RC-v2副本数升为3,从而创建第3个pod-v2,至此完成滚动升级。
引入Deployment
ReplicationController和ReplicaSet这两种资源对象需要其他控制器进行配合才可以实现滚动升级,并且难度大,因此k8s提供了一种基于ReplicaSet的资源对象Deployment可以支持声明式
地更新应用。
Deployment介绍
Deployment概述
Deployment是K8s在1.2版本引入的,是一种更高阶的资源,用于部署应用程序并以声明的方式升级应用,从而更好地解决pod编排问题。
Deployment使用机制
Deployment在内部使用了ReplicaSet实现编排pod功能,当创建一个Deployment时,ReplicaSet资源会随之创建,ReplicaSet是新一代的ReplicationController,并推荐使用它替代ReplicationController来复制和管理Pod,在使用Deployment时,实际的Pod是由Deployment的ReplicaSet创建和管理的。
Deployment使用场景
- 创建Deployment对象生成对应的ReplicaSet并完成pod副本创建;
- 通过检查Deployment状态(查看pod副本数量是否达到预期值)检验应用部署是否完成;
- 更新Deployment从而创建新的pod;
- 当前Deployment不稳定或故障,回滚到之前某个版本的Deployment(历史版本revision)
- 暂停Deployment并修改多个pod的template spec配置项,再恢复Deployment进行新的发布部署;
- 扩展Deployment从而应对高负载场景;
- 清理不再需要使用的旧版本ReplicaSet;
Deployment使用
Deployment基本命令
假设Deployment的服务名称为test-tomcat-deploy,yaml模板文件名为test-tomcat.yaml。使用命令时,deploy等价于deployment等价于deployments。若需要指定命名空间ns_name时,需要加上-n ns_name
。
创建deployment
- 基于模板创建:
kubectl create -f test-tomcat.yaml
删除deployment
- 基于模板删除:
kubectl delete -f test-tomcat.yaml
- 基于名称删除:
kubectl delete deployment test-tomcat-deploy
更新deployment
- 基于模板更新:
kubectl apply -f test-tomcat.yaml
- 基于名称更新:
kubectl edit deploy/test-tomcat-deploy
查看deployment
- 基于模板查看:
kubectl get deploy test-tomcat-deploy -o yaml
- 基于名称查看:
kubectl describe deployments test-tomcat-deploy
- 查看列表:
kubectl get deploy
资源对象信息
Deployment信息
[root@localhost ~]# kubectl get deploy -n kube-system
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
st-ui-wnunzeyg 1 1 1 1 1d
st-ui-x3w4xumy 1 1 1 1 1d
DESIRED
:pod副本数量的期望值(Deployment中定义的Replica数)CURRENT
:当前Replica值(Deployment实际创建的ReplicaSet中Replica值),该值会一直增加到DESIRED值为止才算整个应用实例创建完毕,部署才算完成。UP-TO-DATE
:最新版本的pod副本数量,用于指示在滚动升级过程中,有多少pod副本已成功升级。(Deployment滚动升级过程中ReplicaSet的Replica成功数)AVAILABLE
:当前集群中可用pod副本数。(Deployment创建的ReplicaSet中Replica存活数)AGE
:表示距离最后一次操作的时长。
ReplicaSet信息
[root@localhost ~]# kubectl get rs -n kube-system
NAME DESIRED CURRENT READY AGE
st-ui-wnunzeyg-391614280 1 1 1 1d
st-ui-x3w4xumy-1656786196 1 1 1 1d
我们可以看到ReplicaSet的命名和Deployment是相关的,ReplicaSet命名是以Deployment名为前缀,在Deployment名字基础上又加了一串随机数。
Pods信息
[root@localhost ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
st-ui-wnunzeyg-391614280-3brk8 1/1 Running 0 1d
st-ui-x3w4xumy-1656786196-f4w8z 1/1 Running 0 1d
pod名称以Deployment中的ReplicaSet名称为前缀,在此基础上又加了随机字符串。
Deployment更新
更新策略
在Deployment中,可以通过spec.strategy指定Pod更新的策略,目前支持:Recreate(重建)
和RollingUpdate(滚动更新)
,默认是RollingUpdate。
Recreate:设置spec.strategy.type=Recreate
,更新方式为:Deployment在更新Pod时,会先杀掉所有正在运行的Pod,然后创建新的Pod。
RollingUpdate:设置spec.strategy.type=RollingUpdate
,更新方式为:Deployment会以滚动的方式来渐变性的更新Pod,即Pod新版本的递增,旧版本的递减的一个过程。
滚动更新
概念
“滚动”,给人的是一种“圆”的印象,持续,不中断的意思,类似于“持续交付”的理念。RollingUpdate策略指一次仅更新一个Pod
,并且逐个更新,而不是一次性将所有的服务都关闭,避免业务中断。
原理
- 初始创建Deployment,系统创建了一个ReplicaSet,并按照用户的需求创建了3个Pod副本;
- 当更新Deployment时,系统创建一个新的ReplicaSet,并将其副本数量扩展到1,然后将旧的ReplicaSet缩减为2;
- 系统继续按照相同的更新策略对新旧两个ReplicaSet进行逐个调整。
- 最后,新的ReplicaSet运行了3个新版本的Pod副本,旧的ReplicaSet副本数量则缩减为0。
Deployment回滚
概念
回滚:通过滚动升级的策略可以平滑的升级Deployment,若升级出现问题,需要最快且最好的方式回退到上一次能够提供正常工作的版本。为此K8S提供了回滚机制。
revision:更新应用时,K8S都会记录当前的版次,即为revision,当升级出现问题时,可通过回滚到某个特定的revision,默认配置下,K8S只会保留最近的几个revision,可以通过Deployment配置文件中的spec.revisionHistoryLimit属性增加revision数量。
更新或回滚:每次更新或回滚时,revision都会自增1,回滚可以看作是一次更新,是一次更新为原版本的操作。
kubectl命令使用
查看修订版本记录
kubectl rollout history deployment deployment_name
查看某个历史记录的详细信息
kubectl rollout history deployment deployment_name --revision=2
其中--revision
表示指定修订版本;
回滚到上一个版本
kubectl rollout undo deployment deployment_name
回滚到指定版本
kubectl rollout undo deployment deployment_name --to-revision=2
其中,--to-revision
表示回滚到指定的修订版本。
API接口使用
POST
/apis/apps/v1beta1/namespaces/{namespace}/deployments/{name}/rollback
如:
curl -k -H 'Authorization: Bearer token_xxxx' -H 'Content-Type:application/json' -X POST -d '{
"kind": "DeploymentRollback",
"apiVersion": "extensions/v1beta1",
"name": "deployment_name",
"rollbackTo": {
"revision": 2
}
}' https://localhost:6443/apis/extensions/v1beta1/namespaces/default/deployments/deployment_name/rollback
其中:name和rollbackTo.revision为必须字段,name为资源名称,rollbackTo.revision为回退的版本,若要回退上一个版本,即为0。
Q&A
什么是声明式?和其他方式有什么区别?
除了声明式,我们一般还有指令式,也就是命令式。我们看看这两者定义和区别。
指令式:
定义
:使用计算机某种语言的指令(命令)来完成程序的运行,比如我们通过编写shell脚本、python脚本运行程序应用。编写
:编写复杂,强依赖开发人员的经验,需要考虑目标环境以及流程细节,处理各种异常情况和边缘情况等。事务性
:较难保持事务性,强依赖脚本流程,若脚本在执行过程中出现异常,程序应用会处于一个中间状态,所以多次运行,可能会达到不同的状态和结果。维护性
:开发后,需要有对应的运维文档来协助运维人员维护同一个脚本,不便于维护。
声明式:
定义
:使用配置文件直接描述最终状态,比如k8s中的yaml文件,描述最终要启动多少副本,要多少cpu之类的状态和结果。编写
:易于编写,只要会写配置文件,告诉应用达到什么样的结果和状态即可,不需要考虑流程和目标环境的细节,事务性
:天然的事务性,要么执行成功,要么失败,不会出现多种中间状态,重复执行保持一致的状态和结果。维护性
:配置文件中直接描述了最终状态和结果,无需过多的运维文档来描述信息。
参考
《Kubernetes in Action》
《Kubernetes权威指南》
k8s官网