什么是 Pod
Pod 是 K8s 中最小的调度和管理单元。一个 Pod 是一组(通常是一个,也可以是多个)共享网络和存储的容器集合。同一个 Pod 内的容器:
- 共享同一个网络命名空间(相同 IP 地址,可通过 localhost 互相访问)
- 共享同一个 IPC 命名空间(可以通过共享内存通信)
- 可以挂载相同的存储 Volume
- 总是被调度到同一个 Node 上
Pod 这个抽象层允许将紧密耦合的容器(如应用 + 日志收集 agent)作为一个整体管理,同时保持容器的隔离性。Pod 中有一个隐藏的 Pause 容器(infra 容器),负责持有 Pod 的网络命名空间,其他容器加入这个命名空间。
Pod 完整 YAML 示例
apiVersion: v1
kind: Pod
metadata:
name: web-pod
namespace: default
labels:
app: web
version: v1
spec:
containers:
- name: web # 容器名称
image: nginx:1.25
imagePullPolicy: IfNotPresent # Always/Never/IfNotPresent
ports:
- containerPort: 80
protocol: TCP
resources: # 资源请求和限制
requests: # 调度依据:保证至少得到这么多
cpu: 100m # 100 millicores = 0.1 CPU
memory: 128Mi # 128 Mebibytes
limits: # 硬上限:超出则被限流/OOMKilled
cpu: 500m
memory: 256Mi
env: # 环境变量
- name: APP_ENV
value: production
livenessProbe: # 存活探针:失败则重启容器
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 15 # 容器启动后等待 15s 再开始探测
periodSeconds: 10 # 每 10s 探测一次
failureThreshold: 3 # 连续 3 次失败才重启
readinessProbe: # 就绪探针:失败则从 Service 摘流
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts: # 挂载 Volume
- name: config-vol
mountPath: /etc/nginx/conf.d
volumes: # 声明 Pod 级别的 Volume
- name: config-vol
configMapRef:
name: nginx-config
restartPolicy: Always # Always/OnFailure/Never
terminationGracePeriodSeconds: 30 # 优雅停止等待时间(秒)
Pod 生命周期
Pod 生命周期状态机 ┌──────────────────────────────────────────────────────┐ │ 创建 Pod │ └──────────────────┬───────────────────────────────────┘ ▼ Pending ←── 等待调度 / 拉取镜像 / 等待 PVC 绑定 ▼ Running ←── 至少一个容器在运行 ├──── 所有容器成功退出 ──► Succeeded └──── 容器失败且不再重启 ──► Failed Unknown ←── Node 失联,状态未知 Terminating ←── 收到删除信号,等待优雅退出
多容器 Pod 设计模式
虽然大多数 Pod 只包含一个主容器,但 K8s 定义了三种多容器协作模式:
Sidecar(边车)模式
在主容器旁运行辅助容器,增强或扩展主容器的功能,两者共享相同的存储和网络。
spec:
containers:
- name: app # 主容器:写日志到共享目录
image: my-app:v1
volumeMounts:
- name: log-vol
mountPath: /var/log/app
- name: log-shipper # Sidecar:读日志并发送到 Elasticsearch
image: fluent/fluent-bit:3.0
volumeMounts:
- name: log-vol
mountPath: /var/log/app
readOnly: true
volumes:
- name: log-vol
emptyDir: {} # Pod 生命周期内的临时共享存储
Init 容器
在主容器启动前运行的初始化容器,串行执行,必须全部成功才会启动主容器。
spec:
initContainers: # Init 容器列表,按顺序执行
- name: wait-for-db # 等待数据库就绪
image: busybox:1.36
command:
- sh
- -c
- "until nc -z mysql-svc 3306; do echo waiting...; sleep 2; done"
- name: db-migrate # 执行数据库迁移
image: my-app:v1
command: ["python", "manage.py", "migrate"]
containers:
- name: app # Init 容器全部成功后才启动
image: my-app:v1
资源请求与限制
健康探针(Health Probes)
K8s 提供三种探针,通过不同机制告知 K8s 容器的健康状态:
Liveness Probe(存活探针)
探测容器是否仍在运行。失败时 K8s 重启容器。用于检测死锁等无法自行恢复的状态。
Readiness Probe(就绪探针)
探测容器是否准备好接受流量。失败时将 Pod 从 Service 的 Endpoints 中摘除,不再转发流量,但不重启容器。
containers:
- name: app
image: my-app:v1
startupProbe: # 启动探针:启动慢的应用防止被 Liveness 误杀
httpGet:
path: /healthz
port: 8080
failureThreshold: 30 # 最多等 30 * 10s = 300s 启动
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 0 # startupProbe 通过后立即开始
periodSeconds: 10
timeoutSeconds: 5 # 探测超时时间
failureThreshold: 3
readinessProbe:
tcpSocket: # TCP 端口探测(另一种探针类型)
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
Pod QoS 服务质量等级
K8s 根据容器的 requests/limits 设置,自动将 Pod 分为三个 QoS 等级,决定节点内存紧张时 Pod 被驱逐的优先级:
| QoS 等级 | 条件 | 驱逐优先级 |
|---|---|---|
| BestEffort | 没有设置任何 requests 和 limits | 最先被驱逐 |
| Burstable | 至少有一个容器设置了 requests,但 requests ≠ limits | 其次被驱逐 |
| Guaranteed | 所有容器都设置了 requests == limits(CPU 和内存) | 最后被驱逐 |
生产环境关键服务应设置 requests == limits,达到 Guaranteed QoS,避免在节点资源紧张时被意外驱逐。同时配合 LimitRange 为 Namespace 设置默认资源限制,防止忘记设置的 Pod 成为 BestEffort 等级。
如果你的容器频繁被 OOMKilled,不要盲目提高 memory limit。先用 kubectl top pods 观察实际内存用量,分析是内存泄漏还是正常需求。同时,Java 应用要注意设置 JVM 堆大小(-Xmx)与 K8s memory limit 的对应关系,不然 JVM 会按节点总内存分配堆,很快超出 limit 被 Kill。