1、什么是控制器

k8s中运行了一系列控制器来确保集群的当前状态与期望状态保持一致,它们就是k8s集群内部的管理控制中心或者说是“中心大脑”。

例如ReplicaSet控制器负责维护集群中运行pod的数量;Node控制器负责监控节点的状态,并在节点出现故障时,执行自动化修复流程,确保集群始终处于预期的工作状态,下图是控制器的工作状态

分析上图,从清单中可以看到第一个看到spec定义了pod数量有8个,第二个是spec是容器组。右边是节点的真实状态,而中间就是控制器起到的作用:调谐。

什么叫调谐?我们先要检测当前控制器的状态,再去和清单对比预期状态。如果发现少个几个pod,这时候要去调整资源部署,将一个或多个新的pod在我们当前可用节点上被创建。也会有当前符合要求的pod比清单中预期多的情况,比如有9个满足要求的pod,那么控制器会按照创建时间最新的pod,将它杀死。在重复不断的把当前状态和预期状态做对比,这就叫调谐。

当然也有很实际的一种情况,比如预期pod是8个,但是节点资源不足以容纳这么多pod,这是控制器再怎么调谐也没办法。控制器不指定pod数量的话默认为1

官方自带pod控制器列举,之所以说官方自带是因为公司有能力的话可以自己开发控制器,这是kubernetes强大的冰山一角

  1. ReplicationController和ReplicaSet
  2. Deployment
  3. DaemonSet
  4. StateFulSet
  5. Job/CronJob
  6. Horizontal Pod Autoscaling

2、ReplicationController

ReplicationController(RC)用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的pod来替代;而如果异常多出来的容器也会被自动回收

apiVersion: v1
kind: ReplicationController
metadata:
  name: rc-demo
spec:
  replicas: 3
  selector:
    app: rc-demo
  template:
    metadata:
      labels:
        app: rc-demo
    spec:
      containers:
      - name: rc-demo-container
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        imagePullPolicy: IfNotPresent
        command:
        - "sh"
        - "-c"
        - "sleep 3600"

#replicas:这个是新东西,控制器控制pod数量的字段。如果不写此字段,默认控制器pod数量为1
#selector:也是新东西,叫标签选择器。用于筛选哪些pod受此控制器管理
#template:同样是新东西,这个是pod模板,用于创建pod,前几章单独写pod就没有,但是!控制器要在这个模板下进行pod的创建

创建对象,查询一下控制器状态,可以缩写。期望三个,当前三个,就绪三个,符合清单预期

再看pod,pod名称是标签跟上了md5值,这是控制器创建pod的命名格式

测试一下控制器的特性:对比预期,满足清单预期是三个pod,删除一个看看情况

可以看到控制器根据清单预期立马就创建了一个pod。注意生产环境我们是不会删除pod的,但是无法避免节点损坏

容易混淆的一点是,pod重启策略总是Always的话,pod会自动创建新的容器取代损坏的,恢复当前的pod,只不过pod重启次数会增加。另外pod内部容器损坏不会进行重启,因为控制器控制的级别是pod本身,pod本身损坏才会进行操作

做个标签选择器的实验。selector选择器标签的值必须要是pod标签的子集才行。

#添加标签
kubectl label pod <podName> version=v1

在pod后新加了个标签,版本号。查看发现pod有两个标签了,但他依然是rc的子集

尝试将一个pod标签修改下

#修改标签
kubectl label pod <podName> app=test --overwrite

修改后发现pod变成了四个,因为修改标签后修改过的pod就不是rc的子集了不属于rc控制了,这时候控制器对比预期少了一个pod,就开始创建新的pod

图中报错是告诉我们这个标签的key存在,如果要更改的话必须加--overwrite进行覆盖。

再尝试将修改过的标签在改回来

kubectl label pod <podName> app=rc-demo --overwrite

可以看到pod又变成了三个,因为修改标签后,又归属到rc子集中,又归rc管理了。控制器检查预期状态是三个,现在多了一个,就将创建时间最新的pod进行删除以符合预期

