【云原生 • Kubernetes】(四) k8s 原来不是直接创建 Pod!!

1,978 阅读22分钟

📣 大家好,我是Zhan,一名个人练习时长一年半的大二后台练习生🏀

📣 这篇文章是学习 Kubernetes 的第四篇学习笔记📙

📣 如果有不对的地方,欢迎各位指正🙏🏼

📣 与君同舟渡,达岸各自归🌊


🔔 引语

在上篇文章【云原生 • Kubernetes】(三) k8s 如何运行 Container?中,我们讲解了Kubernetes中 Pod 的使用、Pod 与 Container 的关系,不过我们也提到了 Kubernetes 通常不会直接创建 Pod,而是提供 Controller 来管理 Pod,也就是说 Controller 就是用来管理一个 Pod 对象,关于控制器,本文将会介绍:

  • 控制器的作用
  • 常见的四种控制器以及操作
  • 控制器如何管理Pod
  • 控制器无法解决的问题

1️⃣ Controller 控制器

摘自官网:kubernetes.io/zh-cn/docs/…

ℹ️ 1.1 什么是 Controller 控制器

房间里面的温度自动调节器为例,当你设置了问题,告诉了调节器你的期望状态,房间的实际温度是当前状态,通过对设备的开关控制,温度自动调节器让当前状态接近期望状态

在 Kubernetes 中,Controller 定义了 Pod 的部署特性,比如有几个副本、在什么样的 Node 上运行等,也就是通过监控集群的公共状态,并致力于将当前状态变为期望的状态,用一句话总结就是:Controller 可以管理 Pod 并让 Pod 更具有运维能力

🔢 1.2 常见的 Controller 控制器

  • Deployment 是最常用的 Controller。可以通过 ReplicaSet 管理多个 Pod 的副本,并确保 Pod 按照期望的状态运行
  • Daemonset 用于每个 Node 最多运行一个 Pod 副本的场景
    • 如果使用 Deployment 管理 Pod,例如管理 5 个 Pod,那么可能在两个 Node 上,一个上面有 2 个,一个上面有 3 个
    • 如果使用 Daemonset 管理 Pod,每个 Node 上至多有一个 Pod 副本
  • Statefulset 能够保证 Pod 的每个副本在整个生命周期中名称是不变的, 如果不使用该控制器创建 Pod,Pod 的名字会动态发生变化(由于发生故障而重新启动)
  • Job 用于运行结束就删除的应用,其他的 Controller 中的 Pod 通常是长期运行的

🔄️ 1.3 Controller 如何管理 Pod

说明:此处画图以 Deployment 为例,但是这是所有的 Controller 管理 Pod 的方式,也就是通过标签去进行管理,在上篇文章中我们讲到标签可以用于亲和性判断,而此处 Controller 就是通过标签来管理 Pod,例如下面的 Deployment1 控制的这组 Pod 都使用了 app:controller1 这个标签

2️⃣ Deployment

官方地址:kubernetes.io/zh-cn/docs/…

一个 Deployment 为 Pod 和 ReplicaSet 提供声明式的更新能力。

你负责描述 Deployment 中的 目标状态,而 Deployment 控制器(Controller) 以受控速率更改实际状态, 使其变为期望状态。你可以定义 Deployment 以创建新的 ReplicaSet,或删除现有 Deployment, 并通过新的 Deployment 收养其资源。

✔️ 2.1 创建 Deployment

apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: nginx-deployment  
  # Deployment的标签 = Pod的标签 = 选择器的标签  
  labels:  
    app: nginx  
spec:  
  # 表示副本数为1 也就是只有一个pod 也就是只有一个nginx  
  replicas: 1 
  template:  
    metadata:  
      name: nginx  
      # Pod的标签  
      labels:  
        app: nginx  
    spec:  
      containers:  
        - name: nginx-deployment  
          image: nginx:1.7.9  
          imagePullPolicy: IfNotPresent  
      restartPolicy: Always  
  # Deployment 选择器 根据标签选择 选择 app=nginx 的pod 也就是上面的pod,要注意的是 Deployment 本身的标签也要满足
  selector:  
    matchLabels:  
      app: nginx
  • .metadata.name:Deployment 的名称,此例为nginx-deployment
  • .spec.replicas:Pod 副本的数量
  • .spec.selector:ReplicaSet 查找要管理的 Pod 的方式,这里选择是通过标签 app: nginx
  • .spec.template:Container 的定义

