4Kubernetes 实战

使用 Pod 运行工作负载

Pod 详解

PodSidecar生命周期

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第4章:使用Pod运行工作负载(Running Workloads with Pods)

一、导读

1.1 本章学习目标

Pod 是 Kubernetes 的基本构建块,深入理解 Pod 的内部机制对于高效使用 K8s 至关重要。本章从多容器模式开始,讲解 Pod 的高级用法:Sidecar、Ambassador、Adapter 等设计模式。然后深入 Pod 的存储、资源限制、探针配置等关键主题。

本章的核心学习目标包括:

  • 掌握多容器 Pod 的设计模式:Sidecar、Ambassador、Adapter 模式的适用场景和实现方式。
  • 理解 Pod 的存储机制:emptyDir、hostPath、共享存储卷的使用。
  • 掌握资源限制的配置:requests 和 limits 的区别,QoS 等级的影响。
  • 配置健康检查探针:Liveness、Readiness、Startup Probe 的作用和配置方法。
  • 理解容器的生命周期钩子:postStart 和 preStop 的使用场景。
  • 学会调试 Pod 问题:常见故障的排查方法。

1.2 为什么本章如此重要

在生产环境中,Pod 的配置直接影响应用的可用性、性能和可观测性。错误的探针配置可能导致 Pod 频繁重启,不合理的资源限制可能导致节点资源耗尽,不正确的存储配置可能导致数据丢失。

多容器 Pod 模式是 Kubernetes 的特色能力——它允许你将紧密耦合的容器组合在一起,共享网络和存储。这种模式在微服务架构中提供了更灵活的部署选择。

1.3 核心问题引导

什么时候应该在同一个 Pod 中运行多个容器?什么时候应该拆分为多个 Pod?

Liveness Probe 和 Readiness Probe 的区别是什么?配置错误会导致什么后果?

requests 和 limits 的区别是什么?如果只设置 limits 不设置 requests 会怎样?

emptyDir 和 hostPath 的区别是什么?各自的适用场景?

容器重启后,emptyDir 中的数据会丢失吗?


二、核心概念详解

2.1 多容器 Pod 设计模式

一个 Pod 中可以运行多个容器,它们共享网络命名空间(相同的 IP 和端口)和存储卷。这种设计适用于需要紧密耦合的容器组合。

2.1.1 Sidecar 模式

Sidecar 容器增强主容器的功能。常见的 Sidecar 场景:

  • 日志收集:主容器写日志到共享卷,Sidecar 容器读取并转发到日志系统
  • 配置同步:Sidecar 容器从配置中心拉取配置,主容器读取本地配置文件
  • 代理/网关:Sidecar 容器作为主容器的本地代理
yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-log-sidecar
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
    - name: log-shipper
      image: fluentd:latest
      volumeMounts:
        - name: logs
          mountPath: /var/log/app
          readOnly: true
      env:
        - name: LOG_OUTPUT
          value: "elasticsearch"
  volumes:
    - name: logs
      emptyDir: {}

2.1.2 Ambassador 模式

Ambassador 容器代理主容器与外部服务的通信。典型场景:

  • 数据库代理:主容器连接 localhost 的 Ambassador,Ambassador 代理到实际的数据库
  • 服务网格:Envoy/Istio sidecar 就是 Ambassador 模式
yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-db-proxy
spec:
  containers:
    - name: app
      image: myapp:1.0
      env:
        - name: DB_HOST
          value: "localhost"
        - name: DB_PORT
          value: "6379"
    - name: redis-proxy
      image: envoy-proxy:latest
      ports:
        - containerPort: 6379
      env:
        - name: UPSTREAM_HOST
          value: "redis-cluster.production.svc"

2.1.3 Adapter 模式

Adapter 容器标准化主容器的输出接口。典型场景:

  • 监控标准化:不同应用暴露不同格式的指标,Adapter 统一转换为 Prometheus 格式
  • 日志格式化:将非标准日志格式转换为 JSON
yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-with-metrics-adapter
spec:
  containers:
    - name: app
      image: legacy-app:1.0
      volumeMounts:
        - name: metrics
          mountPath: /var/metrics
    - name: metrics-exporter
      image: prometheus-exporter:latest
      ports:
        - containerPort: 9090
      volumeMounts:
        - name: metrics
          mountPath: /var/metrics
          readOnly: true
  volumes:
    - name: metrics
      emptyDir: {}

2.2 Pod 的存储

2.2.1 emptyDir

emptyDir 在 Pod 被调度到节点时创建,Pod 删除时数据丢失。适用于:

  • 容器间共享临时数据
  • 磁盘缓存
  • 长时间计算中的检查点
yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-emptydir
spec:
  containers:
    - name: app
      image: myapp:1.0
      volumeMounts:
        - name: cache
          mountPath: /tmp/cache
    - name: worker
      image: worker:1.0
      volumeMounts:
        - name: cache
          mountPath: /data/cache
  volumes:
    - name: cache
      emptyDir:
        sizeLimit: 1Gi  # 限制大小
        # medium: Memory  # 使用 tmpfs(内存)

2.2.2 hostPath

hostPath 将节点文件系统中的文件或目录挂载到 Pod。适用于:

  • 访问节点上的 Docker 引擎
  • 日志收集 Agent 访问节点日志
  • 监控 Agent 访问节点指标
yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-hostpath
spec:
  containers:
    - name: log-collector
      image: fluentd:latest
      volumeMounts:
        - name: varlog
          mountPath: /var/log
          readOnly: true
  volumes:
    - name: varlog
      hostPath:
        path: /var/log
        type: Directory

注意:hostPath 有安全风险,因为它可以访问节点文件系统。生产环境中应谨慎使用,配合 RBAC 和 PodSecurityPolicy。

2.3 资源限制

2.3.1 requests 和 limits

  • requests:调度依据,K8s 保证 Pod 能获得这么多资源
  • limits:运行时上限,Pod 不能超过这个限制
yaml
resources:
  requests:
    cpu: 100m       # 0.1 核
    memory: 128Mi   # 128 MB
  limits:
    cpu: 500m       # 0.5 核
    memory: 512Mi   # 512 MB

2.3.2 QoS 等级

K8s 根据资源配置为 Pod 分配 QoS 等级:

  • Guaranteed:所有容器都设置了 requests 和 limits,且相等
  • Burstable:至少一个容器设置了 requests 或 limits
  • BestEffort:没有设置任何 requests 和 limits

节点资源不足时,K8s 按 QoS 等级驱逐 Pod:BestEffort → Burstable → Guaranteed。

2.4 健康检查探针

2.4.1 Liveness Probe

检测容器是否存活。失败时 K8s 重启容器。

yaml
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
  failureThreshold: 3

2.4.2 Readiness Probe

检测 Pod 是否可以接收流量。失败时从 Service 的 Endpoints 中移除 Pod。

yaml
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

2.4.3 Startup Probe

保护慢启动容器。在 Startup Probe 成功之前,Liveness 和 Readiness 不会生效。

yaml
startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30
  periodSeconds: 10
# 最多等待 300 秒启动

2.4.4 探针类型

  • httpGet:发送 HTTP GET 请求,2xx/3xx 为成功
  • tcpSocket:TCP 连接成功
  • exec:执行命令,退出码 0 为成功
  • grpc:gRPC HealthCheck

三、实战案例

3.1 完整的 Pod 配置

yaml
apiVersion: v1
kind: Pod
metadata:
  name: production-app
  labels:
    app: my-app
    env: production
spec:
  containers:
    - name: app
      image: myapp:1.0
      ports:
        - containerPort: 8080
      resources:
        requests:
          cpu: 200m
          memory: 256Mi
        limits:
          cpu: 1000m
          memory: 1Gi
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        initialDelaySeconds: 30
        periodSeconds: 10
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        initialDelaySeconds: 5
        periodSeconds: 5
      lifecycle:
        postStart:
          exec:
            command: ["/bin/sh", "-c", "echo started"]
        preStop:
          exec:
            command: ["/bin/sh", "-c", "sleep 10"]
      volumeMounts:
        - name: cache
          mountPath: /tmp/cache
        - name: config
          mountPath: /etc/config
    - name: sidecar
      image: fluentd:latest
      volumeMounts:
        - name: logs
          mountPath: /var/log
          readOnly: true
  volumes:
    - name: cache
      emptyDir:
        sizeLimit: 500Mi
    - name: config
      configMap:
        name: app-config
    - name: logs
      emptyDir: {}

3.2 调试 Pod 问题

bash
# 查看 Pod 事件
kubectl describe pod my-pod
# 常见问题:
# - ImagePullBackOff:镜像拉取失败
# - CrashLoopBackOff:容器反复崩溃
# - Pending:无法调度(资源不足、nodeSelector 不匹配)

# 查看容器日志
kubectl logs my-pod -c app
kubectl logs my-pod --previous  # 查看上一次崩溃的日志

# 进入容器调试
kubectl exec -it my-pod -c app -- /bin/bash

# 使用 ephemeral container 调试
kubectl debug -it my-pod --image=busybox --target=app

# 查看 Pod 的资源使用
kubectl top pod my-pod

四、本章小结

本章深入讲解了 Pod 的高级用法:

多容器模式:Sidecar 增强功能、Ambassador 代理访问、Adapter 标准化接口。

存储:emptyDir 提供临时共享存储,hostPath 访问节点文件系统。

资源限制:requests 用于调度,limits 用于运行时限制,QoS 等级影响驱逐优先级。

健康检查:Liveness 重启容器、Readiness 控制流量、Startup 保护慢启动。

生命周期钩子:postStart 在容器启动后执行、preStop 在终止前执行。


五、思考与练习

思考题

Sidecar 模式和微服务模式的区别是什么?什么时候选择 Sidecar,什么时候选择独立服务?

如果 Liveness Probe 配置了过短的 initialDelaySeconds,会导致什么问题?

为什么 BestEffort QoS 的 Pod 在资源不足时最先被驱逐?

emptyDir 使用 Memory medium 时有什么限制?适合什么场景?

preStop 钩子中的 sleep 10 有什么作用?为什么需要优雅终止?

练习题

创建一个包含主应用和日志收集 Sidecar 的 Pod,配置共享存储卷。

为 Pod 配置 Liveness 和 Readiness 探针,模拟探针失败,观察 K8s 的行为。

设置不同的资源配置(Guaranteed、Burstable、BestEffort),观察节点压力时的驱逐行为。

使用 kubectl debug 调试一个 CrashLoopBackOff 的 Pod。

4/8使用 P
0%