Kubernetes 学习笔记(四)--- K8S Pod控制器应用进阶

目录

一、Pod控制器类别
    1.1 ReplicaSet
    1.2 Deployment
    1.3 DaemonSet
    1.4 Job
    1.5 CronJob
    1.6 StatufulSet
    1.7 CDR
    1.8 Helm
二、ReplicaSet资源清单
三、Deployment资源清单
    3.1 strategy(Pod更新策略)
    3.2 revisionHistoryLimit
    3.3 paused
    3.4 template
    3.5 Deployment资源清单示例
            3.5.1 更新操作
            3.5.2 通过打补丁的方式更新资源清单配置
            3.5.3 暂停Pod更新
            3.5.4 恢复Pod更新
            3.5.5 回滚操作
四、DaemonSet资源清单

一、Pod控制器类别

1.1 ReplicaSet

ReplicaSet控制器用来管理无状态的Pod资源,核心作用在于代用户创建指定数量的Pod副本,并确保Pod副本数量一直等于用户期望的数量。而且还支持Pod滚动更新、及自动扩缩容等机制;它被称新一代的ReplicationCtroller。

ReplicaSet主要有三个组件组成:

  1. 用户期望的Pod副本数量;
  2. 标签选择器,用来选定由自己管理或控制的Pod副本,如果通过标签选择器挑选到的Pod少于定义的Pod副本数量,则会利用Pod资源模版来创建Pod副本,以达到规定的Pod数量;
  3. Pod资源模版。

但是Kubernetes却不建议用户直接使用ReplicaSet,而是应该使用Deployment

1.2 Deployment

Deployment也是Pod控制器,但是它是工作在ReplicaSet之上的。Deployment是通过控制ReplicaSet,从而来控制Pod。Deployment能够提供比ReplicaSet更为强大的功能。比如:Pod版本回滚、声明式配置(声明式配置是已经创建的Pod可以随时更改配置并应用到Pod)。Deployment是目前管理无状态应用最好的控制器。

1.3 DaemonSet

DaemonSet用于确保集群中的每一个节点只运行一个特定的Pod副本,这种特定的Pod通常是用来实现系统级的后台任务。把这样的任务托管在Kubernetes之上的好处是:如果这个后台任务宕了以后,会由DaemonSet控制器自动重建一个Pod;新建一个Node节点,它也会在新节点上创建一个这样的Pod运行。

约束:我们也可以根据自己的需求,在K8S群集中的部分满足条件的节点上仅运行一个Pod副本。

总结: Deployment和DaemonSet管理的Pod中运行的服务都是无状态的,且是守护进程类的(必须始终持续运行在后台)。但是对于那种只希望运行一次就结束的任务,显然以上两种控制器是不能够使用的。例如:我们需要对数据库进行备份,备份结束后,任务就应该结束了,而不是让任务持续运行在后台。那么对于这种任务只运行一次,只要任务完成就正常退出,没有完成才会重建,这就应该选择使用Job这种控制器了。

1.4 Job

Job控制器控制只能执行一次作业的任务,它确保这个任务确实是正常完成而退出的,如果是异常退出,则Job控制器会重建任务再次执行直到任务正常完成。

那么对于周期性的任务呢?显然Job控制器也是无法胜任的。这就需要CronJob了。

1.5 CronJob

CronJob与Job类似,也是运行一次就退出。不同之处在于,Job是只运行一次,CronJob是周期性运行。但每次运行都会有正常退出的时间。如果前一次任务还没执行完成,又到了下一次任务执行的时间点了怎么办呢?CronJob也可以解决这种问题。

1.6 StatufulSet

StatufulSet控制器能够管理有状态的Pod副本,而且每一个Pod副本都是被单独管理的,它拥有自己独有的标志和独有的数据集。一旦这个副本故障了,在重建Pod之前会做许多初始化操作。以Redis群集为例:如果Redis集群中三个节点中的某一个节点宕机了,为了确保每个节点宕机后数据不丢失,我们传统的做法就是对每个节点做主从复制,当主节点宕机后,需要人为的把从节点提升为主节点,想要恢复从节点,就需要很多运维操作了。

但是利用StatufulSet去定义管理Redis或Mysql或者Zookeeper,它们的配置是不一样的。例如:配置管理Redis主从复制和配置管理Mysql主从复制中间的操作步骤是不一样的。所以这样的配置没有任何规律可循。StatufulSet给我们提供了一个封装,用户把需要人为操作的复杂的执行逻辑定义成脚本,放置在StatufulSet的Pod模板中。这样在每次Pod节点故障后,能通过脚本自动恢复过来。

总结:真正想把有状态的应用托管在Kubernetes之上,还是有相当的难度。

1.7 CDR

Custom Defined Resources K8S 1.8+,用户自定义资源。

1.8 Helm

任何不把用户当傻瓜的应用,都难以取得成功。K8S资源清单定义起来,门槛过高,难度大。这就诞生了Helm,Helm对于Kubernetes来说,就相当于Linux系统中的yum。以后在再部署大型的应用,就可以用Helm直接安装部署。不过Helm到目前为止,诞生也不超过两年的时间。到目前为止,许多大型主流的应用,已经可以通过Helm去部署。

