土法炼钢 · 系统与基础设施

【Linkerd】流量重定向:linkerd-init、CNI 与 opaque 端口

文章导航

分类入口
kubernetesnetwork
标签入口
#linkerd#linkerd-init#cni#iptables#opaque-ports#traffic-redirect#v2.20

目录

第 2 篇 确认 Pod 已被 proxy-injector 写入 linkerd-proxy(及可能的 linkerd-init)。成员资格成立只说明数据面容器存在;应用流量要获得 mTLS、发现与策略,还必须经过 iptables 重定向(或 CNI 等价路径)进入 proxy。许多「已注入但连不上」的事故落在轴 2,却被误当成 identity 或 destination 问题。

本篇回答:TCP 如何透明进入 linkerd2-proxy,init 与 CNI 两条路径差在哪,inbound/opaque 端口如何改变入站路径。 注入决策见第 2 篇;CSR 与握手见 第 4 篇

本篇在系列中的位置

篇目 核心内容
第 2 篇 · 网格成员与注入 proxy-injector、native sidecar
第 3 篇 · 流量重定向 linkerd-init、CNI、iptables、opaque
第 4 篇 · identity 服务 CSR、mTLS 轮转
系列目录 关键问题、阅读路径

版本锚定:Linkerd 2.20(源码 tag version-2.20)。数据面默认 native sidecar;CNI 文档 2.20 树写明 native 下应用 initContainers 可在 proxy 就绪后出网。机制对齐 ArchitectureCNI Plugin 2.20 文档。无真实集群则不粘贴伪造 iptables 列表或 linkerd check 片段。


一、linkerd-init iptables

默认路径(未启用 Linkerd CNI)下,injector 在 Pod 中插入 linkerd-init 作为 init 容器。它在任何应用容器启动前运行,通过 iptables(具体变体由 init 模式配置)把进出 Pod 的 TCP 流量重定向到本机 linkerd-proxy 监听的端口。规则写完后 init 退出;后续由内核在数据路径上把连接交给 proxy,应用进程无需改代码。

官方 Architecture 把该机制称为数据面「透明」的基础:proxy 与业务容器共享网络命名空间,iptables 在命名空间边界内完成劫持。出站连接由 outbound proxy 处理发现、负载均衡与 mTLS 发起;入站连接由 inbound proxy 处理策略 enforcement 与指标。

要素 可核对事实
执行时机 应用容器与(legacy 模式下)proxy 容器启动前
权限需求 CAP_NET_ADMIN(默认 init 路径)
协议范围 文档明确为 TCP 透明代理
与 native sidecar 2.20 默认 proxy 更早就绪;init 仍负责 iptables(非 CNI 时)

工程间隙:iptables 重定向是 Linux 网络命名空间内的经典手法,与 eBPF TC 劫持(如部分 CNI 数据面)相比可移植性高,但依赖 NET_ADMIN 或外挂 CNI;这也是 Linkerd 提供 CNI 插件的原因(第二节)。

出站流量被重定向到 outbound proxy 监听端口后,proxy 才发起对 destinationGet() 流与对 identity 的 CSR——因此轴 2 失败时,指标上可能完全看不到 mTLS 或 golden metrics,容易被误判为「应用本身不兼容 mesh」。验证方法是在 Pod 网络命名空间内确认进程监听与连接跟踪是否经过 proxy 端口(具体端口以 linkerd-config 与注入模板为准),而不是先抓 ServiceProfile。


二、Linkerd CNI 插件

部分集群禁止 Pod 持有 CAP_NET_ADMIN。Linkerd 提供 linkerd-cni DaemonSet:通过 CNI chaining 在 Pod 网络配置阶段写入与 init 等价的 iptables 规则,使 meshed Pod 不再需要 linkerd-init 容器

安装语义(官方 CNI Plugin):

  1. 先安装 linkerd-cni DaemonSet(linkerd install-cni 或 Helm linkerd2-cni);
  2. 控制面安装时加 --linkerd-cni-enabled,在 linkerd-config ConfigMap 写入 cniEnabled
  3. proxy-injector 读取该标志,省略 Pod 内的 linkerd-init

