赞
踩
前言
在 K8s 集群中,Pod 控制器是一种关键的组件,负责管理和控制Pod的生命周期。Pod 是 K8s 中最小的可部署单元,通常包含一个或多个容器,Pod 控制器则确保所需数量的 Pod 实例处于运行状态,并根据定义的规则进行自动扩展或缩减。本文将介绍 K8s 集群中 Pod 控制器的定义、类型以及 Pod 与控制器之间的关系。
目录
2.3 解析 kubernetes 和 nginx-service 名称
概述:
Pod 控制器是一种 K8s 对象,设计用于管理和维护 Pod 实例。它们不是直接操作 Pod,而是通过与 K8s API 交互来间接控制 Pod,从而保证即使面对节点故障、Pod 终止或其他意外情况,也能维持应用的高可用性和期望的部署配置。
作用:
自动扩缩容
自我修复
滚动更新
版本控制
有序部署和管理
定时任务
资源组织和命名空间管理
常见的 Pod 控制器类型包括 ReplicaSet、Deployment、DaemonSet、StatefulSet、Job 和 CronJob 等。
确保在任何给定时间都有指定数量的 Pod 副本在运行,确保 Pod 副本数量符合期望值,并且支持滚动式自动扩容和缩容功能。主要三个组件组成:
它建立在 ReplicaSet 之上,提供了额外的功能,如滚动更新、暂停/恢复更新、版本回滚等。
确保每个节点上都运行着一个指定的 Pod 实例,比如日志收集、监控代理等。当有新的节点加入集群时,DaemonSet 会自动在新节点上创建 Pod;节点从集群移除时,对应的 Pod 也会被清理。
管理有状态应用设计,如数据库、需要持久化存储和稳定的网络标识(如: CEPH)。StatefulSet 中的每个 Pod 都有唯一的、持久的标识符和稳定的存储卷。它确保 Pod 按顺序启动和关闭(理论上是倒序),且在重启后仍能访问相同的存储资源,这对于维护数据一致性至关重要。
用于运行完成特定次数后终止的 Pod,即执行一次性或批处理任务。只要完成就立即退出,不需要重启或重建。
周期性任务控制,基于时间调度来定期执行 Job,类似于Linux的cron定时任务,不需要持续后台运行。
Controllers (控制器)是管理和运行容器的 Pod 对象的实体,在集群中,Pod 通过 Label Selector (标签与选择器)进行相关联。它们通过控制器来实现应用的运维任务,例如伸缩和升级。
可以理解为:Pod 与控制器之间是一种管理和被管理的关系,控制器利用 K8s 的标签系统来识别和控制其管理的 Pod 集合,从而实现了应用的自动化运维和高可用性。
部署并维护一个由3个副本组成的 Nginx 服务,管理 Pod 和 ReplicaSet;应用场景:web服务。
① 定义 yaml 配置
- [root@master01 controller]# vim nginx-deployment.yaml
- apiVersion: apps/v1
- kind: Deployment
- metadata:
- name: nginx-deployment
- labels:
- app: nginx
- spec:
- replicas: 3
- selector:
- matchLabels:
- app: nginx
- template:
- metadata:
- labels:
- app: nginx
- spec:
- containers:
- - name: nginx
- image: nginx:1.14
- ports:
- - containerPort: 80
② 创建控制器
[root@master01 controller]# kubectl apply -f nginx-deployment.yaml
③ 获取集群中Pods、Deployments、以及 ReplicaSets 的信息
- [root@master01 controller]# kubectl get pod,deploy,rs
- NAME READY STATUS RESTARTS AGE
- pod/nfs-client-provisioner-5f7484cd44-ls45v 1/1 Running 0 14h
- pod/nginx-deployment-d9d8cf5c7-j2c8p 1/1 Running 0 50s
- pod/nginx-deployment-d9d8cf5c7-mf578 1/1 Running 0 50s
- pod/nginx-deployment-d9d8cf5c7-xqh57 1/1 Running 0 50s
- NAME READY UP-TO-DATE AVAILABLE AGE
- deployment.apps/nginx-deployment 3/3 3 3 50s
- # READY: 表示期望的Pod副本中有多少是Ready状态。3/3意味着所有3个副本都已准备就绪,可以接收请求。
- # UP-TO-DATE: 表示已经更新到最新配置的Pod副本数量,这里也是3,说明没有正在进行的更新操作或所有Pod都已经是最新配置。
- # AVAILABLE: 表示当前可用的Pod副本数量,同样为3,说明服务完全可用。
- # AGE: 显示了Deployment被创建的时间,这里是50秒。
-
- NAME DESIRED CURRENT READY AGE
- replicaset.apps/nginx-deployment-d9d8cf5c7 3 3 3 50s
- # DESIRED: 表示ReplicaSet期望维持的Pod副本数量,这里是3。
- # CURRENT: 实际存在的Pod副本数量,也是3,符合期望。
- # READY: 准备好提供服务的Pod副本数量,3个副本都已就绪。
④ 查看控制器配置
- kubectl edit deployment/nginx-deployment
- labels:
- app: nginx # Deployment资源的标签
-
- replicas: 3 #期望的pod数量,默认是1
-
- rollingUpdate:
- maxSurge: 25% # 升级过程中会先启动的新Pod的数量不超过期望的Pod数量的25%,也可以是一个绝对值
- maxUnavailable: 25% # 升级过程中在新的Pod启动好后销毁的旧Pod的数量不超过期望的Pod数量的25%,也可以是一个绝对值
- type: RollingUpdate # 滚动升级
-
- spec:
- template:
- labels:
- app: nginx # Pod副本关联的标签
- spec:
- containers:
- - image: nginx:1.14 #镜像名称
- imagePullPolicy: IfNotPresent #镜像拉取策略
- ports:
- - containerPort: 80 #容器暴露的监听端口
-
- restartPolicy: Always #容器重启策略
⑤ 查看历史版本
- [root@master01 controller]# kubectl rollout history deployment nginx-deployment
- deployment.apps/nginx-deployment
- REVISION CHANGE-CAUSE
- 1 <none>
小结:
deployment 部署无状态应用的管理 ReplicaSet 和 Pod 并创建 Pod,主要维护 Pod 副本数量与期望值相同;创建和删除 Pod 时,并行执行,升级时也会创建一部分再删除一部分。
常见的应用场景:数据库StatefulSets | Kubernetes
(1)为什么要有headless?
当节点挂了,重建之后的标识符是不变的,每一个节点的节点名称是不能改变的。pod名称是作为pod识别的唯一标识符,必须保证其标识符的稳定并且唯一。
为了实现标识符的稳定,这时候就需要一个headless service 解析直达到pod,还需要给pod配置一个唯一的名称。
(2)为什么要有volumeClainTemplate?
大部分有状态副本集都会用到持久存储,比如分布式系统来说,由于数据是不一样的,每个节点都需要自己专用的存储节点;
skyDNS:Kubernetes 1.3之前的版本
kubeDNS:Kubernetes 1.3至Kubernetes 1.11
CoreDNS:Kubernetes 1.11开始至今
创建一个service,然后用dns去测试解析。
① 定义 nginx-svc yaml
- [root@master01 controller]# vim nginx-service.yaml
- apiVersion: v1
- kind: Service
- metadata:
- name: nginx-service
- labels:
- app: nginx
- spec:
- type: NodePort
- ports:
- - port: 80
- targetPort: 80
- selector:
- app: nginx
② 创建 nginx-svc
- [root@master01 controller]# kubectl apply -f nginx-service.yaml
- service/nginx-service created
-
- [root@master01 controller]# kubectl get svc
- nginx-service NodePort 10.96.193.207 <none> 80:32037/TCP 7s
③ 定义一个dns-pod yaml
- [root@master01 controller]# vim dns-test.yaml
- apiVersion: v1
- kind: Pod
- metadata:
- name: dns-test
- spec:
- containers:
- - name: busybox
- image: busybox:1.28.4 #一个小型的Unix工具集合,常用于测试和基础任务
- args:
- - /bin/sh
- - -c
- - sleep 36000 #让容器运行后休眠36000秒
- restartPolicy: Never #指定了Pod的重启策略
④ 创建 pod
- [root@master01 controller]# kubectl apply -f dns-test.yaml
- [root@master01 controller]# kubectl get pod
- NAME READY STATUS RESTARTS AGE
- dns-test 1/1 Running 0 48s
⑤ 进入容器测试解析
- [root@master01 controller]# kubectl exec -it dns-test sh
- / # nslookup kubernetes
- Server: 10.96.0.10
- Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
-
- Name: kubernetes
- Address 1: 10.96.0.1 kubernetes.default.svc.cluster.local
- / # nslookup nginx-service
- Server: 10.96.0.10
- Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
-
- Name: nginx-service
- Address 1: 10.96.193.207 nginx-service.default.svc.cluster.local
- kubectl explain statefulset
-
- kubectl explain statefulset.spec
- FIELDS:
- podManagementPolicy <string> #Pod管理策略
- replicas <integer> #副本数量
- revisionHistoryLimit <integer> #历史版本限制
- selector <Object> -required- #选择器,必选项
- serviceName <string> -required- #服务名称,必选项
- template <Object> -required- #模板,必选项
- updateStrategy <Object> #更新策略
- volumeClaimTemplates <[]Object> #存储卷申请模板,必选项
如上所述,一个完整的 StatefulSet 控制器由一个 Headless Service、一个 StatefulSet 和一个 volumeClaimTemplate 组成。定义了一个Kubernetes StatefulSet资源和一个Headless Service(无头服务),用于部署一个有状态应用:
- [root@master01 controller]# vim stateful-demo.yaml
- apiVersion: v1
- kind: Service
- metadata:
- name: myapp-svc
- labels:
- app: myapp-svc
- spec:
- ports:
- - port: 80
- name: web
- clusterIP: None #None表明这是一个无头服务,没有Cluster IP分配,直接返回关联Pod的IP列表
- selector:
- app: myapp-pod #用于选择带有此标签的Pods,与后续的StatefulSet关联
- ---
- apiVersion: apps/v1
- kind: StatefulSet
- metadata:
- name: myapp
- spec:
- serviceName: myapp-svc
- replicas: 3
- selector:
- matchLabels: #为Pod定义标签,与selector匹配
- app: myapp-pod
- template:
- metadata:
- labels:
- app: myapp-pod
- spec:
- containers:
- - name: myapp
- image: ikubernetes/myapp:v1
- ports:
- - containerPort: 80
- name: web
- volumeMounts:
- - name: myappdata
- mountPath: /usr/share/nginx/html #挂载卷myappdata到/usr/share/nginx/html
- volumeClaimTemplates:
- - metadata:
- name: myappdata
- annotations:
- #动态PV创建时,使用annotations在PVC里声明一个StorageClass对象的标识进行关联
- volume.beta.kubernetes.io/storage-class: nfs-client-storageclass
- spec:
- accessModes: ["ReadWriteOnce"] #定义访问模式
- resources:
- requests:
- storage: 2Gi
由于 StatefulSet 资源依赖于一个实现存在的 Headless 类型的 Service 资源,所以需要先定义一个名为 myapp-svc 的 Headless Service 资源,用于为关联到每个 Pod 资源创建 DNS 资源记录。接着定义了一个名为 myapp 的 StatefulSet 资源,它通过 Pod 模板创建了 3 个 Pod 资源副本,并基于 volumeClaimTemplates 向前面创建的PV进行了请求大小为 2Gi 的专用存储卷。
- [root@master01 controller]# kubectl apply -f stateful-demo.yaml
-
- 查看创建的无头服务myapp-svc:
- [root@master01 controller]# kubectl get svc
- NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
- kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 14d
- myapp-svc ClusterIP None <none> 80/TCP 32m
-
- 查看statefulset:
- [root@master01 controller]# kubectl get sts
- NAME READY AGE
- myapp 3/3 24m
-
- 查看pvc绑定:
- [root@master01 controller]# kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- myappdata-myapp-0 Bound pvc-d9b33a5b-076e-4a17-b457-03d7b50d08b7 2Gi RWO nfs-client-storageclass 25m
- myappdata-myapp-1 Bound pvc-4748da6b-1c81-45c0-9b50-a20898cc5f11 2Gi RWO nfs-client-storageclass 5m51s
- myappdata-myapp-2 Bound pvc-a4999f31-ab02-4640-913e-c6cf19ccf7a0 2Gi RWO nfs-client-storageclass 5m46s
-
- 查看pv绑定:
- [root@master01 controller]# kubectl get pv
- NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
- pvc-4748da6b-1c81-45c0-9b50-a20898cc5f11 2Gi RWO Delete Bound default/myappdata-myapp-1 nfs-client-storageclass 8m14s
- pvc-a4999f31-ab02-4640-913e-c6cf19ccf7a0 2Gi RWO Delete Bound default/myappdata-myapp-2 nfs-client-storageclass 8m9s
- pvc-d9b33a5b-076e-4a17-b457-03d7b50d08b7 2Gi RWO Delete Bound default/myappdata-myapp-0 nfs-client-storageclass 8m26s
-
- 查看Pod信息:
- [root@master01 controller]# kubectl get pods
- NAME READY STATUS RESTARTS AGE
- myapp-0 1/1 Running 0 27m
- myapp-1 1/1 Running 0 8m39s
- myapp-2 1/1 Running 0 8m34s
当删除的时候是从myapp-2开始进行删除的,关闭是逆向关闭(不过一般是同时删除);然后再次创建,观察 pod 创建详情:
- [root@master01 volumes]# kubectl get pod -w
- NAME READY STATUS RESTARTS AGE
- myapp-0 1/1 Running 0 32m
- myapp-1 1/1 Running 0 12m
- myapp-2 1/1 Running 0 12m
- nfs-client-provisioner-5f7484cd44-ft5lv 1/1 Running 0 13m
- myapp-1 1/1 Terminating 0 14m
- myapp-2 1/1 Terminating 0 14m
- myapp-0 1/1 Terminating 0 34m
- myapp-1 0/1 Terminating 0 14m
- myapp-2 0/1 Terminating 0 14m
- myapp-0 0/1 Terminating 0 34m
- myapp-1 0/1 Terminating 0 14m
- myapp-1 0/1 Terminating 0 14m
- myapp-2 0/1 Terminating 0 14m
- myapp-2 0/1 Terminating 0 14m
- myapp-0 0/1 Terminating 0 34m
- myapp-0 0/1 Terminating 0 34m
- myapp-0 0/1 Pending 0 0s
- myapp-0 0/1 Pending 0 0s
- myapp-0 0/1 ContainerCreating 0 0s
- myapp-0 1/1 Running 0 2s
- myapp-1 0/1 Pending 0 0s
- myapp-1 0/1 Pending 0 0s
- myapp-1 0/1 ContainerCreating 0 0s
- myapp-1 1/1 Running 0 2s
- myapp-2 0/1 Pending 0 0s
- myapp-2 0/1 Pending 0 0s
- myapp-2 0/1 ContainerCreating 0 0s
- myapp-2 1/1 Running 0 2s
此时PVC依旧存在的,再重新创建pod时,依旧会重新去绑定原来的pvc:
- [root@master01 controller]# kubectl get pvc
- NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
- myappdata-myapp-0 Bound pvc-d9b33a5b-076e-4a17-b457-03d7b50d08b7 2Gi RWO nfs-client-storageclass 36m
- myappdata-myapp-1 Bound pvc-4748da6b-1c81-45c0-9b50-a20898cc5f11 2Gi RWO nfs-client-storageclass 17m
- myappdata-myapp-2 Bound pvc-a4999f31-ab02-4640-913e-c6cf19ccf7a0 2Gi RWO nfs-client-storageclass 17m
StatefulSet 控制器将在 StatefulSet 中删除并重新创建每个 Pod。它将以与 Pod 终止相同的顺序进行(从最大的序数到最小的序数),每次更新一个 Pod。在更新其前身之前,它将等待正在更新的 Pod 状态变成正在运行并就绪。如下操作的滚动更新是按照2-0的顺序更新。
① 修改 yaml 定义
- [root@master01 controller]# vim stateful-demo.yaml
- ……
- image: nginx:1.18.0 # 原来是1.14
- ……
② 更新 svc yaml
[root@master01 controller]# kubectl apply -f stateful-demo.yaml
③ 查看滚动更新的过程
- [root@master01 volumes]# kubectl get pod -w
- NAME READY STATUS RESTARTS AGE
- myapp-0 1/1 Running 0 12s
- myapp-1 1/1 Running 0 9s
- myapp-2 1/1 Running 0 7s
- nfs-client-provisioner-5f7484cd44-ft5lv 1/1 Running 0 29m
- myapp-2 1/1 Terminating 0 51s
- myapp-2 0/1 Terminating 0 52s
- myapp-2 0/1 Terminating 0 53s
- myapp-2 0/1 Terminating 0 53s
- myapp-2 0/1 Pending 0 0s
- myapp-2 0/1 Pending 0 0s
- myapp-2 0/1 ContainerCreating 0 0s
- myapp-2 1/1 Running 0 2s
- myapp-1 1/1 Terminating 0 57s
- myapp-1 0/1 Terminating 0 58s
- myapp-1 0/1 Terminating 0 59s
- myapp-1 0/1 Terminating 0 59s
- myapp-1 0/1 Pending 0 0s
- myapp-1 0/1 Pending 0 0s
- myapp-1 0/1 ContainerCreating 0 0s
- myapp-1 1/1 Running 0 2s
- myapp-0 1/1 Terminating 0 64s
- myapp-0 0/1 Terminating 0 65s
- myapp-0 0/1 Terminating 0 66s
- myapp-0 0/1 Terminating 0 66s
- myapp-0 0/1 Pending 0 0s
- myapp-0 0/1 Pending 0 0s
- myapp-0 0/1 ContainerCreating 0 0s
- myapp-0 1/1 Running 0 2s
④ 进入 dns-test Pod中,每一个 pod 自己的名称都是可以被解析的
- [root@master01 controller]# kubectl exec -it dns-test sh
- kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
- / # nslookup myapp-svc
- Server: 10.96.0.10
- Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
-
- Name: myapp-svc
- Address 1: 10.244.2.40 myapp-0.myapp-svc.default.svc.cluster.local
- Address 2: 10.244.2.39 myapp-1.myapp-svc.default.svc.cluster.local
- Address 3: 10.244.1.201 myapp-2.myapp-svc.default.svc.cluster.local
- / # nslookup myapp-0.myapp-svc.default.svc.cluster.local
- Server: 10.96.0.10
- Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
-
- Name: myapp-0.myapp-svc.default.svc.cluster.local
- Address 1: 10.244.2.40 myapp-0.myapp-svc.default.svc.cluster.local
- / # nslookup myapp-1.myapp-svc.default.svc.cluster.local
- Server: 10.96.0.10
- Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
-
- Name: myapp-1.myapp-svc.default.svc.cluster.local
- Address 1: 10.244.2.39 myapp-1.myapp-svc.default.svc.cluster.local
- / # nslookup myapp-2.myapp-svc.default.svc.cluster.local
- Server: 10.96.0.10
- Address 1: 10.96.0.10 kube-dns.kube-system.svc.cluster.local
DaemonSet 确保全部(或者一些)Node 上运行一个 Pod 的副本。当有 Node 加入集群时,也会为他们新增一个 Pod 。当有 Node 从集群移除时,这些 Pod 也会被回收。删除 DaemonSet 将会删除它创建的所有 Pod。
使用 DaemonSet 的一些典型用法:
应用场景:Agent
官方案例(监控):https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/
示例:
- [root@master01 data]# vim ds.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.14
- ports:
- - containerPort: 80
-
- [root@master01 data]# kubectl apply -f ds.yaml
-
- DaemonSet会在每个node节点都创建一个Pod:
- [root@master01 data]# kubectl get pod -o wide
- nginx-daemonset-bqmtg 1/1 Running 0 15s 10.244.1.202 node01 <none> <none>
- nginx-daemonset-n89xc 1/1 Running 0 15s 10.244.2.42 node02 <none> <none>
① deployment 部署无状态应用的管理 RS 和 pod 创建 Pod ,主要是维护 pod 副本数量与期望状态相同;创建和删除 pod 时并行执行升级时是想创建一部分,再删除一部分;
② statefulset 部署有状态的应用,每个 pod 名称唯一且不变,每个 pod 拥有自己专属的持久化的存储(PVC 和 PV)在 k8s 集群内部可以通过{pod_name}.{service_name}.{namespace).svc.cluster.local 解析出 pod 的 IP(基于 headless service 和 coreDNS)创建和删除 pod 是有顺序的(串行执行的),升级时串行执行的,会删除旧的 pod,再创建新 pod;删除和升级是逆序执行的(先从标识符最大的 n-1开始,一直到最小的0);
③ Daemonset 理论上在 k8s 集群的所有 node 节点上创建相同的 pod(无论 node 节点什么时候加入到 k8s 集群),但是会收到 node 节点上污点影响;
④ 部署一次性任务的 pod,正常完成后容器立即退出并且不重启容器(restartpolicy 不设置Always),也不会重建,异常完成后重试任务,重建次数根据 backofflimit 配置指定(默认为6次);
⑤ cronjob 周期性的部署任务的 pod,正常完成后容器会立即退出并不会重启容器(restartPolicy 不设置 Always),也不会重键 pod schedule 配置周期的性的事件表(*****分时日月周)。
- 无状态:
- 1)deployment 认为所有的pod都是一样的
- 2)不用考虑顺序的要求
- 3)不用考虑在哪个node节点上运行
- 4)可以随意扩容和缩容
-
- 有状态
- 1)实例之间有差别,每个实例都有自己的独特性,元数据不同,例如etcd,zookeeper
- 2)实例之间不对等的关系,以及依靠外部存储的应用。
-
- 常规service和无头服务区别
- service:一组Pod访问策略,提供cluster-IP群集之间通讯,还提供负载均衡和服务发现。
- Headless service:无头服务,不需要cluster-IP,而是直接以DNS记录的方式解析出被代理Pod的IP地址。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。