🔛 2.2 查看 Deployment

Deployment 的常见命令和 Pod 其实差不多,只是说资源类型不同,命令大体相同:

# 部署应用,与部署 Pod 是相同的方式
$ kubectl apply -f nginx-deployment.yaml
# 查看 Deployment
$ kubectl get deployment 
# 查看 Pod
$ kubectl get pod -o wide
# 查看 Pod 详情
$ kubectl describe pod pod-name
# 查看 Deployment 详情
$ kubectl describe deployment nginx-deployment 
# 查看 Log
$ kubectl logs pod-name
# 进入 Pod 容器终端
$ kubectl exec -it pod-name -- bash
# 输出到文件
$ kubectl get deployment nginx-deployment -c yaml >> test.yaml

常用命令:kubectl get deployment

  • NAME 列出了名字空间中 Deployment 的名称
  • READY 显示应用程序可用的副本数——“就绪个数 / 期望个数”
  • UP-TO-DATE 显示为了达到期望状态已经更新的副本数
  • AVAILBLE 显示可以使用的副本数
  • AGE 显示程序运行的时间

**常用命令:kubectl describe deployment nginx-deployment **

🔝 2.3 扩缩 Deployment

实际开发环境可能会出现流量高峰,因此我们可能会面对扩容和缩容的情况,也就是增加和减少副本的数量

# 查询副本,replicaSet 也是一种控制器,它在 Deployment 创建的时候创建了
$ kubectl get replicaSet
# 伸缩扩展副本
$ kubectl scale deployment nginx -replicas=5

问题:创建了五个Nginx容器副本,会不会80端口冲突呢?

我们是在容器中创建的 Nginx 环境,使用的是 容器的环境,也就是占用的容器中的 80 端口,就像使用 Docker 进行创建,会有端口的映射,因此:80 端口是不会冲突的。

🔙 2.4 回滚 Deployment

类似于 Git,我们可以进行版本的管理,进行版本的回滚,当 Deployment Pod 模版改变的时候,例如修改 Pod 的标签,或者更新镜像的时候,才会触发 Deployment 上线。

# 查看上线状态
$ kubectl rollout status deployment nginx-deployment 
# 查看版本历史
$ kubectl rollout history deployment nginx-deployment 
# 查看某个版本的具体信息
$ kubectl rollout history deployment nginx-deployment --revision=2
# 回退到上个版本
$ kubectl rollout undo deployment nginx-deployment 
# 回退到指定的版本
$ kubectl rollout undo deployment nginx-deployment --to-revision = 1
# 重新部署
$ kubectl rollout restart deployment nginx-deployment 

问题: 现修改了 Nginx 的镜像版本,此时就会有两个 Kubernetes 版本,使用 kubectl rollout history deployment nginx-deployment 可以看到,而如果回退到上个版本,此时会多一个版本号吗?

对于相同内容的 Pod 模版,只会存在一个版本,因此如果回退到上一个版本,原来的版本号为 1 和 2,现在的版本号会变为 2 和 3,此时的版本号就是 3,现在版本号为 3 的模版和之前版本号为 1 的模版的内容是一致的,也就是说 Nginx 的版本是一样的。

✖️ 2.5 删除 Deployment

# 删除 Deployment
$ kubectl delete deployment nginx-deployment 
$ kubectl delete -f nginx-deployment.yml
# 删除默认命名空间全部资源
$ kubectl delete all -all
# 查看所有的命名空间(复习)
$ kubectl get namespace

这里是建议是使用通过配置文件去删除,也就是kubectl delete -f nginx-deployment.yml,这样删除 Deployment 更干净彻底,使用第一种删除方式,只能删除控制器,而可能会漏掉一些相关的未删除


