Kubernetes(k8s)Deployment、StatefulSet、DaemonSet、Job、CronJob五种控制器详解

一、Deployment控制器概述

一般情况下,我们并不直接创建 Pod,而是通过 Deployment 来创建 Pod,由 Deployment 来负责创建、更新、维护其所管理的所有 Pods。

ReplicationSet(RS)和ReplicationController(RC)区别

这里就需要说一下ReplicationSet(RS)和ReplicationController(RC),RS是在RC基础上发展来的,在新版的Kubernetes中,已经将RC替换为RS 了,它们两者没有本质的区别,都是用于Pod副本数量的维护与更新的,使得副本数量始终维持在用户定义范围内,即如果存在容器异常退出,此时会自动创建新的Pod进行替代;而且异常多出来的容器也会自动回收。

总结不同点在于:RS在RC的基础上支持集合化的selector

一般情况下RS也是可以单独使用的,但是一般推荐和Deployment一起使用,这样会使得的Deployment提供的一些回滚更新操作同样用于RS上,因为RS不支持回滚更新操作,Deployment支持

二、Deployment工作原理

先看一下Deployment、RS、Pod它们三者之间的关系:

RS负责控制副本数量,由Deployment来创建具体的Pod。

Deployment控制器支持两种更新策略:滚动更新(rolling update)和重新创建(recreate),默认为滚动更新。

1)滚动升级

滚动升级是默认的更新策略,它在删除一部分旧版本Pod资源的同时,补充创建一部分新版本的Pod对象进行应用升级,其优势是升级期间,容器中应用提供的服务不会中断,但要求应用程序能够应对新旧版本同时工作的情形,例如新旧版本兼容同一个数据库方案等。不过,更新操作期间,不同客户端得到的响应内容可能会来自不同版本的应用

Deployment控制器的滚动更新操作并非在同一个ReplicaSet控制器对象下删除并创建Pod资源,而是将它们分置于两个不同的控制器之下:旧控制器的Pod对象数量不断减少的同时,新控制器的Pod对象数量不断增加,直到旧控制器不再拥有Pod对象,而新控制器的副本数量变得完全符合期望值为止,如图所示:

滚动更新时,应用升级期间还要确保可用的Pod对象数量不低于某阈值以确保可以持续处理客户端的服务请求,变动的方式和Pod对象的数量范围将通过spec.strategy.rollingUpdate.maxSurge和spec.strategy.rollingUpdate.maxUnavailable两个属性协同进行定义,它们的功用如图所示:

  • maxSurge:指定升级期间存在的总Pod对象数量最多可超出期望值的个数其值可以是0或正整数,也可以是一个期望值的百分比;例如,如果期望值为3,当前的属性值为1,则表示Pod对象的总数不能超过4个。
  • maxUnavailable升级期间正常可用的Pod副本数包括新旧版本)最多不能低于期望数值的个数,其值可以是0或正整数,也可以是一个期望值的百分比;默认值为1,该值意味着如果期望值是3,则升级期间至少要有两个Pod对象处于正常提供服务的状态。

maxSurge和maxUnavailable属性的值不可同时为0,否则Pod对象的副本数量在符合用户期望的数量后无法做出合理变动以进行滚动更新操作。

2)版本回滚

Deployment控制器也支持用户保留其滚动更新历史中的旧ReplicaSet对象版本,这赋予了控制器进行应用回滚的能力:用户可按需回滚到指定的历史版本。控制器可保存的历史版本数量由“spec.revisionHistoryLimit”属性进行定义。当然,也只有保存于revision历史中的ReplicaSet版本可用于回滚,因此,用户要习惯性地在更新操作时指定保留旧版本。

三、Deployment的资源清单文件详解

apiVersion: apps/v1  #版本号
kind: Deployment  #类型
metadata:    #元数据
  name:    #rs名称
  namespace:   #所属命名空间
  labels:   #标签
    controller: deploy
spec:   #详情描述
  replicas:  #副本数量
  revisionHistoryLimit: #保留历史版本,默认是10
  paused: #暂停部署,默认是false
  progressDeadlineSeconds: #部署超时时间(s),默认是600
  strategy: #策略
    type: RollingUpdates  #滚动更新策略
    rollingUpdate:  #滚动更新
      maxSurge: #最大额外可以存在的副本数,可以为百分比,也可以为整数
      maxUnavaliable: #最大不可用状态的pod的最大值,可以为百分比,也可以为整数
  selector:  #选择器,通过它指定该控制器管理哪些pod
    matchLabels:   #Labels匹配规则
       app: nginx-pod
    matchExpressions:   #Expression匹配规则
      - {key: app, operator: In, values: [nginx-pod]}
  template:  #模板,当副本数量不足时,会根据下面的模板创建pod副本
    metadata:
        labels:
          app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80

四、Deployment实战

1)示例1

创建pc-deployment.yaml,内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pc-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
     app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx:1.17.1

执行以下命令

$ kubectl create namespace dev
$ kubectl create -f pc-deployment.yaml
$ kubectl get deploy -n dev -o wide

查看deployment控制的rs和pod,发现rs是在deployment之后加了一段字符串,而pod是在rs之后加了一段字符串。

2)扩缩容

方式一:命令行

格式

kubectl scale deploy deploy名称 --replicas=pod数量 -n 命名空间

过命令行变更pod数量为5个

$ kubectl scale deploy pc-deployment --replicas=5 -n dev
$ kubectl get pod -n dev


方式二:编辑deploy文件

格式

kubectl edit deploy deploy名字 -n 命名空间

通过编辑deploy文件编辑pod数量为3个

$ kubectl edit deploy pc-deployment -n dev

$ kubectl get pod -n dev

3)镜像更新

deployment支持两种镜像更新策略:重建更新和滚动更新(默认),可以通过strategy选项进行配置

strategy:指定新的pod替换旧的pod的策略,支持两个属性:
  type:指定策略类型,支持两种策略
    Recreate:在创建出新的pod之前会先杀掉所有已存在的pod
    RollingUpdate:滚动更新,就是杀死一部分,就启动一部分,在更新过程中,存在两个版本pod
  rollingUpdate:当type为RollingUpdate时生效,用于为RollingUpdate设置参数,支持两个属性
    maxUnavailable:用来指定在升级过程中不可用pod的最大数量,默认为25%
    maxSurge:用来指定在升级过程中可以超过期望的pod的最大数量,默认为25%

1、重建更新

编辑pc-deployment.yaml,在spec节点下添加更新策略

spec:
  strategy:  #策略
    type: Recreate  #重建更新策略

$ kubectl apply -f pc-deployment.yaml 
$ kubectl get pod -n dev

创建deploy进行验证

#首先记录原本的pod名
$ kubectl get pod -n dev
#更改pod镜像
$ kubectl set image deploy pc-deployment nginx=nginx:1.17.2 -n dev
#再次查看镜像
$ kubectl get pod -n dev

发现pod镜像已经改变了


2、滚动更新
编辑pc-deployment.yaml,在spec节点下添加滚动更新策略(也可以把strategy去掉,因为默认滚动更新策略)

strategy:
  type: RollingUpdate #滚动更新策略
  rollingUpdate:
    maxUnavailable: 25%
    maxSurge: 25%

执行

$ kubectl apply -f pc-deployment.yaml 

创建deploy进行验证

#记录以前的pod
$ kubectl get pod -n dev
#更新镜像
$ kubectl set image deploy pc-deployment nginx=nginx:1.17.3 -n dev
#查看pod状态
$ kubectl get pod -n dev
$ kubectl get pod -n dev

发现pod是旧的一遍停止新的一边创建,最后全变成了新的
滚动更新的过程

3、镜像更新中rs的变化

#重建deployment
$ kubectl delete -f pc-deployment.yaml 
#添加record参数,表明创建时记录
$ kubectl create -f pc-deployment.yaml --record
$ kubectl get deploy,rs,pod -n dev

打开两个窗口,用于监听rs和pod
在2窗口中监听rs,3窗口中监听pod

#在2窗口中输入
$ kubectl get rs -n dev -w
#在3窗口中输入
$ kubectl get pod -n dev -w
#在1窗口中改变pod镜像
$ kubectl set image deploy pc-deployment nginx=nginx:1.17.2 -n dev

查看3窗口中pod的变化,发现序号5开头的pod在逐渐暂停,序号7开头的pod在逐渐创建

