第 1 篇 把 Linkerd 控制面钉成 destination ∥ identity ∥ proxy-injector 三组件,并给出五轴排障坐标。读者若仍把「装了 Linkerd」等同于「Pod 已 mesh」,会在第一步指错组件:一次出站连接卡在成员资格还是流量重定向、identity 还是 destination,证据包完全不同。
本篇只回答一个问题:Pod 如何成为 mesh 成员,2.20 默认的 native sidecar 改变了什么,以及 membership 失败落在哪一层。 难点不在 Helm 装控制面,而在 admission 时刻 Pod spec 被改了什么、以及排障时能否把「未注入」与「已注入但重定向未就绪」分开——后者见 第 3 篇。
本篇在系列中的位置
篇目 核心内容 第 1 篇 · 控制面全景 五轴坐标系、16 篇路线 第 2 篇 · 网格成员与注入 proxy-injector、native sidecar 默认、opaque ports 第 3 篇 · 流量重定向 linkerd-init、CNI、iptables 系列目录 关键问题、阅读路径
版本锚定:Linkerd 2.20(源码 tag
version-2.20,公告 2026-06-23;edge edge-26.6.3)。native sidecar 为 2.20 默认注入形态(2.15 引入、2.19 beta、2.20 stable 默认)。机制叙述对齐 tag 与 Architecture 2.20 文档树;不以linkerd.io/docs/live 滚动页冒充该版本。无真实 Linkerd 集群则不粘贴伪造linkerd check输出或 viz 指标。
一、proxy-injector webhook
Linkerd 的 proxy-injector
是运行在控制面命名空间(默认 linkerd)的
MutatingAdmissionWebhook。Kubernetes 在 Pod
创建时向 webhook 发送
AdmissionReview;injector 检查 namespace 或
workload 是否携带 mesh
注入注解,若命中则原地修改 Pod spec,再交回
apiserver 持久化。
官方 Architecture 描述的触发条件是
linkerd.io/inject: enabled(也可通过 namespace
默认注入策略配置)。注入内容至少包括:
- 数据面
linkerd-proxy(2.20 默认作为 native sidecar,见第二节); - 流量重定向组件
linkerd-init(或在启用 CNI 时省略,见第 3 篇); - 与 identity、destination 通信所需的启动环境变量与卷挂载。
injector 与 destination、identity 是独立 Deployment:injector 挂了不会阻止已运行 Pod 的 mTLS 续签,但新 Pod 无法 mesh——这是 istio-xds/14 强调的「三组件拆分」在轴 1 上的第一个落点,而不是「另一个 istiod 进程内 injection 配置」。
除自动 webhook 外,运维还可对 manifest 执行
linkerd inject
做客户端预注入(把 YAML 发给 injector
同等逻辑处理后再 kubectl apply)。无论 CLI 还是
webhook,变异内容都遵循同一套模板:控制面版本与
linkerd-config ConfigMap 中的全局默认值(含
proxy.nativeSidecar)必须一致,否则会出现「Helm
以为开了 native、旧 injector 缓存仍写
legacy」类版本漂移——升级后应滚动 injector 并重启受影响
workload,而不是只改业务 Deployment 镜像。
flowchart TD
create["Pod CREATE request"] --> apiserver["kube-apiserver"]
apiserver --> webhook["proxy-injector webhook"]
webhook --> check{"inject annotation?"}
check -->|no| pass["unchanged spec"]
check -->|yes| mutate["append proxy plus init or CNI flag"]
mutate --> persist["persisted Pod spec"]
pass --> persist
图:注入决策在 admission 层完成;未带注入注解的 Pod 不会获得 proxy 容器。
谱系:Sidecar 模式在 Burns & Beda,
Designing Distributed
Systems(2018)中被形式化为「与主容器同生命周期、共享网络命名空间的辅助进程」——Linkerd
的 injector 是把该模式自动化到 Kubernetes
admission 路径上,而非应用自行拉 sidecar 镜像。与 Istio 把
injection 配置合并进 istiod 单进程不同,Linkerd 把 webhook
独立成组件,故障域更细,排障时先查
linkerd-proxy-injector Deployment 与 webhook
配置是否就绪。
namespace 级默认注入:除 Pod 注解
linkerd.io/inject: enabled 外,常见做法是给
namespace 打
linkerd.io/inject: enabled,使该空间内新建 Pod
默认 mesh。关闭单个 workload 可用
linkerd.io/inject: disabled 覆盖。这与 Istio 的
istio-injection=enabled 标签同类,但 Linkerd
不经过 istiod 内部模板合并——injector 直接读集群中的
linkerd-config 与版本化注入模板,因此
控制面版本与 injector
镜像必须成对升级,否则会出现注入 spec 与 proxy
镜像能力不匹配(例如 2.20 native 默认未生效到
injector)。
二、native sidecar 默认(2.20 门)
Kubernetes KEP-753(Native
Sidecar Containers,1.28 alpha → 1.33 GA)允许 init 容器设置
restartPolicy: Always,使其在 init
阶段完成后仍以 sidecar 身份常驻。Linkerd 自
2.15 支持该模式,2.19 标为
beta,2.20
将其提升为默认:proxy 以带
restartPolicy: Always 的 init
容器注入,而非常规 containers 列表中的普通
sidecar。
官方 Native sidecars 文档与 2.20 公告写明默认行为及关闭方式:
| 层级 | 关闭 native sidecar(回退 legacy 形态) |
|---|---|
| 全局 Helm | proxy.nativeSidecar: false |
| namespace / workload | config.linkerd.io/proxy-enable-native-sidecar: "false" |
config.beta.linkerd.io/proxy-enable-native-sidecar
在 2.20 已弃用,应改用上述稳定键。
2.20 门改变了什么(机制,非性能排名):
- 启动顺序:native sidecar proxy 在应用
initContainers之前即可就绪,缓解「init 需要出网但 proxy 尚未启动」的经典竞态(CNI 路径下 legacy 模式仍可能踩坑,见第 3 篇)。 - Job / CronJob 终止:legacy 模式下 proxy 作为普通容器常在 Job 主容器退出后继续运行,导致 Pod 无法 Completed;native sidecar 由 kubelet 按平台语义与主容器协同终止(官方博客 The Proxy Died First 讨论 shutdown race)。
- 证据包形状:排障时看 Pod spec——native
路径下
linkerd-proxy出现在initContainers且restartPolicy: Always;legacy 路径下 proxy 在containers,另有一个一次性linkerd-initinit 容器。
控制面升级到 2.20 后,新创建或滚动重启的 meshed workload 默认采用 native 形态;未重启的旧 Pod 仍保留升级前 spec,排障必须分列证据包,不能把集群版本当作每个 Pod 的注入形态。
与 Istio
注入模型的对照(机制,非优劣):Istio 由 istiod
生成 sidecar 容器模板,变更常体现为 istiod 版本与
istio-proxy 镜像的配对;Linkerd 由独立 injector
Deployment 读取 linkerd-config,模板与
linkerd-proxy 镜像由 Linkerd 发行物钉死。xDS
通用协议与专用 linkerd2-proxy-api
的争论在控制面 API 层展开(第 6 篇);在轴 1
上,两者差异首先是 webhook 组件是否独立 与
native sidecar 是否为 2.20 默认门。
三、legacy init+sidecar 路径
在 proxy.nativeSidecar=false
或注解显式关闭时,injector 回退 legacy
布局,与 2.15 之前的主流形态一致:
| 组件 | 在 Pod 中的位置 | 作用 |
|---|---|---|
linkerd-init |
一次性 initContainers |
安装 iptables 规则,将 TCP 流量导向 proxy(CNI 启用时省略) |
linkerd-proxy |
普通 containers |
数据面微代理 |
该路径在 2.20 仍受支持,并非删除项。官方
Architecture 仍把 linkerd-init
描述为「在任何其他容器启动前运行」的 init 容器——在 legacy
模式下,init 先写完 iptables 再退出,随后应用容器与 proxy
并行启动。
与 native 的分叉点仅在 injector 写 spec 的时刻;destination、identity 协议不变。运维上常见误区是把「集群已 2.20」等同于「所有 Pod 已是 native sidecar」——实际上只有触发过重新注入的 workload 才会更新形态。
legacy 路径在以下场景仍合理或不可避免:
- 运行低于 native sidecar GA 要求的 Kubernetes
版本,需显式
proxy.nativeSidecar: false; - 监控 / 日志采集假设 proxy 位于
containers而非initContainers,短期无法改 chart; - 与第三方准入或 OPA 策略交互时,对 init 容器数量与
restartPolicy有硬编码检查。
排障 legacy Pod 时,证据包应同时记录
linkerd-init 退出码 与
proxy 容器 restart 次数。native 路径下
proxy 位于 initContainers,但未启用 CNI
时 linkerd-init 仍可能存在(负责
iptables);启用 CNI 则两者都可能从 spec 中省略。轴 1 与轴 2
的交界见第 3 篇。
四、opaque ports 与跳过注入
注入轴不仅决定「有没有 proxy」,还决定哪些端口走 proxy 的协议栈。两类配置常被混淆:
| 机制 | 典型注解 | 流量路径 | mTLS / 指标 |
|---|---|---|---|
| opaque ports | config.linkerd.io/opaque-ports |
仍经 proxy,跳过 HTTP 协议探测,按 TCP 透传 | 保留 |
| skip ports | config.linkerd.io/skip-inbound-ports /
skip-outbound-ports |
iptables 绕过 proxy | 不保留 |
官方 Protocol Detection 与 Proxy Configuration 强调:opaque 一般优先于 skip——前者只关掉探测,不拆掉安全与观测;后者仅适合调试。opaque 注解应标在流量接收方(destination),skip-outbound 标在发送方。
此外,注入本身也可被关闭:linkerd.io/inject: disabled
显式跳过 webhook
变异;某些系统命名空间默认不注入。这与「已注入但端口
opaque」是不同问题:前者无 proxy 容器,后者有 proxy
但特定端口行为不同。
默认 opaque
端口列表由控制面全局配置提供(安装时写入
linkerd-config),注解
config.linkerd.io/opaque-ports 在 Pod
级覆盖默认值而非追加——误以为是「追加」会导致以为已声明的端口仍未
opaque。对数据库类工作负载,还应优先尝试 Service
ports[].appProtocol(Kubernetes 1.19+),使
meshed 客户端在走协议探测前即可获知语义;仅当 headless、直连
Pod IP 或 unmeshed 客户端等场景才必须依赖 Pod 注解(官方
Protocol Detection)。
| 场景 | 推荐配置位置 | 原因 |
|---|---|---|
| ClusterIP Service,meshed 客户端 | Service appProtocol |
客户端经 Service 发现协议 |
| Headless / Pod IP | 接收方 Pod opaque-ports |
无 Service 级端口元数据 |
| 调试旁路 | skip-*-ports |
明确放弃 mTLS,仅短期 |
开放争论:opaque 流量在入站侧汇聚到 proxy 的 inbound 端口(默认 4143),与基于端口的 NetworkPolicy 可能冲突——社区 issue 表明需允许 4143 入站,否则 CNI/策略层表现为「连不上」而 mesh 成员资格实际成立。该症状易被误判为未 mesh,实则是轴 1 配置与轴 2 策略的交界,详见第 3 篇第三节。
五、membership 失败表象
排障口诀:先确认轴 1(注入与成员),再查轴 2(重定向)。下列表象与建议落点:
| 表象 | 优先核对 | 常见根因 |
|---|---|---|
Pod 无 linkerd-proxy 容器 |
linkerd.io/inject、namespace
注入策略、injector webhook |
未命中注入条件;webhook 失败或 injector 不可用 |
| 有 proxy 但非预期形态 | initContainers vs
containers;restartPolicy |
2.20 默认 native 与 legacy 混部;Helm/注解覆盖 |
| meshed 客户端访问失败,对端无 proxy | 对端 Pod spec | 对端未 mesh(轴 1),不是 destination 空端点 |
| 仅特定端口失败 | opaque / skip 注解;Service
appProtocol |
协议探测或 NP 与 inbound 端口不匹配 |
| Job 长期 Running | proxy 容器形态 | legacy Job 未退出;可评估 native sidecar 或官方 Job 指引 |
注入决策与 xDS
无关:无论数据面之后如何订阅
destination,membership 只由 admission
结果决定。把「未注入」当成「xDS 未推送」是 istiod
心智模型的误用;Linkerd 读者应在 Pod spec 层完成轴 1
否证,再进入 linkerd2-proxy-api(第 6
篇)。同样,linkerd inject 的 dry-run
语义是预览变异后 YAML,不替代集群内 webhook
是否注册成功——webhook 配置错误时 CLI 本地 inject
仍可能成功,而集群内自动注入失败。
不要在轴 1 未确认时改 ServiceProfile
或重装 destination——那属于轴 4–5。与 istio-xds/14
对照:Istio 注入失败查 istiod webhook 与 sidecar
模板;Linkerd 查 linkerd-proxy-injector 与
native vs legacy spec 形状。
开放问题:native sidecar 依赖 Kubernetes 1.33+ GA 语义时,混合版本节点集群如何在 namespace 级关闭 native 而业务 namespace 保持默认,仍缺少统一 runbook;本系列 第 16 篇 与 Job/CronJob 默认策略一并收束。轴 1 排障的底线是:先读 Pod spec,再读 Helm values,最后才动控制面重装。
多集群与注入:multicluster
扩展不改变单集群 injector 语义——每个集群仍有自己的
linkerd-proxy-injector 与
linkerd-config。联邦服务发现发生在 destination
层(第 11 篇),而非在 webhook 层合并 Pod 模板;因此「集群 A
已 mesh、集群 B 未注入」是轴 1
在各自集群独立否证的问题。
ExternalWorkload 与 VM 扩展(2.20 公告提及 Windows VM mesh expansion):轴 1 对非 Pod 工作负载的注入形态不在本篇展开,但原则不变——无 proxy 则无 mesh 成员资格;VM 侧 harness 与 K8s webhook 是不同入口,排障时勿把 VM 未注册当成 injector 故障。
参考资料
规范 / 官方文档(A)
- Linkerd, Architecture(proxy-injector、data
plane 默认 native sidecar;
version-2.20文档树) - Linkerd, Native sidecars(2.20
默认;
proxy.nativeSidecar与config.linkerd.io/proxy-enable-native-sidecar) - Linkerd, Proxy
Configuration(
opaque-ports、skip-inbound-ports、skip-outbound-ports) - Linkerd, Announcing Linkerd 2.20(2026-06-23;native sidecar 默认门)
- Kubernetes KEP-753, Sidecar Containers(native sidecar 平台语义)
博客 / 维护者文章(B)
- Linkerd, The Proxy Died First: How Kubernetes Native Sidecars Solve the Service Mesh Shutdown Problem(2026-05-18)
学术 / 设计谱系(A)
- Burns & Beda, Designing Distributed Systems(O’Reilly 2018)— sidecar 模式定义
站内对照
上一篇:控制面全景
下一篇:流量重定向
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Linkerd】排障坐标系:五轴否证与 native/legacy 证据包
按 Linkerd 五轴映射未 mesh、TLS 失败、无端点、策略拒绝与 502;强调先点名轴、native sidecar 与 legacy init+sidecar 分列证据包;并说明不可与 istio-xds 五轴混因果。
【Linkerd】流量重定向:linkerd-init、CNI 与 opaque 端口
拆解 meshed Pod 内 TCP 如何经 iptables 或 Linkerd CNI 进入 linkerd2-proxy;inbound 与 opaque 端口语义,以及与注入轴衔接的重定向失败落格。
【Linkerd】选型收束与开放问题:排除树与系列边界关闭
用机制排除树收束何时不该跑 Linkerd;回收 istio-xds/16 的 Linkerd 叶;列出 native sidecar 与 Job、GAPI 双轨、与 Falco/Tetragon 联合 runbook 等开放问题;以 ADR 友好语言关闭续作边界。
【Linkerd】控制面全景:缺口、五轴坐标系与 16 篇路线
相对 istio-xds/14 对照篇与 architecture/76 税文,钉清 Linkerd 2.20 非 xDS 控制面缺口;定义注入、identity、destination、策略与数据面五条轴,并强调 native sidecar 与 legacy 路径分列证据包。