Kubernetes:Controller
简介#
Kubernetes集群中的Controller对象可以创建和管理多个Pod,提供副本管理、健康检查、滚动升级和集群级别的自愈能力。例如,如果一个节点故障,Controller就能自动将该节点上的Pod调度到其他健康的节点上。这些Controller运行在Kubernetes集群的主节点上,它们不断控制集群中的资源向期望状态迁移(stauts -> spec)。常用的Controller类型有:
- ReplicaSet
- Deployment
- DaemonSet
- StatefulSet
- Job/Cronjob
ReplicaSet#
决定一个Pod有多少同时运行的副本,并保证这些副本的期望状态与当前状态一致。
配置#
一个典型的ReplicaSet配置如下:
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
replicas: 3 # 副本数
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: docker.io/redis:latest
- 在上述配置信息中,字段
spec.template.metadata.labels
的值必须与spec.selector
值相匹配,否则创建请求会被Kubernetes API拒绝; - 被ReplicaSet控制的Pod在创建或更新后,其
metadata.ownerReferences
字段会添加该ReplicaSet的信息; - 一旦删除了原来的ReplicaSet,就可以创建一个新的来替换它。只要新旧ReplicaSet的
spec.selector
字段是相同的,新的ReplicaSet便会接管原有的Pod。然而,修改ReplicaSet中的template并不会使其接管的Pod的Spec更新。
应用场景#
- 重调度:保证指定数量的Pod正常运行;
- 弹性伸缩:修改
spec.replicas
字段,实现Pod数量弹性伸缩; - 应用多版本追踪:修改
spec.selector
字段,实现对一个Pod的多版本管理。
由于ReplicaSet并不支持使用命令kubectl roll-update对Pod进行滚动更新,因此若想要以可控的方式更新Pod,建议使用Deployment。
Deployment#
Deployment为Pod和ReplicaSet提供声明式的更新能力,用于管理无状态的应用。
配置#
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: docker.io/nginx:latest
ports:
- containerPort: 80
.spec.selector
字段必须匹配.spec.template.metadata.labels
,否则请求会被Kubernetes API拒绝;- 当Pod的标签和Deployment的标签选择器匹配,但其模板和
.spec.template
不同,或者此类Pod的总数超过.spec.replicas
的设置时,Deployment会将其终止; - 如果Pod的总数未达到期望值,Deployment会基于
.spec.template
创建新的Pod。
创建#
[root@test-master1 ~]# kubectl create -f test.yml --record
deployment.apps/nginx-deployment created
[root@test-master1 ~]# kubectl get deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 3 3 3 9s
查看上线状态
[root@test-master1 ~]# kubectl rollout status deployment.v1.apps/nginx-deployment
deployment "nginx-deployment" successfully rolled out
[root@test-master1 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-5cbbd6c556-gj4vp 1/1 Running 0 4m app=nginx,pod-template-hash=1766827112
nginx-deployment-5cbbd6c556-vk4vl 1/1 Running 0 4m app=nginx,pod-template-hash=1766827112
nginx-deployment-5cbbd6c556-z24z8 1/1 Running 0 4m app=nginx,pod-template-hash=1766827112
[root@test-master1 ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-5cbbd6c556 3 3 3 2d
查看详细信息
[root@test-master1 ~]# kubectl describe rs nginx-deployment-5cbbd6c556
Name: nginx-deployment-5cbbd6c556
Namespace: gwr
Selector: app=nginx,pod-template-hash=1766827112
Labels: app=nginx
pod-template-hash=1766827112
...
其中一些参数的含义:
- NAME:列出了集群中Deployment的名称;
- READY:应用程序的可用的副本数,显示的格式是“就绪个数/期望个数”;
- UP-TO-DATE:为了达到期望状态已经更新的副本数;
- AVAILABLE:显示应用可供用户使用的副本数;
- AGE:显示应用程序运行的时间。
我们可以发现ReplicaSet被命名为Deployment名称加一个数字的格式(nginx-deployment-5cbbd6c556),这个数字是使用Pod标签中pod-template-hash
字段作为种子随机生成的。而此标签字段是通过对Pod的template进行哈希处理得到的,可确保Deployment管理的ReplicaSet不重叠。
更新#
使用kubectl edit deployment <deployment-name>命令,可直接对Deployment管理的Pod进行更新。当使用kubectl describe deployments命令查看更新信息时,可以在Events下看到更新的过程:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
- 当第一次创建Deployment时,它自动创建了一个ReplicaSet(nginx-deployment-2035384211)并将其管理的Pod扩容至3个副本;
- 更新Deployment时,它又创建了一个新的ReplicaSet(nginx-deployment-1564180365),并将其管理的Pod数量设置为1,然后将旧ReplicaSet管理的Pod缩容到2,以便至少有2个Pod可用且最多创建4个Pod;
- 然后,它使用相同的滚动更新策略继续对新的ReplicaSet扩容并对旧的ReplicaSet缩容;
- 最终,新ReplicaSet管理的Pod副本数扩容至3个,旧ReplicaSet管理的Pod全部终止,更新完成;
- 在整个更新过程中,最多只有一个Pod副本不提供服务,且同一时刻不会有过多的Pod副本同时运行(默认最多比预期值多一个)。
回滚#
当Deployment不稳定时(例如进入反复崩溃状态),我们需要对其进行回滚操作。默认情况下,Deployment的所有上线记录都保留在系统中,以便可以随时回滚。
- 查看历史版本:kubectl rollout history deployment <deployment-name>
- 回滚至历史版本:kubectl rollout undo deployment <deployment-name> --to-revision=<deployment-version>
StatefulSet#
StatefulSet用于管理有状态的应用程序,被其管理的Pod有一个按顺序增长的ID。它与Deployment最大的不同在于,StatefulSet始终将一系列不变的名字分配给Pod,这些Pod从同一个模板创建但并不能相互替换且每个Pod都对应一个特有的持久化存储标识。
应用场景#
- 每个Pod拥有稳定的、唯一的网络标识符(DNS Name)
- 每个Pod拥有稳定的、持久的存储(PersistentVolume)
- 有序的、优雅的部署和缩放
- 有序的、自动的滚动更新
配置#
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx # has to match .spec.template.metadata.labels
serviceName: "nginx"
replicas: 3 # by default is 1
template:
metadata:
labels:
app: nginx # has to match .spec.selector.matchLabels
spec:
terminationGracePeriodSeconds: 10 # not 0
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi
- 名为nginx的Headless Service用来给每个Pod配置DNS Name;
- 名为web的StatefulSet中的字段
spec.replicas
和spec.template.spec
字段表明将在独立的3个Pod副本中启动nginx容器; volumeClaimTemplates
字段表明将通过PersistentVolumes来为Pod提供持久化存储。
Pod标识#
StatefulSet管理的Pod具备一个唯一标识,该标识由以下几部分组成:
- 序号:假设一个StatefulSet的副本数为N,其中的每一个Pod都会被分配一个序号,序号的取值范围从0到N-1,并且该序号在StatefulSet内部是唯一的。
- 稳定的网络标识:
- StatefulSet中每个Pod根据StatefulSet的名称和Pod的序号派生出它的主机名hostname:<StatefulSet name>-<Pod 序号>;
- StatefulSet可以使用Headless Service来控制其Pod所在的域,该域(domain)的格式为:<Service name>.<namespace>.svc.cluster.local("cluster.local"是集群的域名);
- StatefulSet中每一个Pod将被分配一个DNS Name,格式为:<Pod name>.<所在域名>,因此可以直接通过该Pod的DNS Name访问到Pod。
- 稳定的存储:Kubernetes为每个VolumeClaimTemplate创建一个PersistentVolume。
部署和扩缩容#
在默认情况下.spec.podManagementPolicy
字段值为OrderedReady,它代表依次进行Pod的部署和扩缩容:
- 在创建一个副本数为N的StatefulSet时,其Pod将被按{0...N-1}的顺序逐个创建;
- 在删除一个副本数为N的StatefulSet(或其中所有的Pod)时,其Pod将按照相反的顺序(即 {N-1...0})终止和删除;
- 在对StatefulSet执行扩容操作时,新增Pod所有的前序Pod必须处于Running(运行)和Ready(就绪)的状态;
- 终止和删除StatefulSet中的某一个Pod时,该Pod所有的后序Pod必须全部已终止。
若要并行管理Pod,需要设置.spec.podManagementPolicy
字段值为Parallel,此时StatefulSet将同时并行地创建或终止其所有的Pod。
更新#
StatefulSet的更新策略有两种,它是通过定义spec.updateStrategy.type
字段的方式进行选择的。
- On Delete:Controller将不会自动更新StatefulSet中的Pod,用户必须手动删除Pod以便让StatefulSet创建新的Pod,以此来对
spec.template
的变动作出反应。 - Rolling Updates
StatefulSet会删除和重建StatefulSet中的每个Pod,它将按照与Pod终止相同的顺序(从最大序号到最小序号)进行,每次更新一个Pod。它会等到被更新的Pod进入Running和Ready状态,然后再更新其前序Pod。
若Pod的template出错,导致Pod始终不能进入Running和Ready的状态,StatefulSet将停止滚动更新并一直等待(OrderedReady)。在修复template以后,StatefulSet将继续等待出错的Pod进入就绪状态,而该状态将永远无法出现。因此还必须删除所有已经尝试使用错误template的Pod,随后StatefulSet才会使用修复后的template重建Pod。
DaemonSet#
DaemonSet确保全部(或者某些)节点上运行一个Pod的副本,且当有节点加入集群时,也会为他们新增一个Pod。当有节点从集群移除时,这些Pod同样会被回收。删除DaemonSet将会删除它所创建的所有Pod。
使用场景#
- 在每个节点上运行集群守护进程glusterd、ceph等
- 在每个节点上运行日志收集守护进程fluentd、logstash等
- 在每个节点上运行监控守护进程Prometheus等
Spec配置#
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: fluentd-elasticsearch
namespace: kube-system
labels:
k8s-app: fluentd-logging
spec:
selector:
matchLabels:
name: fluentd-elasticsearch
template:
metadata:
labels:
name: fluentd-elasticsearch
spec:
tolerations:
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: fluentd-elasticsearch
image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
resources:
limits:
memory: 200Mi
requests:
cpu: 100m
memory: 200Mi
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
terminationGracePeriodSeconds: 30
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
spec.template.spec.nodeSelector
字段指定运行Pod的节点,若不设置则默认在全部节点上运行;spec.template.spec.restartPolicy
字段的值默认是always,也必须是always。
调度策略#
DaemonSet Controller将会向DaemonSet管理的的Pod添加spec.nodeAffinity
字段,并进一步由Kubernetes Scheduler将Pod绑定到目标节点。
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
此外,容忍度(toleration)node.kubernetes.io/unschedulable:NoSchedule
将被系统自动添加到DaemonSet的Pod中。由此,默认调度器在调度DaemonSet的Pod时可以忽略节点的unschedulable属性。
通信#
与DaemonSet中的Pod进行通信的几种可能模式如下:
-
Push:配置DaemonSet中的Pod,将更新发送到另一个服务,例如统计数据库;
-
节点IP和已知端口:DaemonSet中的Pod可以使用节点的端口,从而可以通过节点IP访问到Pod。客户端能通过某种方法获取节点IP列表,并且基于此也可以获取到相应的端口;
-
DNS:创建Headless Service并通过设置标签选择器选取Pod,通过使用Endpoints对象或从DNS服务中检索到多个A记录来发现DaemonSet;
-
Service:创建Service并通过设置标签选择器选取Pod,使用该Service随机访问到某个节点上的DaemonSet。由于Service的负载均衡机制,因此没有办法访问到特定节点。
Jobs#
Job会创建一个或者多个Pods,并确保指定数量的Pod可以执行到Succeeded状态。随着Pods成功结束,Job跟踪记录成功完成的Pods个数。当数量达到指定的成功个数阈值时,Job结束。删除Job的操作会清除其创建的全部Pod。
配置#
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never
backoffLimit: 4 # Job 最大的重试次数
spec.template.spec.restartPolicy
字段定义了Pod的重启策略,此处只允许使用Never和OnFailure两个取值;spec.completions
和spec.parallelism
字段值默认为1,代表Job只启动一个Pod;spec.completions
表示Job期望成功运行至结束的Pod数量。当该字段值大于1时,Job将创建至相应数量的Pod,编号为1-spec.completions
;spec.parallelism
表示并行运行的Pod数量。当该字段值大于1时,Job会依次创建相应数量的 Pod 并行运行,直到spec.completions
个Pod成功运行至结束;spec.activeDeadlineSeconds
字段指定Job的存活时长,该字段的优先级高于spec.backoffLimit
;- Job终止后Pod不会被删除,可以通过定义
spec.ttlSecondsAfterFinished
字段实现自动清理Job以及Job管理的Pod。若字段值为100,则代表100秒后清理。若字段值为0,则代表Job完成后立即清理。
Endpoint Controller#
负责维护Endpoint与其对应的Service的关系。Endpoint Controller会周期性地进行检查,确保它们始终运行在用户期望的状态。
GC Controller#
在Kubernetes中,每一个从属对象都有一个metadata.ownerReferences
字段,标识其拥有者是哪一个对象。GC Controller会删除那些曾经有owner,后来又不再有owner的对象。
参考文献#
https://kubernetes.io/docs/home/
https://kuboard.cn/learning/
作者:koktlzz
出处:https://www.cnblogs.com/koktlzz/p/14414016.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现