CNI 与节点上已有 CNI 插件并存,不替代主 CNI;在 Cilium 上安装时需 cni.exclusive=false,避免独占 /etc/cni/net.d

安装顺序错误是最常见的轴 2 生产事故之一:若先装控制面再补 CNI DaemonSet,已运行的 meshed Pod 可能长期缺少节点规则,而新建 Pod 在 CNI 就绪后表现正常——形成「只有旧 Pod 不正常」的诡异分裂。修复通常需要滚动 Pod 或确认节点上 CNI 配置已链入,而不是调高 destination 副本数。

native sidecar 与 CNI 的交叉(2.20):CNI 文档指出,启用 CNI 且 native sidecar 默认开启 时,proxy 在应用 initContainers 之前启动,需要网络的 init 可直接出网。若关闭 native sidecar,legacy 布局下 proxy 晚于所有 init 启动,init 发出的包会被 iptables 截获而 proxy 尚未监听——此时需让 init 以 proxy UID(默认 2102)运行以跳过规则,该流量不经 mesh

flowchart LR
  subgraph init_path ["Default: linkerd-init"]
    pod1["meshed pod"] --> init1["linkerd-init iptables"]
    init1 --> proxy1["linkerd-proxy"]
  end
  subgraph cni_path ["CNI enabled"]
    cni["linkerd-cni on node"] --> pod2["meshed pod no init"]
    pod2 --> proxy2["linkerd-proxy"]
  end

图:两条路径目标一致——TCP 进 proxy;差异在规则安装者与 Pod 是否含 init 容器。


三、inbound / opaque 端口

重定向把流量送到 proxy 后,入站侧如何转发到应用端口,取决于协议探测与 opaque 配置。

这与 skip-inbound-ports 形成对照:后者修改 iptables,使流量根本不进 proxy(第 2 篇第四节)。排障时「只有某端口不通」要先分清是 opaque 汇聚到 4143 的 NP 问题,还是 skip 导致完全旁路。

官方 Protocol Detection 要求:对 meshed 客户端访问 opaque 服务,注解标在接收方 Pod;headless 或直接 Pod IP 访问时 appProtocol 可能不生效,必须依赖注解。

配置 作用点 proxy 是否见流量 mTLS
opaque-ports 接收方
skip-inbound-ports 接收方 iptables
skip-outbound-ports 发送方 iptables

inbound 与 outbound 端口缺省值(以 2.20 文档与 linkerd-config 为准):proxy 在容器内监听 inbound(默认 4143)承接被 iptables 转发的入站 TCP,再转发到应用端口;outbound(默认 4140)承接本机进程出站连接。opaque 并不改变「先进 inbound」的入站路径,只改变 proxy 是否对字节流做 HTTP 探测。NetworkPolicy 若只允许应用端口(如 6379)而拒绝 4143,meshed 客户端访问 opaque 服务会失败——这与 Redis 等 chart 自带 NP 的组合在社区 issue 中已有复现路径。


四、与轴 1 衔接

五轴中轴 1(注入)与轴 2(重定向)是串联门:injector 写入的容器列表与 CNI 标志决定轴 2 是否存在 linkerd-init、proxy 何时就绪。

轴 1 证据包:Pod spec 含 linkerd-proxy;native vs legacy 形状
  → 轴 2 证据包:含 linkerd-init 或集群 cniEnabled;iptables/CNI 是否生效
    → 轴 3+:流量进入 proxy 后才涉及 identity CSR、destination.Get

典型串联失败:

  1. 已注入、init CrashLoop:应用容器可能根本未拿到重定向规则,表现为直连或连接挂起——先查 init 日志与 NET_ADMIN,而非 identity。
  2. CNI 未就绪即注入:缺少节点级规则,Pod 内无 init 兜底时流量旁路——查 linkerd-cni DaemonSet 与 linkerd check --pre --linkerd-cni-enabled 语义(有环境才执行)。
  3. legacy + CNI + 需要网络的 init:需 UID 2102 或改开 native sidecar——这是 2.20 默认门想消除的类。

