identity
解决「我是谁、信任谁」;destination
解决「目标服务有哪些端点、允许什么策略、路由/重试/超时如何」——并通过
linkerd2-proxy-api 的 destination
gRPC 流式推给每个 outbound proxy。读者若把
destination 当成「轻量 Pilot」却用 xDS 口令(CDS/EDS type
URL)排障,会查错订阅形状;istio-xds/14
已说明应按目标 Get() 流理解。
本篇回答:destination Deployment 内部四容器各做什么,Kubernetes 事件如何变成 proxy 可见的端点更新,2.20 内存优化改变了什么。 API 字段级语义见本系列第 6–7 篇;本篇钉架构与 Informer 驱动模型。
本篇在系列中的位置
篇目 核心内容 第 4 篇 · identity 服务 CSR、mTLS 轮转 第 5 篇 · destination 架构 四容器、Informer、2.20 内存门 第 6 篇 · linkerd2-proxy-api gRPC 服务与 xDS 对照 系列目录 关键问题、阅读路径
版本锚定:Linkerd 2.20(源码 tag
version-2.20)。架构对齐 Architecture destination 节、2026 维护者博客 Deep Dive: How linkerd-destination works in the Linkerd Service Mesh,以及linkerd/linkerd2的controller/api/destination(@version-2.20)。无真实集群则不粘贴伪造destination.Get流内容或内存曲线。
一、destination 控制器
官方 Architecture 将 destination 服务列为数据面 proxy 的「行为配置源」:服务发现(发到哪里、对端期望 TLS 身份)、策略信息、ServiceProfile(按路由指标/重试/超时)等均经此服务提供。
实现上,linkerd-destination Pod 内的
destination
容器(Go)是事件驱动控制器:通过
client-go 的 Informer /
Reflector 监视 Kubernetes
API(Pod、Service、EndpointSlice 等),避免对
apiserver 轮询。2026 年官方深度文强调:当 Pod
上线或 EndpointSlice 变更时,事件进入
EndpointTranslator 等翻译层,将 K8s
对象转为 proxy
可消费的端点描述(地址、权重、协议提示、身份元数据等)。
数据面向 destination 的交互形状是
按目标查询的长连接流:proxy
对某一权威名称(如
my-svc.ns.svc.cluster.local:port)调用
destination.Get(),服务端保持 gRPC 流打开并
推送后续变更——这与 xDS 的「按资源类型 +
名字集合订阅」不同,排障时应问「这条目标的 Get
流是否活着」,而不是「EDS 订阅 ACK 了吗」。
除 Get() 外,同一 API 还提供
GetProfile() 流,承载
ServiceProfile 中的按路由指标、重试与超时(第 9
篇规划)。destination 容器把 EndpointSlice 变更与 Profile
变更汇合为 proxy 可见的响应;sp-validator
与 policy 容器则在 admission 或并行 watch
路径上提前拦截非法输入,避免污染已建立的流状态。
flowchart LR
k8s["Kubernetes API watches"] --> informer["Informer Reflector"]
informer --> translator["EndpointTranslator"]
translator --> grpc["destination.Get stream"]
grpc --> proxy["linkerd2-proxy outbound"]
图:控制面从事件到 per-target 流;节点英文标签便于渲染。
谱系:Informer 模式源自 Kubernetes controller 生态(Borca et al. 的控制器模式实践),Linkerd 将其用于「把集群动态状态投影到 mesh 路由面」。争论点在于 per-target 流 的可扩展性:订阅粒度细、语义直接,但在超大服务名扇出时连接与状态成本成为开放问题(本系列第 16 篇收束;不在此写未测数字)。
与 istiod 合并进程 + xDS 广播
对照:Pilot 侧常为多种资源类型维护统一推送管道;Linkerd
destination 为每个活跃目标维护独立 gRPC 流,2.20
内存优化减少的是等价过滤器订阅者之间的重复状态,不是把协议改成
xDS。来自 istio-xds 系列的读者应把「无 EDS
订阅」翻译成「检查该 service 的 Get() 流与
EndpointSlice watch 是否一致」。
二、sp-validator
同一 Pod 内的 sp-validator 容器运行 ValidatingAdmissionWebhook,在 ServiceProfile 资源持久化到 etcd 之前校验语法与约束。官方深度文将其定位为「守门人」:坏配置被挡在集群外,避免 destination 向数千 proxy 推送无效 Profile。
与 destination 控制器的关系是 分工而非串行依赖:
| 组件 | 触发时机 | 失败后果 |
|---|---|---|
| sp-validator | ServiceProfile CREATE/UPDATE admission | 资源被拒绝,客户端收到 webhook 错误 |
| destination | 运行时 watch 已合法 CR | Profile 进入发现响应 |
排障「路由/重试不生效」时,先确认 ServiceProfile 是否通过校验(轴 4),再查 destination 是否 watch 到该资源(轴 3–4 交界)。本篇不展开每条 Profile 字段;见本系列第 9 篇规划。
Webhook
失败与运行时失败的证据包不同:前者在
kubectl apply 时返回 Denied 与
webhook 消息;后者 Profile 已存在但 proxy 仍用默认路由——需查
GetProfile() 流是否建立、destination 日志是否
watch 到对应 Service 名。不要把 admission 成功误当作「L7
行为已生效」,中间还有 destination 索引与流推送延迟(第 7
篇展开,不写未测延迟数字)。
三、policy 容器
policy 容器是独立控制器,求值 Server、AuthorizationPolicy、MeshTLSAuthentication 等策略 CRD(Linkerd 2.x policy 模型),并把结果供 destination 组合进对 proxy 的响应。官方深度文强调「解耦」:策略求值不与端点翻译缠在同一 goroutine 热路径,便于独立扩缩与故障隔离。
轴 4(策略)与轴 3(发现)在 proxy 侧汇合:outbound 发起连接前需要「端点列表 + 是否允许 + mTLS 要求」;inbound 侧由数据面 enforcement(第 10 篇规划)。destination Pod 内的 policy 容器负责 把 K8s 策略对象变成控制面决策,而非在应用 Pod 内执行 iptables。
策略求值与端点翻译解耦的好处是:policy
控制器可独立升级或扩容,且 admission 阶段的 ServiceProfile
错误不会污染已运行的 Get() 流。代价是排障「403
/ denied」时必须分清是 policy 容器 deny
还是 数据面 inbound
enforcement,二者在指标与日志入口不同(第 8、13
篇规划)。
四、反身 proxy
destination Pod 的第四个容器是注入的
linkerd-proxy——控制面「吃自己的狗粮」:组件间
gRPC 与控制面 HTTP 流量同样经 mesh,获得 mTLS
与黄金指标。这与三组件各自 Deployment
拓扑一致:不是三个裸 Pod,而是 meshed
控制面。
反身 proxy 的运维含义:
- 控制面升级或 identity 故障会同时表现为「destination 业务容器健康」与「其 sidecar 握手/发现」;
- 抓包或 tap 控制面流量时,路径与业务 Pod 相同,需用五轴中数据面健康轴(第 13 篇规划)一并查看。
flowchart TB
subgraph dest_pod ["linkerd-destination pod"]
dest["destination"]
spv["sp-validator"]
pol["policy"]
px["linkerd-proxy"]
end
k8sapi["Kubernetes API"] --> dest
k8sapi --> pol
adm["ServiceProfile admission"] --> spv
dest --> px
pol --> dest
图:四容器分工;gRPC 对外仍通过 Service 暴露,Pod 内协作。
EndpointTranslator 的角色(官方 2026
深度文):EndpointSlice 事件进入 translator
后,被转换为带地址、权重、可用区与 TLS
身份提示的端点集,再附着到对应目标的 Get()
流。translator 不替代 kubelet 就绪语义——selector 错误时
destination 会诚实推送空集,与「对端未
mesh」或「策略拒绝」表象不同(第 13 篇分列)。
四容器扩缩容:Kubernetes 对单 Pod 内容器统一调度;destination Pod 内任一容器 OOM 会导致整 Pod 重启,四进程共享同一生命周期边界。这与「三独立 Deployment」的拓扑看似矛盾——实际上 跨 Pod 的故障域(destination 挂而 identity 仍活)在 Deployment 层成立,Pod 内仍是单故障域。2.20 内存优化降低的是 destination 容器 OOM 概率,不改变四容器同 Pod 的事实。
五、2.20 内存优化门(指针 12)
Linkerd 2.20 公告将 destination 控制器内存优化列为控制面 headline:在端点变更频繁的大集群中,destination 往往占控制面内存大头。2.20 重构 内部状态管理——据公告与 changelog #15166,在负载测试中通过 在具有相同过滤条件的订阅者之间共享端点过滤与 diff 状态,内存最高约降 84%(官方 load test 口径;非本站 benchmark)。
机制含义(工程判断,依据公告措辞):
- 2.20 之前:per-subscriber 状态随 proxy 连接数近似线性增长,在 churn 高的集群易触发 destination OOM;
- 2.20 之后:等价过滤条件的
Get()流共享后端状态,减少重复 EndpointSlice diff 副本。
运维门登记为 第 12 篇 ·
运维与升级 的主话题:升级后应结合 Prometheus
观察 linkerd-destination 内存,再调整
request/limit——不要直接把公告百分比当作你的集群节省量。本节只钉「2.20
改变了 destination 状态模型」,不展开 cert-manager
或制品边界(第 15 篇)。
工程间隙:论文与公告中的负载测试通常假设高
Pod churn、大量并发 Get()
流;若你的集群服务名扇出小、churn
低,内存下降可能不明显,但行为语义不变。相反,在 churn
极高且策略复杂的集群,destination
仍可能是第一个需要水平扩容的控制面组件——优化的是单副本内存曲线,不是取消
watch 成本。与 istiod 合并进程相比,Linkerd 选择拆分
destination 使 OOM 故障域局部化,代价是组件间 gRPC
依赖需在五轴排障中单独点名。
| 门 | 2.20 事实 | 主篇 |
|---|---|---|
| destination 内存共享优化 | 有(#15166) | 本篇、12 |
| rate-limit-aware LB | 有(数据面) | 10 |
| native sidecar 默认 | 有 | 02、03 |
下一篇衔接:第 6 篇将展开
linkerd2-proxy-api 四个 gRPC 服务(destination
/ identity / inbound / tap)的 proto 边界与相对 xDS
的寻址差;本篇四容器拓扑是理解「为何 policy 与 destination
同 Pod
却不同进程」的前提。读者若只记一个结论:destination
Pod 是发现、Profile 校验、策略求值与自 mesh 的合体,2.20
优化的是其中 destination 容器的内存状态模型。
空端点 vs 流断开:Get()
流因网络或 destination 重启而断开时,proxy 会按 gRPC
客户端语义重连;若 Kubernetes 侧确实无 Ready
端点,流可能仍活着但推送空集——二者在应用层都可表现为超时,但证据包不同:前者查
destination Pod 事件与 gRPC 日志,后者查 EndpointSlice 与
Service selector(第 7 篇)。
参考资料
规范 / 官方文档 / 源码(A)
- Linkerd, Architecture(destination 服务职责)
- Linkerd, Deep Dive: How linkerd-destination works in
the Linkerd Service
Mesh(2026-02-26;四容器、Informer、EndpointTranslator、
Get()流) linkerd/linkerd2@version-2.20:controller/api/destination- Linkerd, Announcing Linkerd 2.20(destination 内存优化;#15166)
linkerd/linkerd2-proxy-api(destination gRPC 定义)
站内对照
争论 / 开放问题
- per-target gRPC 流 vs xDS type-subscription 的可扩展性权衡(机制对照见 istio-xds/14;本系列 06–07 展开,16 收束)
上一篇:identity 服务
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
【Linkerd】服务发现流:per-target Get 与 EndpointTranslator
展开 Linkerd 2.20 destination.Get 的 per-target 流式语义:EndpointTranslator 如何把 EndpointSlice 增量翻译成 add/remove/no_endpoints,identity 与 zone 富化,以及相对 xDS EDS 的失败落格与空流表象。
【Linkerd】控制面全景:缺口、五轴坐标系与 16 篇路线
相对 istio-xds/14 对照篇与 architecture/76 税文,钉清 Linkerd 2.20 非 xDS 控制面缺口;定义注入、identity、destination、策略与数据面五条轴,并强调 native sidecar 与 legacy 路径分列证据包。
【Linkerd】linkerd2-proxy-api:专用 gRPC 与 xDS 寻址差
钉清 Linkerd 2.20 控制面与 linkerd2-proxy 之间的四套专用 gRPC 服务(destination/identity/inbound/tap),说明 per-target Get 流式寻址与 xDS type-subscription 的机制差,以及错误落在 gRPC 层而非 ACK/NACK。
【Linkerd】策略模型:Server、AuthorizationPolicy 与 policy 容器
说明 Linkerd 2.20 策略 CRD(Server、AuthorizationPolicy、MeshTLSAuthentication)如何与 destination Pod 内 policy 容器分工,入站授权求值位置,以及策略拒绝与发现失败如何分列表象。