K8s 学习笔记(二):Pod 与容器管理

写在前面

本文是 K8s 学习笔记系列的第二篇,深入 Pod 的生命周期、多容器模式、健康检查和资源限制。前置知识:集群搭建和基本操作(第一篇)。


一、Pod 基础

1.1 什么是 Pod

Pod 是 K8s 最小的调度单元,包含一个或多个容器,共享网络和存储。

1
2
3
4
5
6
Pod
├── 容器1(应用容器)
├── 容器2(Sidecar)
├── 共享网络(同一个 IP,localhost 互通)
├── 共享存储(Volume)
└── 共享配置(环境变量、ConfigMap)

为什么不直接调度容器?因为有些容器需要紧密协作(如应用 + 日志收集),把它们放在一个 Pod 里共享网络和存储。

1.2 Pod YAML 详解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
kind: Pod
metadata:
  name: my-app
  labels:
    app: my-app
    env: prod
spec:
  containers:
  - name: app
    image: my-app:1.0
    ports:
    - containerPort: 8080
    env:
    - name: APP_ENV
      value: "production"
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef:
          name: db-secret
          key: password
    resources:
      requests:
        memory: "128Mi"
        cpu: "100m"
      limits:
        memory: "256Mi"
        cpu: "500m"
  restartPolicy: Always

1.3 Pod 生命周期

1
2
3
4
5
创建 Pod → 调度到节点 → 拉取镜像 → 启动容器 → 运行中
                                              崩溃/健康检查失败
                                                   重启容器

Pod 的 phase(阶段):

1
2
3
4
5
Pending    — 等待调度或拉取镜像
Running    — 至少一个容器在运行
Succeeded  — 所有容器正常退出(不会重启)
Failed     — 至少一个容器异常退出
Unknown    — 无法获取状态

1.4 容器重启策略

1
2
3
4
spec:
  restartPolicy: Always     # 总是重启(默认,适合长期运行的服务)
  restartPolicy: OnFailure  # 只在失败时重启(适合 Job)
  restartPolicy: Never      # 从不重启

二、多容器模式

2.1 Sidecar(边车模式)

主容器 + 辅助容器,最常用的模式:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: Pod
metadata:
  name: app-with-sidecar
spec:
  containers:
  - name: app                    # 主容器:业务应用
    image: my-app:1.0
    volumeMounts:
    - name: logs
      mountPath: /var/log/app

  - name: log-collector          # Sidecar:日志收集
    image: busybox
    command: ["sh", "-c", "tail -f /var/log/app/*.log"]
    volumeMounts:
    - name: logs
      mountPath: /var/log/app

  volumes:
  - name: logs
    emptyDir: {}                  # 共享的临时目录

2.2 常见多容器场景

1
2
3
4
Sidecar     — 日志收集、代理(如 Envoy/Istio)
Ambassador  — 代理外部服务连接
Adapter     — 标准化输出(如监控指标转换)
Init 容器   — 启动前执行初始化任务

2.3 Init 容器

在主容器启动前执行,完成后退出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
spec:
  initContainers:
  - name: init-db
    image: busybox
    command: ["sh", "-c", "until nslookup mysql-service; do echo waiting; sleep 2; done"]
    # 等待数据库服务可用后再启动主容器

  containers:
  - name: app
    image: my-app:1.0

Init 容器按顺序执行,全部成功后才开始主容器。任何一个失败,Pod 都会重启。


三、健康检查

K8s 通过探针(Probe)检查容器健康状态。

3.1 三种探针

1
2
3
livenessProbe   — 存活检查:失败则重启容器
readinessProbe  — 就绪检查:失败则从 Service 摘除流量
startupProbe    — 启动检查:先等这个通过,再执行上面两个

3.2 探针配置方式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
spec:
  containers:
  - name: app
    image: my-app:1.0

    # 存活检查:挂了就重启
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
      initialDelaySeconds: 10   # 容器启动后等10秒开始检查
      periodSeconds: 10         # 每10秒检查一次
      failureThreshold: 3       # 连续失败3次才判定不健康

    # 就绪检查:没准备好就不接收流量
    readinessProbe:
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

    # 启动检查:慢启动应用用这个(避免被 liveness 杀掉)
    startupProbe:
      httpGet:
        path: /healthz
        port: 8080
      failureThreshold: 30      # 允许失败30次
      periodSeconds: 10         # 最长等 30*10=300秒

3.3 探针类型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# HTTP GET(最常用)
httpGet:
  path: /health
  port: 8080

