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

Kubernetes 1.35 sidecar原生 sidecar 稳定后工作负载怎样调整

来源:17golang原创

时间:2026-11-04 14:45:22 378浏览 收藏

Kubernetes 1.35 里,原生 sidecar 已经不应该再被当成“需要额外开关才能试用”的实验能力:官方文档标明它从 v1.33 起稳定,原来的 SidecarContainers feature gate 也已经锁定。真正需要调整的是工作负载模板,把辅助容器的启动顺序、就绪条件、终止顺序和 Job 完成语义写清楚。

我在迁移这类 Pod 时会先问一个问题:这个辅助进程是否必须先于应用启动、持续伴随应用,并且在应用结束后再退出?如果三个条件都成立,才优先使用原生 sidecar;只需要一次性准备文件的仍然是普通 init 容器,不要求顺序的并行进程则继续放在 containers。

最小改法是把长驻辅助容器从 containers 移到 initContainers,并设置 restartPolicy: Always;然后为真正的依赖补上探针,分别审查 Deployment 和 Job 的退出逻辑。

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

先把 sidecar 的职责放回 Pod 生命周期

普通容器并排放在 spec.containers 时,Kubernetes 不会替你表达“谁先启动、谁最后退出”。很多旧模板只能靠入口脚本轮询本地端口,或者让 sidecar 自己无限等待。原生 sidecar 的关键区别在于:它仍写在 initContainers,但带有容器级 restartPolicy: Always,启动后保持运行,同时保留 init 容器的有序启动语义。

原生 sidecar 与常规 init 和应用容器的启动顺序结构说明图
图1:结构说明图,展示原生 sidecar 的启动顺序、就绪关系和共享 Pod 资源。

例如日志转发器需要在应用产生日志前就位,但应用又不应该等待一个永远不会结束的普通 init 容器。可以这样改写模板:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: report-api
spec:
  selector:
    matchLabels:
      app: report-api
  template:
    metadata:
      labels:
        app: report-api
    spec:
      # 只做一次性文件准备的容器仍然是普通 init 容器
      initContainers:
        - name: prepare-config
          image: busybox:1.36
          command: ["sh", "-c", "cp /input/config.yaml /work/config.yaml"]
          volumeMounts:
            - name: work
              mountPath: /work
        # restartPolicy: Always 让这个 init 容器成为原生 sidecar
        - name: log-forwarder
          image: example/log-forwarder:1.4
          restartPolicy: Always
          startupProbe:
            httpGet:
              path: /healthz
              port: 15020
            failureThreshold: 30
            periodSeconds: 2
          readinessProbe:
            httpGet:
              path: /ready
              port: 15020
            periodSeconds: 2
          volumeMounts:
            - name: work
              mountPath: /var/log/app
      containers:
        - name: api
          image: example/report-api:2.8
          # 应用与 sidecar 通过同一个 Pod 网络和 volume 协作
          volumeMounts:
            - name: work
              mountPath: /var/log/app
      volumes:
        - name: work
          emptyDir: {}

这里的重点不是复制字段,而是把职责拆开:prepare-config 做完就退出,log-forwarder 保持运行,api 只承担业务。原生 sidecar 和应用容器共享 Pod 的网络命名空间,也可以通过 emptyDir 共享文件,但这不意味着它们的资源请求可以省略。

候选方案怎么选:原生 sidecar、普通容器还是 init

稳定之后最容易出现的误区,是把所有辅助进程都迁移到原生 sidecar。我的做法是先按约束筛选,而不是按“新能力”筛选。

场景推荐写法理由不必迁移的情况
一次性下载配置或生成目录普通 init 容器完成后退出,应用只消费结果需要持续刷新配置
长驻日志、代理或同步辅助进程原生 sidecar可表达先启动、伴随运行、最后退出不依赖启动顺序且与应用完全独立
两个同等重要的服务共同决定 Pod 健康普通容器不需要 init 阶段的有序保证辅助进程必须先就绪
一次性 Job 中的日志收集原生 sidecar主容器完成后 sidecar 不会阻塞 Job 完成收集结果必须在主容器退出前落盘

如果 sidecar 只是在同一个 Pod 里“顺手启动”,但应用并不等待它,也没有共享数据或生命周期要求,继续使用普通容器反而更直白。稳定能力的价值是准确表达约束,而不是增加模板字段。

把“进程已启动”改成“服务已就绪”

原生 sidecar 会在其启动状态满足条件后允许后续 init 容器继续推进。没有 startup probe 时,容器里有进程运行就可能被认为已经 started;如果应用依赖 sidecar 的 HTTP 接口、证书或本地 socket,仅仅看到进程存在并不够。

迁移时应把等待逻辑从应用入口脚本移到 sidecar 的探针。startupProbe 适合描述“初始化完成”,readinessProbe 适合描述“现在可以接收依赖请求”。如果 Pod 的 Ready 状态必须反映 sidecar 的工作状态,就给 sidecar 配置 readiness probe;否则 sidecar 短暂未就绪可能被应用误判成自身故障。