3️⃣ Statefulset

官方地址:kubernetes.io/zh-cn/docs/…


🔎 3.1 什么是 StatefulSet

StatefulSet 是用来管理有状态应用的工作负载 API 对象。

  • 有状态应用:应用本身需要存储相关数据应用为有状态应用
  • 无状态应用:应用本身不存储任何数据的应用为无状态应用
  • 例如一个博客系统,其中前端文件 Vue、后端 Java 文件都是无状态的应用,而 MySQL、Redis、ES……这类就是有状态应用

StatefulSet 用来管理某 Pod 集合的部署和扩缩, 并为这些 Pod 提供持久存储和持久标识符。

和 Deployment 类似, StatefulSet 管理基于相同容器规约的一组 Pod。但和 Deployment 不同的是, StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。

为什么对于 MySQL 这类的需要存储数据的应用,要使用 StatefulSet,而不是使用 Deployment 呢?我们从以下四个问题来解析:

问题一:对于一个 MySQL 应用,它是创建在容器中,也就是在一个 Pod 中,那么如果一个 Pod 失效了,那是不是数据就会丢失了呢?

对此,Docker 的做法是进行数据卷挂载,把 /data 中的数据挂载到宿主机上,这样就可以做到即使 Docker 容器挂掉,数据也持久化在宿主机了,只需要记住宿主机上 /data 挂载的目录即可

问题二:Kubernetes 是集群模式,而 Docker 是单体模式,因此如果把数据放在宿主机 node1 上,而下次 Pod 被调度到了 node2 上,数据卷是不是又丢失了呢?

想要把数据持久化,但是又不能持久化到宿主机上,因此引入了 NFS(网络共享的一种实现),或者买一些云服务,把数据放在云服务上,这样就可以做到两个结点都可以去访问了

问题三:如果两个结点上都有 MySQL 应用,也就是说它们都会去请求云服务器上的 /data 目录,那么是不是会有冲突呢

当然是会有冲突的,如果两个结点去操作同一份 /data 目录,因此我们会开拓 /data 下的子目录,例如 node1 上的 MySQL 应用的 ID1001,去操作目录 /data/1001node2 上的 MySQL 应用 ID 为 3006,操作目录 /data/3006,这样就解决了冲突的问题

问题四:如果是这样的话,是不是 Deployment 也能做呢,StatefulSet 的意义在哪呢?

在讲解 Pod 的时候我们说过,如果 Pod 发生了宕机重新启动,它的 ID 是动态分配的,那 node1 上的 MySQL 的 ID 如果发生了变化,从 1001 变成 7281,那么是不是原来的目录又变得无意义了呢?

因此就有了 StatefulSet,正如我们介绍的那样,StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID。这些 Pod 是基于相同的规约来创建的, 但是不能相互替换:无论怎么调度,每个 Pod 都有一个永久不变的 ID。这样我们就可以 MySQL 应用每次操作的数据卷是同一个数据卷。

如果希望使用存储卷为工作负载提供持久存储,可以使用 StatefulSet 作为解决方案的一部分。 尽管 StatefulSet 中的单个 Pod 仍可能出现故障, 但持久的 Pod 标识符使得将现有卷与替换已失败 Pod 的新 Pod 相匹配变得更加容易。


📑 3.2 StatefulSet 特点

StatefulSet 对于需要满足以下一个或者多个需求的应用程序很有价值:

  • 稳定的、唯一的网络标识符
  • 稳定的、持久的存储
  • 有序地、优雅的部署和扩展
  • 有序地、自动的滚动更新 “稳定的”意味着 Pod 调度或者重调度的整个过程是有持久性的。如果应用程序不要任何稳定的标识符或者有序的部署,则应该使用由一组无状态的副本控制器提供的工作负载来部署整个应用程序。比如 Deployment 或者 ReplicaSet 可能更适用于无状态应用部署需要。