#删除标签,将想删除的标签键后面跟“-”
kubectl label pod <podName> <标签键>-

最后,可以调整控制器的副本数量

#修改控制器副本数量
kubectl scale <controllerType> <podName> --replicas <Num>

#也可以在yaml中修改副本数量,使用kubectl apply -f <fileName>进行覆写

3、ReplicaSet

在新版的k8s中官方建议用RplicaSet(RS)取代RC,RS和RC没有本质的不同,只是RS支持集合式的selector,通俗的说是RS的升级版

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo
spec:
  replicas: 3
  selector:
    matchLabels:
      app: rs-demo
      ver: v1
  template:
    metadata:
      labels:
        app: rs-demo
        ver: v1
        main: study
    spec:
      containers:
      - name: rs-demo-container
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["sh","-c","sleep 3600"]

一切都和RC控制器差不多,唯一区别是selector下面多的两个字段,并且这两个字段对RC以外的所有控制器适用。这两个字段被称为标签选择算符

  1. matchLabels(常用)

  2. matchExpressions

标签选择算符

matchLabels

匹配标签。用于匹配 Pod 的标签,它指定了 ReplicaSet 应该管理哪些 Pod。matchLabels 的键值对必须与Pod 的 metadata.labels 完全一致才能匹配,不然的话启动会报错。匹配成功的 Pod 会被这个 ReplicaSet 管理,参考上面的RS实验

selector:
  matchLabels:
    app: rs-demo
    ver: v1

表示:ReplicaSet 只会管理 同时带有 app: rs-demo 和 ver:v1 这两个标签的 Pod

matchExpressions

匹配运算符,在matchLabels基础上提供了多种选择,目前支持的操作符有以下四个

 1、In:标签的值必须与列表中至少一个值匹配

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo-matchlabels
spec:
  replicas: 2
  selector:
    matchExpressions:
    - key: study      # 定义标签键
      operator: In    # 匹配操作符为 "In",表示匹配该键值对中的任意值,
      values: 
      - hahaha
      - hehehe
      - hihihi
  template:
    metadata:
      labels:
        study: hehehe    #标签值在上面标签算符值的列表中,可以是values值中的任意一个
    spec:
      containers:
      - name: rs-demo-matchExpressions-container
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["sh","-c","sleep 3600"]

标签修改后,这个pod不属于rs控制了,所以根据清单预期,立马新建了一个,如果改成hihihi的话这个pod依然在标签算符的列表值内,依旧属于rs控制。这就是在列表的含义


2、NotIn:标签的值不能与列表中任何一个值匹配(不常用)

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo-matchlabels
spec:
  replicas: 2
  selector:
    matchExpressions:
    - key: study      # 定义标签键
      operator: NotIn    # 匹配操作符为 "NotIn",表示不能匹配到列表中的任意值,
      values: 
      - hahaha
      - hehehe
      - hihihi
  template:
    metadata:
      labels:
        study: hohoho    #标签值在上面标签算符值的列表中,匹配的值不能在values值的列表中
    spec:
      containers:
      - name: rs-demo-matchExpressions-container
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["sh","-c","sleep 3600"]

如果将pod模板中的标签改成列表中的任意值,会得到如下报错,意思是选择器和模板中标签不匹配


3、Exists:只要资源包含该标签键即可,不关心具体的值

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo-matchexpressions-exists
spec:
  replicas: 2
  selector:
    matchExpressions:
    - key: study        # 匹配标签的键是study。
      operator: Exists  # 使用操作符 `Exists`,表示选择所有带有study键的 Pod,无论值是什么。
  template:
    metadata:
      labels:
        study: fafafa
    spec:
      containers:
      - name: rs-demo-matchexpressions-container
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["sh","-c","sleep 3600"]

#修改标签键,需要添加新的键值,在删除旧的,目前本人只知道这个方法
kubectl lable pod <podName> key=values oldKey- --overwrite

修改标签键后再看看pod状态,就会发现控制器新增了一个pod,原本的pod由于标签键修改已经不属于控制器控制了


现在有个疑问,如果有很多相同的标签键值pod,那为什么其他pod的没有加入到我们的控制器中?

因为k8s中有个机制,当前的pod对象是基于哪个控制器创建的,也就是它的父亲是谁,只有父亲是我的时候才开始去匹配标签,并且标签要符合我的要求。两点都达到了才是我的,防止把一些不相干的pod加入进来


4、DoesNotExist:资源不能包含该标签键(不常用)

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: rs-demo-matchexpressions-doesnotexists
spec:
  replicas: 2
  selector:
    matchExpressions:
    - key: study                 #定义标签键
      operator: DoesNotExist    #匹配操作符为 "DoesNotExist",表示不能匹配到定义的标签键
  template:
    metadata:
      labels:
        app: hihihi
    spec:
      containers:
      - name: rs-demo-matchexpressions-container
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        imagePullPolicy: IfNotPresent
        command: ["sh","-c","sleep 3600"]

如果将pod模板中的标签键改成匹配算符定义的键,会得到如下报错,意思是选择器和模板中标签不匹配


关于四个匹配算符,只用1和3是天天用的,2和4较为罕见,一般都是处于比较复杂的生产环境配合matchLabels来使用,建议各位同志只熟悉1和3比较好


4、Deployment(重点)

先说明一点,Deployment实际上是通过创建RS控制器,继而创建Pod。就是说Deployment实际上是RS的控制器,RS才是Pod的控制器。这个机制就是为了稍后要说的更新策略而设计的

Deployment(deploy)为pod和ReplicaSet提供了一个声明式定义(declarative)方法,用来替代以前的ReplicationController来方便的管理应用,解释下什么是声明式

  1. 声明式(Declarative) 是通过资源清单(YAML/JSON 配置文件) 来描述期望的最终状态,然后 Kubernetes 根据这些文件自动管理和调节资源的实际状态,使其与期望状态一致。就是告诉系统你想要什么

  2. 命令式(Imperative) 是通过直接的命令行命令来操作资源,指定你要执行的具体操作(如创建、删除、更新),并且这些操作是一步一步执行的,通常是一次性任务。就是告诉系统做什么

这两个概念过于抽象,同志们初学肯定会懵圈,不要紧,只要继续下去肯定会理解,本人就是例子

在介绍一下Deployment的应用场景,Deployment的典型应用场景包括以下四种,几个应用场景都会通过实验来进行演示

  1. 定义Deployment来创建pod和rs
  2. 滚动升级和回滚应用
  3. 扩容和缩容
  4. 暂停和继续Deployment的升级和回滚

Deployment更新策略

更新策略分为两种:

RollingUpdate

滚动更新,最常见的更新策略,允许应用逐步更新,避免了服务中断,保持了较高的可用性。在 Deployment 中,滚动更新通过逐步替换旧的 Pod 来实现版本更新,同时保证在整个更新过程中始终有可用的 Pod 处理流量,可以指定 maxUnavailable 和 maxSurge 来控制滚动更新过程

简单来说就是滚动更新时deploy会创建一个新的rs,等下的实验速度够快的话进行rs控制器的查询,是可以看到更新过程中有两个rs出现的,等更新过程结束,旧的rs被删除

针对滚动升级做个实验,用nginx镜像比较方便。先用写个dockerfile封装一下,让两个nginx镜像主页分为v1和v2

1、自己写两个index.html文件,内容分别为v1和v2

2、写dockerfile进行封装
vim Dockerfile

FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nginx:1.27.0
COPY index.html /usr/share/nginx/html/index.html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

3、别忘了封装的镜像和文件要在同一目录下
docker build -t my-nginx:v1 .
docker build -t my-nginx:v2 .

4、将封装的镜像导出至本地
docker save -o <本地路径> <镜像名称>