# 查看 Pod 中 init、sidecar 和应用容器的状态字段
kubectl get pod report-api-0 -o jsonpath='{range .status.initContainerStatuses[*]}{.name}{" started="}{.started}{" ready="}{.ready}{"\n"}{end}'

# 查看事件,区分探针失败、镜像拉取和真正的调度问题
kubectl describe pod report-api-0

上面的命令只读状态,不改变工作负载。排查时我会先看 started、ready 和事件时间,再判断是探针路径错误、端口未监听、镜像问题,还是变更准入后字段被抹掉。

Deployment 和 Job 要分别调整

长驻 Deployment 和一次性 Job 的生命周期目标不同,不能共享一套“等待 sidecar 退出”的脚本。

Deployment 与 Job 使用原生 sidecar 时的终止和完成关系说明图
图2:生命周期说明图,对比 Deployment 与 Job 使用原生 sidecar 时的结束语义。

对于 Deployment,Pod 终止时 kubelet 会先让主要应用容器结束,再按相反顺序处理 sidecar。这样日志转发或代理有机会处理应用最后产生的数据,但 sidecar 不应承担不可丢失的事务提交,真正需要持久化的结果仍要落到合适的外部存储。

对于 restartPolicy: Never 或 OnFailure 的 Job,原生 sidecar 不会因为自己持续运行而阻止 Pod 完成。主容器完成后,Job 可以进入完成状态;这正是迁移时最值得删除的旧逻辑:不要再让主容器等待一个永不退出的 sidecar,也不要为“sidecar 最后退出”额外写一个共享信号文件来欺骗 Job 控制器。

apiVersion: batch/v1
kind: Job
metadata:
  name: export-report
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: exporter
          image: example/exporter:3.2
          command: ["/bin/export"]
          # 主容器完成后,Job 可以结束,不等待 sidecar 自己退出
      initContainers:
        - name: upload-log
          image: example/log-uploader:1.4
          restartPolicy: Always
          command: ["/bin/sidecar"]
          # sidecar 只负责伴随收集,不能替代结果持久化
          volumeMounts:
            - name: logs
              mountPath: /var/log/export
      volumes:
        - name: logs
          emptyDir: {}

如果上传动作必须确认成功后 Job 才算成功,就把“确认上传”设计成主容器的显式步骤,或者使用独立的后处理工作流,不要把业务成功条件藏在 sidecar 的退出时机里。

稳定能力落地前,先检查三个兼容边界

原生 sidecar 稳定不等于所有集群周边组件都已经正确处理该字段。迁移前我会重点检查以下边界:

  1. 控制面和节点版本:确保 API Server、kubelet 与实际使用的客户端能够识别并保留 init 容器上的 restartPolicy。不要只看本地 kubectl 版本。
  2. 变更准入与注入器:全量更新 Pod 的 webhook、模板渲染器或旧客户端可能在重写对象时丢弃未知字段。用 kubectl describe pod 查看变更后的最终对象,而不是只看 Helm 输入文件。
  3. 资源与 QoS:sidecar 仍然消耗资源。Pod 的有效请求会同时受到 init/sidecar 阶段和运行阶段容器请求影响,不能因为 sidecar 放到了 initContainers 就把它当作零成本。

若注入器同时保留旧式普通容器 sidecar 和原生 sidecar,可能造成重复进程和重复资源请求。迁移方案必须明确“旧模式关闭条件”,并准备一个只删除新字段、恢复旧模板的回滚版本。

我的迁移决策表

最后可以用下面的规则快速判断,不必因为版本升级就全量改写:

问题是否
辅助容器必须在应用前启动并保持运行?继续判断探针和共享资源,优先原生 sidecar普通容器或普通 init 更简单
主容器完成后,辅助进程还要短暂收尾?使用原生 sidecar,删除 Job 等待脚本按应用自身退出即可
注入器会完整重写 Pod 对象?先升级或审查注入器字段保留能力可以从单个工作负载灰度
sidecar 的就绪决定应用能否接收请求?补 readinessProbe 并观察 Pod Ready只需要 startupProbe 或不设置依赖探针

一句话总结:Kubernetes 1.35 的原生 sidecar 适合把“伴随关系”交给 Pod 生命周期管理,但不替你定义业务成功、数据持久化和组件兼容。先按职责选择容器类型,再把探针、Job 完成条件、资源请求和准入链路一起迁移,工作负载才会真正变得可维护。

相关问题

  • 原生 sidecar 为什么要写在 initContainers 而不是 containers?
  • Job 使用原生 sidecar 后,主容器完成时还需要显式关闭 sidecar 吗?
  • sidecar 的 readinessProbe 会不会影响整个 Pod 的 Ready 状态?
  • 旧版 webhook 丢掉 restartPolicy: Always 时应该从哪里排查?
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>