Dawn's Blogs

分享技术 记录成长

0%

Kubernetes学习 (6) Pod和工作负载

Pod

Pod 是可以在 Kubernetes 中创建和管理的、最小的可部署的计算单元,是一组容器,这些容器共享存储、网络(容器间可以使用 localhost 相互通信)、以及怎样运行这些容器的声明。有些 Pod 具有 Init 容器和应用容器,Init 容器会在启动应用容器之前运行并完成。

如下面是一个 Nginx Pod 示例:

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

通常情况下,使用 Deployment、ReplicaSet 或者 Job 这类工作负载来创建 Pod,如果 Pod 需要跟踪状态,可以考虑 StatefulSet 资源。

生命周期

Pod 被认为是临时性的实体(而不是长期存在的)。Pod 起始于 Pending 阶段,如果至少其中有一个主要容器正常启动,则进入 running,之后取决于 Pod 中是否有容器以失败状态结束而进入 Succeed 或者 Failed 阶段

Pod 在其生命周期中只会被调度一次。一旦 Pod 被调度(分派)到某个节点,Pod 会一直在该节点运行,直到 Pod 停止或者被终止。Pod 一旦给定,就不会被调度到不同的节点上;相反,只能被一个全新的、几乎相同的 Pod 所代替。

Pod 阶段

Pod 阶段的可能值:

  • Pending: Pod 已被 Kubernetes 系统接受,但有一个或者多个容器尚未创建亦未运行。此阶段包括等待 Pod 被调度的时间和通过网络下载镜像的时间。
  • Running:Pod 已经绑定到了某个节点,Pod 中所有的容器都已被创建。至少有一个容器仍在运行,或者正处于启动或重启状态。
  • Succeed:Pod 中的所有容器都已成功终止,并且不会再重启。
  • Failed:Pod 中的所有容器都已终止,并且至少有一个容器是因为失败终止。
  • Unknown: 因为某些原因无法取得 Pod 的状态。

容器状态

Kubernetes 会跟踪 Pod 内每一个容器的状态,容器有三种状态:

  • waiting:如果容器没有处于 running 或者 terminated 状态,那么容器就处于 waiting 状态。
  • running:容器正在运行,且没有发生任何问题。
  • terminated:已经开始执行并且或者正常结束或者因为某些原因失败。

容器重启策略

Pod 的 spec 中包含一个 restartPolicy 字段,其可能取值包括 Always、OnFailure 和 Never。默认值是 Always。

当容器发生重启时,会按指数回退方式计算重启的延迟(10s、20s、40s、…),其最长延迟为 5 分钟。一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行重置操作。

使用标签和选择器约束调度

通常来说,向 Kubernetes 中添加节点时,都将标签(label)附加到节点上,通过附加标签对节点进行分类。比如一个节点用于 GPU 计算,那么可以附加一个标签 gpu=true

在 Pod 的 yaml 文件中声明 spec.nodeSelector 字段,就可以按照标签选择该 Pod 被部署的节点。

1
2
3
4
5
6
7
8
9
10
apiVersion: v1
kind: Pod
metadata:
name: kubia-gpu
spec:
nodeSelecotr:
gpu: "true"
containers:
- image: xxx
- name: kubia

Init 容器

Init 容器是一种特殊容器,在 Pod 内应用容器启动之前运行

如果为一个 Pod 指定了多个 Init 容器,这些容器会按顺序逐个运行。 每个 Init 容器必须运行成功,下一个才能够运行。当所有的 Init 容器运行完成时, Kubernetes 才会为 Pod 初始化应用容器并像平常一样运行。 如果某容器因为容器运行时的原因无法启动,或以错误状态退出,kubelet 会根据 Pod 的 restartPolicy 策略进行重试,Init 容器失败则 Kubernetes 会将整个 Pod 状态设置为失败。

为 Pod 设置容器需要在 spec 中添加 initContainers 字段,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]

Pod QoS 类

Kubernetes 对你运行的 Pod 进行分类,并将每个 Pod 分配到特定的 QoS 类中。Kubernetes 基于 Pod 中容器的资源请求进行分类。有三种 QoS 类:Guaranteed、Burstable、BestEffort。当一个 Node 耗尽资源时,Kubernetes 将首先驱逐在该 Node 上运行的 BestEffort Pod,接着是 Burstable Pod,最后是 Guaranteed Pod。

Guaranteed

Guaranteed Pod 具有最严格的资源限制,并且最不可能面临驱逐。同时,这些 Pod 爷可以使用 static CPU 管理策略来使用独占的 CPU。

Pod 被赋予 Guaranteed QoS 类的几个判据:

  • Pod 中的每个容器必须有内存 limit 和内存 request。
  • 对于 Pod 中的每个容器,内存 limit 必须等于内存 request。
  • Pod 中的每个容器必须有 CPU limit 和 CPU request。
  • 对于 Pod 中的每个容器,CPU limit 必须等于 CPU request。

Burstable

Burstable Pod 有一些基于 request 的资源下限保证,但不需要特定的 limit。 由于没有指定 limit,Pod 在资源可用时可以灵活的增加资源。因为 Burstable Pod Pod 可以包括没有资源 limit 或资源 request 的容器, 所以可以尝试使用任意数量的节点资源。