5、将封装的nginx导入到每个node节点中,不然k8s调度大概率会出现无法pull镜像问题
docker load -i <镜像名称>
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-demo
spec:
  replicas: 10
  selector:
    matchLabels:
      app: deploy
  template:
    metadata:
      labels:
        app: deploy
    spec:
      containers:
      - name: deploy-demo-container
        image: my-nginx:v1
        imagePullPolicy: IfNotPresent

可以看到访问任意一个pod都是没问题的,这时修改将清单镜像修改为v2版本,apply后立刻观察pod状态

这时候可以看到新建pod,删除pod,可老的pod三种状态在一起,可以直观的看到滚动更新特性,它不是全部删除在进行重建,而是删除一部分,新建一部分逐渐替换,直至全部pod更新至最新。

或者可以这样,用这个命令,这个命令简单来说是创建一个负载均衡,不详细说,下一章会学到

#svc会自动将和自己名称一样的pod标签进行匹配,归拢至一个负载均衡
kubectl create svc clusterip <pod的标签值> --tcp=80:80

curl循环访问这个svc的ip

将清单中的v1版本镜像修改为v2版本,apply应用,持续观察访问状况

本来一直访问的是v1,滚动更新后导致部分pod被删掉,所以出现了访问报错;部分更新成功所以出现了v2。这就是滚动更新

同志们做实验的时候应该会出现循环访问卡住的情况,这是因为访问pod的请求已经被pod接收,但是要回复的时候pod被删除了,导致收不到回复,所以卡住了,小问题


最大不可用maxUnavailable
.spec.strategy.rollingUpdate.maxUnavailable
 是一个可选字段, 用来指定更新过程中不可用的 Pod 的个数上限。这个不可用指的是滚动更新时最多几个不可用。该值可以是绝对数字(例如,5),也可以是所需 Pod 的百分比(例如,10%)。百分比值会转换成绝对数并去除小数部分。 如果maxSurge 为 0,则此值不能为 0。 不写这个字段的话默认值为 25%。在1.16版本以前这个数值默认是1,不是百分比

例如,当此值设置为 30% 时,滚动更新开始时会立即将旧 ReplicaSet 缩容到期望 Pod 个数的70%。 新 Pod 准备就绪后,可以继续缩容旧有的 ReplicaSet,然后对新的 ReplicaSet 扩容, 确保在更新期间可用的 Pod 总数在任何时候都至少为所需的 Pod 个数的 70%。

最大峰值maxSurge
.spec.strategy.rollingUpdate.maxSurge
 是一个可选字段,用来指定可以创建的超出期望 Pod 个数的 Pod 数量。此值可以是绝对数(例如,5)或所需 Pod 的百分比(例如,10%)。 如果 MaxUnavailable 为 0,则此值不能为 0。百分比值会通过向上取整转换为绝对数。 此字段的默认值为 25%。在1.16版本以前这个数值默认是1,不是百分比

例如,当此值为 30% 时,启动滚动更新后,会立即对新的 ReplicaSet 扩容,同时保证新旧 Pod 的总数不超过所需 Pod 总数的 130%。一旦旧 Pod 被杀死,新的 ReplicaSet 可以进一步扩容, 同时确保更新期间的任何时候运行中的 Pod 总数最多为所需 Pod 总数的 130%。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-demo
spec:
  replicas: 10
  selector:
    matchLabels:
      app: deploy
  strategy:
    type: RollingUpdate    #可以省略,因为滚动更新是默认字段,因为是做实验所以加上了
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  template:
    metadata:
      labels:
        app: deploy
    spec:
      containers:
      - name: deploy-demo-container
        image: my-nginx:v2
        imagePullPolicy: IfNotPresent

更新可以多弄些pod副本比如20个,很轻松就可以看出来区别


Recreate

在 Kubernetes 中,Recreate 更新策略是一种特殊的Deployment 策略,与默认的滚动更新策略不同,它的行为是先删除所有旧 Pod,再创建新 Pod。这种策略在更新过程中会导致服务中断,但适用于某些对高可用性要求不高或无法并存旧版本和新版本的场景

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-demo
spec:
  replicas: 10
  selector:
    matchLabels:
      app: deploy
  strategy:
    type: Recreate    #这个不能省略了
    metadata:
      labels:
        app: deploy
    spec:
      containers:
      - name: deploy-demo-container
        image: my-nginx:v2
        imagePullPolicy: IfNotPresent