🔒 3.3 StatefulSet 限制

  • 给定 Pod 的存储必须由 PersistentVolume Provisioner 基于所请求的 storage class 来制备,或者由管理员预先制备
  • 删除或者扩缩 StatefulSet 并不会删除它所关联的数据卷,也是为了保证数据的安全性,它通常比自动清除相关的资源是更有价值的
  • StatefulSet 当前需要 无头服务 来负责 Pod 的网络表示,你需要负责创建此服务
  • 当删除一个 StatefulSet 的时候,该 StatefulSet 不提供任何终止 Pod 的保证,为了实现 StatefulSet 中的 Pod 可以有序且体面的终止,可以在已删除之前把 StatefulSet 缩容到 0
  • 在默认 Pod 管理策略(OrderedReady)时使用公洞更新,可能进入需要人工干预才能修复的损坏状态

⚒️ 3.4 使用 StatefulSet

📲 1 搭建 NFS 服务

# 安装 nfs-utils
$ yum install -y rpcbind nfs-utils
# 创建 NFS 目录,也就是需要共享的数据卷
mkdir -p /root/nfs/data
# 编辑 /etc/exports 输入以下内容
	# insecure:通过 1024 以上端口发送
	# rw:读写
	# sync:请求时写入共享
	# no_root_squash:root 用户有完全根目录访问权限
echo "/root/nfs/data *(insecure,rw,sync,no_root_squash)" >> /etc/exports
# 启动相关服务并开启开启自启动
$ systemctl start rpcbind
$ systemctl start nfs-server
$ systemctl enable rpcbind 
$ systemctl enable nfs-server 
# 重新挂载 使得 /etc/export 生效
exportfs -r
# 查看共享情况
exportfs 

搭建成功后,使用 exportfs 查看共享情况可以看到:


🖥️ 2 客户端测试

此时我们可以使用其他的节点作为客户端对该 NFS 进行访问:

# 安装 nfs-utils
$ yum install -y rpcbind nfs-utils
# 创建本地目录
$ mkdir -p /root/nfs
# 挂载远程 nfs 目录到本地
$ mount -t nfs 大家自己服务器的IP:/root/nfs/data /root/nfs/data
# 写入一个测试文件
$ echo "hello world" > /root/nfs/data/test.txt
# 去远程 NFS 查看
$ cat /root/nfs/data/test.txt

# 取消挂载
$ unmount -f -l nfs目录

挂载的时候发现会一直停留在那个页面,因此问了一下万能的 ChatGPT

开放端口号后成功的解决了问题,并且实现了数据卷的挂载,以下是测试的截图:


⚒️ 3 使用 StatefulSet

注意:在使用的过程中,我们会提到 StorageClassVolume 的概念,这些是后面会讲解的点,因此使用起来会有点困难,理解起来同样也是,不过如果能够看懂这里的配置文件,后面再理解数据卷存储类的时候就更轻松了

apiVersion: v1  
kind: Namespace  
metadata:  
  name: ems  
---  
apiVersion: storage.k8s.io/v1  
kind: StorageClass  
metadata:  
  name: nfs-client  
  namespace: ems  
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner  
parameters:  
  onDelete: "remain"  
---  
apiVersion: apps/v1  
kind: StatefulSet  
metadata:  
  name: mysql  
  labels:  
    app: mysql  
  namespace: ems  
spec:  
  serviceName: mysql  
  replicas: 1  
  template:  
    metadata:  
      name: mysql  
      labels:  
        app: mysql  
    spec:  
      containers:  
        - name: mysql  
          image: mysql:8.0  
          imagePullPolicy: IfNotPresent  
          env:  
            - name: MYSQL_ROOT_PASSWORD  
              value: "123456"  
          volumeMounts:  
            - mountPath: /var/lib/mysql  
              name: data  
          ports:  
            - containerPort: 3306  
  volumeClaimTemplates:  
    - metadata:  
        name: data  
        namespace: ems  
      spec:  
        accessModes:  
          - ReadWriteMany  
        storageClassName: mysql-nfs-sc  
        resources:  
          requests:  
            storage: 2G  
  selector:  
    matchLabels:  
      app: mysql

