Pod 是 Kubernetes 集群中的最小管理单元,其中包含一个或多个应用容器,它们在 Pod 内共享网络配置和存储卷配置。可被看作面向应用的“逻辑主机”,是 Kubernetes 中核心的资源对象。
1. Pod 定义详解
yaml 格式的 Pod 配置文件的标准示例如下:
apiVersion: v1
kind: Pod
metadata:
name: string
namespace: strinig
labels:
- name: string
annotations:
- name: string
spec:
containers:
- name: string
image: string
imagePullPolicy: [Always | Never | IfNotPresent]
command: [string]
args: [string]
workingDir: string
volumeMounts:
- name: string
mountPath: string
readOnly: boolean
ports:
- name: string
containerPort: int
hostPort: int
protocol: string
env:
- name: string
value: string
resources:
limits:
cpu: string
memory: string
requests:
cpu: string
memory: string
livenessProbe:
exec:
command: [string]
httpGet:
path: string
port: number
host: string
scheme: string
httpHeaders:
- name: string
value: string
tcpSocket:
port: number
initialDelaySeconds: 0
timeoutSeconds: 0
periodSeconds: 0
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure]
nodeSelector: object
imagePullSecrets:
- name: string
hostNetwork: false
volumes:
- name: string
emptyDir: {}
hostPath:
path: string
secret:
secretName: string
items:
- key: string
path: string
configMap:
name: string
items:
- key: string
path: string
YAML上述 yaml 文件中各字段的详细说明见下表:
属性名称 | 取值类型 | 是否必选 | 取值说明 |
version | String | Required | API 版本号,v1 |
kind | String | Required | 资源类型,pod |
metadata | Object | Required | 元数据 |
metadata.name | String | Required | Pod 的名称,命名需要符合 RFC 1035 规范 |
metadata.namespace | String | Required | Pod 所属的命名空间,默认值为 default |
metadata.labels[] | List | 自定义标签列表 | |
metadata.annotations[] | List | 自定义注解列表 | |
spec | Object | Required | Pod 的详细配置定义 |
spec.containers[] | List | Required | Pod 中的容器列表 |
spec.containers[].name | String | Required | 容器的名称,命名需要符合 RFC 1035 规范 |
spec.containers[].image | String | Required | 容器的镜像名称 |
spec.containers[].imagePullPolicy | String | 镜像拉取策略,可选值包括:Always、Never、IfNotPresent,默认值为Always。 (1) Always:表示每次都尝试重新拉取镜像。 (2) IfNotPresent:表示若本地镜像已存在,则使用本地的镜像,否则拉取镜像。 (3) Never:表示仅使用本地镜像。 另外,如果包含以下设置,系统则将默认设置 “imagePullPolicy=Always”: (1) 不设置imagePullPolicy,也未指定镜像的 tag; (2) 不设置imagePullPolicy,镜像 tag 为 latest; (3) 启用了名为“AlwayspPlllmages” 的准入控制器 (Admission Controller) | |
spec.containers[].command | List | 容器的启动命令列表,如果不指定,则使用镜像内置的启动命令 | |
spec.containers[].args | List | 容器的启动命令参数列表 | |
spec.containers[].workingDir | String | 容器的工作目录 | |
spec.containers[].volumeMounts[] | List | 挂载到容器内的存储卷配置 | |
spec.containers[].volumeMounts[].name | String | 引用 Pod 定义的共享存储卷的名称,需要使用volumes[] 部分定义的共享储存卷名称 | |
spec.containers[].volumeMounts[].mountPath | String | 存储卷在容器内挂载的绝对路径,应少于512个字符 | |
spec.containers[].volumeMounts[].readOnly | Boolean | 是否为只读模式,默认为读写模式 | |
spec.containers[].ports[] | List | 容器需要暴露的端口号列表 | |
spec.containers[].ports[].name | String | 端口的名称 | |
spec.containers[].ports[].containerPort | Int | 容器需要监听的端口号 | |
spec.containers[].ports[].hostPort | Int | 容器所在主机需要监听的端口号,默认与containerPort 相同。在设置 hostPort 时,同一台宿主机将无法启动 该容器的第2个副本。 | |
spec.containers[].ports[].protocol | String | 端口协议,支持 TCP 和UDP,默认值为TCP | |
spec.containers[].env[] | List | 在容器运行前需要设置的环境变量列表 | |
spec.containers[].env[].name | String | 环境变量的名称 | |
spec.containers[].env[].value | String | 环境变量的值 | |
spec.containers[].resources | Object | 资源限制和资源请求的设置 | |
spec.containers[].resources.limits | Object | 资源限制的设置 | |
spec.containers[].resources.limits.cpu | String | CPU 限制,单位为 core数,将用于 docker run –cpu-shares 参数 | |
spec.containers[].resources.limits.memory | String | 内存限制,单位可以为MiB、GiB 等,将用于docker run –memory 参数 | |
spec.containers[].resources.requests | Object | 资源请求的设置 | |
spec.containers[].resources.requests.cpu | String | CPU 请求,单位为 core数,即容器启动时的初始可用数量 | |
spec.containers[].resources.requests.memory | String | 内存请求,单位可以为MiB、GiB 等,即容器启动的初始可用数量 | |
spec.containers[].livenessProbe | Object | 对 Pod 内各容器健康检查的设置,在周期性健康检查无响应几次之后,系统将自动重启该容器。可以设置的方法包括:exec、 httpGet和tcpSocket。对一个容器仅需设置一种健康检查方法。 | |
spec.containers[].livenessProbe.exec | Object | 对 Pod 内各容器健康检查的设置,采用exec方式 | |
spec.containers[].livenessProbe.exec.command[] | String | 采用 exec 方式时需要指定的命令或者脚本 | |
spec.containers[].livenessProbe.httpGet | Object | 对 Pod 内各容器健康检查的设置,采用 httpGet 方式,需要指定 path、port | |
spec.containers[].livenessProbe.tcpSocket | Object | 对 Pod 内各容器健康检查的设置,采用 tcpSocket 方式 | |
spec.containers[].livenessProbe.initialDelaySeconds | Number | 容器启动完成后首次探测的时间,单位为 s | |
spec.containers[].livenessProbe.timeoutSeconds | Number | 对容器进行健康检查等特响应的超时时间设置,单位为 s,默认值为 1s 。若超过该超时时间,则认为容器不健康 | |
spec.containers[].livenessProbe.periodSeconds | Number | 对容器健康检查的定期检查时间设置,单位为 s ,默认 10s 检查一次 | |
spec.restartPolicy | String | Pod 的重启策略,可选值为 Always、OnFailure 默认值为 Always。 (1)Always:Pod 一旦终止运行,则无论容器是如何终止的,kubelet都将重启它。 (2)OnFailure:只有Pod 以非零退出码终止时,kubelet 才会重启该容器。如果容器正常结束(退出码为0),kubelet 则不会重启它。 (3) Never:在 Pod 终止后,kubelet 会将退出码报告给 Master,不会再重启该 Pod。 | |
spec.nodeSelector | Object | 设置 Node 的 Label,以key : value 格式指定,Pod 将被调度到具有这些 Label 的Node上。 | |
spec.imagePullSecrets | Object | 拉取镜像时使用的Secret 名称,以name : secretkey 格式指定。 | |
spec.hostNetwork | Boolean | 是否使用主机网络模式,默认值为 false。设置为”true”时,表示容器使用宿主机网络,不再使用 CNI 网络插件 | |
spec.volumes[] | List | 在该 Pod 中定义的存储卷列表 | |
spec.volumes[].name | String | 存储卷的名称,在一个Pod 中,每个存储卷都定义了一个名称,命名应符合 RFC 1035 规范。容器定义部分的 spec.containers[].volumeMounts[].name 将引用该共享存储卷的名称。 Volume 的类型包括: emptyDir、hostPath、 gcePersistentDisk、 awsElasticBlockStore、gitRepo、secret、nfs、 iscsi、glusterfs、persistentVolumeClaim、rbd、flexVolume、 cinder、cephfs、flocker、downwardAPI、fc、azureFile、configMap、 vsphereVolume,可以定义多个 Volume,每个Volume 的 name 都保持唯一。 | |
spec.volumes[].emptyDir | Object | 类型为 emptyDir 的存储卷,表示与 Pod 同生命周期的一个临时目录,其值为一个空对象: emptyDir:{} | |
spec.volumes[].hostPath | Object | 类型为 hostPath 的存储卷,表示 Pod 容器挂载的宿主机目录,通过 spec.volumes[].hostPath.path 指定 | |
spec.volumes[].hostPath.path | String | 类型为 hostPath 的存储卷的宿主机目录 | |
spec.volumes[].secret | Object | 类型为 secret 的存储卷,表示挂载集群预定义的 secret 对象到容器内 | |
spec.volumes[].configMap | Object | 类型为 configMap 的存储卷,表示挂载集群预定义的 configMap 资源对象的数据到容器内 |
2. Pod 的基本用法
Pod 可以由一个或多个容器组成,在下面的示例中,名为“frontend”的 Pod 只由一个容器组成:
# frontend-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
labels:
name: frontend
spec:
containers:
- name: frontend
image: php:8.2-fpm
ports:
- containerPort: 80
YAML另外一种场景是,当 frontend 和 redis 这两个容器应用为紧耦合的关系,并组合为一个整体对外提供服务时,应将这两个容器封装为一个 Pod 。
# frontend-localredis-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-php
labels:
name: redis-php
spec:
containers:
- name: frontend
image: php:8.2-fpm
ports:
- containerPort: 80
- name: redis
image: redis
ports:
- containerPort: 6379
# 属于同一个 Pod 的多个容器应用之间在相互访问时仅需通过 localhost 就可以通信
YAML创建上述两个 pod:
kubectl apply -f frontend-pod.yaml
kubectl apply -f frontend-localredis-pod.yaml
ShellScript查看已创建的 pod:
kubectl get pods
kubectl get pods -o wide
# 查看 pod 详细信息
kubectl describe pod redis-php
ShellScript删除 pod:
kubectl delete pod <pod_name>
ShellScript注意:同一个 pod 内的容器可以共享网络与存储资源。
3. Pod 的类型
pod 的类型分为普通 pod 和静态 pod 两大类,其中普通 pod 又分为裸部署 pod 和被控制器管理的 pod。
- 普通 pod:创建 pod 的请求是提交给 Api server 的。
- 裸部署 pod:资源清单里指定的 kind 就是 Pod ,与任何控制器资源都无关,没有自愈等由控制器实现的相关功能。
- 被控制器管理的 pod:可通过控制器实现自愈或者自己定制的相关功能。
- 静态 pod:直接通过配置文件或 HTTP 的方式交给 kubelet 创建的 pod ,不通过 API Server 创建。
创建静态 pod 有两种方式:
- 基于本地配置文件
- 基于网络上的配置文件
基于本地配置文件:
需要在 kubelet 的主配置文件中设置 staticPodPath (在比较旧的 Kubernetes 版本中也可以通过命令行参数 -pod-manifest-pth 进行配置,该命令行参数将被逐渐奔用),指定 kubelet 需要监控的配置文件所在的目录,kubelet 会定期扫描该目录,并根据该目录下的 .yaml 或 json 文件创建静态 Pod。(注意:kubelet 在扫描文件时会忽略以“.”开头的隐藏文件。)
kubelet 的默认 staticPodPath 为 /etc/kubernetes/manifests ,如果想修改为其他路径可修改该字段为 staticPodPath: /xxxx。在配置文件中如果该字段不存在,可以手动添加该字段,后重启 kubelet。
基于网络上的配置文件:
基本同上,只需将 staticPodPath 指向一个 URL 路径,例如:staticPodPath: http://example.com/static-pods。
4. Pod 的启动退出流程简述
- 创建pause基础容器,提供共享名称空间。
- 串行初始化容器,初始化容器运行成功后运行业务容器。
- 启动业务容器,启动那一刻会同时运行主容器上定义的 Poststart 钩子事件。
- startupProbe 健康状态监测,判断容器是否启动成功。
- 持续健康检测 livenessProbe、readnessProbe。
- 结束时,在容器结束之前会先执行 Prestop 钩子事件,然后才终止容器。
5. Pod 的生命周期管理
5.1. Pod 运行的各个阶段(Phase)
Phase | 描述 |
Pending | Pod 已被 API Server 接收,但尚未调度或容器未完全启动(如镜像下载中)。 |
Running | Pod 已完成调度到特定 Node,其包含的所有容器均已创建,并且至少有一个容器处于正在运行状态、正在启动状态或正在重启状态。 |
Succeeded | Pod 中的所有容器已成功完成任务并退出。这通常发生在执行一次性任务或作业后,所有容器成功完成并退出。 |
Failed | Pod 内的所有容器均已终止,但至少有一个容器在运行过程中发生了错误或异常。 |
Unknown | 由于某种原因无法获得 Pod 的状态,原因可能是从 Master 到 Pod 所在 Node 网络通信失败。 |
Pod 在创建之后,首先进入 Pending 阶段;然后等到至少一个容器正常启动就进入 Running 阶段;如果全部容器都运行完成并成功结束,则进人 Succeeded 阶段;如果有部分容器运行失败,则进人 Failed 阶段。在 Pod 生命周期内的各个阶段,Kubernetes 会持续监控其中每个容器的状态,并根据重启策略和健康检查策略进行相应操作。
5.2. Pod 的各种状态(Conditions)
Conditions
是一组更细粒度的状态,描述 Pod 是否满足某些关键条件。每个条件包含:
type
(类型)status
(True
/False
/Unknown
)lastProbeTime
(上一次探测 Pod 状态的时间戳)lastTransitionTime
(Pod 从上一个状态转换到当前状态的时间戳)reason
(原因)message
(详细信息)
常见的条件类型:
Condition Type | 描述 |
PodScheduled | Pod 是否已被调度到节点(status=True 表示已调度)。 |
PodReadyToStartContainers | Pod 已创建并且完成网络配置,可以启动容器。该特性从 v1.25 开始引入。 |
Initialized | 所有 Init 容器 是否成功完成(status=True 表示初始化完成)。 |
ContainersReady | 所有容器是否通过就绪探测(status=True 表示容器就绪)。 |
Ready | Pod 是否可提供服务(通常用于 Service 流量路由)。 |
查看 Pod 状态示例:
kubectl -n kube-flannel get pod kube-flannel-ds-956vj -o yaml
apiVersion: v1
kind: Pod
...
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2025-08-06T00:20:49Z"
status: "True"
type: PodReadyToStartContainers
- lastProbeTime: null
lastTransitionTime: "2025-07-14T02:08:31Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2025-08-06T00:21:02Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2025-08-06T00:21:02Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2025-07-14T02:07:40Z"
status: "True"
type: PodScheduled
Bash5.3. 容器的状态(ContainerStatuses)
ContainerStatuses
描述 Pod 中每个容器的详细状态,包括:
state
:容器的当前状态(Waiting
、Running
或Terminated
)。Waiting
(等待中),容器尚未启动,可能原因:ImagePullBackOff
:镜像拉取失败。CrashLoopBackOff
:容器崩溃后等待重启。ContainerCreating
:容器正在创建(如挂载卷未就绪)。
Running
(运行中),容器正在运行。Terminated
(已终止),表示容器运行结束。
lastState
:容器上一次的状态(用于排查崩溃或重启问题)。restartCount
:容器重启次数。
可通过 kubectl describe pod <pod_name>
命令查看容器详细信息。
5.4. Events(事件)
Events
记录 Pod 生命周期中的关键事件(如调度失败、镜像拉取错误等),可通过 kubectl describe pod <pod-name>
查看:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 10s default-scheduler Successfully assigned default/mypod to node-1
Normal Pulling 8s kubelet Pulling image "nginx"
Warning Failed 5s kubelet Failed to pull image "nginx:404"
Bash常见事件:
Scheduled
:Pod 已调度到节点。Pulling
/Pulled
:拉取镜像中/成功。Created
/Started
:容器创建/启动。Failed
/BackOff
:容器启动失败或崩溃。Evicted
:表示 Pod 被驱逐(Evicted)或驱逐出节点。当 Pod 被驱逐时,它的状态会变为 “Evicted”,这通常发生在节点资源不足或节点发生故障时。OOMkilled
:在 Kubernetes 中,如果一个容器被 OOM Killer 终止,容器的状态会被标记为 “OOMkilled”。- 系统级别的 OOM:系统内存不足,杀进程的范围是系统中所有的进程。
- k8s 级别的 OOM:针对某个 Pod,该 pod 的容器对内存的使用达到 limits 的限定。
5.5. Pod 的重启策略
Pod 的重启策略应用于 Pod 内所有容器,并且仅在 Pod 所处的 Node 上由 kubelet 进行判断和重启操作。Pod 的重启策略包括 Always、OnFailure 和 Never,默认为 Always。
- Always:当容器失效时,由 kubelet 自动重启该容器。
- OnFailure:当容器终止运行且退出码不为0时,由 kubelet 自动重启该容器。
- Never:不论容器处于哪种运行状态,kubelet 都不会重启该容器。
Pod 的重启策略与控制方式息息相关,控制器对 Pod 的重启策略要求如下:
- Deployment、ReplicationController (RC)、DaemonSet 和 StatefulSet:必须被设置为“Always”,需要保证该容器持续运行。
- Job:OnFailure 或 Never,确保容器执行完成后不再重启。
- 静态 pod:不允许设置 estartPolicy,在静态 pod 失效是会由 kubelet 自动重启。
5.6. Pod 终止和垃圾清理
在 Kubernetes 中,Pod 的终止和垃圾清理是一个系统化的过程,涉及优雅终止(Graceful Termination)、资源释放、垃圾回收机制等。
Pod 的终止流程:
- 触发终止
- 用户删除:通过
kubectl delete pod
或 API 请求删除。 - 系统驱逐:因资源不足、节点维护等被 kubelet 驱逐。
- 优先级抢占:高优先级 Pod 抢占低优先级 Pod 的资源。
- 用户删除:通过
- 优雅终止(Graceful Termination)
- API Server 标记 Pod 为“Terminating”。
- kubelet 探测到 Pod 状态为“Terminating”则向容器发送 SIGTERM 信号。
- 默认等待时间:30 秒(可通过
spec.terminationGracePeriodSeconds
修改)。
- 默认等待时间:30 秒(可通过
- 强制终止
- 如果容器在优雅终止期内未退出,kubelet 发送
SIGKILL
强制终止。
- 如果容器在优雅终止期内未退出,kubelet 发送
- 清理容器和网络资源
- 删除容器运行时(Docker/Containerd)中的容器实例。
- 释放 Pod 占用的网络接口(如 CNI 插件管理的 IP 地址)。
垃圾回收(Garbage Collection):
- 垃圾回收类型
资源类型 | 回收机制 |
终止的 Pod | kubelet 定期清理 Failed /Succeeded 状态的 Pod(需手动或配置自动清理)。 |
悬挂的镜像 | kubelet 根据磁盘压力自动清理未使用的容器镜像(通过 image-gc-high-threshold 配置)。 |
停止的容器 | kubelet 清理已退出的容器(通过 --container-gc-threshold 控制保留数量)。 |
Evicted Pod | 需手动清理或通过脚本定期删除(如 kubectl delete pods --field-selector=status.phase=Failed )。 |
- 配置示例
# kubelet 参数(通常在 /var/lib/kubelet/config.yaml 中配置)
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
memory.available: "500Mi"
nodefs.available: "10%"
imageGCHighThresholdPercent: 85 # 磁盘使用率超过 85% 时触发镜像清理
containerGCHighThreshold: 80 # 保留最多 80 个停止的容器
YAML6. 容器的探针和健康检查机制
容器探针(Probe)是Kubernetes中用于检测容器健康状况的机制,它通过定期执行诊断来评估容器的运行状态。
6.1. 探针类型
- Liveness Probe (存活探针)
- 作用:检测容器是否正在运行。
- 失败后果:kubelet 会杀死容器并根据重启策略决定是否重启。如果未配置该探针,则 kubelet 会认为探针返回的值永远为 Success。
- Readiness Probe (就绪探针)
- 作用:检测容器服务是否处于 Ready 状态,只有处于 Ready 状态的 Pod 才能接收请求。
- 失败后果:从 Service 的端点列表中移除该 Pod,停止向其发送流量。就绪探针也是定期触发的,存在于整个 Pod 生命周期。如果未配置该探针,则 kubelet 会认为探针返回的值永远为 Success。
- Startup Probe (启动探针)
- 作用:检测容器应用是否已启动。
- 失败后果:在启动探针成功前,其他探针不会执行,如果启动探针检测失败,kubelet 会杀死容器并根据重启策略决定是否重启。如果未配置该探针,则 kubelet 会认为探针返回的值永远为 Success。
6.2. 探针检查方式
上述三种探针都可以配置以下几种检查方式:
- exec:在容器内执行指定命令,返回0表示成功。
- tcpSocket:对指定端口进行 TCP 检查,如果能建立 TCP 连接表示成功。
- httpGet:对指定路径和端口发送HTTP GET请求,状态码2xx或3xx表示成功。
每种探针都可以配置如下字段:
- initialDelaySeconds:容器启动后等待多少秒开始探测,默认值为 0,最小值为 0。
- periodSeconds:执行探测的频率(秒),默认值为 10,最小值为 1。
- timeoutSeconds:探测超时时间(秒),当发生超时时则认为探针失败。默认值为 1,最小值为 1。
- successThreshold:探测连续成功多少次才认为成功,默认值为 1,最小值为 1。LivenessProbe 和 StartupProbe 该值必须被设置为 1。
- failureThreshold:探测连续失败多少次才认为失败,默认值为 3,最小值为 1。
配置示例:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- name: liveness
image: my-app:v1
livenessProbe:
httpGet:
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 1
failureThreshold: 3
readinessProbe:
exec:
command:
- cat
- /tmp/ready
initialDelaySeconds: 5
periodSeconds: 5
startupProbe:
httpGet:
path: /healthz
port: 8080
# 在下面的配置中,探测时间间隔 periodSeconds 被设置为 10s,失败次数 failureThreshold 被设置为 30 次,表示允许容器在 300s 内完成启动。这通常用来保护需要启动时间很长的容器。如果容器在 300s 后仍未启动,则探测启动失败,kubelet 会杀掉该容器,并根据重启策略决定是否重启。
failureThreshold: 30
periodSeconds: 10
YAML7. Pause 容器
Pause容器(Pause Container)是 Kubernetes 集群中一个特殊的辅助容器,主要用于为 Pod 提供共享的基础设施(如网络命名空间)。
核心功能:
- 共享网络命名空间:Pod中的多个容器共享同一个网络栈(相同的IP和端口空间),这是通过Pause容器实现的。Pause容器启动后,会创建网络命名空间,其他容器通过
Join
方式共享该空间,使它们可以通过localhost
直接通信。 - 充当PID 1进程:在Linux中,PID 1进程负责管理孤儿进程并避免僵尸进程。Pause容器作为Pod的“根容器”(PID 1),确保其他容器进程被正确回收。
使用 Pause 容器的优点:
- 解耦Pod生命周期与业务容器:如果业务容器崩溃重启,Pod的网络命名空间不会因此销毁(因为Pause容器仍在运行),确保Pod网络稳定性。
- 简化设计:通过一个轻量级、稳定的中间层管理共享资源,避免每个容器重复实现命名空间逻辑。
结构示例:
一个包含Nginx和Sidecar容器的Pod,实际结构如下:
Pod (IP: 10.1.0.3)
│
├── Pause容器(维护网络命名空间)
├── Nginx容器(共享Pause容器的网络)
└── Sidecar容器(共享Pause容器的网络)
TeXNginx和Sidecar通过localhost
直接通信,因为它们在同一个网络命名空间中。
查看 Pause 容器:
- 执行
kubectl describe pod <pod-name>
时,可以看到 Pause 容器的信息。通过容器运行时管理工具也能查看到它(名称包含pause
)。
8. Init 容器
8.1. Init 容器概述
初始化容器(Init Container)是在Pod的主容器启动之前运行的专用容器,用于执行初始化任务。它们与常规容器类似,但具有以下特点:
- 先于应用容器启动:必须成功完成才会启动主容器。
- 顺序执行:按照定义的顺序依次运行,并且只有前一个初始化容器运行成功才会运行行一个初始化容器。
- 一次性:运行完成后即终止,不会持续运行。不支持健康检查机制,应为必须在初始化容器运行成功后才能启动普通容器。
系统会在 Pod 的状态信息的 initContainerStatuses 字段中显示初始化容器的运行状态信息。
8.2. Init 容器使用场景
在很多应用场景中,应用容器在启动之前都可能需要进行一些初始化操作,例如:
- 等待其他关联组件正确运行(例如数据库或某个后台服务)。
- 预先基于环境变量或配置模板生成应用所需的配置文件。
- 从远程数据库中获取本地所需配置,或者将自身注册到某个中央数据库中。
- 下载相关依赖包,或者对系统进行一些预配置操作。
- 以更高的权限调整内核参数。
8.3. Init 容器基本配置示例
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
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; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
YAML在初始化容器中也可以设置资源限制、Volume 等等。但对资源限制的设置与应用容器略有不同,如下所述:
- 如果有多个初始化容器定义了资源请求或资源限制,则取最大的值作为所有初如化容器的资源请求值或资源限制值。
- Pod 的有效(effective)资源请求值或资源限制值取以下二者中的较大值:①所有应用容器的资源请求值或资源限制值之和;②初始化容器的有效资源请求值或资源限制值。
- 初始化容器终止后,其请求(request)和限制(limit)的CPU、内存资源会立即释放,只有应用容器的资源需求会被计入Pod的总资源需求。所以调度器在分配节点时,会考虑所有初始化容器和应用容器的资源请求中的最大值(即有效值),但运行后只保留常规容器的资源占用。
8.4. 将初始化容器作为长时间运行的边车容器
9. 钩子函数
9.1. 基本概念
PostStart 和 PreStop 是 Kubernetes 为容器提供的两种生命周期钩子(Lifecycle Hooks),允许在容器生命周期的特定时刻执行自定义操作。
对比概览:
特性 | PostStart | PreStop |
触发时机 | 容器启动后立即执行(异步运行) | 容器终止前执行 |
主要用途 | 初始化配置、服务注册 | 优雅关闭、服务注销 |
执行保证 | 不保证在ENTRYPOINT前完成 | 保证在容器终止前完成 |
失败影响 | 容器会被杀死,并根据RestartPolicy决定是否重启。 | 如果钩子运行失败,也会强制删除 Pod |
注意:如果一些初始化工作一定要在业务容器运行前运行,那就用 initcontainers 来执行,如果这些初始化工作没有要求必须在业务容器运行前运行,则可以使用 PostStart 来执行。
9.2. PostStart 钩子
配置方式:
# 示例1:Exec方式(执行命令)
lifecycle:
postStart:
exec:
command:
- "/bin/sh"
- "-c"
- "echo 'Container started' > /tmp/start.log"
# 示例2:HTTP方式(发送请求)
lifecycle:
postStart:
httpGet:
path: /initialize
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Initialization
YAML9.3. PreStop 钩子
配置方式:
# 示例1:Exec方式
lifecycle:
preStop:
exec:
command:
- "/bin/sh"
- "-c"
- "sleep 10 && nginx -s quit"
# 示例2:HTTP方式
lifecycle:
preStop:
httpGet:
path: /graceful-shutdown
port: 8080
YAML注意:当 Pod 开始终止时,Kubernetes 会执行 preStop
钩子。钩子有一个超时时间(默认为 30 秒,可通过 terminationGracePeriodSeconds 调整)。如果钩子在超时时间内没有成功完成,Kubernetes 会终止 Pod,而不再继续等待钩子完成。
9.3. 完整配置示例
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: main-container
image: nginx:1.19
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo 'Start at $(date)' >> /var/log/lifecycle.log"]
preStop:
exec:
command: ["/bin/sh", "-c", "nginx -s quit; echo 'Stop at $(date)' >> /var/log/lifecycle.log"]
volumeMounts:
- name: logs
mountPath: /var/log
volumes:
- name: logs
emptyDir: {}
YAML