查看2窗口中rs的变化,可以看见序号5开头的rs的pod数在减少,序号7开头的rs的pod数在增加

在1窗口中查看最终rs变化,发现原来的rs依旧存在,只是pod数量变为了0,而后又新产生了一个rs,pod数量为3,其实这就是deployment能够进行版本回退的奥妙所在,后面会详细解释

4)版本回退

1、简介

deployment支持版本升级过程中的暂停,继续功能以及版本回退等诸多功能,下面具体来看
kubectl rollout:版本升级相关功能,支持下面的选项:

  • status:显示当前升级状态
  • history:显示升级历史记录
  • pause:暂停版本升级过程
  • resume:继续已经暂停的版本升级过程
  • restart:重启版本升级过程
  • undo:回滚到上一级版本(可以使用--to-revision回滚到指定版本)

查看升级状态

$ kubectl rollout status deploy pc-deployment -n dev

查看升级历史(注意:如果只显示版本号说明一开始使用yaml创建文件的时候没有加上--record命令

$ kubectl rollout history deploy pc-deployment -n dev

2、版本回滚实验

这里使用--to-revision=1回滚到1版本,如果省略这个选项,则会回退到上个版本

$ kubectl rollout undo deploy pc-deployment --to-revision=1 -n dev

查看是否回滚成功,发现5序号开头的rs被启动了

$ kubectl get rs -n dev

可以看到版本7开头的已经回滚到5开头的版本了,这也就是rs依旧存在的原因。

五、Deployment金丝雀发布(灰度发布)

deployment支持更新过程中的控制,如"暂停(pause)"或"继续(resume)"更新操作。

比如有一批新的pod资源创建完成后立即暂停更新过程,此时,仅存在一部分新版本的应用,主体部分还是旧的版本。然后,再筛选一小部分的用户请求路由到新的pod应用,继续观察能否稳定地按期望的方式运行。确定没问题之后再继续完成余下的pod资源滚动更新,否则立即回滚更新操作。这就是所谓的金丝雀发布,其实也叫做灰度发布。

更新deployment版本,并配置暂停deployment

$ kubectl set image deploy pc-deployment nginx=nginx:1.17.2 -n dev && kubectl rollout pause deploy pc-deployment -n dev

查看rs,发现老版本rs没有减少,新版本rs增加一个

$ kubectl get rs -n dev

查看更新过程

$ kubectl rollout status deploy pc-deployment -n dev
$ kubectl get rs -n dev

发现老版本均停止,新版本已经创建好

六、有状态、无状态服务区别

1)无状态:

  • 上面所说的deployment 认为所有的pod都是一样的
  • 不用考虑顺序的要求
  • 不用考虑在哪个node节点上运行
  • 可以随意扩容和缩容

2)有状态

  • 实例之间有差别,每个实例都有自己的独特性,元数据不同,例如etcd,zookeeper
  • 实例之间不对等的关系,以及依靠外部存储的应用

七、PV、PVC、NFS、SC

1)PV概述

PersistentVolume (PV:持久化存储卷)是集群中由管理员提供或使用存储类动态提供的一块存储。它是集群中的资源,就像节点是集群资源一样。

PV是与Volumes类似的卷插件,但其生命周期与使用PV的任何单个Pod无关。由此API对象捕获存储的实现细节,不管是NFS、iSCSI还是特定于云提供商的存储系统。

2)PVC概述

PersistentVolumeClaim(PVC:持久化存储卷声明),PVC 是用户存储的一种声明,PVC 和 Pod 比较类似,Pod 消耗的是节点,PVC 消耗的是 PV 资源,Pod 可以请求 CPU 和内存,而 PVC 可以请求特定的存储空间和访问模式。对于真正使用存储的用户不需要关心底层的存储实现细节,只需要直接使用 PVC 即可。

3)通过NFS实现持久化存储

NFS工作原理

  • 首先服务器端启动RPC服务,并开启111端口

  • 服务器端启动NFS服务,并向RPC注册端口信息

  • 客户端启动RPC(rpcbind服务),向服务端的RPC(rpcbind)服务请求服务端的NFS端口

  • 服务端的RPC(rpcbind)服务反馈NFS端口信息给客户端。

  • 客户端通过获取的NFS端口来建立和服务端的NFS连接并进行数据的传输。