# TCP 检查(适合非 HTTP 服务)
tcpSocket:
  port: 3306

# 执行命令(适合自定义检查)
exec:
  command:
  - cat
  - /tmp/healthy

3.4 探针配置建议

1
2
3
4
Web 服务       → httpGet + liveness + readiness
数据库          → tcpSocket + readiness
慢启动应用      → startupProbe + liveness + readiness
健康检查接口    → 返回 200 表示健康,返回 500 或超时表示不健康

四、资源限制

4.1 requests 和 limits

1
2
3
4
5
6
7
resources:
  requests:           # 调度依据:保证最少有这么多资源
    memory: "128Mi"
    cpu: "100m"       # 100m = 0.1 核
  limits:             # 上限:最多用这么多,超过会被限制或杀掉
    memory: "256Mi"
    cpu: "500m"       # 500m = 0.5 核
1
2
3
4
5
requests  — 调度器用来决定 Pod 放在哪个节点
limits    — 运行时的硬上限

CPU 超限  → 被限流(throttled),不会杀容器
内存超限  → 被杀掉(OOMKilled)

4.2 CPU 单位

1
2
3
1      = 1 核 CPU
500m   = 0.5 核(500 millicores)
100m   = 0.1 核

4.3 内存单位

1
2
3
Mi = Mebibytes(1024 KiB,K8s 中常用)
Gi = Gibibytes(1024 Mi)
M  = Megabytes(1000 KB,不推荐用)

4.4 QoS 等级

根据 requests 和 limits 的设置,Pod 分为三个等级:

1
2
3
Guaranteed  — requests = limits(最高优先级,最后被杀)
Burstable   — 设置了 requests 但不等于 limits
BestEffort  — 没设置 requests 和 limits(最先被杀)

建议生产环境所有 Pod 都设置 requests 和 limits,保证 Guaranteed 或 Burstable。

4.5 LimitRange(默认资源限制)

给命名空间设置默认值,防止忘记配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
spec:
  limits:
  - default:               # 默认 limits
      cpu: "500m"
      memory: "256Mi"
    defaultRequest:         # 默认 requests
      cpu: "100m"
      memory: "128Mi"
    type: Container

五、环境变量与配置注入

5.1 直接定义

1
2
3
4
5
env:
- name: APP_ENV
  value: "production"
- name: APP_PORT
  value: "8080"

5.2 从 ConfigMap 引用

1
2
3
4
5
6
env:
- name: DB_HOST
  valueFrom:
    configMapKeyRef:
      name: app-config        # ConfigMap 名
      key: database_host      # ConfigMap 中的 key

5.3 从 Secret 引用

1
2
3
4
5
6
env:
- name: DB_PASSWORD
  valueFrom:
    secretKeyRef:
      name: db-secret         # Secret 名
      key: password           # Secret 中的 key

5.4 挂载为文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
spec:
  containers:
  - name: app
    volumeMounts:
    - name: config-volume
      mountPath: /etc/config
      readOnly: true

  volumes:
  - name: config-volume
    configMap:
      name: app-config

六、Pod 排错

6.1 常见问题速查

1
2
3
4
5
6
Pending           → 资源不足,kubectl describe pod 看 Events
CrashLoopBackOff  → 容器启动后崩溃,kubectl logs --previous 看上次日志
ImagePullBackOff  → 镜像拉取失败,检查镜像名和仓库权限
OOMKilled         → 内存超限,增大 limits.memory
Completed         → 容器执行完退出了,正常(Job)或命令写错
ContainerCreating → 一直在创建,检查镜像拉取和挂载

6.2 排查步骤

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 1. 查看 Pod 状态
kubectl get pods -o wide

# 2. 查看 Pod 详情和事件
kubectl describe pod <pod-name>

# 3. 查看容器日志
kubectl logs <pod-name>
kubectl logs <pod-name> --previous          # 上次崩溃的日志
kubectl logs <pod-name> -c <container>      # 指定容器

# 4. 进入容器排查
kubectl exec -it <pod-name> -- sh

# 5. 查看资源使用
kubectl top pods

七、小结

本文学习了 Pod 的核心知识:

  • Pod 的概念和生命周期
  • 多容器模式(Sidecar、Init 容器)
  • 健康检查(liveness、readiness、startup 探针)
  • 资源限制(requests/limits、QoS)
  • 环境变量与配置注入
  • Pod 常见问题排查

下一篇将学习工作负载管理:Deployment 滚动更新、StatefulSet 和 DaemonSet。