小知识点
kubectl get pods podA -n NAMEAPSCE -o yaml --export
如果'不带上--export' 生成文件会有'很多无用的内容'
备注: 可以换成'其它系列'的资源
注意: 新版本已经'废弃'-->1.18.4有,1.19.3已经废弃了
一 Deployment理解
Deployment 是'Workload'中的一种 --> '无状态应用'
滚动更新 --> 理解为'灰度发布一种',只是'粒度'不一样
+++++++++++++++
滚动更新: 比如我们应用更新了,我们只需要'更新我们的容器镜像',然后修改 Deployment 里面的 'Pod 模板镜像',那么 Deployment 就会用'滚动更新(Rolling Update)'的方式来升级现在的 Pod
明确滚动更新'触发的表现形式' --> 'set image'、'path字段'、'修改后直接apply'
而 Deployment '这个能力的实现',依赖的' ReplicaSet 这个资源对象',实际上我们可以通俗的理解就是'每个 ReplicaSet' 就对应集群中的'一次部署'
(1)本章节的示例代码
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 3 '期望的 Pod 副本数量'
selector: Label Selector,'必须匹配 Pod 模板中的标签'
matchLabels:
app: nginx
template: 'Pod 模板'
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
+++++++++++++ '重点知识'
1)dp通过'控制rs'来'控制pod'
2)目前'更新应用'-->通过'镜像版本'来标识
3)ds的'名字发生变化'--> 由于'修改template中的属性了'
1)deployment部署,然后查看pod状态
2)思考ds
结果: 这个 'Pod 的控制器'是一个 ReplicaSet 对象啊,我们'不是创建的一个 Deployment 吗'?为什么 Pod 会'被 RS 所控制呢'?
3)看下这个对应的 RS 对象的详细信息
意思就是我们的'Pod 依赖的控制器'--> 'RS 实际上被我们的 'Deployment 控制着'
4) deployment、replicaset、pod之间的关系
ReplicaSet '明确调整 Pod 的个数',而 Deployment 是通过管理 ReplicaSet 的'数量和属性'来实现'水平扩展/收缩'以及'滚动更新'两个功能的
二 滚动更新理解
如果只是'水平扩展/收缩'这两个功能,就完全'没必要设计 Deployment 这个资源对象了',Deployment 最突出的一个功能是'支持滚动更新'
说明: ReplicSet也能完成'水平扩展/收缩'
(1)滚动更新的方案
1)Recreate -->'先删除所有'已存在的pod,'重新创建新的';
2)RollingUpdate -->'滚动升级','逐步替换-->灰度替换'的策略,同时滚动升级时,支持更多的'附加参数';例如设置'最大不可用'pod数量,'最小升级间隔'时间等等
(2)Recreate
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 3 # 期望的 Pod 副本数量,默认值为1
selector: # Label Selector,必须匹配 Pod 模板中的标签
matchLabels:
app: nginx
strategy:
type: Recreate '关注这个字段'
template: # Pod 模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
注意: 滚动更新的时候加上'--record参数',使用此参数将'记录后续创建对象的操作-->记录当时滚动更新的命令',方便'管理'与'问题追溯'
备注: 后续我们通过'其它策略'让滚动更新时记录的'CHANGE-CAUSR' -->变得'更有意义'
(3)RollingUpdate
minReadySeconds'含义'
当'新的'pod启动'多少秒'后,再kill'掉旧'的pod
这里需要估一个'比较合理'的值-->从容器启动到'应用正常提供服务'
maxSurge: 升级过程中,比目标pod'多出的'pod数量('某个时刻') -->'绝对值和百分比'(默认是25%)
maxUnavailable: 最大'不能提供'服务的pod
策略: 先创建'maxSurge'个,然后删除'maxUnavailable'个
1)修改配置文件 -->最好做'版本控制',每次通过'不同的文件-->不同文件标识不同的配置'或者'相同的文件名-->即使record记录了,但是也毫无意义'
2)path修改字段 --> 以'补丁的形式'修改-->'set image'也算是patch中特殊的一种
3)set image --> '直截了当,record看到当前对应更新的原因'
修改yaml文件中的镜像信息准备滚动更新
'3+1+1' -->先创建一个('过程'-->'最大4个pod')-->删除一个(最多一个'不能提供服务')
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
namespace: default
spec:
replicas: 3 # 期望的 Pod 副本数量,默认值为1
selector: # Label Selector,必须匹配 Pod 模板中的标签
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 1 '理解含义' -->'百分比向上取整'
maxUnavailable: 1 '理解含义'
template: # Pod 模板
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx '1.18-->latest'
ports:
- containerPort: 80
~
查看滚动更新的过程
1) get pods -w -->'查看过程'
2) rollout status -->'查看详细信息的滚动过程'
3) describle deployment -->'看到详细的信息'-->更'推荐'
上面过程: '先启动'一个'新'的 Pod,'杀掉'一个'旧'的 Pod,然后再启动一个新的 Pod,这样滚动更新下去,直到全都变成新的 Pod
思考:如果replicas和images同时改变,如何滚动更新
例如: replica '4-->3'; image --> 'nginx:1.18 --> nginx:latest'
所以 Deployment 控制器首先是将'old-->之前控制'的 nginx-deploy-7848d4b86f 这个 RS 资源对象'先进行缩容'操作,然后'滚动更新'开始了
思考:rs的名称组成
rs名称 = 'deployment名称' + 'yaml文件的哈希数值-->随机字符串'
思考:随机字符串'如何生成的'
pod名字: 'deployment名字'-'replicaset模板hash名字'-'pod模板hash名字'
需求:暂停过程发现有小问题
滚动更新 '暂停'
kubectl rollout 'pause' deployment app
备注: '此时的状态' -->混合达到'预期'的数目吗?
需求:发现没有问题,滚动更新继续
kubectl rollout 'resume' deploy app
需求:想查看滚动更新的历史
kubectl rollout history deployment nginx-deploy
CHANGE CAUSE -->'需要滚动更新的时候加上 --record参数' --> 把'执行的命令记录'下来 --> '上面讲解了记录的方式'
思考:如何让'CHANGE CAUSE更有意义' --> kubectl set image deployment/nginx nginx=nginx:1.16 --record
形式: 'image' (-f FILENAME | TYPE NAME) 'CONTAINER_NAME_1'=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
需求:升级发现有大问题,如何回滚到指定版本
回滚'undo'到'指定'版本 --> 类似git的'回退'
kubectl 'rollout undo' deployment app --to-revision=1
备注: 如果'没有指定'具体版本,默认是'最近的一个历史'版本
每次更新应用的时候都会'记录下当前的配置',保存为一个'revision',这样就可以'回滚到某个特定的'revision
备注: 'deploy配置'和'revision'是一一对应的
简单原理: undo '某个revision' --> 查看对应'rs中匹配的'revision --> 按照'rs模板'创建
备注: 这种'文件形式',可以'多处改动',纳入'git版本控制'更好 --> 通过'yaml文件'的版本控制进行滚动更新
注意: record仅仅'一条记录信息(保证意义)',而不是按照'该条指令'去滚动更新 -->例如'文件形式',回滚的时候'当前目录没有这个文件',还是可以'成功的'
目的: 让'滚动更新有意义',能够'记录'滚动的版本信息!
(4)revisionHistoryLimit
从上面的结果可以看出在执行Deployment升级的时候最好带上record参数,便于查看历史版本信息
默认情况下,所有通过kubectl xxxx --record都会被kubernetes记录到etcd进行持久化,这无疑会占用资源,最重要的是,时间久了,当你kubectl get rs时,会有成百上千的垃圾RS返回给你,那时你可能就眼花缭乱了
生产环境:我们最好通过设置Deployment的.spec.revisionHistoryLimit来限制最大保留的revision number
比如15个版本,回滚的时候一般只会回滚到最近的几个版本就足够了,系统默认是记录最近的10个更新记录,一般10个就不少了
++++++++++++ '深层次思考' ++++++++++++
滚动更新的过程'没有完成',又继续进行滚动更新,导致'rollout history'记录的信息不准确
'换句话说': 上次滚动更新没有完成,'又进行'滚动更新
导致现象: revisionHistoryLimit超过'预设'的数值
代码分析原因: 回滚'删除revision与否',是通过'判断rs下面的pod数量是否为0',如果pod不为0,则不会删除该revision
+++++++++++++++++++++ '分割线'
revisorHIstoryLimit:3 --> 当前rs'没有pod'才会删除
做法:没有等到滚动更新完成,又'修改参数'进行滚动更新
rs是否能够真正的被删除的'标准' -->'没有副本的时候才可以删除','换句话说'滚动更新的过程中'只能删除没有pod的rs'
rollout history 读取的是rs
(5)滚动更新的原理
首先: 在前面我们'知道deploy是通过控制rs来控制pod的副本',通过'滚动更新'我们看到'产生了许多rs'
rollout history中'记录的revision个数'都和'ReplicaSets'一一对应
验证:手动delete某个ReplicaSet,对应的rollout history是否会被删除
结论: 一旦'手动删除rs',ectd中就'没有记录了',对应的rollout history中'记录的record会被删除',后续无法'回滚到这个revison了'
后续: '本地缓存'是否会影响
可以'回滚的原因':rs保存了'当前资源的信息'(-o yaml导出)、只是'这个rs下面没有pod'
后续1:查询etcd中存储的
后续2:直接做滚动更新,导致请求丢失,如何避免0宕机,引出Service