Kubernetes Pod 深入解析:从概念到实践

7 阅读4分钟

什么是 Pod?

Pod 是 Kubernetes 中最小的部署单元,可以把它想象成一个"豆荚",里面装着"豆子"(容器)。Pod 中的容器共享网络和存储资源,这种设计让容器间通信变得简单高效。

Infra 容器(pause容器)

每个 Pod 启动的第一个容器就是 pause 容器,它负责:

  • 初始化网络命名空间
  • 挂载必要的存储卷
  • 回收僵尸进程
  • 为其他容器提供共享的基础环境

共享命名空间包括:

  • network:网络命名空间,Pod 内所有容器共享相同的 IP 地址和端口空间
  • pid:进程命名空间,容器间可以相互看到对方的进程
  • ipc:进程间通信命名空间,允许容器间使用 System V IPC 或 POSIX 消息队列通信

正是因为这种共享机制,Pod 内部的容器可以直接通过 localhost 相互访问。

Pod 网络特性

  • 每个 Pod 都有独立的 IP 地址
  • Pod 之间可以直接通信(由 CNI 插件实现)
  • Pod 是一种逻辑概念,并不真实存在物理实体
  • Pod 的生命周期由 kubelet 管理

资源清单

Kubernetes 中的所有内容都抽象为资源,资源实例化之后称为对象。

apiVersion: v1          # API 版本
kind: Pod               # 资源类型
metadata:               # 元数据
  name: my-pod
  labels:
    app: myapp
spec:                   # 期望状态
  containers:
  - name: myapp
    image: nginx:latest

Pod 生命周期

pause容器(初始化网络) → init容器(初始化任务) → 主容器启动 → 启动后钩子 → 
就绪探针 → 存活探针 → 业务运行 → 停止前钩子 → 容器终止

1. Init 容器

Init 容器在 Pod 的主容器启动之前运行,主要用于执行初始化任务。所有 Init 容器必须成功执行(返回码为 0),否则 Pod 会一直处于 Init 状态。

apiVersion: v1
kind: Pod
metadata:
  name: initc-1
  labels:
    app: initc
spec:
  containers:
  - name: myapp-container
    image: busybox
    command: ['sh', '-c', 'echo the app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice.default.svc.cluster.local; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb.default.svc.cluster.local; do echo waiting for mydb; sleep 2; done;']

创建对应的 Service 来让 Init 容器通过检测:

kubectl create svc clusterip myservice --tcp=80:80
kubectl create svc clusterip mydb --tcp=80:80

2. 探针(Probes)

Kubernetes 提供了三种探针来监控容器的健康状态:

启动探针(startupProbe)

  • 作用:检查容器是否已经启动
  • 成功:开始执行其他探针
  • 失败:容器会被重启

存活探针(livenessProbe)

  • 作用:检查容器是否还在运行
  • 成功:容器正常运行
  • 失败:根据重启策略重启容器

就绪探针(readinessProbe)

  • 作用:检查容器是否准备好接收流量
  • 成功:将容器标记为就绪,可以接收流量
  • 失败:从 Service 的负载均衡中移除该容器

3. 探针类型示例

HTTP GET 探针

apiVersion: v1
kind: Pod
metadata:
  name: readiness-httpget-pod
  namespace: default
  labels:
    app: myapp
    env: test
spec:
  containers:
  - name: readiness-httpget-container
    image: nginx
    readinessProbe:
      httpGet:
        port: 80
        path: /index1.html
      initialDelaySeconds: 1    # 延迟检测时间
      periodSeconds: 3          # 每3秒检测一次
      timeoutSeconds: 1         # 超时时间

Exec 探针

apiVersion: v1
kind: Pod
metadata:
  name: readiness-exec-pod
  namespace: default
spec:
  containers:
  - name: readiness-exec-container
    image: busybox
    command: ["/bin/sh","-c", "touch /tmp/live ; sleep 60; rm -rf /tmp/live; sleep 3600"]
    readinessProbe:
      exec:
        command: ["test", "-e", "/tmp/live"]
      initialDelaySeconds: 1
      periodSeconds: 3

TCP 探针

apiVersion: v1
kind: Pod
metadata:
  name: readiness-tcp-pod
spec:
  containers:
  - name: readiness-exec-container
    image: nginx
    readinessProbe:
      initialDelaySeconds: 5
      timeoutSeconds: 1
      tcpSocket:
        port: 80

4. 启动探针示例

apiVersion: v1
kind: Pod
metadata:
  name: startupprobe-1
  namespace: default
spec:
  containers:
  - name: myapp-container
    image: nginx
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        port: 80
        path: /index2.html
      initialDelaySeconds: 1
      periodSeconds: 1
    startupProbe:
      httpGet:
        path: /index1.html
        port: 80
      failureThreshold: 30
      periodSeconds: 10

5. 钩子(Hooks)

钩子允许在容器生命周期中的特定时刻执行自定义操作,由 kubelet 执行。

Exec 钩子

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-exec-pod
spec:
  containers:
  - name: lifecycle-exec-container
    image: nginx
    lifecycle:
      postStart:      # 容器启动后执行
        exec:
          command: ["/bin/bash", "-c", "echo postStart > /usr/share/message"]
      preStop:        # 容器停止前执行
        exec:
          command: ["/bin/sh", "-c", "echo preStop > /usr/share/message"]

HTTP GET 钩子

apiVersion: v1
kind: Pod
metadata:
  name: lifecycle-http-pod
spec:
  containers:
  - name: lifecycle-http-container
    image: nginx
    lifecycle:
      postStart:
        httpGet:
          host: 192.168.200.10
          path: /index.html
          port: 1234
      preStop:
        httpGet:
          host: 192.168.200.10
          path: /indexhostname.html
          port: 1234

实践建议

  1. Init 容器:用于数据库迁移、配置文件下载、等待依赖服务就绪等场景
  2. 就绪探针:确保只有完全就绪的容器才接收流量
  3. 存活探针:及时重启崩溃的容器
  4. 启动探针:对于启动较慢的应用,避免存活探针过早杀死容器
  5. 钩子:用于初始化配置、优雅关闭等场景

总结

Pod 是 Kubernetes 的核心概念,理解其生命周期和各个组件的工作原理对于构建稳定的微服务应用至关重要。合理使用 Init 容器、探针和钩子,可以大大提高应用的可靠性和可维护性。

通过本文的示例和解释,你应该对 Pod 有了更深入的理解。在实际使用中,根据应用的特点选择合适的配置,才能发挥 Kubernetes 的最大价值。