这段配置文件描述了一个 Kubernetes 集群中的一些资源,包括命名空间(Namespace)、存储类(StorageClass)和有状态副本集(StatefulSet)。以下是对每个部分的解释:

  1. Namespace(命名空间):
    • apiVersion: v1:使用的 Kubernetes API 版本。
    • kind: Namespace:指定资源类型为命名空间。
    • metadata:包含关于命名空间的元数据。
    • name: ems:命名空间的名称为 "ems"。
  2. StorageClass(存储类):
    • apiVersion: storage.k8s.io/v1:使用的 Kubernetes 存储 API 版本。
    • kind: StorageClass:指定资源类型为存储类。
    • metadata:包含关于存储类的元数据。
    • name: nfs-client:存储类的名称为 "nfs-client"。
    • namespace: ems:存储类所属的命名空间为 "ems"。
    • provisioner: k8s-sigs.io/nfs-subdir-external-provisioner:指定提供者为 NFS 存储,使用 k8s-sigs.io/nfs-subdir-external-provisioner 提供的插件。
    • parameters:存储类的参数配置。
      • onDelete: "remain":指定删除 PVC(持久卷声明)时是否删除底层存储。
  3. StatefulSet(有状态副本集):
    • apiVersion: apps/v1:使用的 Kubernetes Apps API 版本。
    • kind: StatefulSet:指定资源类型为有状态副本集。
    • metadata:包含关于有状态副本集的元数据。
    • name: mysql:有状态副本集的名称为 "mysql"。
    • labels:用于标识有状态副本集的标签。
    • namespace: ems:有状态副本集所属的命名空间为 "ems"。
    • serviceName: mysql:指定关联的服务名称为 "mysql"。
    • replicas: 1:指定副本数量为 1。
    • template:指定有状态副本集的 Pod 模板。
      • metadata:包含关于 Pod 的元数据。
      • name: mysql:Pod 的名称为 "mysql"。
      • labels:用于标识 Pod 的标签。
      • containers:定义 Pod 中的容器。
        • name: mysql:容器的名称为 "mysql"。
        • image: mysql:8.0:指定容器所使用的镜像为 mysql:8.0。
        • imagePullPolicy: IfNotPresent:指定镜像拉取策略为仅在本地不存在时才拉取。
        • env:定义容器的环境变量。
          • name: MYSQL_ROOT_PASSWORD:指定环境变量名称为 "MYSQL_ROOT_PASSWORD"。 value: "123456":指定环境变量的值为 "123456"。
        • volumeMounts:定义容器的挂载点。
          • mountPath: /var/lib/mysql:指定挂载点的路径为 "/var/lib/mysql"。 name: data:指定挂载的持久卷名称为 "data"。
        • ports:定义容器暴露的端口。
          • containerPort: 3306:指定容器监听的端口为 3306。
    • volumeClaimTemplates:定义有状态副本集中的持久卷声明模板。
      • metadata:包含关于持久卷声明的元数据。
        • name: data:持久卷声明的名称为 "data"。 namespace: ems:持久卷声明所属的命名空间为 "ems"。
      • spec:持久卷声明的规格。
        • accessModes:指定持久卷的访问模式,这里是 ReadWriteMany(可读写多节点)。
        • storageClassName: mysql-nfs-sc:指定使用的存储类名称为 "mysql-nfs-sc"。
        • resources:指定持久卷的资源需求。
          • requests:指定请求的资源。 storage: 2G:指定请求的存储资源为 2GB。
    • selector:通过标签选择器选择有状态副本集管理的 Pod。
      • matchLabels:用于匹配标签选择器的标签。 app: mysql:选择具有标签 "app: mysql" 的 Pod。

这个配置文件提供了创建 StatefulSet 所需的基本配置,但是要实现完整的 StatefulSet 功能,还需要进行其他配置和操作。也就是下面的 NFS 客户端提供器 的部署

apiVersion: apps/v1  
kind: Deployment  
metadata:  
  name: nfs-client-provisioner  
  labels:  
    app: nfs-client-provisioner  
  namespace: kube-system  
spec:  
  replicas: 1  
  strategy:  
    # 重新创建 也就是删除旧的创建新的  
    type: Recreate  
  template:  
    metadata:  
      labels:  
        app: nfs-client-provisioner  
    spec:  
      # 服务账号 也就是权限  
      serviceAccountName: nfs-client-provisioner  
      containers:  
        - name: nfs-client-provisioner  
          image: chronolaw/nfs-client-provisioner:v3.1.0-k8s1.11  
          volumeMounts:  
            - mountPath: /persistentvolumes  
              name: nfs-client-root  
          env:  
            - name: PROVISIONER_NAME  
              value: k8s-sigs.io/nfs-subdir-external-provisioner  
            - name: NFS_SERVER  
              value: 175.178.104.61  
            - name: NFS_PATH  
              value: /root/nfs/data  
          imagePullPolicy: IfNotPresent  
      restartPolicy: Always  
      volumes:  
        - name: nfs-client-root  
          nfs:  
            server: 175.178.104.61  
            path: /root/nfs/data  
  selector:  
    matchLabels:  
      app: nfs-client-provisioner

以下是对这个 Deployment 配置的解释:

  1. apiVersion: apps/v1:使用的 Kubernetes Apps API 版本。
  2. kind: Deployment:指定资源类型为 Deployment。
  3. metadata:包含关于 Deployment 的元数据。
    • name: nfs-client-provisioner:Deployment 的名称为 "nfs-client-provisioner"。
    • labels:用于标识 Deployment 的标签。
      • app: nfs-client-provisioner:标签 "app: nfs-client-provisioner" 用于选择相关的 Pod。
    • namespace: kube-system:Deployment 所属的命名空间为 "kube-system"(根据实际需求进行配置)。
  4. spec:指定 Deployment 的规格。
    • replicas: 1:指定副本数量为 1。
    • strategy:指定 Deployment 的更新策略。
      • type: Recreate:指定重新创建策略,即删除旧的 Pod,然后创建新的 Pod。
    • template:指定 Deployment 中的 Pod 模板。
      • metadata:包含关于 Pod 的元数据。
        • labels:用于标识 Pod 的标签。
          • app: nfs-client-provisioner:标签 "app: nfs-client-provisioner" 用于选择相关的 Pod。
      • spec:指定 Pod 的规格。
        • serviceAccountName: nfs-client-provisioner:指定使用的服务账号为 "nfs-client-provisioner"。
        • containers:定义 Pod 中的容器。
          • name: nfs-client-provisioner:容器的名称为 "nfs-client-provisioner"。
          • image: chronolaw/nfs-client-provisioner:v3.1.0-k8s1.11:指定容器所使用的镜像为 chronolaw/nfs-client-provisioner:v3.1.0-k8s1.11。
          • volumeMounts:定义容器的挂载点。
            • mountPath: /persistentvolumes:指定挂载点的路径为 "/persistentvolumes"。 name: nfs-client-root:指定挂载的持久卷名称为 "nfs-client-root"。
          • env:定义容器的环境变量。
            • name: PROVISIONER_NAME:指定环境变量名称为 "PROVISIONER_NAME"。 value: k8s-sigs.io/nfs-subdir-external-provisioner:指定环境变量的值为 "k8s-sigs.io/nfs-subdir-external-provisioner"。
            • name: NFS_SERVER:指定环境变量名称为 "NFS_SERVER"。 value: 175.178.104.61:指定 NFS 服务器的 IP 地址。
            • name: NFS_PATH:指定环境变量名称为 "NFS_PATH"。 value: /root/nfs/data:指定 NFS 服务器的路径。
          • imagePullPolicy: IfNotPresent:指定容器的镜像拉取策略为 "IfNotPresent"。
        • restartPolicy: Always:指定 Pod 的重启策略为 "Always"。
        • volumes:定义 Pod 中的卷。
          • name: nfs-client-root:指定卷的名称为 "nfs-client-root"。 nfs:指定卷类型为 NFS。
            • server: 175.178.104.61:指定 NFS 服务器的 IP 地址。 path: /root/nfs/data:指定 NFS 服务器的路径。
    • selector:通过标签选择器选择由 Deployment 管理的 Pod。
      • matchLabels:用于匹配标签选择器的标签。 app: nfs-client-provisioner:选择具有标签 "app: nfs-client-provisioner" 的 Pod。