安装NFS

1、所有节点安装nfs

$ yum -y install  nfs-utils rpcbind

2、在master节点创建共享目录并授权

$ mkdir /opt/nfsdata
# 授权共享目录
$ chmod 666 /opt/nfsdata

3、编辑exports文件

$ cat /etc/exports
/opt/nfsdata *(rw,no_root_squash,no_all_squash,sync)

4、配置生效

$ exportfs -r

exportfs命令

常用选项
-a 全部挂载或者全部卸载
-r 重新挂载
-u 卸载某一个目录
-v 显示共享目录 以下操作在服务端上

5、启动rpc和nfs(客户端只需要启动rpc服务)(注意顺序)

$ systemctl start rpcbind
$ systemctl start nfs-server
$ systemctl enable rpcbind
$ systemctl enable nfs-server

6、查看

$ showmount -e
$ showmount -e 192.168.0.113

-e 显示NFS服务器的共享列表
-a 显示本机挂载的文件资源的情况NFS资源的情况
-v 显示版本号

7、客户端

# 启动rpc服务
$ systemctl start rpcbind
$ systemctl enable rpcbind
# 创建挂载目录
$ mkdir /mnt/nfsdata
# 挂载
$ echo "192.168.0.113:/opt/nfsdata /mnt/nfsdata     nfs    defaults  0 1">> /etc/fstab
$ mount -a

8、测试

# 客户端执行
$ touch /mnt/nfsdata/test{1..5}
$ ll /mnt/nfsdata/
# 服务端执行
$ ll /opt/nfsdata/

4)基于NFS存储创建PV

查看nfs版本号

# nfs服务端,只能看到大版本
$ nfsstat -s
# nfs客户端看
$ nfsstat -m

# pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: bxy-pv
  labels:
    name: bxy-pv-labels
spec:
  capacity:
    storage: 6Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: bxy-storageclass
  mountOptions:
    - hard
    - nfsvers=4.2
  nfs:
    path: /opt/nfsdata
    server: 192.168.0.113

spec.storageClassName 字段对应 StorageClass 配置中的 metedata.name 字段

capacity: #容量
volumeMode: 存储卷模式(默认值为filesystem,除了支持文件系统外(file system)也支持块设备(raw block devices))
accessModes: 访问模式
ReadWriteMany :(RWO/该volume只能被单个节点以读写的方式映射),ReadOnlyMany (ROX/该volume可以被多个节点以只读方式映射), ReadWriteMany (RWX/该volume可以被多个节点以读写的方式映射)
persistentVolumeReclaimPolicy: 回收策略 ,Retain(保留)、 Recycle(回收)或者Delete(删除)
storageClassName: 存储类(通过设置storageClassName字段进行设置。如果设置了存储类,则此PV只能被绑定到也指定了此存储类的PVC)
mountOptions: 挂接选项
path: 我的本地挂载路径为
server: NFS 文件系统所在服务器的真实 IP

执行

$ kubectl apply -f pv-nfs.yaml
$ kubectl get pv
$ kubectl describe pv bxy-pv

注意创建完 PV 后,会看到 Status 类型为 Available ,这是因为 PV 还没有和 PVC 绑定,当绑定成功后会自动改成 Bound。

5)基于NFS-PV创建PVC

# nfs-pv-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: bxy-pvc
spec:
  accessModes:
    - ReadWriteMany
  volumeMode: Filesystem
  resources:
    requests:
      storage: 5Gi
  storageClassName: bxy-storageclass
  selector:
    matchLabels:
      name: bxy-pv-labels

【注意】storage: 5Gi:我写的是 5G ,但实际绑定成功后会自动改变为 PV 中设置的容量大小 6G。

pvc 通过 matchLabels和pv中的label匹配,来关联要使用的存储空间。表明此PVC希望使用Label:name: "bxy-pv-labels"的PV。

执行

$ kubectl apply -f nfs-pv-pvc.yaml
$ kubectl get pvc
# 再查看pv状态
$ kubectl get pv

6)SC(StorageClass:存储类)

