Fork me on GitHub

版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc

1. 引言

kt-connect是阿里开源的k8s的调试工具,它的作用类似于VPN,能够打通k8s集群和本地的网络。

传送门: alibaba/kt-connect

它有3种模式
* Connect 本地网络直接访问k8s集群网络
* Exchange 转发集群流量到本地
* Service Mesh 支持

另外它提供了一个Dashboard可以查看k8s集群内的所有可访问的service资源以及正在进行调试的ConnectExchange数量, 用处不大。

2. 使用介绍

这里萌叔只简单介绍ConnectExchange2种模式,更详细的使用说明见参考资料1

2.1 Connect模式

sudo ktctl -i ik8share/kt-connect-shadow:stable connect

注意: kt-connect 依赖sshuttle, 且运行时必须拥有root权限。另外sshuttle 又依赖了iptables(linux操作系统), ptctl(macOS)

-i 参数指定镜像的地址

这里ik8share/kt-connect-shadow:stable是镜像的名字,阿里默认提供的镜像地址rdc-incubator/kt-connect-shadow在萌叔的测试k8s集群中无法正常拉取。这里提供了一个docker hub的镜像地址。

2.2 Exchange模式

sudo ktctl -n test -i ik8share/kt-connect-shadow:stable exchange dm-backend-v0-0-1 --expose 3000

注意: 这里的dm-backend-v0-0-1 是k8s集群中Deployment资源的名称。

该命令会将所有发往dm-backend-v0-0-1所属Pod的3000端口的请求都转发到本地的3000端口上。

总结:ConnectExchange 模式都是单向的,一个是从集群外部到集群内部,一个是从集群内部到集群外部。

3. 原理和实现

kt-connect设计巧妙,且最大限度的避免了重复发明轮子,值得称赞。

3.1 Connect模式

我们先来看看Connect模式要达到的目标
假定
Namespace: test
Service: sv-backend-v0-0-1
Pod的IP: 172.20.1.29

curl http://sv-backend-v0-0-1.test.svc.cluster.local/info
curl 172.20.1.29:3000/info

那么显然,
对于场景1: kt-connect需要知道sv-backend-v0-0-1.test.svc.cluster.local是k8s集群内的域名,针对此类域名的请求,需要转发到k8s内网

对于场景1: kt-connect 需要知道 172.20.1.29,是k8s集群的内网IP,请求需要转发到k8s内网

kt-connect 需要能够自动捕获这两类流量,然后转发到k8s内网。

3.1.1 ① 创建Pod

此Pod镜像为rdc-incubator/kt-connect-shadow,并且暴露SSH端口

3.1.2 ② 在Local和K8s之间建立通道
kubectl -n default port-forward kt-connect-daemon-dnwvy-5dbf9cb9c6-l96g6 2222:22
3.1.3 ③ 捕获请求,并重新路由
sshuttle --dns --to-ns 172.20.3.25 -v -e ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -r root@127.0.0.1:2222 -x 127.0.0.1 172.20.0.0/24 172.20.2.0/24 172.20.1.0/24 172.20.3.0/24 10.68.0.0/16

sshuttle内部会调用iptablespfctl修改NAT规则

--dns --to-ns 172.20.3.25表示DNS解析使用172.20.3.25,实时上这个IP就是Pod kt-connect-daemon-dnwvy-5dbf9cb9c6-l96g6的IP

规则形如

iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 10.68.0.0/16  -p tcp --to-ports 2222 
3.1.4 ④ sshuttle重建对目标的连接

我们再来梳理一遍流程。当使用curl请求接口时,域名解析会使用自定义的DNS服务器172.20.3.25,因此能够成功解析sv-backend-v0-0-1.test.svc.cluster.local,解析得到的A记录是10.68.54.179, 显然命中了shuttle创建的NAT规则(10.68.0.0/16),于是请求被转发到127.0.0.1:2222端口, 请求又经过port-forward转发到kt-connect-daemon-dnwvy-5dbf9cb9c6-l96g6的22端口。在这个Pod中,sshuttle重建对目标的连接,请求会被转发。

3.2 Exchange模式

3.2.1 ① 创建Pod & ② 删除原有Pod


实际上,kt-connect将原来的Deployment dm-backend-v0-0-1的replicas置为0,变相删除了Pod
创建了一个新的Deployment dm-backend-v0-0-1-kt-dfoje, 注意看它使用的镜像是kt-connect-shadow。由它创建的Pod,使用的Label和原先的一模一样,这样它就能欺骗k8s,使得对Service backend的请求都转发到它这里来。

3.2.2 ③在Local和K8s之间建立通道
kubectl -n test port-forward dm-backend-v0-0-1-kt-dfoje-7ff5d9564-kmklv 2226:22

访问本地的2226端口,相当于访问了dm-backend-v0-0-1-kt-dfoje-7ff5d9564-kmklv的22端口

3.2.3 ④ssh 远程转发
ssh -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -R 3000:127.0.0.1:3000 root@127.0.0.1 -p2226 sh loop.sh

ssh自带远程转发功能,它会在dm-backend-v0-0-1-kt-dfoje-7ff5d9564-kmklv中监听3000端口,然后把所有发到3000端口的请求转发到127.0.0.1:3000(见参考资料2)

我们再来梳理一遍流程。当其他服务访问Service backend时,由于

  labels:
    app: backend

只剩由kt-connect伪造的1个Pod dm-backend-v0-0-1-kt-dfoje-7ff5d9564-kmklv了,所以流量会被转发到这个Pod中。请求的3000端口的流量会被SSH的远程转发功能转发给本地的3000端口。

后记

2021年04月12日
如果启动kt-connect,控制台中提示

socat not found

port-forward启动失败,则需要在在k8s集群,以及运行kt-connect的机器上,都安装socat

yum install -y socat

参考资料

1.Kt Connect Docs
2.SSH的三种端口转发


微信公众号

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注