这个 Deployment 配置会创建一个 Pod,其中运行 nfs-client-provisioner 容器,该容器负责将 PersistentVolumeClaim 映射到指定的 NFS 服务器和路径。这样,StatefulSet 中的 Pod 就可以使用这个部署好的 NFS 客户端提供器来进行动态卷的创建和挂载了。请注意,你需要根据实际需求和环境配置中的 IP 地址、路径等参数。


4️⃣ DaemonSet

官方地址:kubernetes.io/zh-cn/docs/…

🔎 4.1 什么是 DaemonSet

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 的副本。 当有节点加入集群时, 也会为他们新增一个 Pod 。 当有节点从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。

DaemonSet 的一些典型用法:

  • 在每个节点上运行集群守护进程,例如每个节点都是有 kubelet、kube-proxy 如果每个节点都去创建其实就是很麻烦的一件事
  • 在每个节点上运行日志收集守护进程,如果要进行日志采集,每增加一个节点还需要使用配置文件进行创建也是很麻烦
  • 在每个节点上运行监控守护进程

一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个 DaemonSet。 一个稍微复杂的用法是为同一种守护进程部署多个 DaemonSet;每个具有不同的标志, 并且对不同硬件类型具有不同的内存、CPU 要求。

⚒️ 4.2 使用 DaemonSet

apiVersion: apps/v1  
kind: DaemonSet  
metadata:  
  name: nginx-daemonset  
  labels:  
    app: nginx-daemonset  
spec:  
  template:  
    metadata:  
      name: nginx-daemonset  
      labels:  
        app: nginx-daemonset  
    spec:  
      containers:  
        - name: nginx-daemonset  
          image: nginx:1.7.9  
          imagePullPolicy: IfNotPresent  
      restartPolicy: Always  
  selector:  
    matchLabels:  
      app: nginx-daemonset

5️⃣ Job

官方地址:kubernetes.io/zh-cn/docs/…

🔎 5.1 什么是 Job

Job 会创建一个或者多个 Pod,并将继续重试 Pod 的执行,直到指定数量的 Pod 成功终止。 随着 Pod 成功结束,Job 跟踪记录成功完成的 Pod 个数。 当数量达到指定的成功个数阈值时,任务(即 Job)结束。 删除 Job 的操作会清除所创建的全部 Pod。 挂起 Job 的操作会删除 Job 的所有活跃 Pod,直到 Job 被再次恢复执行。

一种简单的使用场景下,你会创建一个 Job 对象以便以一种可靠的方式运行某 Pod 直到完成。 当第一个 Pod 失败或者被删除(比如因为节点硬件失效或者重启)时,Job 对象会启动一个新的 Pod。

🛠️ 5.2 使用 Job

apiVersion: batch/v1
kind: Job
metadata:
  name: pi
spec:
  template:
    spec:
      containers:
      - name: pi
        image: perl:5.34.0
        command: ["perl",  "-Mbignum=bpi", "-wle", "print bpi(2000)"]
      restartPolicy: Never
  backoffLimit: 4

这段代码是一个用于计算π(圆周率)的 Kubernetes Job 的配置文件。以下是对各个部分的解释:

  • apiVersion: batch/v1:使用的 Kubernetes API 版本为 batch/v1,表示这是一个 Job 对象的配置。
  • kind: Job:指定资源类型为 Job,表示这是一个 Job 对象的配置。
  • metadata:Job 对象的元数据。
    • name: pi:指定 Job 的名称为 "pi"。
  • spec:定义 Job 的规格。
    • template:指定 Job 中的 Pod 模板,即运行 Job 的 Pod 的配置。
      • spec:定义 Pod 的规格。
        • containers:定义 Pod 中的容器。
          • name: pi:容器的名称为 "pi"。
          • image: perl:5.34.0:指定容器使用的镜像为 perl:5.34.0,这个镜像中包含了 Perl 编程语言的运行环境。
          • command:定义容器运行的命令。
            • ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]:指定容器运行的 Perl 命令。这段命令使用 Perl 的 bignum 模块来计算 π 的近似值,精度为 2000 位,并打印结果。
        • restartPolicy: Never:指定 Pod 的重启策略为 "Never",表示一旦任务完成或容器终止,就不会重新启动该 Pod。
    • backoffLimit: 4:指定 Job 的重试次数上限为 4。如果 Job 中的 Pod 在运行过程中失败,最多会进行 4 次重试。

