登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  业界新闻

Kubernetes 原生 Sidecar Containers 稳定后怎样理解生命周期

来源:17golang原创

时间:2026-11-03 16:08:05 458浏览 收藏

Kubernetes 原生 Sidecar Containers 稳定后,最容易混淆的一点是:它不是把一个普通辅助容器随手放进 containers,而是把它声明在 initContainers 中,再设置容器级 restartPolicy: Always。这样 Kubernetes 既保留初始化容器的有序启动语义,又允许这个辅助容器在应用运行期间持续工作。

官方地址:https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/

Sidecar Containers 自 Kubernetes v1.33 起为 Stable。它会先按 init container 的顺序完成启动判断,随后与应用并行运行;Pod 终止时,应用容器先停止,sidecar 再按声明顺序的反向顺序关闭。这个语义特别适合日志转发、代理和数据同步等伴随服务。

先分清三类容器的职责

在同一个 Pod 里,普通 init container 只负责启动阶段的准备工作,成功退出后才会让后续容器继续;应用容器承载主要业务;原生 sidecar 则处在两者之间:它用 init container 的声明位置获得启动顺序,又通过容器级重启策略保持运行。

类型声明位置生命周期重点典型用途
普通 init containerinitContainers启动阶段执行,结束后退出初始化目录、生成配置
原生 sidecarinitContainers + restartPolicy: Always启动后持续运行,与应用并行日志转发、代理、同步
应用容器containers承载主要业务逻辑接口服务、批处理任务
Kubernetes Pod 中应用容器、原生 sidecar、共享网络和共享卷的关系说明图
图1:Kubernetes Pod 内的容器边界与共享关系说明图,不是截图或运行证据。

最小 YAML 关键在 initContainers

声明原生 sidecar 时,决定性字段不是容器名称,而是它位于 initContainers,并拥有自己的 restartPolicy: Always。下面的示例把应用写入共享卷,sidecar 持续读取这个文件并承担日志转发的角色:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sidecar-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sidecar-demo
  template:
    metadata:
      labels:
        app: sidecar-demo
    spec:
      containers:
        - name: app
          image: alpine:3.20
          command: ["sh", "-c"]
          # 应用把示例日志写入与 sidecar 共享的目录。
          args: ["while true; do date >> /opt/logs/app.log; sleep 5; done"]
          volumeMounts:
            - name: shared-logs
              mountPath: /opt/logs
      initContainers:
        - name: log-sidecar
          image: alpine:3.20
          restartPolicy: Always
          command: ["sh", "-c"]
          # Always 让这个 init container 启动后继续运行,成为原生 sidecar。
          args: ["tail -F /opt/logs/app.log"]
          volumeMounts:
            - name: shared-logs
              mountPath: /opt/logs
      volumes:
        - name: shared-logs
          emptyDir: {}
          # emptyDir 只用于展示同一 Pod 内的共享文件边界。

这里的 emptyDir 只是为了让两个容器看到同一份文件。实际系统可以替换为合适的卷类型,但不要把“共享卷”误解为跨 Pod 的持久化存储。

启动时由 started 决定下一个 init container

普通 init container 必须完成后才会进入下一项;sidecar 则只要被 Kubernetes 判定为已经 started,就可以让后面的 init container 继续。没有配置 startupProbe 时,容器内已有进程运行通常会让 started 变为 true;配置了启动探针后,则以启动探针成功为准。

这带来一个重要结果:sidecar 可以在初始化链路中占据一个有序位置,但不会因为自己长期运行而把后续初始化永久堵住。若配置了 readinessProbe,该探针结果还会参与 Pod 的 Ready 状态,因此“已经 started”和“已经对外就绪”是两个不同判断。

initContainers:
  - name: prepare-config
    image: busybox:1.36
    command: ["sh", "-c"]
    # 先生成 sidecar 和应用都会读取的配置文件。
    args: ["echo ready > /work/status"]
    volumeMounts:
      - name: work
        mountPath: /work
  - name: proxy-sidecar
    image: envoyproxy/envoy:v1.31-latest
    restartPolicy: Always
    startupProbe:
      httpGet:
        path: /ready
        port: 9901
      # 启动探针成功后,后续 init container 才能继续。
      periodSeconds: 2
    readinessProbe:
      httpGet:
        path: /ready
        port: 9901
      # 就绪探针决定 sidecar 是否把 Pod 标记为 Ready。
      periodSeconds: 5

如果 sidecar 需要先完成自身初始化,再允许下一项执行,优先使用 startupProbe 表达这个门槛;如果只是希望控制 Pod 对外是否可用,则配置 readinessProbe。二者不要混成一个“启动成功”概念。

运行期间并行,终止时应用先停

