RKE2 + Cilium + kubeProxyReplacement + NodeLocalDNS + LRP 使用注意事项

在使用以下配置组合时,不同 RKE2 版本可能会遇到不同问题,本文对已知问题进行总结:

  • RKE2 使用 Cilium CNI
  • Cilium 启用 kubeProxyReplacement
  • 使用 RKE2 CoreDNS 的 nodelocal.enabled 配置开启 NodeLocalDNS
  • 使用 RKE2 CoreDNS 的 nodelocal.use_cilium_lrp 配置创建 Cilium LocalRedirectPolicy(LRP),将集群 DNS 的流量重定向至本节点的 node-local-dns Pod

在 Cilium 完全替代 kube-proxy 后,ClusterIP 流量由 eBPF 在进入 Pod 网络栈前处理,传统 NodeLocalDNS 依赖的 iptables 截获方式不再适用,因此需要使用 LRP。


相关配置

RKE2 Cilium Helm Chart 配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# https://github.com/rancher/rke2-charts/tree/main/charts/rke2-cilium/rke2-cilium
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: rke2-cilium
namespace: kube-system
spec:
valuesContent: |-
k8sServiceHost: <KUBE_API_SERVER_IP>
k8sServicePort: <KUBE_API_SERVER_PORT>
kubeProxyReplacement: true
# 部分旧版本使用 localRedirectPolicy: true
localRedirectPolicies:
enabled: true

RKE2 CoreDNS Helm Chart 配置:

1
2
3
4
5
6
7
8
9
10
11
# https://github.com/rancher/rke2-charts/tree/main/charts/rke2-coredns/rke2-coredns
apiVersion: helm.cattle.io/v1
kind: HelmChartConfig
metadata:
name: rke2-coredns
namespace: kube-system
spec:
valuesContent: |-
nodelocal:
enabled: true
use_cilium_lrp: true

RKE2 配置:

1
2
cni: cilium
disable-kube-proxy: true

通过 Rancher 创建的 RKE2 集群配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spec:
rkeConfig:
chartValues:
rke2-cilium:
k8sServiceHost: <KUBE_API_SERVER_IP>
k8sServicePort: <KUBE_API_SERVER_PORT>
kubeProxyReplacement: true
# 部分旧版本使用 localRedirectPolicy: true
localRedirectPolicies:
enabled: true
rke2-coredns:
nodelocal:
enabled: true
use_cilium_lrp: true
machineGlobalConfig:
cni: cilium
disable-kube-proxy: true

已知问题


问题一:NodeLocalDNS Pod 卡在 Init 阶段

在较旧的 RKE2 CoreDNS Helm Chart 中,Cilium LRP 模式下的 node-local-dns Pod 仍包含 wait-coredns 初始化容器。

相关 issue:

初始化容器通过集群 DNS 地址(10.43.0.10)检查 CoreDNS 是否可访问,但此时 node-local-dns 主容器尚未启动,LRP 也没有可用的本地后端,因此形成启动依赖问题,Pod 会一直停留在 Init:0/1

1
kube-system   node-local-dns-xxx   0/1   Init:0/1

initContainer 日志:

1
2
3
waiting for dns service
nc: 10.43.0.10 (10.43.0.10:53): Operation not permitted
waiting for dns service

PR #809 调整了 Cilium LRP 模式下的 NodeLocalDNS 渲染逻辑,避免继续依赖不适用于该启动顺序的 CoreDNS 初始化检查,并为 Cilium LRP 模式生成相应的 NodeLocalDNS 配置。

RKE2 包含该修复的版本为:

  • v1.31.14+rke2r2
  • v1.32.11+rke2r1
  • v1.33.7+rke2r1
  • v1.34.3+rke2r1

另外,从该修复开始,RKE2 CoreDNS Helm Chart 将 LRP 的 frontend 从 serviceMatcher 改为 addressMatcher

1
2
3
4
5
6
7
8
9
10
# 旧配置
redirectFrontend:
serviceMatcher:
serviceName: {{ default (include "coredns.fullname" .) .Values.service.name }}
namespace: {{ .Release.Namespace }}

# 新配置
redirectFrontend:
addressMatcher:
ip: "{{ template "clusterDNSServerIP" . }}"

PR #809 中的描述来看,当时通过 serviceMatcher 重定向 Service 流量存在问题,因此改为直接匹配 rke2-coredns-rke2-coredns Service 的 ClusterIP。此时 Service 仍然存在,从而引发了问题三中描述的问题。


问题二:LRP 端口名称不一致,BPF 后端未正确编程

旧版 LRP 模板中,前端端口名称为 udp-53tcp-53,而 LRP 后端及 node-local-dns Pod 使用 dnsdns-tcp

当 LRP 包含多个端口时,Cilium 会根据端口名称建立前端与后端之间的映射。端口名称必须是符合 Kubernetes IANA 规范的名称,并且必须能够与后端 Pod 实际声明的端口对应。名称不一致时,Cilium 可能创建 LocalRedirect frontend,但不能为其正确配置本地 BPF backend。

相关 issue:

Pod 内执行 DNS 查询时可能出现:

1
nslookup: can't connect to remote host (10.43.0.10): Operation not permitted

Cilium Pod 可以看到 LocalRedirect frontend,但 BPF backend 不正确:

1
2
3
root@test-2:~# kubectl -n kube-system exec ds/cilium -c cilium-agent -- cilium-dbg lrp list
10.43.0.10:53/TCP (0) 0.0.0.0:0 (...) [LocalRedirect]
10.43.0.10:53/UDP (0) 0.0.0.0:0 (...) [LocalRedirect]

该问题有时不是在部署后立即出现,而是在运行约 10–15 分钟、Cilium 重新同步相关对象后出现。

PR #854 将 LRP 前端和后端的端口名称统一为:

  • UDP/53:dns
  • TCP/53:dns-tcp

修复版本为:

  • v1.32.11+rke2r3
  • v1.33.7+rke2r3
  • v1.34.3+rke2r3
  • v1.35.1+rke2r1

Workaround 为手动调整 LRP,使前端、后端与 node-local-dns Pod 的端口映射统一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: cilium.io/v2
kind: CiliumLocalRedirectPolicy
metadata:
annotations:
meta.helm.sh/release-name: rke2-coredns
meta.helm.sh/release-namespace: kube-system
labels:
app.kubernetes.io/managed-by: Helm
name: lrp-nodelocal
namespace: kube-system
spec:
redirectBackend:
localEndpointSelector:
matchLabels:
k8s-app: node-local-dns
toPorts:
- name: dns
port: "53"
protocol: UDP
- name: dns-tcp
port: "53"
protocol: TCP
redirectFrontend:
addressMatcher:
ip: 10.43.0.10
toPorts:
# - name: tcp-53
- name: dns
port: "53"
protocol: TCP
# - name: udp-53
- name: dns-tcp
port: "53"
protocol: UDP
skipRedirectFromBackend: true

问题三:addressMatcher 与现有 RKE2 CoreDNS Service 竞争同一个 IP

Cilium 对 serviceMatcheraddressMatcher 的定义如下:

  • 目标 IP / 端口属于 Kubernetes Service 时,应使用 serviceMatcher
  • 目标 IP / 端口不属于 Kubernetes Service 时,应使用 addressMatcher

某些旧版 RKE2 CoreDNS Helm Chart 会同时创建:

  1. 名为 rke2-coredns-rke2-coredns 的 Kubernetes Service,ClusterIP 为 10.43.0.10
  2. 使用 10.43.0.10addressMatcher LRP

在这种情况下,Cilium LRP 和 Kubernetes Service 会同时尝试管理同一个 IP,从而产生竞态问题。

相关 KB 和 issue:

Cilium Pod 会看到错误日志:

1
time=2026-09-16T03:58:16.174198083Z level=warn msg="Failure processing services" module=agent.controlplane.loadbalancer-reflectors.k8s-reflector error="frontend already owned by another service: 10.43.0.10:53/TCP is owned by kube-system/lrp-nodelocal:local-redirect"

且 Backend 为空:

1
2
3
4
root@test-2:~# kubectl -n kube-system exec ds/cilium -c cilium-agent -- cilium-dbg service list
ID Frontend Service Type Backend
1 10.43.0.10:53/TCP LocalRedirect
2 10.43.0.10:53/UDP LocalRedirect

最终修复没有将 RKE2 CoreDNS Helm Chart 自动生成的 LRP 改回 serviceMatcher,而是调整了配置的渲染:启用 nodelocal.enablednodelocal.use_cilium_lrp 时,不再创建 rke2-coredns-rke2-coredns 的 Kubernetes Service。

PR #892 引入了修复,RKE2 修复版本为:

  • v1.32.13+rke2r2
  • v1.33.9+rke2r1
  • v1.34.6+rke2r1
  • v1.35.3+rke2r1

Workaround 为手动调整 LRP,改回 serviceMatcher 避免竞争问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
apiVersion: cilium.io/v2
kind: CiliumLocalRedirectPolicy
metadata:
annotations:
meta.helm.sh/release-name: rke2-coredns
meta.helm.sh/release-namespace: kube-system
labels:
app.kubernetes.io/managed-by: Helm
name: lrp-nodelocal
namespace: kube-system
spec:
redirectBackend:
localEndpointSelector:
matchLabels:
k8s-app: node-local-dns
toPorts:
- name: dns
port: "53"
protocol: UDP
- name: dns-tcp
port: "53"
protocol: TCP
redirectFrontend:
# addressMatcher:
# ip: 10.43.0.10
serviceMatcher:
namespace: kube-system
serviceName: kube-dns-upstream
toPorts:
- name: dns
port: "53"
protocol: UDP
- name: dns-tcp
port: "53"
protocol: TCP
skipRedirectFromBackend: true

RKE2 + Cilium + kubeProxyReplacement + NodeLocalDNS + LRP 使用注意事项

https://warnerchen.github.io/2026/09/16/RKE2-Cilium-kubeProxyReplacement-NodeLocalDNS-LRP-使用注意事项/

Author

Warner Chen

Posted on

2026-09-16

Updated on

2026-09-16

Licensed under