这个 Job 的目的是在 Kubernetes 集群中创建一个 Pod,运行一个 Perl 脚本来计算 π 的近似值。Pod 中的容器使用 perl:5.34.0 镜像,执行指定的 Perl 命令来进行计算,并将结果打印出来。重试次数上限为 4,表示如果计算任务失败,最多会进行 4 次重试。

通过将这个配置文件保存为 YAML 文件,并使用 kubectl 命令或其他 Kubernetes API 工具进行创建,就可以在 Kubernetes 集群中创建并运行这个 Job,以进行π的计算。


🗑️ 5.3 自动清理完成 Job

完成的 Job 通常不需要留存在系统中。在系统中一直保留它们会给 API 服务器带来的额外的压力。如果 Job 被更高级别的控制器来管理,例如 CronJob,那么 Job 可以根据 CronJob 基于特定的根据容量规定的清理策略清理掉。

自动清理已完成的 Job 的另一种方式是由 TTL 控制器所提供的 TTL 机制。通过设置 Job 的 .spec.ttlSecondAfterFinished 字段,可以让该控制器清理掉已结束的资源,TTL 控制器清理 Job 的时候,会级联式地删除 Job 对象,即删除所有依赖的对象,包括 Pod


6️⃣ 控制器无法解决的问题

控制器能够让 Pod 更具有运维能力,同时让 Pod 的使用场景更加的丰富,方便我们更好的去使用 Kubernetes 集群,但是也有控制器无法解决的问题:

  • 无法解决网络相关的问题。我们到现在部署的例如 Nginx 容器,其实是无法通过网络去访问的,在使用 Docker 的时候,会有端口的映射,但是现在控制器显然无法做到这一点
  • 无法实现多个 Pod 之间的负载均衡

这些无法解决的问题,我们将在下一篇文章有关 Service 的讲解中解决


💬 总结

本文讲解了使用 Controller 来管理 Pod,用一句话总结就是 Controller 让 Pod 更具有运维的能力,Controller 控制 Pod 的实现原理是通过 Label 进行管理,然后我们分别详细介绍了四种控制器:

  • Deployment:使用最多的控制器,它可以为 Pod 创建多个副本,支持动态的扩缩容版本的回滚,其中副本管理是通过 ReplicaSet 实现的
  • StatefulSet: 相较于 Deployment,它更多的使用在 有状态应用 上,我们通过四个问题了解到了 DeploymentStatefulSet 的区别,StatefulSet 能够为 Pod 提供持久的标识符,也就是说具备唯一的 ID,进而提供持久的存储,在使用过程中提到了 数据卷Volume存储类StorageClass 这两个后面学习的知识点,也是使用 StatefulSet 的难点,如果根据下面对配置文件的解释 对应 配置文件 去看,相信还是可以理解的
  • DaemonSet: 它的特点是,运行该控制器后,每个节点上都会部署对应的容器,会随着节点的增加而增加,随着节点的删除而删除,一般用于:监控、日志、集群的守护
  • Job: 顾名思义,它就是一个任务,会随着任务的结束而被删除,我们以计算 π 的 1000 位为例子,可以看到它的执行任务、被删除的过程

🍁 友链


✒写在最后

都看到这里啦~,给个点赞再走呗~,也欢迎各位大佬指正以及补充,在评论区一起交流,共同进步!也欢迎加微信一起交流:Goldfish7710。咱们明天见~