McCanne & Jacobson(1993)BPF 谱系与 mesh 重定向的关系是间接的:iptables REDIRECT/TPROXY 仍是 Linux 上最广泛部署的「在内核路径选路」手段之一;Linkerd 没有为通用 L7 选择 Envoy,而是在 Rust 微代理内做协议探测(第 10 篇)。轴 2 的职责仅是把字节送进 proxy,不在此做 L7 路由——那是 destination + proxy 出站链的事。

istio-xds/14 对照:Istio 同样依赖 init/iptables 或 CNI 变体,但排障口令常落在 xDS 推送;Linkerd 在轴 2 必须先确认 init 或 CNI 路径哪条生效,再谈 linkerd2-proxy-api


五、重定向失败表象

表象 优先轴 核对项
注入 Pod 内 curl 直连 Service IP 绕过 mesh 2 iptables 是否存在;是否误用 skip 注解
linkerd-init CrashLoopBackOff 2 NET_ADMIN;安全策略是否禁止 init
仅 CNI 集群无 init 但流量未进 proxy 2 cniEnabled;节点 CNI 配置与 Cilium exclusive
init 需要拉镜像/调 API 失败 1→2 native sidecar 是否开启;legacy 下 UID 2102
某 L4 端口超时,其他端口正常 2→4 opaque 与 4143;NetworkPolicy 是否放行 inbound
meshed 两端仍明文 2→3 流量是否经 proxy(skip 与未重定向)

iptables 模式变体(官方 Architecture 仅点名「不同 mode 决定 iptables 变体」):具体 flag 以 version-2.20linkerd-init 镜像与 linkerd-config 为准。排障时若仅 IPv6 失败而 IPv4 正常,应回到 init/CNI 规则族是否与双栈集群匹配,而不是先调 destination。

验证顺序建议(语义级,非伪造命令输出):先确认轴 1 注入与 proxy 监听;再确认轴 2 的 init 或 cniEnabled;对可疑端口检查 opaque/skip 与 NetworkPolicy;最后才进入 identity / destination 日志。

linkerd-init 退出后规则是否仍在:init 容器成功退出后,iptables 规则应保留在 Pod 网络命名空间内直至 Pod 销毁。若安全策略使用每容器网络隔离或某些 CRI 实现对 init 网络命名空间有特殊处理,可能出现「init 成功但规则未留存」的极端情况——此类问题需对照节点 CRI 版本与 Linkerd 发行说明,而非调整 ServiceProfile 超时。

开放问题:基于端口的 NetworkPolicy 与 opaque 流量经统一 inbound 端口的组合,在多 CNI 环境下仍易出现「成员资格成立、策略层拒绝」的灰区;社区讨论倾向于放宽 NP 或改用标签选择器,而非放弃 opaque。完整策略求值见本系列第 8 篇规划。

与 eBPF L4 的边界:Cilium 等可在 L3/L4 做身份与策略,但 Linkerd 轴 2 的 iptables/CNI 劫持发生在 Pod 网络命名空间内,与节点级 eBPF 程序是否共存取决于 CNI chaining 配置(第 14 篇对照)。在同时安装 Linkerd CNI 与 Cilium 时,必须先核对 cni.exclusive 与 chaining 顺序,否则表现为「部分节点重定向失效」——这是节点级证据包,不是单 Pod 注解能修复的。

meshed 连接定义回顾Architecture):仅当发起方与接受方 Pod 均已注入且流量经双方 proxy 时,连接才算 meshed。轴 2 失败时常见「一侧明文一侧 mesh」——出站 proxy 可能仍尝试 mTLS,入站却未走 inbound proxy,握手与指标都会异常。排障表中的「两端仍明文」应优先确认 iptables 是否对双方生效,而不是只查客户端。

UDP 与非 TCP 流量:官方架构明确透明代理对象为 TCP;UDP 等协议不在 linkerd-init 默认重定向范围内。若应用主要走 UDP,轴 2 的「透明 mesh」假设不成立——这是机制边界,不是配置遗漏。


参考资料

规范 / 官方文档(A)

站内对照

工程反例(B)


上一篇网格成员与注入

下一篇identity 服务

读完这篇,下一步读什么

优先读同系列或同问题的下一篇,把单篇消费变成主题集群。


By .