金丝雀

首先说明这是一种理念,不是实际的操作。也就是国内常说的灰度发布。通俗来说就是小范围更新新版本,只让小部分人使用,没问题在进行全部更新,出问题立马回滚旧版本,也不会影响业务。

像大厂的k8s业务,金丝雀的更新部署流程时标配,而且需要专门的工具Argo Rollouts来进行分流。我做的这个实验虽说也是金丝雀的部署,但是毕竟没有大厂的专业,只是为了扩展一下这个概念而进行的,并且个人学习的话没必要这么深入了解金丝雀部署,知道就行

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-demo
  labels:
    app: deployment-demo
spec:
  replicas: 10
  selector:
    matchLabels:
      app: deployment-demo
  template:
    metadata:
      labels:
        app: deployment-demo
    spec:
      containers:
        - name: deployment-demo-container
          image: nginx:v1
          imagePullPolicy: IfNotPresent
#将资源对象输出为yaml显示
kubectl get <resourceKind> <resourceName> -o yaml

创建对象后可以用命令看下默认峰值就是这两个maxUnavailable,maxSurge可以看到默认值是不是想我说的那样

先在修改下最大不可用和最大峰值,这时候问题来了!资源清单中没有写这两个字段,该怎么进行修改?

k8s中,当创建或更新资源时,对于没有填写的字段,Kubernetes 会使用默认值填充。参考上面的-o输出内容

回归正题,k8s对于字段修改给了kubectl patch这么个命令,这个命令写起来对我来说算是相当复杂,要写一大长串,所以我就直接用kubectl edit,看同志们喜欢哪个就用哪个,不要纠结

#用默认编辑器打开资源对象,修改保存后立即生效
kubectl edit <resourceKind> <resourceName>
#打补丁
kubectl patch deployment deployment-demo -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge":1,"maxUnavailable":1},"type":"RollingUpdate"}}}'

这里我将最大不可用maxUnavailable改成了0,就是说更新过程中我不允许任何旧的pod先被销毁;maxSurge改成了1,就是说允许超出期望副本数(10个)的 Pod 数量,只允许它多一个。

总结一下,滚动更新过程中我只允许一个一个增加新版本pod,并且在新pod变为running之后,再去删除一个旧版本pod,以此类推持续进行,直至更新结束。再更新下nginx版本,改成v2

保存退出后立马进行一个暂停更新的操作

#暂停滚动更新
kubectl rollout pause deploy <deploymentName>
#恢复滚动更新
kubectl rollout resume deploy <deploymentName>

看图,更新很快啊,敲个命令的功夫更新三个了已经,访问记录也是有v1版本和v2版本。

欸?是不是很熟悉?这不就是金丝雀更新部署吗?所以说金丝雀部署只是个抽象理念,任何软件发布过程只要符合这个理念,都可以叫金丝雀

再次重申!大厂金丝雀部署流程是配合专业工具的,具有分流,压测等功能的专业工具,我这个实验只是个人学习或者公司更新不严谨采用的方式,我只是为了拓展这个理念才做的实验

恢复滚动更新,更新成功


现在10个pod都更新了v2版本,但是这个版本有问题,需要重新回到v1版本。前文提过deployment控制器实际上是控制replicaSet进行pod的管理。从创建时间看第二个三分钟的明显是滚动更新时候创建的新rs,并且可以看到更新之后旧的rs是依旧保留的,执行命令回滚再看下

#回滚版本
kubectl rollout undo <resourceKind> <resourceName>

 可以看到回滚过程

看图,访问都变成了v1版本,这代表回滚版本成功

现在有这么个情况哈,从v1升级到v2,在升级到v3。这个时候!我想回滚到v1版本,该怎么做呢?连用两次回滚命令吗?不不不,v3回滚一次后回到v2,此时v2的上个版本已经变成了v3,在回滚一次后还会回到v3。想要回滚到v1该怎么做?