sidecar 被标记为 started 后,会与应用容器并行运行。它们位于同一 Pod,因此共享网络命名空间,也可以按配置共享卷。修改 sidecar 镜像通常只会触发该容器重启,不会因为 sidecar 镜像变化就让整个 Pod 重新启动。

Pod 终止时,kubelet 会先等待应用容器停止,再处理 sidecar。多个 sidecar 按它们在 initContainers 中的声明顺序反向关闭,这样后声明的辅助服务先退出,前面的服务可以继续支撑尚未结束的组件。

还要注意优雅终止时间的现实边界:如果其他容器已经消耗了 Pod 的终止宽限时间,sidecar 可能来不及优雅退出而收到 SIGTERM,随后收到 SIGKILL。因此,sidecar 在 Pod 结束时出现非零退出码并不必然表示业务故障,外部工具需要结合 Pod 终止原因判断。

Kubernetes 原生 sidecar 从 started、就绪到应用先停和反向关闭的生命周期说明图
图2:原生 sidecar 的启动判断、持续运行和反向关闭语义说明图,不是截图或运行证据。

Job 场景不会被长期运行的 sidecar 卡住

在 Job 中,应用容器完成任务后,原生 sidecar 不会因为仍在运行就阻止 Job 完成。这个行为适合“主任务写结果、sidecar 持续采集或转发”的批处理场景。关键是要让应用容器的退出真正代表任务完成,并把 sidecar 当成伴随服务,而不是第二个必须独立完成的主任务。

spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: worker
          image: alpine:3.20
          command: ["sh", "-c"]
          # 主容器完成工作后退出,Job 可以据此判断任务完成。
          args: ["echo result > /work/result.txt"]
      initContainers:
        - name: collector
          image: alpine:3.20
          restartPolicy: Always
          command: ["sh", "-c"]
          # sidecar 持续观察共享目录,但不承担 Job 的完成信号。
          args: ["tail -F /work/result.txt"]

稳定后的兼容与采用边界

Sidecar Containers 首次在 Kubernetes v1.28 提供,v1.29 起默认启用相关能力,v1.33 起标记为 Stable。稳定后不能再通过 feature gate 关闭;即使显式设置相关 gate,Kubernetes 也会忽略该设置而不报错。

如果集群仍低于支持容器级 restartPolicy 的版本,不要把同一份 YAML 直接下发。可以退回普通的多个应用容器模型,但这会失去明确的 init 顺序和 sidecar 终止语义。迁移时重点检查以下项目:

  • 集群版本是否支持在 initContainers 中给单个容器设置 restartPolicy。
  • sidecar 的启动完成条件是进程启动,还是 startupProbe 成功。
  • 是否需要用 readinessProbe 影响 Pod 的 Ready 状态。
  • 日志、代理或同步服务是否真的适合与主容器共享网络和卷。
  • Pod 的资源预算是否把 sidecar 的长期运行成本算进去。

资源计算会影响调度,不只是写法变化

sidecar 虽然写在 initContainers,但它并不是一次性资源。Kubernetes 计算 Pod 的有效资源请求和限制时,会比较所有非 init 容器的合计值与 init 容器的有效值,取其中较高者,再结合 Pod overhead。sidecar 的资源声明因此可能直接影响调度、配额和 QoS,不应只按“辅助进程很轻”来估算。

判断问题采用原生 sidecar 的信号需要谨慎的信号
是否依赖启动顺序需要先启动代理或采集器,再进入下一阶段所有容器无先后关系
是否需要长期运行应用运行期间一直提供伴随服务只需执行一次准备动作
是否共享数据通过同一 Pod 的网络或卷交互需要跨 Pod 持久化或独立扩缩容
是否是批任务主容器退出应能让 Job 完成sidecar 自己也承担独立业务结果

一句话总结:原生 sidecar 解决的是“有序启动、持续伴随、可控终止”这一组生命周期问题,不是把所有辅助服务都塞进 initContainers 的通用替代方案。

相关问题

Sidecar 为什么不直接写在 containers 里?

普通应用容器没有原生 sidecar 的 init 顺序和反向终止语义。写入 initContainers 并设置 restartPolicy: Always,才能表达“先完成启动判断、再持续运行”的关系。

readinessProbe 和 startupProbe 应该怎么选?

startupProbe 用于决定容器何时算 started,影响后续 init container 是否继续;readinessProbe 用于表达是否应该把 Pod 视为就绪。一个控制启动门槛,一个控制就绪状态。

sidecar 退出码非零一定是故障吗?

不一定。Pod 终止时 sidecar 可能因宽限时间耗尽而被强制结束,外部系统需要结合终止场景,而不是只看退出码。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>