K8s 容器设计模式

什么是容器设计模式?

容器设计模式(Container Design Patterns)是在 Kubernetes 这样的容器编排平台中,如何合理地组合和管理多个容器以实现复杂应用需求的一套方法论。它类似于软件开发中的"设计模式",但专注于容器的组织和协作方式。

为什么需要容器设计模式?

单个容器通常只运行一个进程(比如一个 Web 服务),但实际应用场景往往需要多个进程协作,比如日志收集、数据预处理、服务代理等。如果把所有功能都塞进一个容器,会导致:

  • 维护困难:功能耦合,难以独立更新
  • 升级复杂:牵一发而动全身
  • 耦合度高:组件间依赖关系复杂
  • 资源浪费:无法精确控制资源分配

容器设计模式帮助我们将这些功能拆分到不同的容器中,并通过 Pod 这种机制让它们协作。


一、Sidecar 模式(边车模式)

核心理念

就像摩托车旁边的"边车",主容器负责核心业务,边车容器负责辅助功能。两者在同一个 Pod 中运行,共享网络和存储卷。
image.png

应用场景

  • 日志收集和转发:Fluentd/Promtail 作为 Sidecar 采集主容器日志
  • 配置文件同步:从配置中心拉取最新配置并写入共享卷
  • 服务网格代理:Istio Envoy 作为 Sidecar 代理服务间流量(最经典用例)
  • 监控数据收集:Prometheus exporter 采集业务指标

实战配置:Web 应用 + 日志收集

image.png

apiVersion: v1
kind: Pod
metadata:
  name: web-app-with-logging
spec:
  containers:
  # 主容器:Web 应用
  - name: web-app
    image: nginx:1.20
    ports:
    - containerPort: 80
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/nginx

  # Sidecar 容器:日志收集
  - name: log-collector
    image: fluentd:v1.14
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/nginx
    - name: fluentd-config
      mountPath: /fluentd/etc

  volumes:
  - name: log-volume
    emptyDir: {}
  - name: fluentd-config
    configMap:
      name: fluentd-config

关键点:主容器和 Sidecar 通过 emptyDir 共享卷交换数据(此处共享日志目录)。Sidecar 的生命周期与主容器绑定。


二、Init Container 模式(初始化容器模式)

核心理念

如同"启动助手",在 Pod 的主容器启动前执行必要的初始化任务,确保主容器运行时环境已准备就绪。Init Container 执行完毕后会自动退出并释放资源。
image.png

应用场景

  • 环境准备与依赖检查:验证外部服务可用性、检查网络连接
  • 数据库迁移:执行数据库 schema 更新、数据初始化
  • 配置文件生成:动态生成应用配置文件、密钥注入
  • 权限与安全设置:设置文件权限、挂载密钥、安全扫描

设计优势

  1. 职责分离:初始化逻辑与业务逻辑解耦
  2. 资源优化:初始化完成后立即释放资源
  3. 错误隔离:初始化失败不影响已运行的主容器
  4. 顺序控制:多个 Init Container 按顺序串行执行,确保依赖项就绪后再启动主服务

实战配置:应用初始化

apiVersion: v1
kind: Pod
metadata:
  name: app-with-init
spec:
  # 初始化容器
  initContainers:
  - name: init-setup
    image: busybox:1.35
    command: ['sh', '-c']
    args:
    - |
      echo "初始化应用环境..."
      mkdir -p /shared/config
      echo "app.env=production" > /shared/config/app.properties
      echo "初始化完成"
    volumeMounts:
    - name: shared-data
      mountPath: /shared

  # 主容器
  containers:
  - name: main-app
    image: openjdk:11-jre
    command: ['java', '-jar', '/app/app.jar']
    volumeMounts:
    - name: shared-data
      mountPath: /app/config

  volumes:
  - name: shared-data
    emptyDir: {}

典型案例:Init Container 从 Git 仓库拉取最新代码到 Pod 的共享存储卷,然后主容器(Nginx)启动后直接使用已准备好的代码文件提供服务,实现代码更新与容器运行的解耦。


三、Ambassador 模式(大使模式)

核心理念

像"使者"一样,负责与外部世界沟通,为主容器提供网络代理服务。它将复杂的网络通信逻辑从主应用中解耦,让主容器专注于业务逻辑。
image.png

