04-K8S之pod控制器
pod控制器类型
ReplicationController: 最初的控制器,一个控制器实现所有的功能,过于庞大。已被废弃
ReplicaSet:
Deployment: 并不直接管理pod,而是工作在ReplicaSet之上,通过控制ReplicaSet来控制pod,帮我们管理无状态应用的。比ReplicaSet强大,支持扩缩容,滚动更新和回滚,以及声明式更新配置的功能(创建资源可以根据声明式的逻辑来控制,改变我们在apiserver定义的目标状态,只要这个状态支持动态运行时修改,不像kubectl create)。
DaemonSet:在集群中的每一个节点之上都运行一个pod,pod挂了,会自动重启,在新加入的节点上也会自动创建一个DaemonSet管理的pod。使用场景比如:运行一个代理,日志收集器(filebeat、flunted)
Job:一次性作业的pod
CronJob:周期性地运行pod,有明确的退出时间
StatefulSet:管理有状态应用,每一个pod副本都是被单独管理的,它拥有着自己独有的标识和数据集,一旦这个节点或pod出现故障,在重新加入集群或者重新启动pod,需要做很多初始化的操作,场景:redis集群,集群中的每一个主机是按照槽位实现分布的,并且集群中的每一个redis主机的槽位是固定的,比如:redis1槽位:1-5000,redis2槽位:5001-10000,redis3槽位:10001-16384;每一个redis主机都不能被取代
'''
1.不论是Deployment,还是DaemonSet,这些服务管理的pod无状态(无状态应用)的,通常用于只关注群体,而不关注个体的场景;
2.不论是Deployment,还是DaemonSet,这种服务是守护进程类的,必须持续运行在后台,没有终止的那一刻,不繁忙的时候在忙着监听(文件的变动、用户对某个套接字的访问请求)。
3.有时候需要对数据库做备份操作,可以启动一个定时任务来备份,也可以、启动一个pod来实现,当备份结束之后停止运行,也没必要重启(pod只运行一次)。这时,Deployment,DaemonSet控制器是不适合的,因为它们始终保持pod处于运行状态。需要使用Job控制器
4. Cronjob控制器,如果一个任务在当前周期内没有处理完,pod终止了,该怎么办?所以CronJob控制器还需要处理此类问题。好处就是Job和CronJob不需要持续后台运行。
'''
1.ReplicaSet控制器
先看一个示例:
vim pod-rs.yaml
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: replicaset-pod # 控制器名称,也是pod的名称,最好定义控制器、pod模板中名称、container的名称一致
namespace: default
spec: # 控制器的spec
replicas: 2
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
name: myapp-pod # pod模板里定义的这个名称是不起作用的,创建出来的pod的名称是 控制器名称+随机串
labels: # 这里定义的标签要和上面selector定义的标签一致,不然创建的pod的标签和选择器标签不一致,会一直创建下去,k8s会被撑爆。这里的标签是给pod贴的标签。
app: myapp
release: canary
environment: qa # 可以创建标签选择器之外的其他标签
spec: # 创建pod的spec
containers:
- name: myapp-container
image: nginx:1.20
ports:
- name: http
containerPort: 80
replicaset控制器通过标签选择器控制我们定义的副本数量,如果这时我们强行修改别的pod的标签和replicaset控制器标签完全一样,那么我们原本的pod将被杀死1个。
可以在pod前面加一个负载均衡service,而service是通过自身定义的标签选择器中的标签来选择带有符合标签的pod,进行流量转发,和控制器的选择器标签没有关系。比如:
replicaset1:
selector:
matchLabels:
app: myapp
release: canary
replicaset2:
selector:
matchLabels:
app: myapp
release: prod
而service的selector为:
service:
selector:
app: myqpp
则此service对replicaset1和replicaset2控制器控制的pod副本都能进行流量转发。当然这种需要一定的场景,一般根据标签的唯一性,只选取某一个控制器控制的pod进行流量转发。
使用控制器动态扩缩容副本数
kubectl edit rs replicaset-pod # 在线编辑副本控制器的配置,更新副本数量
2.deployment控制器
三层结构:deployment控制replicaSet,replicaSet控制pod
重要字段
kubectl explain deployment.spec
strategy <Object> # 更新策略 maxSurge和maxUnavailable不能同时为零。
rollingUpdate <Object> # 定义滚动更新方式(控制粒度)
maxSurge <string> # 定义滚动更新pod数量可以超出当前值多少,可以是具体数字,亦可以是百分比。(先更新,再删除)
maxUnavailable <string> # 定义滚动更新最大不可用的pod数量,可以是具体数字,亦可以是百分比。(先删除,再更新)
type <string>
"Recreate" or "RollingUpdate",Default is RollingUpdate.
Recreate:删除一个pod,创建一个新的pod,删除一个,创建一个,直到所有副本全部更新
RollingUpdate:滚动更新,如果type定义为Recreate类型,rollingUpdate将不起作用。
revisionHistoryLimit <integer> # 支持回滚的老replicaSet版本的数量,默认是10个
paused <boolean> # 暂停deployment立马更新的动作。不定义此字段默认,立马更新。
定义一个deployment示例
vim pod-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy-controll
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app:myapp
release: canary
template:
metadata:
name: myapp-deploy-controll
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: nginx:1.20
ports:
- name: http
containerPort: 80
kubectl apply -f pod-deploy-controll.yaml # 及支持创建pod,也支持更新pod,可以重复apply 下图1
# 通过编辑配置文件修改副本数,再次apply yaml文件,每一次yaml文件的变化,当apiserver发现当前的状态与etcd中的不同,都会通过apiserver同步到etcd当中。同时修改现有状态到期望状态。 下图2
replicas: 3
# 查看deploy状态信息 下图3
kubectl describe deploy myapp-deploy-controll
图1:
图2:
图3:
imagePullPolicy:镜像拉取策略
restartPolicy:容器重启策略
strategy:滚动更新pod策略
1.该配置清单文件直接更新
vim pod-deploy-controll.yaml
# 修改镜像版本:
image: nginx:1.20 --> image: nginx:1.20.2
kubectl get pods -l app=myapp,release=canary -w # 下图1
kubectl apply -f pod-deploy-controll.yaml
kubectl get pods -l app=myapp,release=canary # 查看新镜像的pod 图2
kubectl get rs -o wide # 图3 老的replicaSet管控的pod副本全部迁移到使用新镜像重新创建的replicaSet上了,但是老版本会保留10,随时等待用户回滚。
kubectl get deploy -o wide
kubectl describe deploy myapp-deploy-controll # 图4
kubectl rollout history deploy myapp-deploy-controll # 图5 查看可以滚动的所有保留的历史版本,默认保留10个最近版本
2.使用kubectl patch打补丁的方式更新,后跟json格式的字符串; # 比如:修改配置清单参数strategy、replicas,比如:滚动更新策略(strategy), maxSurge,minUnavailable
kubectl patch --help
# 打补丁方式增加副本数(扩容)
kubectl patch deployment myapp-deploy-controll -p '{"spec":{"replicas":5}}' # 图6
# 通过修改strategy的maxSurge和minUnavailavle,比如:最多不可用0,最大超出个数为1;在更新这1个的时候,让它暂停下来,当前更新的这1个是中间迭代版本,暂停的时候还没来得及删除老的一个版本,这样一共就有6个pod了,这就是我们设置最多不可用0,最大超出个数为1的作用;这样就实现了灰度发布,新增的这个pod就是我们放的金丝雀。。。。
实现方式:
# 使用命令
1) kubectl rollout pause --help
# 1.首先使用打补丁的方式修改滚动更新策略
kubectl patch deployment myapp-deploy-controll -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":0}}}}'
kubectl describe deployment myapp-deploy-controll # 图7
'''
Waiting for deployment "myapp-deploy-controll" rollout to finish: 1 out of 5 new replicas have been updated...
'''
# 2.根据更新策略,监听pod的更新变动情况
kubectl get po -l app=myapp,release=canary -w # 图8
或者使用:
kubectl rollout status deployment myapp-deploy-controll
# 3.放出一个金丝雀,并暂停deployment控制器
kubectl set image deploment myapp-deploy-controll myapp=nginx:1.21.4 && kubectl rollout pause deployment myapp-deploy-controll
'''
deployment.apps/myapp-deploy-controll image updated
deployment.apps/myapp-deploy-controll paused
'''
# 4.此时deployment 和 replicaSet的情况 下图9
kubectl get deploy -o wide
kubectl get rs -o wide
# 从deployment控制器的暂停状态恢复到滚动更新状态
kubectl rollout resume deployment myapp-deploy-controll
kubectl get po -l app=myapp,release=canary -w # 执行resume命令后,剩下5个老的5个副本的滚动更新情况,并最终达到我们的期望的5个副本全部更新为新镜像的pod。
kubectl get po -l app=myapp,release=canary # 图11
# 版本回滚,不指定版本号,默认回滚到上衣版本
kubectl rollout undo --help # --to-revision=REVISION
kubectl get po -l app=myapp,release=canary -w # 发现所有副本都回滚到 v1版本。
kubectl rollout history deployment myapp-deploy-controll
'''
deployment.apps/myapp-deploy-controll
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
4 <none>
'''
# 现在我们从当前版本REVISION:4,回滚到REVISION:1
kubectl rollout undo deployment myapp-deploy-controll --to-revision=1
'''
deployment.apps/myapp-deploy-controll rolled back
'''
kubectl get rs -o wide # 下图12
kubectl get po -l app=myapp,release=canary -o wide
kubectl rollout history deployment myapp-deploy-controll # 当前的v5就是我们回滚的v1版本,原v1被v5取代。
'''
REVISION CHANGE-CAUSE
2 <none>
3 <none>
4 <none>
5 <none>
'''
2)修改配置清单的pause字段 # 下图13
3.如果只是更新镜像文件,也可以使用 kubectl set image 的方式进行更新
图1:
图2:
图3:
图4:
图5:
图6:
图7:
图8:
图9:
图10:
图11:
图12:
图13:
3.daemonSet控制器
kubectl explain daemonSet
docker pull elastic/filebeat:6.8.15
docker image inspect elastic/filebeat:6.8.15 # 查看镜像内部的封装结构,比如:查看内部定义的环境变量
[root@master01 controll]# vim pod-daemonset-controll.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: redis
role: logstor
template:
metadata:
labels:
app: redis
role: logstor
spec:
containers:
- name: redis
image: redis:6.0.3
ports:
- name: redis
containerPort: 6379
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: pod-daemonset
namespace: default
spec: # 控制器的spec
selector:
matchLabels:
app: filebeat
release: stable
template:
metadata:
name: filebeat
labels: # 这里定义的标签要和上面selector定义的标签一致,不然创建的pod的标签和选择器标签不一致,会一直创建下去,k8s会被撑爆。
app: filebeat
release: stable
spec: # 创建pod的spec
containers:
- name: filebeat
image: elastic/filebeat:6.8.15
env:
- name: REDIS_HOST
value: redis.default.svc.cluster.local
- name: REDIS_LOG_LEVEL
value: info
kubectl apply -f pod-daemonset-controll.yaml # 图1
kubectl get po
kubectl exec -it pod-daemonset-sbfs5 -- /bin/sh # 图2
# 给redis暴露端口(添加一个service)
kubectl expose deployment redis --port=6379
kubectl exec -it redis-67cb65d499-24jdl -- /bin/sh # 查看filebeat发送到redis pod的日志收集其概况 ls /data
图1:
图2: