聊聊k8s调试工具kt-connect的实现
版权声明 本站原创文章 由 萌叔 发表
转载请注明 萌叔 | https://vearne.cc
1. 引言
kt-connect是阿里开源的k8s的调试工具,它的作用类似于VPN,能够打通k8s集群和本地的网络。
传送门: alibaba/kt-connect
它有3种模式
* Connect 本地网络直接访问k8s集群网络
* Exchange 转发集群流量到本地
* Service Mesh 支持
另外它提供了一个Dashboard可以查看k8s集群内的所有可访问的service资源以及正在进行调试的Connect
和Exchange
数量, 用处不大。
2. 使用介绍
这里萌叔只简单介绍Connect
和Exchange
2种模式,更详细的使用说明见参考资料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端口上。
总结:Connect
和Exchange
模式都是单向的,一个是从集群外部到集群内部,一个是从集群内部到集群外部。
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
内部会调用iptables
或pfctl
修改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的三种端口转发