判据:

  • 不满足 Guaranteed QoS 类判据。
  • Pod 中至少一个容器有内存或 CPU 的 request 或 limit。

BestEffort

BestEffort QoS 类中的 Pod 可以使用未专门分配给其他 QoS 类中的 Pod 的节点资源;同样的,如果节点遇到资源压力,kubelet 会优先驱逐 BestEffort Pod。

当 Pod 不满足 Guaranteed 和 Burstable 的判据时,那么这个 Pod 的 QoS 类为 BestEffort。

存活探针

Kubernetes 可以通过存活探针(liveness probe)来检查容器是否存活运行,可以为 pod 中的每一个容器单独指定存活探针。如果探测失败,Kubernetes 将定期执行探针并重启容器。Kubernetes 支持三种存活探针:

  • HTTP Get 探针:通过对指定的 URL 发送 HTTP GET 请求,如果收到响应且响应码不代表错误则认为探测成功。
  • TCP 套接字探针:与容器指定端口建立 TCP 链接,如果建立成功则说明探测成功。
  • Exec 探针:在容器内部执行命令,返回码是 0 则探测成功。

存活探针还可以定义其他属性,如 delay(延迟),timeout(超时),period(周期)等。

必要时设置初始延迟(initialDelaySeconds),如果没有设置初始延迟,探针将在启动时立即开始探测容器, 这通常会导致探测失败, 因为应用程序还没准备好开始接收请求。

可以定义一个健康检查接口 /health 以供检查健康状态,需要注意的是这个接口不应该有任何的认证,否则探针会一直失败导致重启。

在健康检查接口内部不应该定义重试逻辑,因为 Kubernetes 在探测失败时会自行重试。

工作负载

Deployment

Deployment 控制器是工作在 ReplicaSet 之上的(Kubernetes 也建议使用 Deployment),Deployment 通过控制 ReplicaSet 来控制 Pod,并不是直接控制 Pod。Deployment 的示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

同其他 Kubernetes 配置一样, Deployment 需要 apiVersion,kind 和 metadata 字段。在 Deployment 规约中,只有 spec.template 和 spec.selector 是必须的字段。

spec.template 是一个 Pod 模板,和 Pod 的语法完全签筒,这里它是嵌套的,因此不需要 apiVersion 和 kind。

副本

spec.replicas 指定 Pod 的副本数量,默认为 1。

应该让 Kubernetes 控制面自动的管理 Pod 副本数量,不应该自己去手动的扩容或者缩容。

选择运算符

spec.selector 指定这个 Deployment 的 Pod 标签选择运算符,必须匹配 spec.template.metadata.labels,否则会被 API 拒绝。

Deployment 和 ReplicaSet 仅仅通过标签匹配来选择管理的 Pod。如果手动变更 Pod 的标签使之无法匹配到 Deployment 中,则相当于手动将这个 Pod 从 Deployment 移除,而 Deployment 因为水平复制数量少一个,则会创建一个新的 Pod。

策略

spec.strategy 策略用于指定新 Pod 替换旧的 Pod 的策略,可选值为 Recreate 或者 RollingUpdate。默认为 RollingUpdate。

  • Recreate:在创建新 Pod 之前,所有现有的 Pod 会被杀死。
  • RollingUpdate:采取滚动更新的方式更新 Pod,可以指定 spec.strategy.rollingUpdate.maxUnavailable(最大不可用,用来指定更新过程中不可用的 Pod 的个数上限)和 spec.strategy.rollingUpdate.maxSurge(可以创建的超出期望 Pod 个数的 Pod 数量,即新旧 Pod 总数的最大值)来控制更新进程。

最短就绪时间

spec.minReadySeconds 是一个可选字段,用于指定新创建的 Pod 在没有任意容器崩溃情况下的最小就绪时间, 只有超出这个时间 Pod 才被视为可用。默认值为 0(Pod 在准备就绪后立即将被视为可用)。

ReplicaSet

ReplicaSet 的核心作用在于帮助用户创建指定数量的 Pod 副本,并确保 Pod 副本一直处于期望的数量。

Deployment 是一个更高级的概念,它管理 ReplicaSet,并向 Pod 提供声明式的更新以及许多其他有用的功能。

建议使用 Deployment 而不是直接使用 ReplicaSet。

StatefulSet

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

和 Deployment 一样,StatefulSet 也是用来管理 Pod 的部署和扩缩。但是与 Deployment 不同的是,StatefulSet 为它们的每个 Pod 维护了一个有粘性的 ID

DaemonSet

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

DaemonSet 的一些典型用法

  • 在每个节点上运行集群守护进程
  • 在每个节点上运行日志收集守护进程
  • 在每个节点上运行监控守护进程

DaemonSet 通过变迁选择节点,只要标签匹配到的节点,都会在节点上创建指定的 Pod。

Job

Job 用于完成只执行一次就结束的任务,Job 会自动重启或者重新分配返回错误的任务。

可以在 Job 中配置多个 Pod,并且可以声明以串行或者并行的方式运行他们。也可以配置 Pod 的完成时间,超过此时间的 Pod 将会被终止,然后将 Job 标记为失败(Job 的默认失败重试次数为 6,这是可以配置的)。

CronJob

Cron用于完成定时任务,spec.schedule 用于指定运行时间,spec.jobTemplate 用于指定创建出的 Job 模板。