试一下,先用常规版本替代v3

#查看Deployment(或其他资源类型,如 StatefulSet、DaemonSet)的当前滚动更新状态可以配合回滚命令使用,打印回滚过程
kubectl rollout status <resourceKind> <resourceName> 

可配合echo $?使用,如果回滚成功,echo出来的为0

访问没问题。刚才我从v2版本回滚到v1版本,又从v1版本更新到了v3版本。现在如果我想回到v2版本的话用上面的回滚命令已经不行了,看新命令

#查看Deployment(或其他资源,如 StatefulSet)的历史版本信息。它允许你查看某个资源的滚动更新历史,特别是用于查看更新版本的详情
kubectl rollout history <resourceKind> <resourceName>

REVISION:表示版本号,滚动更新的每次更新都会增加版本号。

CHANGE-CAUSE:表示变更的原因。

但是为什么变更原因是none?因为--record参数,在更新的过程中,命令结尾加上这个参数,把你执行的 kubectl 命令记录下来,方便你日后查看每次变更到底是为了什么。这个适用于pacht补丁命令进行更新的方式,不能用在apply更新资源清单的方式

但是这个命令有缺点,假设你在第三次更新的时候忘了加这个参数,那么第三次的更新记录会直接复制上一次的记录。这个命令使用时候会提示被k8s弃用,并且在未来版本被移出。不过官方应该还没开发出更好的,目前1.31版本还是健在

好,开始回到回滚v1的实验中,在rollout history中可以看到记录了版本,这时我们回滚要指定版本

#--to-revision=Number,指定回滚版本
kubectl rollout undo <resourceKind> <sourceName> --to-revision=Number

版本号从1开始但是随着回滚次数,版本号会发生改变

Deployment清理策略

在滚动更新和回滚的时候,replieset全部都保存在了etcd里。可以在 Deployment 中设置以指定保留此 Deployment 的多少rs旧版本。这个字段.spec.revisionHistoryLimit 。其余的rs将在后台被垃圾回收。 默认情况下,此值为 10。如果将该项设置为0,deployment就不允许回滚了。试一下

可以看到更新了之后旧的rs就没了。不会在保留rs的历史记录了,那么etcd的资源消耗也就会减少了

相对于前面的滚动更新,其实可以用备份清单的方式来实现更新和回滚的记录。

假设我们从v1升级到v2,这时可以将v1的清单备份一下,然后在进行修改,kubectl apply -f来应用的这么一种方式,再从v2升级到v3,继续将v2备份然后修改。这样历史版本就都保存下来了

而且前面那么多滚动更新的方法,他一切的信息都保存在了etcd里面,一旦更新的版本多了,etcd里面杂而乱。对比下用清单保存的方式更简洁。

而且一个清单的大小也是几kb的,可以保存无数份。当然!这只是一种思想!需要自己选择

5、DaemonSet

DaemonSet确保集群中每个Node节点上运行一个指定的pod副本。并且集群新增Node时,也会为它新增一个pod。当有Node从进群移除时,这些pod也会被回收。删除DaemonSet将会删除它创建的所有pod

DaemonSet 的一些典型用法

  1. 在每个节点上运行集群守护进程,如gluserd、ceph
  2. 在每个节点上运行日志收集守护进程,如fluentd、logstash
  3. 在每个节点上运行监控守护进程,如prometheus
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: daemonset-demo
  labels:
    app: daemonset-demo
spec:
  selector:
    matchLabels:
      app: daemonset-demo
  template:
    metadata:
      labels:
        app: daemonset-demo
    spec:
      containers:
        - name: daemonset-demo-contaienr
          image: nginx:v1

启动资源对象后get po一下会发现有两个pod。并且清单中没有replicas参数,如果在这个控制器中加replicas这个字段的话会报错因,为ds控制器没有这个参数,它会自动匹配node节点来控制pod数量

前面说了每个节点都会存在一个pod,但是为什么master节点没有?因为master节点存在一个叫做污点的机制,这个后面学习调度器会学到。kubectl describe node k8s-master查下主节点

6、Job

负责批处理任务,即仅执行一次的任务,他保证批处理任务的一个或多个pod成功结束,有几个字段需要介绍下

  1. 单个pod时,默认pod成功运行后job即结束
  2. completions标志job结束需要成功运行的pod个数,默认为1。就是控制整个 Job 需要多少个 Pod 成功完成,Job 才算完全结束
  3. parallelism标志并行运行的pod个数,默认为1。就是控制在同一时间有多少个 Pod 一起工作
  4. RestartPolicy仅支持Never或OnFailure
  5. backoffLimit,pod失败重启次数,重启几次后不行,超过这个数值不会继续重试
  6. activeDeadlineSeconds标志失败pod的重试最大时间,超过这个时间不会继续重试
apiVersion: batch/v1
kind: Job
metadata:
  name: timestamp-job
spec:
  completions: 10
  parallelism: 5
  backoffLimit: 4
  activeDeadlineSeconds: 30    #它和backoffLimit之间,谁先触发谁决定最终结果
  template:
    metadata:
      name: timestamp
    spec:
      containers:
      - name: timestamp
        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
        command: ["sh", "-c", "echo Current timestamp: $(date)"]
      restartPolicy: Never

这个就是打印时间的一个简单需求,最终结果会出现十个pod副本,命令结束后pod就会停止运行,关于他的用处,因为我也是初学者,暂不明朗,先了解把

7、CoronJob

CronJob管理基于时间的Job,即

  1. 在给定时间点只运行一次
  2. 周期性的在给定时间点运行

使用条件,当前使用的k8s集群版本大于等于1.8,典型的用法如下

  1. 在给定的时间点调度job运行
  2. 创建周期性运行的job,例如数据库备份、发送邮件

CronJob关键字段

  1. schedule:调度,必须字段,指定任务运行周期,格式同Crontab
  2. jobTemplate:job模板,必须字段,指定需要运行的任务,格式同Job
  3. startingDeadlineSeconds:启动job的期限(秒级别),该字段是可选的。如果因为任何原因因而错过了被调度的时间,那么错过执行时间的job将被认为是失败的。如果没有指定,则没有期限
  4. concurrencyPolicy:并发策略,该字段可选。它指定了如何被CronJob创建的job的并发执行。只允许指定下面策略中的一种
    • Allow:默认,允许并发运行job
    • Forbid:禁止并发运行,如果前一个还没有完成,则直接跳过下一个
    • Replace:取消当前正在运行的job,用一个新的来替换
    • 注意,当前策略只能应用于同一个CronJob创建的job。如果存在多个CronJob,他们创建的Job之间总是允许并发运行
  5. suspend:挂起,该字段可选。如果设置为true,后续所有执行都会被挂起。他对已经开始执行的job不起作用。默认值为false
  6. successfulJobsHistoryLimit和failedJobsHistoryLimit:历史限制,可选字段。他们指定了可以保留多少完成和失败的job。默认情况下,他们分别设置为3和1.设置限制的值为0.相关类型的job完成后将不会被保留
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cj-demo
spec:
  schedule: "*/1 * * * *"
  jobTemplate: 
    spec:
      template:
        spec:
          containers:
          - name: cj-demo-container
            image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/busybox:1.28
            imagePullPolicy: IfNotPresent
            command: 
            - sh
            - -c
            - "date ; echo Hello form the kubernetes cluster"
          restartPolicy: OnFailure

可以看到pod在周期的创建,关于他的用处,因为我也是初学者,暂不明朗,先了解把

8、StatefulSet

这个控制器会在第八章“存储”篇中进行实验展示,现阶段实验没有意义。因为要结合后面的知识点来进行实验

既然到这步了,各位同志不妨试试自己的水准,将前面学的pod生命周期和这一章的知识点结合起来写个deployment控制器,给自己出个考试看看自己能到什么地步

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