CNI 网络流量 5.4 Cilium 流量分析(三) -- k8s services
这样通常有一个问题,即 pod 收到的报文源 IP 不是真正的 clientIP,这通常对一些需要通过访问者 IP 有需求的应用有一定的影响;当通过 nodePort 或 ExternalIP 访问集群服务时,如果 后端 pod 不在访问的 节点,那么通常会 snat 成 访问节点默认路由网卡的 ip,然后转发到 pod 所在节点;如下图所示,在 pod1 访问 services 时,通过查看目的
关闭 kube-proxy
Cilium cm
kube-proxy-replacement: strict
可以看到 EnableSocketLB 等都为 True,在 ebpf 中 ENABLE_SOCKET_LB_TCP 和 ENABLE_SOCKET_LB_UDP 都是打开的状态。
if option.Config.KubeProxyReplacement == option.KubeProxyReplacementProbe ||
option.Config.KubeProxyReplacement == option.KubeProxyReplacementStrict {
log.Infof("Trying to auto-enable %q, %q, %q, %q, %q features",
option.EnableNodePort, option.EnableExternalIPs,
option.EnableSocketLB, option.EnableHostPort,
option.EnableSessionAffinity)
option.Config.EnableHostPort = true
option.Config.EnableNodePort = true
option.Config.EnableExternalIPs = true
option.Config.EnableSocketLB = true
option.Config.EnableHostServicesTCP = true
option.Config.EnableHostServicesUDP = true
option.Config.EnableSessionAffinity = true
}
控制面 与 services
- Cilium-agent deamon 运行 k8sWatcher,其中有 K8sServiceHandler,此 K8sServiceHandler 接收 service event 进行业务处理
d.k8sWatcher.RunK8sServiceHandler()
func (k *K8sWatcher) RunK8sServiceHandler() {
go k.k8sServiceHandler()
}
- 有以下内容会触发 service event
- UpdateService
- EnsureService // policyBackend 变化时
- DeleteService
- updateEndpoints
- deleteEndpoints
- MergeExternalServiceUpdate
- MergeExternalServiceDelete
- MergeClusterServiceDelete
- updateSelfNodeLabels
- 处理 services,将 k8s.service 转换格式,并存到 lbmap,如果是 nodePort,是单独的一条 lb
s.upsertServiceIntoLBMaps(svc, onlyLocalBackends, prevBackendCount,
newBackends, obsoleteBackendIDs, prevSessionAffinity, prevLoadBalancerSourceRanges,
obsoleteSVCBackendIDs, scopedLog)
$ cilium bpf lb list
SERVICE ADDRESS BACKEND ADDRESS (REVNAT_ID) (SLOT)
10.96.0.10:53 10.0.1.230:53 (2) (2)
0.0.0.0:0 (2) (0) [ClusterIP, non-routable]
10.0.2.15:53 (2) (1)
10.99.181.236:8080 10.0.0.65:80 (4) (1)
0.0.0.0:0 (4) (0) [ClusterIP, non-routable]
10.0.0.225:80 (4) (2)
10.0.1.109:80 (4) (3)
10.96.0.1:443 172.18.22.111:6443 (1) (1)
0.0.0.0:0 (1) (0) [ClusterIP, non-routable]
10.96.0.10:9153 10.0.1.230:9153 (3) (2)
0.0.0.0:0 (3) (0) [ClusterIP, non-routable]
10.0.2.15:9153 (3) (1)
host-Reachable Services
根据上述配置,介绍下 cilium 支持的 host-Reachable Services。该功能依赖 内核 5.9
如下图所示,在 pod1 访问 services 时,通过查看目的 ip,发现是 service 后,直接选择一个 backend,实际上省略了 dnat 流程。
Host-reachable service 可以简单理解为集群内 service 是应该访问到的,通过 给 socket 挂 ebpf 实现直接访问到 endpoint 的能力。
一个应用的访问大致流程:
- socket:创建一个新的套接字;
- setsockopt:设置套接字选项;
- bind:将套接字绑定到本地 IP 地址和端口;
- listen:监听传入的连接请求;
- accept:接受传入的连接请求,并返回新的已连接套接字;
- getpeername:获取已连接套接字的对端 IP 地址和端口;
- recvmsg:从已连接套接字接收数据;
- post_bind4:在已连接套接字上执行一些后续的操作;
- sendmsg:将数据发送到已连接的套接字;
- close:关闭套接字。
在 cilium 中有以下挂载点
__section(“cgroup/connect4”),__section(“cgroup/post_bind4”),__section(“cgroup/bind4”),__section(“cgroup/sendmsg4”),__section(“cgroup/getpeername4”),__section(“sockops”)
pod 访问 service 时
__section("cgroup/connect4")
|- sock4_connect
|- __sock4_xlate_fwd
|- lb4_key 生成 lb4_key,根据目的地址和 目的 port
|- lb4_lookup_service 使用 lb4_key 在 LB4_SERVICES_MAP_V2 查找 service
|- lb4_affinity_backend_id_by_netns 判断是否是 affinity svc
|- __lb4_lookup_backend 指定一个 endpoint
|-> ctx->user_ip4 = backend->address; 将 endpoint 的 ip + port 设置到 socket 中
|-> ctx_set_port(ctx, backend->port);
Socket 连接时,直接连 endpoint 的 ip + port,没有 nat 等操作了
DSR services
当通过 nodePort 或 ExternalIP 访问集群服务时,如果 后端 pod 不在访问的 节点,那么通常会 snat 成 访问节点默认路由网卡的 ip,然后转发到 pod 所在节点;pod 回复时回复到之前的访问节点,再 nat 成访问节点的回复报文;
这样通常有一个问题,即 pod 收到的报文源 IP 不是真正的 clientIP,这通常对一些需要通过访问者 IP 有需求的应用有一定的影响;虽然 k8s 提供 externalTrafficPolicy=Local 保持 clinetIP,但是这只能当访问后端在 访问节点时有效。
测试环境
clientIP: 172.20.150.110
node1: 172.18.22.111; node2: 172.18.22.112
svc: nginx-service NodePort 10.99.181.236 <none> 8080:32334/TCP 6d1h
pod 在 node1 上 10.0.0.48
当发送请求到 node1 时 curl 172.18.22.111:32334
pod 抓包
172.20.150.110.36800 > 10.0.0.225.http
10.0.0.225.http > 172.20.150.110.36800
当发送请求到 node2 时 curl 172.18.22.112:32334
172.18.22.112.55864 > 10.0.0.225.http // 非真实clientIP,而是 node2 ip
10.0.0.225.http > 172.18.22.112.55864
修改 cilium 配置
bpf-lb-mode: dsr
当发送请求到 node2 时 curl 172.18.22.112:32334
172.20.150.110.41534 > 10.0.0.225.http // 真实clientIP
172.20.150.110.41534 > 10.0.0.225.http
更多推荐
所有评论(0)