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 容器的有序启动语义。

例如日志转发器需要在应用产生日志前就位,但应用又不应该等待一个永远不会结束的普通 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,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 稳定不等于所有集群周边组件都已经正确处理该字段。迁移前我会重点检查以下边界:
- 控制面和节点版本:确保 API Server、kubelet 与实际使用的客户端能够识别并保留 init 容器上的
restartPolicy。不要只看本地kubectl版本。 - 变更准入与注入器:全量更新 Pod 的 webhook、模板渲染器或旧客户端可能在重写对象时丢弃未知字段。用
kubectl describe pod查看变更后的最终对象,而不是只看 Helm 输入文件。 - 资源与 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时应该从哪里排查?
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
448 收藏
-
490 收藏
-
339 收藏
-
328 收藏
-
科技周边 · 业界新闻 | 1小时前 | WEB开发 · PHP · parse_url PHP 8.5 Uri\Rfc3986\Uri URI extension Uri\WhatWg\Url WHATWG URL RFC 3986273 收藏
-
305 收藏
-
356 收藏
-
271 收藏
-
145 收藏
-
463 收藏
-
337 收藏
-
科技周边 · 业界新闻 | 23小时前 | 云原生 · kubernetes · 云原生 Kubernetes restartPolicy Sidecar Containers initContainers Pod生命周期458 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习