SC是StorageClass的缩写,表示存储类;这种资源主要用来对pv资源的自动供给提供接口;所谓自动供给是指用户无需手动创建pv,而是在创建pvc时对应pv会由persistentVolume-controller自动创建并完成pv和pvc的绑定;使用sc资源的前提是对应后端存储必须支持restfull类型接口的管理接口,并且pvc必须指定对应存储类名称来引用SC;简单讲SC资源就是用来为后端存储提供自动创建pv并关联对应pvc的接口;如下图:

【提示】使用sc动态创建pv,对应pvc必须也是属于对应的sc;上图主要描述了用户在创建pvc时,引用对应的sc以后,对应sc会调用底层存储系统的管理接口,创建对应的pv并关联至对应pvc。

创建sc资源

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/glusterfs
parameters:
  resturl: "http://127.0.0.1:8081"
  clusterid: "630372ccdc720a92c681fb928f27b53f"
  restauthenabled: "true"
  restuser: "admin"
  secretNamespace: "default"
  secretName: "heketi-secret"
  gidMin: "40000"
  gidMax: "50000"
  volumetype: "replicate:3"

【提示】在创建pvc时用storageClassName字段来指定对应的SC名称即可。上述是官方文档中的一个示例,在创建sc资源时,对应群组是storage.k8s.io/v1,类型为StorageClass;provisioner字段用于描述对应供给接口名称;parameters用来定义向对应存储管理接口要传递的参数。

7)基于动态sc(StorageClass:存储类)创建一个pv

第一步:创建statefueset的命名空间

$ cat << EOF > nginx-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: nginx-ss
EOF
$ kubectl apply -f nginx-ns.yaml

第二步:创建ServiceAccount,为nfs-client-provisioner授权
如果集群启用了RBAC,则必须执行如下命令授权provisioner。(k8s1.6+默认开启)

$ cat << EOF > nfs-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: nginx-ss        #根据实际环境设定namespace,下面类同
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
  namespace: nginx-ss
rules:
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: nginx-ss
    # replace with namespace where provisioner is deployed
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nginx-ss
    # replace with namespace where provisioner is deployed
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  namespace: nginx-ss
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: nginx-ss
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
EOF

第三步:创建nfs的nfs-client-provisioner

nfs-client-provisioner 是k8s简易的NFS外部提供者(provisioner),本身不提供NFS,做为NFS的客户端为StorageClass提供存储。

$ cat << EOF > nfs-deployment-provisioner.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
  name: nfs-client-provisioner
  namespace: nginx-ss
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes #容器内挂载点
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 192.168.0.113
            - name: NFS_PATH
              value: /opt/nfsdata
      volumes:
        - name: nfs-client-root #宿主机挂载点
          nfs:
            server: 192.168.0.113
            path: /opt/nfsdata
EOF
$ kubectl apply -f nfs-deployment-provisioner.yaml
$ kubectl get deploy -n nginx-ss

第四步:基于sc创建动态存储

cat << EOF > nginx-sc.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nginx-nfs-storage
  namespace: nginx-ss
provisioner: fuseim.pri/ifs  # or choose another name, must match deployment's env PROVISIONER_NAME'
reclaimPolicy: Retain        #回收策略:Retain(保留)、 Recycle(回收)或者Delete(删除)
volumeBindingMode: Immediate    #volumeBindingMode存储卷绑定策略
allowVolumeExpansion: true    #pvc是否允许扩容
EOF

volumeBindingMode存储卷绑定策略

  • Immediate:创建 PVC 后立即创建后端存储卷,并且立即绑定新创建的 PV 和 PVC。
  • WaitForFirstConsumer:当 PVC 被 Pod 使用时,才触发 PV 和后端存储的创建,同时实现 PVC/PV 的绑定,启用该配置后,Storage Class 中的 Zone 和 Region 将不再生效,而是使用 Pod 调度所在节点的 zone 和 region 创建文件系统,保证文件系统能被 Pod 挂载。)

StorageClass的定义包含四个部分:

  • provisioner:该字段指定使用存储卷类型,不同的存储卷提供者类型这里要修改成对应的值。【注意】provisioner必须和上面得Deployment的YAML文件中PROVISIONER_NAME的值保持一致。
  • parameters:指定 provisioner 的选项,比如 glusterfs 支持 resturl、restuser 等参数。
  • mountOptions:指定挂载选项,当 PV 不支持指定的选项时会直接失败。比如 NFS 支持 hard 和 nfsvers=4.2 等选项。
  • reclaimPolicy:指定回收策略,同 PV 的回收策略。Retain(保留)、 Recycle(回收)或者Delete(删除)