应用场景

  • 数据库连接代理:统一管理数据库连接、连接池和故障转移
  • 服务发现与负载均衡:动态发现后端服务并实现负载均衡
  • 网络安全与认证:集中处理 TLS 加密、身份验证和授权
  • API 网关功能:作为 API 网关,处理路由、限流和监控

实战配置:数据库代理

image.png

Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-with-db-proxy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-service
  template:
    metadata:
      labels:
        app: web-service
    spec:
      containers:
      # 主应用容器
      - name: web-service
        image: myapp:latest
        ports:
        - containerPort: 8080
        env:
        - name: DB_HOST
          value: "localhost"    # 通过 Ambassador 访问
        - name: DB_PORT
          value: "5432"

      # Ambassador 数据库代理容器
      - name: db-proxy
        image: haproxy:2.4
        ports:
        - containerPort: 5432
        volumeMounts:
        - name: haproxy-config
          mountPath: /usr/local/etc/haproxy
        command: ["haproxy", "-f", "/usr/local/etc/haproxy/haproxy.cfg"]

      volumes:
      - name: haproxy-config
        configMap:
          name: haproxy-config

HAProxy ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: haproxy-config
data:
  haproxy.cfg: |
    global
        daemon
    defaults
        mode tcp
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    frontend db_frontend
        bind *:5432
        default_backend db_servers

    backend db_servers
        balance roundrobin
        server db1 postgres-primary.default.svc.cluster.local:5432 check
        server db2 postgres-replica.default.svc.cluster.local:5432 check backup

关键点:主容器通过 localhost:5432 访问数据库,实际由 Ambassador(HAProxy)负责连接池管理、主从切换和故障转移,主应用无需关心这些网络细节。


四、Adapter 模式(适配器模式)

核心理念

如同一个"转换器",主要负责数据格式转换和协议适配,使原本不兼容的系统能够顺利协作。

应用场景

  • 日志格式标准化:将不同格式的日志统一转换为标准格式(如 JSON)
  • 监控指标转换:将各种监控指标转换为统一的数据格式(如 Prometheus 格式)
  • 协议转换:实现不同协议间的转换,如 HTTP 到 gRPC
  • 数据格式适配:调整数据格式以满足不同系统的需求
    image.png

实战配置:遗留系统监控数据转 Prometheus

apiVersion: apps/v1
kind: Deployment
metadata:
  name: legacy-app-with-adapter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: legacy-service
  template:
    metadata:
      labels:
        app: legacy-service
    spec:
      containers:
      # 主应用容器(遗留系统)
      - name: legacy-app
        image: legacy-service:1.0
        ports:
        - containerPort: 8080
        volumeMounts:
        - name: metrics-volume
          mountPath: /var/metrics

      # Adapter 监控适配器容器
      - name: metrics-adapter
        image: prometheus/node-exporter:latest
        ports:
        - containerPort: 9100
        volumeMounts:
        - name: metrics-volume
          mountPath: /host/metrics
        - name: adapter-script
          mountPath: /scripts
        command: ["/scripts/convert-metrics.sh"]
        env:
        - name: LEGACY_METRICS_PATH
          value: "/host/metrics"
        - name: PROMETHEUS_PORT
          value: "9100"

      volumes:
      - name: metrics-volume
        emptyDir: {}
      - name: adapter-script
        configMap:
          name: metrics-adapter-script
          defaultMode: 0755

关键点:主容器输出原始格式指标,Adapter 容器读取并转换为 Prometheus 格式后通过 HTTP 端点暴露,Prometheus 直接 scrape 即可。


四种模式对比

维度 Sidecar Init Container Ambassador Adapter
运行时机 与主容器同时运行 主容器启动前运行 与主容器同时运行 与主容器同时运行
生命周期 与主容器绑定 执行完毕后退出 与主容器绑定 与主容器绑定
核心职责 辅助增强 环境初始化 外部通信代理 数据/协议转换
数据流方向 主→Sidecar(采集) Init→共享卷→主 主→Ambassador→外部 主→Adapter→外部系统
典型代表 Istio Envoy、Fluentd DB migration、Git pull HAProxy、Cloud SQL Proxy Prometheus exporter
与 Sidecar 的区别 运行时机不同 专注出站代理 专注格式转换

选型指南

  • 需要增强主容器能力(日志、监控、安全)→ Sidecar
  • 需要启动前准备环境 → Init Container
  • 需要代理外部网络通信 → Ambassador
  • 需要转换数据格式或协议 → Adapter
  • Ambassador 和 Adapter 本质上都是 Sidecar 的特化形式,区别在于关注点不同