Pod 是 Kubernetes 中最小的可部署、可调度、可管理单元。
通常可以把 Pod 理解为:
一个或多个容器
+ 共享网络命名空间
+ 共享存储卷
+ 统一的调度和生命周期最常见的 Pod 只运行一个业务容器:
Pod
└── app container也可以包含多个强关联容器:
Pod
├── app container
└── sidecar container例如:
但是,Pod 不是虚拟机,也不是通常意义上的进程组。它是 Kubernetes 调度和管理容器的基本边界。
如果 Kubernetes 直接以容器为最小单位,会很难表达多个容器之间的紧密关系。
Pod 提供了一个共同运行环境:
同一个 Pod 内的容器:
localhost 通信例如:
业务容器监听 8080
Sidecar 监听 15001业务容器可以访问:
localhost:15001但同一个 Pod 内不能让两个容器同时监听相同端口。
Pod 中的容器可以共同挂载 Volume:
volumes:
- name: shared-data
emptyDir: {}然后分别挂载:
volumeMounts:
- name: shared-data
mountPath: Pod 中的所有容器必须被调度到同一个节点。
调度器不是分别调度 Pod 内的每个容器,而是根据整个 Pod 的资源需求进行调度。
Pod 是一个整体:
主要组成部分:
| 部分 | 作用 |
|---|---|
metadata.name | Pod 名称 |
metadata.namespace | 所属 Namespace |
metadata.labels | 标签,用于选择和分组 |
metadata.annotations | 扩展元数据 |
|
Pod 本身没有一个简单固定的“类型枚举”。实际工作中,通常从以下几个维度分类。
直接通过 YAML 创建:
apiVersion: v1
kind: Pod适合:
不适合直接用于生产长期运行服务,因为它没有自动副本管理和发布能力。
生产环境最常见。
适合无状态服务:
Deployment
└── ReplicaSet
└── Pod用于:
适合有稳定身份和存储需求的服务:
StatefulSet
├── database-0
├── database-1
└── database-2特点:
适合:
但 StatefulSet 不会自动让普通应用变成高可用数据库,应用本身仍需要支持复制、选主和故障恢复。
每个符合条件的节点运行一个或多个 Pod:
DaemonSet
├── node-a: Pod
├── node-b: Pod
└── node-c: Pod适合:
Job 用于运行一次性任务,直到任务成功完成。
Job
└── Pod示例:
特点:
restartPolicy: Never 或 OnFailureJob 关注的是:
任务是否完成而不是:
服务是否一直运行CronJob 按时间周期创建 Job,Job 再创建 Pod。
CronJob
└── Job
└── Pod示例:
常见配置:
| 字段 | 作用 |
|---|---|
schedule | Cron 表达式 |
concurrencyPolicy | 是否允许任务并发 |
startingDeadlineSeconds | 错过调度后的最大补偿时间 |
successfulJobsHistoryLimit | 保留成功 Job 数 |
|
CronJob 的生产重点不是只有时间表达式,还包括:
DaemonSet 保证符合条件的节点上运行 Pod。
适合运行:
DaemonSet 的特殊风险是:
节点数量增加,Pod 数量和总资源消耗也会增加例如每个节点消耗 200m CPU,100 个节点就是约 20 CPU 的 request。
Static Pod 由节点上的 kubelet 直接管理,不由 API Server 或普通控制器创建。
通常通过 kubelet 配置目录定义:
/etc/kubernetes/manifests/例如:
/etc/kubernetes/manifests/etcd.yaml
/etc/kubernetes/manifests/kube-apiserver.yaml
/etc/kubernetes/manifests/kube-controller-manager.yaml
/etc/kubernetes/manifests/kube-scheduler.yaml常见于:
特点:
生产环境中不要随意修改控制平面 Static Pod 文件,变更前应确认:
Pod 内所有容器一定运行在同一个节点上。
如果一个 Pod 有:
业务容器
Sidecar
Init Container它们不能被分散到不同节点。
因此,一个 Pod 中的容器应该满足:
生命周期紧密相关
必须共享网络或存储
必须一起调度
必须共同扩缩容如果两个容器:
通常应该拆成两个工作负载,而不是强行放进一个 Pod。
Deployment、StatefulSet、HPA 扩缩容的对象都是 Pod。
如果一个 Pod 中有:
业务容器 + SidecarHPA 扩容时,两个容器会一起复制:
1 个 Pod -> 3 个 Pod不能只扩业务容器而不扩 Sidecar。
因此,容器是否放入同一个 Pod,需要考虑它们是否应该具有相同的:
Pod IP 通常具有以下特点:
应用之间访问通常应该使用 Service:
客户端 -> Service -> Pod而不是直接访问 Pod IP。
Service 提供:
Pod 的 status.phase 主要包括:
| Phase | 含义 |
|---|---|
Pending | 已创建,但尚未运行 |
Running | 至少一个容器正在运行 |
Succeeded | 所有容器成功退出 |
Failed | 至少一个容器失败退出,且不会继续重启 |
|
查看:
kubectl get pod -n production示例:
NAME READY STATUS RESTARTS AGE
api-1 1/1 Running 0 10m
job-1 0/1 Completed 0 2m注意:
Running 不等于业务一定可用Pod 处于 Running,只能说明容器进程处于运行状态,不代表:
需要结合探针和业务指标判断。
每个容器通常有以下状态:
| 状态 | 含义 |
|---|---|
Waiting | 等待启动或等待某个条件 |
Running | 正在运行 |
Terminated | 已退出 |
查看:
kubectl describe pod <pod-name> -n <namespace>或者:
kubectl get pod <pod-name> 常见 Waiting.reason:
ContainerCreating
ImagePullBackOff
ErrImagePull
CrashLoopBackOff
CreateContainerConfigError常见 Terminated.reason:
Completed
Error
OOMKilled一个 Pod 从提交到运行,大致经历:
任何一个阶段失败,都可能导致 Pod 停留在 Pending 或容器反复重启。
restartPolicyPod 级别的 restartPolicy 有:
restartPolicy: AlwaysrestartPolicy: OnFailurerestartPolicy: Never含义:
| 策略 | 行为 |
|---|---|
Always | 容器退出后总是重启 |
OnFailure | 容器异常退出时重启 |
Never | 容器退出后不重启 |
使用建议:
AlwaysNever 或 OnFailureNever 或 OnFailure实际上,Deployment 等长期运行控制器通常要求使用:
restartPolicy: AlwaysCrashLoopBackOffCrashLoopBackOff 表示:
容器启动后反复崩溃,kubelet 正在逐步增加重启等待时间常见原因:
排查命令:
--previous 用于查看上一次已经退出的容器日志。
删除 Pod 时通常会经历:
示例:
应用需要正确处理:
SIGTERM生产服务应该在收到 SIGTERM 后:
不要只依赖 kill -9,否则可能造成:
Kubernetes 提供三类常用探针。
用于判断应用是否完成启动。
适合:
在 Startup Probe 成功之前,通常不会执行 Liveness 和 Readiness 的正常判断。
用于判断 Pod 是否可以接收流量。
Readiness 失败时:
Readiness 适合检查:
用于判断容器是否已经失去自我恢复能力。
Liveness 连续失败时,kubelet 可能重启容器。
不应该把外部依赖全部放进 Liveness:
数据库暂时不可用
Redis 暂时不可用
下游接口暂时超时如果这些依赖失败就触发 Liveness,可能造成:
依赖故障 -> 所有 Pod 重启 -> 恢复能力更差更合理的做法通常是:
探针可以使用:
httpGet:
path: /healthz
port: 8080tcpSocket:
port: 8080
grpc:
port: 9090不同探针方式要根据应用能力选择。生产环境优先使用应用提供的专用健康检查接口,避免用复杂脚本模拟健康状态。
Pod
├── app
└── sidecar示例:
Sidecar 与主容器通常:
适合强耦合协作,但会增加:
主容器通过本地代理访问外部服务:
app -> localhost:8080 -> ambassador -> external service适合:
Sidecar 将主容器的输出转换成统一格式。
例如:
应用日志格式 -> Sidecar -> 统一日志格式
应用指标格式 -> Sidecar -> 统一指标格式适合接入统一监控、日志和审计体系。
Init Container 在业务容器之前顺序执行。
适合:
Init Container 的特点:
不建议让 Init Container 无限等待外部服务,应该配合超时和明确错误日志。
Kubernetes 常见网络模型是:
Pod-to-Pod 通信无需 NAT
Node-to-Pod 通信可达
Pod 可通过 Service 访问其他 PodPod 内所有容器共享:
IP 地址
网络接口
端口空间
localhost例如:
app 监听 8080
sidecar 监听 15001同一个 Pod 内访问:
localhost:8080
localhost:15001下面的配置:
ports:
- name: http
containerPort: 8080主要用于描述和元数据,不会自动创建 Service,也不会自动让外部访问。
要提供稳定访问,需要创建 Service:
流量路径:
客户端 -> Service:80 -> Pod:8080spec:
hostNetwork: falsePod 使用独立网络命名空间,最常见。
spec:
hostNetwork: truePod 直接使用节点网络。
适合某些节点级组件,但需要谨慎:
spec:
hostPID: truePod 可以看到节点进程,通常只用于特殊系统级工具。
spec:
hostIPC: true共享节点 IPC 命名空间,生产环境需要严格限制。
emptyDirPod 创建时生成,Pod 删除后数据消失:
volumes:
- name: cache
emptyDir: {}适合:
不适合:
emptyDir 使用内存数据写入内存,速度较快,但会消耗 Pod 内存。
需要注意:
emptyDir.medium: Memory 不是免费资源如果写入太多,可能导致容器或 Pod 内存压力。
生产持久数据通常使用 PVC:
容器挂载:
volumeMounts:
- name: data
mountPath: PVC 适合:
需要配合:
配置注入示例:
挂载:
需要注意:
nodeSelector最简单的节点选择:
spec:
nodeSelector:
workload: high-memory要求节点存在:
workload=high-memory适合简单的节点池选择。
更灵活:
两种常见类型:
| 类型 | 含义 |
|---|---|
requiredDuringSchedulingIgnoredDuringExecution | 必须满足 |
preferredDuringSchedulingIgnoredDuringExecution | 尽量满足 |
Pod Affinity:尽量与指定 Pod 放在一起。
Pod Anti-Affinity:尽量分散到不同节点或可用区。
示例:
含义:
同一个 api 应用的 Pod 不要调度到同一节点适合:
更明确地控制分布:
含义:
不同可用区之间的 api Pod 数量差异最多为 1生产环境中,高可用服务通常需要考虑:
节点维度
可用区维度
故障域维度节点设置 Taint:
kubectl taint nodes node-a workload=gpu:NoSchedulePod 设置 Toleration:
Toleration 只表示:
允许调度到带该 Taint 的节点它不等于:
一定调度到该节点通常还需要配合:
nodeSelector:
workload: gpu或 node affinity。
Pod 可以使用指定身份:
spec:
serviceAccountName: app-sa如果 Pod 需要访问 Kubernetes API,需要配合:
不要默认给业务 Pod 使用高权限 ServiceAccount。
Pod 级别:
容器级别:
常见安全原则:
privileged: true,除非确有必要Namespace 可以配置 Pod Security Admission 标签,例如:
常见级别:
privileged
baseline
restricted生产环境建议:
baseline 或 restrictedwarn 和 audit 观察enforce不推荐:
kind: Pod直接运行生产 API。
原因:
推荐:
Deployment -> Pod
StatefulSet -> Pod
DaemonSet -> Pod
Job -> Pod
CronJob -> Job -> Pod资源配置会影响:
一个比较完整的服务容器:
应用自身也应正确处理 SIGTERM。
PDB 主要保护:
它不能阻止:
至少保证关键服务的副本不全部落在同一节点:
跨可用区部署时,还可以使用:
topologyKey: topology.kubernetes.io/zone对于关键服务:
maxUnavailable: 0 可以减少发布期间容量下降maxSurge 不能太大,否则会突然增加资源需求配套 Service:
适合:
两个容器共享:
/var/run/app 目录注意需要分别设置:
适合:
注意:
StatefulSet 只提供稳定身份和存储编排,
不会自动替数据库实现复制、选主和故障恢复。这种 Pod 通常需要:
hostPath 具有较高风险,因为它直接访问节点文件系统。生产环境应:
/生产注意事项:
concurrencyPolicy: Forbid 表示上一次任务未完成时,不启动下一次任务。
清理任务尤其要注意:
Pod 创建后,一般不能随意修改其核心字段。很多字段修改会被 API Server 拒绝,常见做法是:
修改工作负载模板
|
v
控制器创建新 Pod
例如修改 Deployment:
会触发 ReplicaSet 滚动更新。
不建议直接修改线上 Pod 来完成发布,因为:
以下变化通常会触发新的 ReplicaSet:
仅仅修改 Deployment 的副本数,不会触发新的 Pod 模板版本。
例如:
更新期间可能最多存在:
5 个旧 Pod + 2 个新 Pod因此需要预留:
否则可能出现:
新 Pod Pending
Deployment ProgressDeadlineExceeded
ResourceQuota exceededPod 适合执行工作负载,但 Pod IP 不稳定。Service 提供稳定访问入口。
Deployment -> Pod
Service -> 选择 Pod
客户端 -> ServiceService 通过 Selector 选择 Pod:
Pod 必须有匹配标签:
metadata:
labels:
app: api如果标签不匹配,Service 会没有 Endpoint。
排查:
kubectl get endpointslice -n production
常见问题:
Pod Running
Service 也存在
但访问不到服务可能原因:
127.0.0.1适合:
环境变量在容器启动时生成。Secret 或 ConfigMap 更新后,已经运行的进程通常不会自动获得新的环境变量值。
挂载文件可能被 kubelet 最终更新,但应用是否重新读取取决于应用本身。
常见处理方式:
如果应用需要写临时文件,可以挂载专门的 emptyDir:
这样可以在根文件系统只读的情况下保留必要的临时写入能力。
以下配置需要严格审查:
还应避免:
volumeMounts:
- name: docker-socket
mountPath挂载容器运行时 Socket 可能使容器获得近似节点控制能力。
完整的终止流程通常是:
推荐应用自身处理 SIGTERM,而不是只依赖:
preStop 的作用通常是提供额外的下线窗口,但不能替代应用的优雅关闭逻辑。
生产配置示例:
应用应确保:
kubectl describe pod <pod-name> -n <namespace>重点检查:
常见原因:
常见原因:
检查:
kubectl describe pod <pod-name> -n <namespace>可能原因:
私有仓库示例:
spec:
imagePullSecrets:
- name: registry-secret检查:
如果容器启动后立即退出,通常优先查看:
kubectl logs --previous检查:
重点确认:
targetPort 是否正确localhost检查:
同时观察:
不要直接盲目扩大内存 limit。应先确认:
是应用泄漏?
是峰值不足?
是缓存配置过大?
是 JVM/Go 参数不合理?
是 Sidecar 占用?
是节点压力驱逐?仅设置:
replicas: 3不能保证三个 Pod 分布在不同故障域。
还需要考虑:
如果三个副本都在同一节点,该节点故障可能同时丢失全部副本。
PDB 可以限制:
不能防止:
所以 PDB 不是故障转移机制,而是运维中断保护机制。
推荐工作负载结构:
无状态服务:Deployment
有稳定身份和存储:StatefulSet
每节点一个实例:DaemonSet
一次性任务:Job
定时任务:CronJob
集群底层组件:Static Pod 或专用控制器生产 Pod 通常至少应考虑:
适合放在同一个 Pod:
应用 + 必须共享 localhost 的代理
应用 + 必须共享文件目录的 Sidecar
应用 + 启动前配置初始化容器不适合放在同一个 Pod:
两个可以独立扩缩容的服务
两个发布周期不同的服务
两个资源模型差异很大的服务
两个故障域不同的服务Pod 不是:
应用应该尽量做到:
可重启
可重建
可迁移
无状态或状态外置
错误做法:
把业务配置写死到某个 Pod IP正确做法:
通过 Service DNS 访问服务StatefulSet 场景下,才可以利用稳定的 Pod DNS,例如:
postgres-0.postgres.data.svc.cluster.local但也应确保应用具备正确的集群发现和故障处理能力。
需要分别评估:
不能只管理主业务容器,而忽略 Sidecar 或 Init Container。
最重要的一点:
Pod 负责承载运行实例;
控制器负责维持期望状态;
Service 负责稳定访问;
Volume 负责存储;
Policy 负责约束;
监控负责验证。Pod 是 Kubernetes 中最小的可调度和可部署单元,由一个或多个紧密协作的容器组成。
它提供:
共享网络
共享存储
共同调度
共同生命周期
统一扩缩容边界常见 Pod 来源包括:
裸 Pod
Deployment
StatefulSet
DaemonSet
生产环境中:
无状态服务使用 Deployment
有状态服务使用 StatefulSet
节点级组件使用 DaemonSet
一次性任务使用 Job
周期性任务使用 CronJob一个成熟的生产 Pod 设计通常需要同时处理:
最核心的理解是:
Pod 不是一个长期存在的服务器,
而是一个可以被调度、创建、销毁和替换的运行单元。生产环境应让控制器管理 Pod,让 Service 访问 Pod,让 PVC 保存数据,让探针判断状态,让资源配置约束消耗,让监控和策略保证整体运行质量。 有。前面已经覆盖了 Pod 的主体内容,下面补充一些更偏底层和生产治理的高级细节。
status.phase 只有几个粗粒度状态,排障时更应该查看 Pod Conditions:
kubectl get pod <pod-nam常见 Conditions:
| Condition | 含义 |
|---|---|
PodScheduled | 是否已经成功调度到节点 |
Initialized | Init Container 是否执行完成 |
ContainersReady | 所有容器是否 Ready |
Ready | Pod 是否可以接收业务流量 |
例如:
Pod phase: Running
Ready: False这表示容器可能正在运行,但还没有通过 Readiness Probe,Service 不应该把流量发送给它。
排查时建议同时看:
除了容器探针,Pod 还可以使用自定义 Readiness Gate。
示意:
spec:
readinessGates:
- conditionType: "example.com/load-balancer-ready"外部控制器可以更新:
只有当自定义 Condition 和容器 Readiness 都满足时,Pod 才会整体 Ready。
适合:
这比简单地让容器启动后立即接流量更可靠。
这是非常重要的区别:
Readiness 失败:
Pod 暂时不接收 Service 流量
因此,业务应用不应该通过返回 Readiness 失败来掩盖永久性启动错误,也不应该把所有异常都放进 Liveness。
推荐设计:
/startup:应用是否完成初始化
/ready:是否可以接收流量
/healthz:进程是否还能继续运行一个过于激进的 Liveness Probe:
意味着一次短暂网络或 GC 抖动就可能触发重启。
生产环境应该结合:
合理设置:
timeoutSeconds
periodSeconds
failureThreshold
initialDelaySeconds对于启动慢的应用,优先使用 startupProbe,不要把 initialDelaySeconds 无限调大。
Pod UID 不变,通常是同一个 Pod 内的容器被重新启动:
Pod 仍然存在
容器 restartCount 增加
Pod IP 通常不变控制器删除旧 Pod,再创建新 Pod:
旧 Pod UID 消失
新 Pod UID 产生
Pod IP 可能变化
本地临时数据丢失例如:
kubectl delete pod <pod-name> -n <namespace>如果它由 Deployment 管理,通常会创建新的 Pod。
排查问题时要区分:
应用进程在同一个 Pod 中反复重启
还是 Pod 本身被控制器替换Pod 名称和 UID 都不应该被业务当作永久身份。
以下内容都可能变化:
如果应用需要稳定身份,应使用:
但即使使用 StatefulSet,也不能假设 Pod 永远不会被重建。
Ephemeral Container 用于向正在运行的 Pod 中临时注入调试容器。
适合:
curl、nslookup、tcpdump注意:
生产建议:
临时授权
明确审计
限定 Namespace
排障完成后记录和清理shareProcessNamespace 可以共享进程视图Pod 可以配置:
spec:
shareProcessNamespace: true这样同一 Pod 内的容器可以看到彼此的进程。
适合:
但要注意:
默认情况下,同一 Pod 内的容器通常不会共享完整的进程命名空间。
默认 DNS 策略通常是:
dnsPolicy: ClusterFirst这意味着 Pod 使用集群 DNS 解析 Service 和集群域名。
常见配置:
spec:
dnsPolicy: ClusterFirstHostNetwork Pod 通常需要:
spec:
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet还可以使用:
生产中 DNS 问题可能表现为:
ndots 导致查询次数增加排查:
普通容器的启动顺序通常不应被业务强依赖。
如果容器 B 必须等待容器 A 完成初始化,优先考虑:
不要简单假设:
YAML 中排在前面的容器一定先完全启动容器启动和应用真正 Ready 是两个概念。
传统 Sidecar 通常与主容器一起运行。如果主容器退出,Sidecar 可能仍然继续运行,导致 Job Pod 无法完成。
典型问题:
主任务已完成
Sidecar 仍在运行
Pod 一直处于 Running
Job 不会结束对于 Job + Sidecar,需要考虑:
不能只把长期运行的代理容器直接放进 Job。
节点关机时,kubelet 可以根据配置执行优雅关机,让 Pod 按顺序收到终止信号。
需要关注:
terminationGracePeriodSeconds对于有状态服务,节点关机期间的优雅终止尤其重要。
常见中断类型:
例如:
PDB 通常可以参与保护。
例如:
PDB 通常不能阻止。
因此高可用不能只依赖 PDB,还需要:
多副本
跨节点分布
跨可用区分布
正确的 Service
数据复制
故障恢复机制命令:
会绕过正常终止流程,可能造成:
生产环境仅在确认 Pod 所在节点已经不可达或对象严重卡死时使用。
terminationGracePeriodSeconds 需要按业务设置默认值通常是 30 秒,但不同应用差异很大:
| 应用类型 | 可能需要关注的终止时间 |
|---|---|
| 无状态 HTTP | 等待在途请求完成 |
| 消息消费者 | 等待当前消息处理完成 |
| 数据库 | 刷盘、关闭连接、完成选主 |
| 批处理 | 保存进度或输出结果 |
| 大模型服务 | 卸载模型和释放设备 |
如果设置太短:
应用来不及完成清理,最终被 SIGKILL如果设置太长:
发布、扩缩容和节点维护变慢应结合真实关闭时间和最大在途请求时间测试。
一个 Pod 的资源峰值可能出现在不同阶段:
Init Container 阶段
应用启动阶段
正常运行阶段
流量峰值阶段
优雅退出阶段例如:
因此不能只测稳定运行 5 分钟就决定资源规格,应该覆盖完整生命周期。
可以使用下面的检查框架:
Pod 的高级理解可以归纳为:
Pod 是资源、网络、存储、调度、生命周期和安全策略的组合边界。其中:
生产环境真正需要管理的,不只是“Pod 能不能启动”,而是:
Pod 是否能被正确调度
是否能安全接流量
是否能平滑发布
是否能正确终止
最核心的一句话是:
Pod 是短生命周期、可替换的运行实例;
生产系统应该围绕 Pod 的可替换性来设计,而不是把 Pod 当成固定服务器。还有一些,主要是 Pod 的边界行为、调度细节、版本更新风险和生产运维规范。这些内容在实际故障处理中很有价值。
同一个 Pod 内的容器共享:
网络命名空间
IP 地址
端口空间
IPC 命名空间(取决于配置)
但它们并不自动共享:
文件系统根目录
环境变量
进程空间
Linux capabilities
例如,同一个 Pod 内的两个容器不能直接访问对方的根文件系统,除非通过共享 Volume。
每个容器可以有自己的:
resources:
requests:
limits:但它们最终运行在同一个 Pod 和节点上。
一个容器资源异常,可能影响:
例如:
Sidecar 内存泄漏可能导致:
Sidecar OOM
Pod 重启
业务容器连接中断
Service Endpoint 短暂减少所以 Sidecar 不能被当作“免费附属进程”。
同一个 Pod 内,某个容器崩溃时,kubelet 会根据 restartPolicy 处理该容器。
例如:
业务容器崩溃
Sidecar 仍然运行这时 Pod 可能仍然是:
Running但业务已经不可用。
因此不能只判断 Pod Phase,还要检查:
生产监控应按容器维度监控:
Pod Ready 通常不是只由一个容器决定,而是综合:
所有业务容器的 Readiness
+ Readiness Gates
+ Pod 条件例如一个 Pod 有两个容器:
app:Ready
sidecar:NotReady整个 Pod 可能仍然不是 Ready,Service 不应将其作为可用后端。
因此,部署多容器 Pod 时需要确认:
传统 Sidecar 通常写在:
spec:
containers:而较新的 Kubernetes 版本开始支持原生 Sidecar 语义,通常通过 Init Container 的特殊配置表达长期运行的初始化容器。
概念上类似:
这种方式可以改善:
但是否可用取决于 Kubernetes 版本和相关 Feature Gate。使用前检查:
kubectl explain pod.spec.initContainers.restartPolicy
kubectl version不要在未验证集群兼容性的情况下直接使用。
普通 Pod 一旦被调度到节点,通常不会被调度器“搬迁”到另一个节点。
当节点故障、Pod 被驱逐或控制器发现实例缺失时,常见流程是:
删除旧 Pod
创建新 Pod
重新调度因此应用必须能够承受:
如果业务无法接受这些变化,就需要使用:
以下数据一般不应作为持久数据:
容器可写层
emptyDir
/var/tmp
/tmp
应用本地缓存
Pod 内生成的临时文件Pod 删除后,这些数据通常都会丢失。
需要持久化的数据应使用:
PVC
外部数据库
对象存储
消息系统
分布式文件系统即使是 StatefulSet,也不是因为 Pod 名称稳定就自动拥有持久化能力,必须显式配置 PVC。
删除 StatefulSet 或 Pod 时,PVC 是否保留,取决于具体配置和操作方式。
生产数据库需要明确:
删除 Pod 是否保留 PVC
删除 StatefulSet 是否保留 PVC
缩容 StatefulSet 是否保留 PVC
数据恢复如何执行
PVC 是否有快照和备份不要把下面两件事混为一谈:
删除 Pod
删除 PVC删除 Pod 通常不等于删除 PVC,但执行批量清理、Namespace 删除或自动化脚本时,可能连带删除存储对象。
一个 Pod 的标签如果同时匹配多个控制器,可能造成混乱。
例如:
Deployment A selector: app=api
Deployment B selector: app=api两个控制器都可能认为自己管理这些 Pod。
生产环境要求:
不同控制器的 selector 必须互不冲突检查:
kubectl get deployment,statefulset,daemonset -A -o yaml重点审查:
spec.selector这是控制器管理 Pod 时非常重要的设计约束。
查看 Pod 的控制器归属:
通常关系是:
Deployment
└── ReplicaSet
└── Pod删除对象时,Kubernetes 可能根据 OwnerReference 执行级联删除。
例如删除 ReplicaSet,可能导致其 Pod 被删除;删除 Deployment,通常会进一步影响 ReplicaSet 和 Pod。
批量删除前建议先确认:
kubectl get pod <pod-name> 查看:
metadata:
ownerReferences:restartPolicy: Always 只能让 kubelet尝试重启容器,不能替代 Deployment 的副本管理。
区别如下:
| 能力 | restartPolicy | Deployment |
|---|---|---|
| 重启退出容器 | 可以 | 间接支持 |
| Pod 被删除后重新创建 | 不可以 | 可以 |
| 副本数管理 | 不可以 | 可以 |
| 滚动更新 | 不可以 | 可以 |
| 回滚 | 不可以 | 可以 |
| HPA | 不可以 | 可以 |
| 版本历史 | 不可以 | 可以 |
因此:
容器级故障恢复:restartPolicy
Pod 实例级恢复:控制器
业务副本级恢复:Deployment/StatefulSet可以给 Pod 配置:
spec:
priorityClassName: production-criticalPriorityClass 会影响:
但高优先级 Pod 不应被无限使用。生产环境要配合:
否则普通业务可能滥用高优先级,导致其他工作负载被抢占。
如果高优先级 Pod 无法调度,调度器可能抢占低优先级 Pod,为其释放资源。
因此资源不足时,可能出现:
高优先级 Pod 调度成功
低优先级 Pod 被终止需要注意:
生产中应该谨慎使用抢占,尤其是跨团队共享集群。
activeDeadlineSeconds 适合限制任务最长运行时间Job 或一次性 Pod 可以设置:
spec:
activeDeadlineSeconds: 3600表示 Pod 最长运行 1 小时。
适合:
超过期限后,Pod 会被终止。它不能解决任务本身的逻辑重试问题,还需要结合:
backoffLimit
restartPolicy
ttlSecondsAfterFinishedterminationMessagePolicy 可以保留退出摘要容器退出时,可以配置终止消息:
Kubernetes 可以将容器终止信息写入:
/dev/termination-log适合保存:
它不能替代完整日志系统,但有助于查看:
kubectl describe pod <pod-name>中的退出信息。
使用:
kubectl logs <pod-name> -n <namespace>读取的是容器标准输出和标准错误。
Pod 被删除后,Pod 日志通常也会随着节点上的容器文件被清理。生产环境不能只依赖 kubectl logs,应将日志发送到:
Elasticsearch/OpenSearch
Loki
云日志服务
Kafka
对象存储推荐应用写入:
stdout/stderr然后由节点级日志 Agent 采集,而不是让每个应用自行写入不可管理的本地文件。
如果应用同时:
写 stdout
写本地文件日志 Agent 可能采集两份,导致:
生产环境应明确:
应用日志输出位置
日志采集方式
日志轮转策略
失败缓存策略
节点磁盘上限推荐使用稳定、规范的标签:
标签会影响:
修改关键标签可能改变:
因此标签不是普通备注,而是资源之间的连接契约。
annotations 适合保存:
配置声明
注入开关
变更信息
外部系统元数据例如:
metadata:
annotations:
example.com/release: "2025-01-01"但 Service、Deployment Selector、NetworkPolicy 等选择逻辑主要基于 Label,而不是 Annotation。
不要把需要被选择、分组或路由的字段放在 Annotation 中。
生产 Pod 不只需要关注运行时安全,还应关注镜像供应链:
latest更稳定的方式:
containers:
- name: app
image: 相比:
image: example/app:latestDigest 能避免同一个 Tag 在不同时间指向不同镜像。
latestlatest 带来几个问题:
建议使用:
明确版本 Tag
或镜像 Digest并根据发布策略设置:
imagePullPolicy: IfNotPresent或:
imagePullPolicy: Always但 imagePullPolicy 不能替代版本固定。
securityContext一个常见的加固示例:
但必须结合应用实际需要。若应用需要写入固定目录,就应通过 Volume 提供可写位置,而不是直接放开整个根文件系统。
一个容器是否应该放进某个 Pod,可以问以下问题:
如果大部分答案是否定的,通常应该拆成不同的工作负载,通过:
Service
ConfigMap
Secret
消息队列
共享存储
API进行协作。
Pod 的完整定位可以概括为:
Pod 是 Kubernetes 中一组强耦合容器的最小运行环境,
同时也是调度、网络、存储、健康检查、资源和生命周期的组合边界。生产环境最重要的不是记住 Pod 有多少字段,而是理解它的边界:
Pod 可以被替换
Pod IP 可以变化
Pod 数据默认不持久
Pod 内容器共同调度
Pod 是扩缩容和故障恢复的基本单位
Pod 不应直接当作固定服务器使用一个可靠的生产系统应围绕 Pod 的可替换性设计:
还有,但已经进入 Kubernetes Pod 的高级边界和运维细节。下面补充一些前面未展开的内容。
较新的 Kubernetes 支持 schedulingGates,可以在 Pod 创建后暂时阻止调度:
spec:
schedulingGates:
- name: example.com/network-ready外部控制器完成准备工作后,移除对应 Gate,Pod 才允许被调度。
适合:
排查 Pending Pod 时,如果看到:
PodScheduled=False还应检查是否存在:
spec:
schedulingGatesPod 可能已经成功调度,但随后卡在 Volume 阶段:
PodScheduled=True
Initialized=False常见原因:
排查:
对于 ReadWriteOnce 存储,不能简单认为多个 Pod 可以同时挂载到不同节点。
Readiness 和 Service Endpoint 不是完全同步的Readiness 变化后,EndpointSlice 更新和各节点网络规则同步需要一定时间。
因此下线流程不能只做:
返回 Readiness=false
立即退出进程更稳妥的流程是:
设置应用为不可接收新流量
等待 EndpointSlice 和网络规则传播
等待在途请求完成
处理 SIGTERM
退出常见做法是:
但 sleep 只是简单的缓冲手段,最好由应用实现明确的 drain 机制。
Service 通常只选择:
标签匹配
且 Ready
且符合 EndpointSlice 条件的 Pod。
因此:
Pod Running并不意味着它一定是 Service 的后端。
检查 Service 后端:
如果 Pod Running 但无法接流量,重点检查:
publishNotReadyAddressespublishNotReadyAddresses 要谨慎使用Headless Service 或 StatefulSet 场景有时会配置:
spec:
clusterIP: None
publishNotReadyAddresses: true这意味着即使 Pod 尚未 Ready,也可能被发布到 DNS 或 Endpoint 中。
适合:
但普通在线服务不建议使用,否则可能把尚未准备好的 Pod 暴露给客户端。
Projected Volume 可以将多个数据源组合到一个目录:
适合统一挂载:
这比在容器中配置多个不同目录更容易管理。
可以关闭自动挂载:
spec:
automountServiceAccountToken: false如果业务不需要访问 Kubernetes API,建议关闭。
如果需要访问,应显式使用:
spec:
serviceAccountName: app-sa
automountServiceAccountToken: true并通过 RBAC 只授予最小权限。
生产中常见风险是:
业务容器不需要 Kubernetes API
但默认拿到了 ServiceAccount Token这会增加凭据泄露后的攻击面。
Pod 可以将自身元数据注入环境变量:
也可以挂载到文件:
适合:
不要把 Pod IP 当作永久身份。
配置:
spec:
hostname: app-0
subdomain: app结合 Headless Service,可以形成稳定 DNS 结构:
app-0.app.namespace.svc.cluster.localStatefulSet 会自动使用类似机制提供稳定网络身份。
适合:
但稳定 hostname 不代表数据一定持久,数据仍需要 PVC 或外部存储。
hostAliases 只适合非常有限的场景可以向 Pod 的 /etc/hosts 注入静态解析:
适合:
不适合:
因为它不会自动跟随目标 IP 变化。
Pod 默认能否互相访问,取决于 CNI 和集群网络策略。生产环境不能只依赖“默认行为”。
示例:只允许同 Namespace 中带 app=frontend 的 Pod 访问后端:
还要注意:
即使 Pod 配置了:
runAsNonRoot: true仍需要关注:
Pod 安全应分为:
镜像供应链安全
运行时权限安全
网络安全
身份和凭据安全
主机隔离
数据安全即使 Pod 没有超过自己的 memory limit,也可能因为节点整体压力被驱逐。
典型情况:
节点可用内存低于 evictionHardkubelet 开始驱逐 Pod。
常见条件:
MemoryPressure
DiskPressure
PIDPressure查看节点状态:
kubectl describe node <node-name>Pod 被驱逐时可能看到:
Reason: Evicted这与:
Reason: OOMKilled不是同一件事。
PriorityClass 决定调度优先级,QoS 主要反映资源配置方式。
一个 Pod 可以同时具有:
PriorityClass: high
QoS: Burstable也可以:
PriorityClass: normal
QoS: Guaranteed不要把二者混为一谈:
| 机制 | 主要作用 |
|---|---|
| QoS | 资源配置和压力处理相关 |
| PriorityClass | 调度排序和抢占相关 |
| PDB | 主动中断保护 |
| ResourceQuota | Namespace 总量限制 |
如果集群同时有 amd64 和 arm64 节点,可以使用:
nodeSelector:
kubernetes.io/arch: arm64也可以通过 Node Affinity 选择:
还可以关注:
kubernetes.io/os
kubernetes.io/arch生产中常见问题:
推荐:
image: registry.example.com/api:v1.2.3更严格:
image: registry.example.com/api@sha256:...不建议:
image: registry.example.com/api:latest原因:
镜像版本、PodTemplate 和 Git 提交应当可以相互追溯。
一个长期运行的生产服务 Pod,至少应具备:
Pod 的完整边界可以概括为:
Pod 是 Kubernetes 中最小的运行和调度单元,
但不是永久主机,也不是单纯的容器集合。它同时承载:
生产环境设计 Pod 时,应围绕以下事实展开:
最终推荐的设计模型是:
这部分已经覆盖了 Pod 的 API 结构、管理类型、网络、存储、调度、安全、生命周期、健康检查、发布、故障处理和生产治理边界。
apiVersion: v1
kind: Pod
metadata:
name: nginx
namespace: default
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- name: http
containerPort: 80
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"| 业务容器 |
spec.initContainers | 初始化容器 |
spec.volumes | 存储卷 |
spec.nodeSelector | 节点选择 |
spec.affinity | 亲和性和反亲和性 |
spec.tolerations | 容忍节点 taint |
spec.restartPolicy | 容器重启策略 |
spec.securityContext | 安全上下文 |
spec.serviceAccountName | 使用的身份 |
spec.dnsPolicy | DNS 策略 |
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
namespace: production
spec:
backoffLimit: 3
activeDeadlineSeconds: 1800
template:
spec:
restartPolicy: Never
containers:
- name: migration
image: example/migration:v1.0.0
command: ["/app/migrate"]
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2"
memory: "1Gi"apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-report
namespace: production
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 86400
template:
spec:
restartPolicy: Never
containers:
- name: report
image: example/report:v2.0.0
command: ["/app/generate-report"]
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2"
memory: "2Gi"| 保留失败 Job 数 |
ttlSecondsAfterFinished | 完成后自动清理 Job |
backoffLimit | 失败重试次数 |
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
tolerations:
- operator: Exists
containers:
- name: node-exporter
image: prom/node-exporter:v1.8.0
resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "200m"
memory: "256Mi"| 无法获取 Pod 状态 |
创建 Pod 对象
|
v
Admission 默认值和策略校验
|
v
Scheduler 选择节点
|
v
kubelet 接收 Pod
|
v
拉取镜像
|
v
创建 Sandbox
|
v
配置网络
|
v
挂载 Volume
|
v
运行 Init Container
|
v
运行业务容器
|
v
执行 Startup/Readiness/Liveness 探针kubectl describe pod <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous发送删除请求
|
v
执行 PreStop Hook
|
v
从 Service Endpoint 中移除
|
v
发送 SIGTERM
|
v
等待 terminationGracePeriodSeconds
|
v
发送 SIGKILLspec:
terminationGracePeriodSeconds: 30
containers:
- name: app
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"]startupProbe:
httpGet:
path: /startup
port: 8080
failureThreshold: 30
periodSeconds: 10readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3spec:
initContainers:
- name: init-config
image: busybox:1.36
command: ["sh", "-c", "cp /source/config /work/config"]
volumeMounts:
- name: work
mountPath: /work
containers:
- name: app
image: example/app:v1
volumeMounts:
- name: work
mountPath: /app/config
volumes:
- name: work
emptyDir: {}apiVersion: v1
kind: Service
metadata:
name: api
namespace: production
spec:
selector:
app: api
ports:
- name: http
port: 80
targetPort: 8080volumes:
- name: cache
emptyDir:
medium: Memory
sizeLimit: 256Mivolumes:
- name: data
persistentVolumeClaim:
claimName: app-datavolumes:
- name: config
configMap:
name: app-config
- name: secret
secret:
secretName: app-secretvolumeMounts:
- name: config
mountPath: /etc/app/config
- name: secret
mountPath: /etc/app/secret
readOnly: trueaffinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: workload
operator: In
values:
- high-memoryaffinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app: api
topologyKey: kubernetes.io/hostnametopologySpreadConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: apitolerations:
- key: workload
operator: Equal
value: gpu
effect: NoSchedulespec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefaultcontainers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALLmetadata:
labels:
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restrictedresources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"containers:
- name: api
image: example/api:v1.0.0
ports:
- name: http
containerPort: 8080
startupProbe:
httpGet:
path: /startup
port: http
failureThreshold: 30
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: http
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
livenessProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 10
timeoutSeconds: 2
failureThreshold: 3spec:
terminationGracePeriodSeconds: 30
containers:
- name: api
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- "sleep 5"apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: api-pdb
namespace: production
spec:
minAvailable: 2
selector:
matchLabels:
app: apitopologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: apistrategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0apiVersion: apps/v1
kind: Deployment
metadata:
name: api
namespace: production
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
terminationGracePeriodSeconds: 30
containers:
- name: api
image: example/api:v1.2.0
ports:
- name: http
containerPort: 8080
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"
startupProbe:
httpGet:
path: /startup
port: http
failureThreshold: 30
periodSeconds: 5
readinessProbe:
httpGet:
path: /ready
port: http
periodSeconds: 5
livenessProbe:
httpGet:
path: /healthz
port: http
periodSeconds: 10apiVersion: v1
kind: Service
metadata:
name: api
namespace: production
spec:
selector:
app: api
ports:
- port: 80
targetPort: httpapiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
containers:
- name: app
image: example/app:v1
volumeMounts:
- name: shared
mountPath: /var/run/app
- name: log-forwarder
image: example/log-forwarder:v1
volumeMounts:
- name: shared
mountPath: /var/run/app
volumes:
- name: shared
emptyDir: {}apiVersion: v1
kind: Pod
metadata:
name: app-with-init
spec:
initContainers:
- name: generate-config
image: example/config-generator:v1
command: ["/bin/generate-config"]
volumeMounts:
- name: config
mountPath: /generated
containers:
- name: app
image: example/app:v1
volumeMounts:
- name: config
mountPath: /etc/app
volumes:
- name: config
emptyDir: {}apiVersion: apps/v1
kind: StatefulSet
metadata:
name: postgres
namespace: data
spec:
serviceName: postgres
replicas: 3
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
terminationGracePeriodSeconds: 60
containers:
- name: postgres
image: postgres:16
ports:
- name: postgres
containerPort: 5432
env:
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: postgres-secret
key: password
resources:
requests:
cpu: "1"
memory: "2Gi"
limits:
cpu: "2"
memory: "4Gi"
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: fast-ssdapiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-agent
namespace: logging
spec:
selector:
matchLabels:
app: log-agent
template:
metadata:
labels:
app: log-agent
spec:
tolerations:
- operator: Exists
containers:
- name: agent
image: example/log-agent:v1
resources:
requests:
cpu: "100m"
memory: "128Mi"
ephemeral-storage: "100Mi"
limits:
cpu: "500m"
memory: "512Mi"
ephemeral-storage: "1Gi"
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:apiVersion: apps/v1
kind: DaemonSet
metadata:
name: log-agent
namespace: logging
spec:
selector:
matchLabels:
app: log-agent
template:
metadata:
labels:
app: log-agent
spec:
tolerations:
- operator: Exists
containers:
- name: agent
image: example/log-agent:v1
resources:
requests:
cpu: "100m"
memory: "128Mi"
ephemeral-storage: "100Mi"
limits:
cpu: "500m"
memory: "512Mi"
ephemeral-storage: "1Gi"
volumeMounts:
- name: varlog
mountPath: /var/log
readOnly: true
volumes:
- name: varlog
hostPath:
path: /var/log
type: DirectoryapiVersion: batch/v1
kind: Job
metadata:
name: schema-migration
namespace: production
spec:
backoffLimit: 2
activeDeadlineSeconds: 1800
ttlSecondsAfterFinished: 86400
template:
metadata:
labels:
app: schema-migration
spec:
restartPolicy: Never
containers:
- name: migrate
image: example/app:v2.0.0
command:
- /app/migrate
envFrom:
- secretRef:
name: database-credentials
resources:
requests:
cpu: "250m"
memory: "256Mi"
limits:
cpu: "1"
memory: "1Gi"apiVersion: batch/v1
kind: CronJob
metadata:
name: cleanup
namespace: production
spec:
schedule: "0 */6 * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 300
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 86400
template:
spec:
restartPolicy: Never
containers:
- name: cleanup
image: example/cleanup:v1.0.0
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"spec:
template:
spec:
containers:
- name: api
image: example/api:v2replicas: 5
strategy:
rollingUpdate:
maxSurge: 2
maxUnavailable: 1apiVersion: v1
kind: Service
metadata:
name: api
spec:
selector:
app: api
ports:
- name: http
port: 80
targetPort: 8080env:
- name: APP_ENV
value: production
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: passwordvolumes:
- name: app-config
configMap:
name: app-config
containers:
- name: app
image: example/app:v1
volumeMounts:
- name: app-config
mountPath: /etc/app
readOnly: truespec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: example/app:v1
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALLvolumes:
- name: tmp
emptyDir: {}
containers:
- name: app
volumeMounts:
- name: tmp
mountPath: /tmphostNetwork: true
hostPID: true
hostIPC: true
privileged: true
hostPath: /Pod 被删除
|
v
EndpointSlice 移除或标记不可接收流量
|
v
执行 PreStop
|
v
发送 SIGTERM
|
v
等待 terminationGracePeriodSeconds
|
v
发送 SIGKILLlifecycle:
preStop:
exec:
command: ["sleep", "10"]spec:
terminationGracePeriodSeconds: 60
containers:
- name: api
lifecycle:
preStop:
httpGet:
path: /drain
port: 8080FailedScheduling
Insufficient cpu
Insufficient memory
nodeSelector
affinity
taint
toleration
PVC
ResourceQuotakubectl describe pod <pod-name> -n <namespace>
kubectl get events -n <namespace> --sort-by=.lastTimestampkubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous
kubectl describe pod <pod-name> -n <namespace>kubectl get pod -o wide -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl describe service <service-name> -n <namespace>
kubectl get endpointslice -n <namespace>kubectl describe pod <pod-name> -n <namespace>
kubectl top pod <pod-name> -n <namespace> --containers[ ] requests 和 limits
[ ] startupProbe
[ ] readinessProbe
[ ] livenessProbe
[ ] 优雅终止
[ ] Service
[ ] 滚动更新
[ ] PDB
[ ] 副本分布
[ ] 安全上下文
[ ] ServiceAccount
[ ] Secret/ConfigMap
[ ] 日志策略
[ ] 监控指标
[ ] 网络策略
[ ] PVC 备份
[ ] 节点和可用区约束Namespace
└── Deployment
└── ReplicaSet
└── Pod
├── Init Container
├── App Container
└── Sidecar Container
Service
└── 通过 Label Selector 选择 Pod
HPA
└── 调整 Deployment/StatefulSet 的副本数
PDB
└── 保护 Pod 的主动中断
ConfigMap/Secret
└── 向 Pod 注入配置和敏感信息
PVC
└── 向 Pod 提供持久化存储
NetworkPolicy
└── 控制 Pod 网络访问
ServiceAccount
└── 为 Pod 提供 Kubernetes API 身份资源 requests/limits
容器探针
优雅终止
安全上下文
配置和 Secret
网络策略
Service 访问
副本分布
PDB
持久化存储
日志和监控
发布与回滚
故障排查kubectl get pod <pod-name> -n <namespace> -o wide
kubectl describe pod <pod-name> -n <namespace>status:
conditions:
- type: "example.com/load-balancer-ready"
status: "True"livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 5
timeoutSeconds: 1
failureThreshold: 1kubectl debug -it pod/<pod-name> \
-n <namespace> \
--image=busybox:1.36 \
--target=appdnsConfig:
nameservers:
- 10.96.0.10
searches:
- production.svc.cluster.local
options:
- name: ndots
value: "2"kubectl exec -it <pod-name> -n <namespace> -- nslookup kubernetes.default
kubectl exec -it <pod-name> -n <namespace> -- cat /etc/resolv.confkubectl delete pod <pod-name> \
-n <namespace> \
--grace-period=0 \
--force身份:
[ ] Namespace
[ ] ServiceAccount
[ ] RBAC
运行:
[ ] 镜像版本固定
[ ] imagePullPolicy 合理
[ ] 容器启动命令明确
[ ] 所有容器资源明确
健康:
[ ] Startup Probe
[ ] Readiness Probe
[ ] Liveness Probe
[ ] 探针不会互相误伤
网络:
[ ] Service
[ ] NetworkPolicy
[ ] DNS
[ ] 端口冲突
[ ] 监听地址
存储:
[ ] emptyDir 是否可丢失
[ ] PVC 是否需要备份
[ ] 临时存储是否有边界
[ ] 数据目录权限
调度:
[ ] 节点选择
[ ] 污点和容忍
[ ] 跨节点分布
[ ] 跨可用区分布
[ ] 节点池容量
安全:
[ ] 非 root
[ ] 禁止特权
[ ] Drop capabilities
[ ] Seccomp
[ ] 只读根文件系统
[ ] 不必要的 Host namespace 已关闭
生命周期:
[ ] SIGTERM
[ ] terminationGracePeriodSeconds
[ ] PreStop
[ ] PDB
[ ] 版本回滚
观测:
[ ] 日志
[ ] 指标
[ ] 事件
[ ] OOMKill
[ ] 重启次数
[ ] 探针失败容器:运行进程
Pod:组合运行环境
Controller:维持 Pod 数量和版本
Service:提供稳定访问
Volume:提供数据存储
Probe:判断健康和可用
Policy:限制安全和网络
Scheduler:决定运行位置
Kubelet:负责节点上的实际执行kubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{range .status.containerStatuses[*]}{.name}{" ready="}{.ready}{" restarts="}{.restartCount}{"\n"}{end}'spec:
initContainers:
- name: sidecar
image: example/sidecar:v1
restartPolicy: Alwayskubectl get pod <pod-name> -n <namespace> \
-o jsonpath='{.metadata.ownerReferences}'containers:
- name: app
image: example/app:v1
terminationMessagePolicy: FallbackToLogsOnErrormetadata:
labels:
app.kubernetes.io/name: api
app.kubernetes.io/instance: api-prod
app.kubernetes.io/version: "1.2.0"
app.kubernetes.io/component: backend
app.kubernetes.io/part-of: order-system
app.kubernetes.io/managed-by: helmapiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: registry.example.com/app@sha256:...
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}[ ] 是否必须与另一个容器共享 localhost?
[ ] 是否必须共享同一个 Volume?
[ ] 是否必须一起调度?
[ ] 是否必须一起扩缩容?
[ ] 是否必须一起发布?
[ ] 是否必须一起终止?
[ ] 是否拥有相同的故障域?
[ ] 是否拥有相近的资源需求?控制器维持实例
Service 提供稳定访问
PVC 保存状态
Probe 判断健康
Resource 约束消耗
Policy 限制权限
Topology 保证分布
监控负责验证kubectl get pvc -n <namespace>
kubectl describe pvc <pvc-name> -n <namespace>
kubectl describe pod <pod-name> -n <namespace>
kubectl get volumeattachmentlifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 5"]kubectl get endpointslice \
-l kubernetes.io/service-name=<service-name> \
-n <namespace> -o yamlvolumes:
- name: projected
projected:
sources:
- configMap:
name: app-config
- secret:
name: app-secret
- downwardAPI:
items:
- path: labels
fieldRef:
fieldPath: metadata.labelsenv:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: POD_NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeNamevolumes:
- name: podinfo
downwardAPI:
items:
- path: labels
fieldRef:
fieldPath: metadata.labelsspec:
hostAliases:
- ip: "10.0.0.20"
hostnames:
- "legacy.example.com"apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-frontend
namespace: production
spec:
podSelector:
matchLabels:
app: backend
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: frontend
ports:
- protocol: TCP
port: 8080affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64[ ] 由 Deployment、StatefulSet 或 DaemonSet 管理
[ ] 镜像使用固定版本
[ ] 显式配置 requests/limits
[ ] 配置 startupProbe
[ ] 配置 readinessProbe
[ ] 配置 livenessProbe
[ ] 正确处理 SIGTERM
[ ] 设置合理的 terminationGracePeriodSeconds
[ ] 配置 Service
[ ] 配置 PDB
[ ] 配置副本分布策略
[ ] 配置 NetworkPolicy
[ ] 使用最小权限 ServiceAccount
[ ] 关闭不必要的 Token 自动挂载
[ ] 使用非 root 和 RuntimeDefault Seccomp
[ ] 持久数据使用 PVC 或外部存储
[ ] 日志输出到 stdout/stderr
[ ] 有指标、日志和事件监控
[ ] 有发布、回滚和故障排查方案Pod 会被重启
Pod 会被删除
Pod IP 会变化
Pod 可能被驱逐
Pod 可能跨节点重建
Pod 内所有容器共同调度和扩缩
Pod 本地数据默认不持久
Pod 的 Ready 状态决定是否接流量控制器管理 Pod
Service 访问 Pod
PVC 保存状态
Probe 判断健康
NetworkPolicy 控制通信
ServiceAccount 提供身份
Resource 限制消耗
Topology 保证分布
PDB 保护主动中断
监控和审计验证运行结果