$ kubectl apply -f nginx-sc.yaml
$ kubectl get sc -n nginx-ss

八、StatefulSet控制器

1)简介

StatefulSet是用来管理有状态应用的工作负载API对象,实例之间有不对等关系,以及实例对外部数据有依赖关系的应用,称为”有状态应用“。

StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。

在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless service,headless service,即无头服务,与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。

除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:

$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local

2)常规service和无头服务区别

  • service:一组Pod访问策略,提供cluster-IP群集之间通讯,还提供负载均衡和服务发现。
  • Headless service 无头服务,不需要cluster-IP,直接绑定具体的Pod的IP。

3)特点

  • Pod一致性:包含次序(启动、停止次序)、网络一致性。此一致性与Pod相关,与被调度到哪个node节点无关;
  • 稳定的次序:对于N个副本的StatefulSet,每个Pod都在[0,N)的范围内分配一个数字序号,且是唯一的;
  • 稳定的网络:Pod的hostname模式为( statefulset 名 称 ) − (statefulset名称)-(statefulset名称)−(序号);
  • 稳定的存储:通过VolumeClaimTemplate为每个Pod创建一个PV。删除、减少副本,不会删除相关的卷。

4)组成部分

  • Headless Service:用来定义Pod网络标识( DNS domain);
  • volumeClaimTemplates :存储卷申请模板,创建PVC,指定pvc名称大小,将自动创建pvc,且pvc必须由存储类供应;

上面【1-4】都得执行,这里是第五步
此处是基于SC,上面已经创建过了SC,这里就直接创建StatefulSet了

cat << EOF > nginx-ss.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
  namespace: nginx-ss
spec:
  selector:
    matchLabels:
      app: nginx #必须匹配 .spec.template.metadata.labels
  serviceName: "nginx"  #声明它属于哪个Headless Service.
  replicas: 3 #副本数
  template:
    metadata:
      labels:
        app: nginx # 必须配置 .spec.selector.matchLabels
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx:1.17.1
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: nginx-pvc
          mountPath: /usr/share/nginx/html

  volumeClaimTemplates:   #可看作pvc的模板
  - metadata:
      name: nginx-pvc
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "nginx-nfs-storage"  #存储类名,就是上面nginx-sc.yaml metadata.name
      resources:
        requests:
          storage: 1Gi
EOF

这里的storageClassName必须与上面SC里面的metadata.name一样。
执行命令

$ kubectl apply -f nginx-ss.yaml
$ kubectl get pods -n nginx-ss

上述例子中:

  • 名为 nginx 的 Headless Service 用来控制网络域名。
  • 名为 web 的 StatefulSet 有一个 Spec,它表明将在独立的 3 个 Pod 副本中启动 nginx 容器。
  • volumeClaimTemplates 将通过 PersistentVolumes 驱动提供的 PersistentVolumes 来提供稳定的存储。

【问题】Kubernetes v1.20 (opens new window)开始,默认删除了 metadata.selfLink 字段,然而,部分应用仍然依赖于这个字段,例如上面的nfs-deployment-provisioner.yaml。其实上面创建pod是没成功的。报错如下:

【解决】
通过配置 apiserver 启动参数中的 –feature-gates 中的 RemoveSelfLink=false,可以重新启用 metadata.selfLink 字段。

修改 /etc/kubernetes/manifests/kube-apiserver.yaml 文件,并在其启动参数中增加一行 – –feature-gates=RemoveSelfLink=false,如下第 43行所示:

重新加载配置,如果一次未加载成功,多执行几次。

$ kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml

加载完配置后,我们再看pod创建情况。

$ kubectl get pvc -n nginx-ss
$ kubectl get pods -n nginx-ss

最后命令总结:

# 清除,只需要删除命名空间就行
$ kubectl delete -f nginx-ns.yaml
# 重新执行
$ kubectl apply -f nginx-ns.yaml
$ kubectl apply -f nfs-rbac.yaml
$ kubectl apply -f nfs-deployment-provisioner.yaml
$ kubectl apply -f nginx-sc.yaml
$ kubectl apply -f nginx-ss.yaml
# 检测
$ kubectl get pvc -n nginx-ss
$ kubectl get pods -n nginx-ss

九、DaemonSet控制器

DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本,通常用于实现系统级后台任务。比如ELK服务

创建DaemonSet

DaemonSet的描述文件和Deployment非常相似,只需要修改Kind,并去掉副本数量的配置即可。

cat << EOF > nginx-daemonset.yaml 
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: nginx-daemonset
  labels:
    app: nginx
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.13.12
        ports:
        - containerPort: 80
EOF
$ kubectl apply -f nginx-daemonset.yaml

在每个node节点上都运行了一个pod副本

十、Job控制器

Job控制器用于调配pod对象运行一次性任务,容器中的进程在正常运行结束后不会对其进行重启,而是将pod对象置于completed状态。若容器中的进程因错误而终止,则需要依据配置确定重启与否,未运行完成的pod对象因其所在的节点故障而意外终止后会被重新调度。

简单示例

cat << EOF > job-demo.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: job-demo
spec:
  template:
    metadata:
      name: job-demo
    spec:
      restartPolicy: Never
      containers:
      - name: counter
        image: busybox
        command:
        - "bin/sh"
        - "-c"
        - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
EOF

Pod模板中的spec.restartPolicy默认为Always,这对job控制器来说只能设定为Never或OnFailure。

$ kubectl apply -f job-test.yaml

十一、CronJob 控制器

CronJob其实就是在Job的基础上加上了时间调度,我们可以:在给定的时间点运行一个任务,也可以周期性地在给定时间点运行。这个实际上和我们Linux中的crontab就非常类似了。

一个CronJob对象其实就对应中crontab文件中的一行,它根据配置的时间格式周期性地运行一个Job,格式和crontab也是一样的。

crontab的格式如下:

分 时 日 月 星期 要运行的命令 第1列分钟0~59 第2列小时0~23) 第3列日1~31 第4列月1~12 第5列星期0~7(0和7表示星期天) 第6列要运行的命令

现在,我们用CronJob来管理我们上面的Job任务

cat << EOF > cronjob-demo.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: cronjob-demo
spec:
  schedule: "*/1 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: hello
            image: busybox
            args:
            - "bin/sh"
            - "-c"
            - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
EOF

执行

$ kubectl get jobs
$ kubectl get cronjobs.batch

十二、总结

1)ReplicationController(RC)主要功能

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

2)ReplicaSet主要功能(RS)

在新版本的Kubernetes中建议使用ReplicaSet来取ReplicationController。ReplicaSet跟ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector

虽然ReplicaSet可以独立使用,但一般还是建议使用 Deployment 来自动管理ReplicaSet,这样就无需担心跟其他机制的不兼容问题(比如ReplicaSet不支持rolling-update但Deployment支持)。

  • 用户期望的pod副本数量
  • 标签选择器,判断哪个pod归自己管理
  • 当现存的pod数量不足,会根据pod资源模板进行新建

3)deployment的主要功能

  • 管理无状态应用
  • 管理Pod和ReplicaSet
  • 具有上线部署、副本设定、滚动升级、回滚等功能
  • 提供声明式更新,例如只更新一个新的Image
    应用场景:web服务

4)SatefulSet控制器

  • 管理有状态应用
  • kind:service
  • 解决Pod独立生命周期,保持Pod启动顺序和唯一性
  • 稳定,唯一的网络标识符,持久存储(例如:etcd配置文件,节点地址发生变化,将无法使用)
  • 有序,优雅的部署和扩展、删除和终止(例如:mysql主从关系,先启动主,再启动从),有序,滚动更新
  • 应用场景:数据库

5)DaemonSet控制器

  • 它用于确保集群中的每一个节点只运行特定的pod副本。

6)Job&CronJob

  • Job只要完成就立即退出,不需要重启或重建。
  • CronJob其实就是在Job的基础上加上了时间调度。
posted @ 2022-06-12 18:17  大数据老司机  阅读(5977)  评论(0编辑  收藏  举报