二、ReplicaSet资源清单

ReplicaSet资源清单定义时的一级字段:

apiVersion: apps/v1
kind: ReplicaSet
metadata: 
spec: 

spec下一级核心字段主要的有三个:

replicas    <integer>       # 定义Pod副本数量
selector    <Object>        # 选择器
template    <Object>        # 模板

template字段中嵌套的就是Pod资源清单定义的字段:

metadata    <Object>        # 这是定义Pod的元数据
spec        <Object>        # Pod的spec

接下来,我们来定义一个ReplicaSet的资源清单:rs-demo.yaml

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: myapp
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      name: myapp-pod
      labels:
        app: myapp
        release: canary
        environment: qa
    spec:
      containers:
      - name: myapp-container
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80

注意事项看下图:


image.png

利用上述清单创建一个名为myapp的ReplicaSet:

kubectl create -f rs-demo.yaml

查看创建成功的ReplicaSet:


image.png

ReplicaSet可以简写为rs。

值得注意的是,在Pod模板中定义的Pod名称(如上代码:name: myapp-pod)实际上是不起作用的。因为通过控制器清单文件创建的Pod名称是由按照 控制器名称-随机字符串这样的形式命名的。如下图:

获取创建的Pod:


image.png

更新Pod容器的镜像后,新版本Pod更新示意图:


image.png

三、Deployment资源清单

Deployment管理保留的ReplicaSet版本数量可以由用户自定义,默认保留10个历史版本。Deployment能够使用声明式配置,声明式配置是使用kubectl apply -f demo.yaml命令。对于声明式配置的资源,将来还可以在命令行使用patch子命令去打补丁实现配置修改更新。

Deployment在控制Pod滚动更新时,还可以配置Pod的滚动更新逻辑。

Deployment、ReplicaSet、Pod三者之间的关系:


image.png

Deployment可以简写为deploy
接下来看看Deployment资源清单一级字段:

apiVersion: apps/v1
kind: Deployment
metadata: 
spec:

Deployment的spec与ReplicaSet的spec区别不大。
Deployment中的spec字段:

replicas    <integer>   # Pod副本数量
selector    <Object>    # 标签选择器
template    <Object> -required-     # Pod模板
strategy    <Object>    # 定义Pod更新策略
paused      <boolean>
revisionHistoryLimit    <integer>

3.1 strategy(Pod更新策略)

spec:
  strategy:
    type:                     # <string>
    rollingUpdate:            # <Object>

strategy.type字段取值:

  • Recreate: 重建更新,就是删除一个Pod,再重建一个Pod。当typerecreate时,与type同级的rollingUpdate字段就失效了。当typerollingUpdate,与type同级的rollingUpdate字段定义滚动更新的策略。
  • RollingUpdate滚动更新

strategy.rollingUpdate字段:

  • maxSurgePod滚动更新时,最多能超出replicas定义的Pod副本数的个数。有两种取值方式:1. 直接指定一个数字(ex: 5);2. 指定一个百分比(ex: 10%)。
  • maxUnavailablePod滚动更新时,最多有几个不可用。假设replicas值为5,maxUnavailable值为1,那么可用的Pod数量至少为5-1=4个。此字段同样可以指定一个百分比做为值。

例如:Pod滚动更新时,多则只能多2个,少则只能少1个,则可以这样定义:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 1

3.2 revisionHistoryLimit

revisionHistoryLimit <integer>表示要保留以允许回滚的旧ReplicaSet的数量。默认是10个。如果值为0,表示不保存旧版本。

3.3 paused

paused <boolean> 表示部署Pod时是否暂停,通常情况下是不暂停的,执行命令后会立即部署Pod。

3.4 template

template <Object> -required- Pod模板与ReplicaSet中Pod模板定义一致。

3.5 Deployment资源清单示例

编辑yaml文件:deploy-demo.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deploy
  namespace: default
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
      release: canary
  template:
    metadata:
      labels:
        app: myapp
        release: canary 
    spec:
      containers:
      - name: myapp
        image: ikubernetes/myapp:v1
        ports:
        - name: http
          containerPort: 80

这里我们用声明式创建:

[root@k8s-master manifests]# kubectl apply -f deploy-demo.yaml 
deployment.apps/myapp-deploy created

看一下创建的结果:


image.png

同时还会自动创建一个ReplicaSet,如下图:


image.png

自动创建的ReplicaSet命名规则:deploy名称-Pod模板hash值

查看创建的Pod,如下图:


image.png

Pod的命令规则:deploy名称-Pod模板hash值-随机字符串

这时我们想要改变Pod副本数量,可以直接vim deploy-demo.yaml修改replicas: 4,然后再执行kubectl apply -f deploy-demo.yaml

注意:声明式创建,相同的yaml文件可以多次执行kubectl apply。而kubectl create只能执行一次。

上述示例清单中,有很多字段我们都没有定义。Kubernetes会自动填充默认值。可以通过命令:kubectl get deploy myapp-deploy -o yaml查看。

3.5.1 更新操作

我们先修改deploy-demo.yaml,将容器的镜像版本修改为v2:
vim deploy-demo.yaml

image.png

再次部署:

[root@k8s-master manifests]# kubectl apply -f deploy-demo.yaml 
deployment.apps/myapp-deploy configured

访问新版本Pod,可以看到已经更新到v2版本了。


image.png

查看滚动历史记录:

[root@k8s-master manifests]# kubectl rollout history deployment myapp-deploy 
deployments "myapp-deploy"
REVISION  CHANGE-CAUSE
1         <none>
2         <none>
3.5.2 通过打补丁的方式更新资源清单配置
[root@k8s-master manifests]# kubectl patch deployment myapp-deploy -p '{"spec": {"replicas": 5}}'
deployment.extensions/myapp-deploy patched

可以看到Pod副本个数立即更新到5个了。


image.png

通过打补丁的方式修改滚动更新策略:

[root@k8s-master manifests]# kubectl patch deployment myapp-deploy -p '{"spec": {"strategy": {"type": "RollingUpdate", "rollingUpdate": {"maxSurge": 1, "maxUnavailable": 0}}}}'
deployment.extensions/myapp-deploy patched

查看一下滚动更新策略,已经应用修改:


image.png
3.5.3 暂停Pod更新

为了做这个示例,我们可以先修改镜像版本,然后立即暂停滚动更新。
修改镜像版本除了使用vim命令直接编辑yaml文件或使用kubectl patch打补丁外,还可以使用kubectl set image直接修改镜像。示例:kubectl set image deployment/nginx busybox=busybox nginx=nginx:1.9.1
命令如下:

[root@k8s-master ~]# kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment myapp-deploy 
deployment.extensions/myapp-deploy image updated
deployment.extensions/myapp-deploy paused

另开启一个终端,监控label为app=myapp的Pod:

image.png

通过上图可以看到,滚动更新暂停命令执行后,会先创建一个新Pod并运行,然后就暂停住了,旧Pod也没有删除一个。此时有6个Pod,如下图:


image.png

通过命令:kubectl rollout status deployment myapp-deploy可以看到滚动更新的状态,如下图:

image.png

图中提示信息告诉我们:等待部署“myapp-deploy”部署完成:5个新副本中的1个已更新...

接下来我们恢复Pod更新...

3.5.4 恢复Pod更新

恢复Pod更新使用命令:

[root@k8s-master ~]# kubectl rollout resume deployment myapp-deploy 
deployment.extensions/myapp-deploy resumed

查看一下滚动更新的状态:


image.png

从图中可以看出,滚动更新完成。

看一下ReplicaSet的状态:


image.png

从上图中可以看到镜像已经更新到v3版了,而且有5个Pod已经准备就绪了。

接下来执行回滚操作。。。

3.5.5 回滚操作

假如新版本的应用Pod有问题,想要回滚,就要使用命令:kubectl rollout undo

kubectl rollout undo deployment myapp-deploy --to-revision=1

--to-revision=1 表示回滚到第1版,如果不指定--to-revision选项,则默认是回滚到前一个版本。可以通过命令kubectl rollout history deployment myapp-deploy查看。

image.png

回滚后,原来的第1版变成第4版,所以第4版的前一版就是第3版了。如果在第4版的基础上向前回滚一个版本,就会回滚到第3版。

再来 看看ReplicaSet状态:


image.png

从上图中可以看到,已经回滚到v1版了,v1版有5个Pod准备就绪了。而v3版的Pod数为0 。

四、DaemonSet资源清单

DaemonSet控制器能够在指定节点上运行能够实现系统级的管理功能的Pod,而且每个指定节点只运行一个这样的Pod副本。还可以把节点的目录挂载至Pod中,通过Pod实现某些管理功能。

DaemonSet定义资源清单时,不再需要用replicas字段指定副本数量了。

DaemonSet资源清单文件中spec字段包含的子字段:

revisionHistoryLimit    <integer>   # rs历史版本保存个数,与Deployment中的此字段意义相同。
selector    <Object>    # 标签选择器
template    <Object> -required-     # Pod模板
updateStrategy  <Object>            # Pod更新策略

更新策略:

spec
  updateStrategy:
    type: RollingUpdate
    rollingUpdate: 
      maxUnavailable: 2

DaemonSet的Pod更新策略有两种:"RollingUpdate""OnDelete",只有类型为RollingUpdate时,与type同级的字段rollingUpdate才生效。rollingUpdate字段下只有maxUnavailable一个字段。也就是说DaemonSet的Pod更新时,只能少,不能多。

DaemonSet资源清单示例:

apiVersion: apps/v1
kind: DaemonSet
metadata: 
  name: filebeat-ds
  namespace: default
spec: 
  selector:
    matchLabels:
      app: filebeat
      release: stable
  template:
    metadata: 
      labels:
        app: filebeat
        release: stable
    spec: 
      containers:
      - name: filebeat
        image: ikubernetes/filebeat:5.6.5-alpine
        env: 
        - name: REDIS_HOST
          value: redis-svc
        - name: REDIS_LOG_LEVEL
          value: info

DaemonSet资源清单定义时,不用再指定replicas了。

推荐阅读更多精彩内容