docker version:20.10.2
kubernetes version:1.20.1
本文概述Kubernetes Pod资源控制器的ReplicaSet、Deployment、DaemonSet、Job和CronJob工作负载资源的基本原理及使用。
ReplicaSet
ReplicaSet的目的是维护一组在任何时候都处于运行状态的Pod副本的稳定集合。通常用来保证给定数量的、完全相同的Pod的可用性。
ReplicaSet通过定义期望的副本、标签选择器等模板来使用,每个ReplicaSet都通过根据需要创建和删除Pod以使得副本个数达到期望值。
定义ReplicaSet
主要包含apiVersion、kind、metadata、spec字段;
replicaSet.spec.replicas:定义的副本数量
replicaSet.spec.selector:主要包含matchExpressions和matchLabels;用于选定指定标签的Pod加入此ReplicaSet
replicaSet.spec.template:Pod模板;主要包含参数内容类似于Pod控制器的Yaml文件;其metadata.labels必须同spec.selector标签选择器选择的标签,否则根据Pod模板创建的Pod则是无法满足RS控制器spec.replicas参数的
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: gcr.io/google_samples/gb-frontend:v3
缩放ReplicaSet
通过更新.spec.replicas字段,ReplicaSet可以被轻松的进行缩放。ReplicaSet控制器能确保匹配标签选择器的数量的Pod是可用的和可操作的。
可以通过改变标签来从ReplicaSet的目标集中移除Pod。这种技术可以用来从服务中去除Pod,以便进行排错、数据恢复等。如果副本的数量没有改变,以这种方式移除的Pod将被自动替换。
ReplicationController
ReplicaSet是ReplicationController的后继者。二者目的相同且行为类似,只是ReplicationController不支持标签选择器。因此,相比于ReplicationController,应优先考虑ReplicaSet。
Deployment
Deployment为Pods和ReplicaSets提供声明式的更新能力。
Deployment构建于ReplicaSet之上;支持扩缩容、滚动更新回滚等。
Deployment示例;创建一个ReplicaSet,启动三个ngixn Pods:
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.2
ports:
- containerPort: 80
通过kubectl get deploy
命令检查创建结果:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 3 0 0 0 1s
NAME:Deployment的名称
READY:可用副本数;“就绪个数/期望个数”
UP-TO-DATE:为了达到期望状态已经更新的副本数
AVAILABLE:可供使用的副本数
AGE:运行的时间
查看Deployment创建的ReplicaSet命令:kubectl get rs
更新与回滚Deployment
deployment.spec.strategy:更新策略;默认RollingUpdate更新方式
deployment.spec.strategy.type:指定更新策略;Recreate:重建方式更新;RollingUpdate:滚动方式更新,默认
deployment.spec.strategy.type.Recreate:重建方式更新;RollingUpdate字段失效
deployment.spec.strategy.type.RollingUpdate.maxSurge:滚动更新时最大能超出N个Pod副本
deployment.spec.strategy.type.RollingUpdate.maxUnavailable:滚动更新时最多有N个不可用副本
deployment.spec.reversionHistoryLimit:最多保存的版本历史
当修改了部署清单文件,执行kubectl apply filename.yaml
后,默认情况下按照默认的更新方式(RollingUpdate ,最大25%个超出副本,最大25%个不可用副本)
通过命令查看及回滚Deployment:
# 更新Deployment数量
kubectl patch deployment nginx-deployment -p '{"spec": {"replicas": 2}}'
# 查看deployment控制器下的nginx-deployment的更新历史
kubectl rollout history deployment nginx-deployment
# 回滚至上一次的版本
kubectl rollout undo deployment nginx-deployment
# 回滚到指定版本
kubectl rollout undo deployment nginx-deployment --to-revision=1
DaemonSet
DaemonSet确保集群中(满足条件)的节点上运行一个Pod的副本。当有节点加入集群时,也会为他们新增一个Pod。当有节点从集群移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。
DaemonSet的一些典型用法:
- 在每个节点上运行集群守护进程
- 在每个节点上运行日志收集守护进程
- 在每个节点上运行监控守护进程
一种简单的用法是为每种类型的守护进程在所有的节点上都启动一个DaemonSet。一个稍微复杂的用法是为同一种守护进程部署多个DaemonSet;每个具有不同的标志,并且对不同硬件类型具有不同的内存、CPU要求。
示例:
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
Daemon Pods的调度
DaemonSet确保所有符合条件的节点都运行该Pod的一个副本。通常运行Pod的节点由Kubernetes调度器选择。不过DaemonSet Pods由DaemonSet控制器创建和调度。但会带来以下问题:
- Pod行为的不一致性:正常Pod在被创建后等待调度时处于Pending状态,DaemonSetPods创建后不会处于Pending状态下。
- Pod抢占由默认调度器处理。启用抢占后,DaemonSet控制器将在不考虑Pod优先级和抢占的情况下制定调度决策。
使用默认调度方法是将NodeAffinity条件添加到DaemonSet Pods(NodeAffinity条件不能使.spec.nodeName
)。
示例:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchFields:
- key: metadata.name
operator: In
values:
- target-host-name
此外,系统会自动添加node.kubernetes.io/unschedulable:NoSchedule
容忍度到DaemonSet Pods。在调度DaemonSet Pod时,默认调度器会忽略unschedulable
节点。
污点和容忍度
尽管Daemon Pods遵循污点和容忍度规则,根据相关特性,控制器会自动将以下容忍度添加到DaemonSet Pod:
容忍度键名 | 效果 | 版本 | 描述 |
---|---|---|---|
node.kubernetes.io/not-ready | NoExecute | 1.13+ | 当出现类似网络断开的情况导致节点问题时,DaemonSet Pod 不会被逐出。 |
node.kubernetes.io/unreachable | NoExecute | 1.13+ | 当出现类似于网络断开的情况导致节点问题时,DaemonSet Pod 不会被逐出。 |
node.kubernetes.io/disk-pressure | NoSchedule | 1.8+ | |
node.kubernetes.io/memory-pressure | NoSchedule | 1.8+ | |
node.kubernetes.io/unschedulable | NoSchedule | 1.12+ | DaemonSet Pod 能够容忍默认调度器所设置的 unschedulable 属性. |
node.kubernetes.io/network-unavailable | NoSchedule | 1.12+ | DaemonSet 在使用宿主网络时,能够容忍默认调度器所设置的 network-unavailable 属性。 |
Daemon Pods通信
与DaemonSet中的Pod进行通信的几种模式:
- 推送(Push):配置DaemonSet中的Pod,将更新发送到另一个服务,例如统计数据库。
- NodeIP和已知端口:DaemonSet中的Pod可以使用hostPort,从而可以通过节点IP访问到Pod。客户端能通过某种方法获取节点IP列表,并且基于此也可以获取到相应的端口。
- DNS:创建具有相同Pod标签选择器的
无头服务(headless-services)
, 通过使用endpoints
资源或从DNS中检索到多个A记录来发现DaemonSet。 - Service:创建具有相同Pod选择算符的服务,并使用该服务随机访问到某个节点上的守护进程(没有办法访问到特定节点)。
Jobs
Job会创建一个或者多个Pods,并将继续重试Pods的执行,直到指定数量的Pods成功终止。随着Pods成功结束,Job跟踪记录成功完成的Pods个数。当数量达到指定的成功个数阈值时,任务(即Job)结束。删除Job的操作会清除所创建的全部Pods。
一种简单的使用场景下,你会创建一个Job对象以便以一种可靠的方式运行某Pod直到完成。当第一个Pod失败或者被删除(比如因为节点硬件失效或者重启)时,Job对象会启动一个新的Pod。
也可以使用Job以并行的方式运行多个Pod。
示例:它负责计算π到小数点后2000位,并将结果打印出来。 此计算大约需要10秒钟完成。
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
通过kubectl logs PodName
命令查看Pod的标准输出
编写Job规约
.spec中只有job.spec.template
是必需字段,定义规范与Pod相同。
除此之外,Job中的Pod模板必需设置合适的标签和重启策略。
Job中Pod的RestartPolicy
只能设置为Never
或OnFailure
。
Job的并行执行
适合以Job形式来运行的任务主要有三种:
- 非并行Job
- 通常只启动一个Pod,当Pod成功终止时,立即视Job为完成状态
- 具有确定完成计数的并行Job
-
.spec.completions
字段设置为非0的正数值 - Job用来代表整个任务,当对应于1和
.spec.completions
之间的每个整数都存在一个成功的Pod时,Job被视为完成
-
- 带有工作队列的并行Job
- 不设置
spec.completions
,默认值为.spec.parallelism
- 多个Pod之间必须相互协调,或者借助外部服务确定每个Pod要处理哪个工作条目
- 每个Pod都可以独立确定是否其它Pod都已完成,进而确定Job是否完成
- 当Job中任何Pod成功终止,不在创建新Pod
- 一旦至少1个Pod成功完成,并且所有Pod都已终止,即可宣告Job成功完成
- 一旦任何Pod成功退出,任何其它Pod都不应再对此任务执行任何操作或生成任何输出。所有Pod都应启动退出程序。
- 不设置
对于非并行的Job,你可以不设置spec.completions和spec.parallelism。这两个属性都不设置时,均取默认值1。
对于确定完成计数类型的Job,你应该设置.spec.completions为所需要的完成个数。你可以设置.spec.parallelism,也可以不设置。其默认值为1。
对于一个工作队列Job,你不可以设置.spec.completions,但要将.spec.parallelism设置为一个非负整数。
CronJob
CronJob创建基于时间调度的Jobs
一个CronJob对象就像crontab文件中的一行。它用Cron格式进行编写,并周期性地在给定的调度时间执行Job。
CronJobs对于创建周期性的、反复重复的任务很有用,例如执行数据备份或者发送邮件。CronJobs也可以用来计划在指定时间来执行的独立任务,例如计划当集群看起来很空闲时执行某个Job。
示例:下面的CronJob示例清单会在每分钟打印出当前时间和问候消息
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: hello
spec:
schedule: "*/1 * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox
imagePullPolicy: IfNotPresent
args:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure