上个星期五,我的一位同事们走近了我,并询问了关于如何在带客户端的POD中执行命令的问题。我不知道答案,我注意到我从未想过“Kubectl Exec”的机制。我有一些关于它应该是什么的想法,但我不是100%肯定。我注意到这个话题再次检查,我在阅读了一些博客,文档和源代码后我已经学到了很多。在这个博文章中,我将分享我的理解和调查结果。
我克隆了https://github.com/ecomm-integration -ballerina/kubernetes-clust,以便在我的MacBook中创建一个K8S群集。我修复了kubelet配置中节点的IP地址,因为默认配置没有让我运行kubectl exec。您可以在此处找到根本原因。
kubectl执行过程:当我们在计算机中运行“kubectl exec ...”时,将开始进程。您可以在任何计算机中运行它,该计算机可以访问K8S API服务器。
API Server:主机上的组件公开Kubernetes API。它是Kubernetes控制平面的前端。
kubelet:在群集中的每个节点上运行的代理。它确保容器在POD中运行。
Container Runtime:负责运行容器的软件。例子:Docker,Cri-O,Containerd ...
内核:Worker节点中的操作系统内核,负责管理进程。
目标容器:作为POD的一部分的容器,其在其中一个工人节点上运行。
//任何机器$ ps -ef | grep kubectl501 8507 8409 0 7:19 PM Ttys000 0:00.13 kubectl exec-it exec-test-nginx-6558988d5-fgxgg - sh
当我们检查该过程的网络活动时,我们可以看到它与API-Server有一些连接(192.168.205.10.6443)
//任何机器$ netstat -ATNV | GEP 8507TCP4 0 0 192.168.205.1.51673 192.168.205.10.6443已建立的131072 131768 8507 0 0x0102 0x0000000020TCP4 0 0 192.168.205.1.51672 192.168.205.10.6443建立了131072 131768 8507 0 0 0x0102 0x0000000028
让我们检查代码。 kubectl使用子源EXEC创建一个POST请求,并发送REST请求。
handler.go:143] kube-apiserver:post" / api / v1 /命名空间/默认/ pods / exec-test-nginx-6558988d5-fgxgg / exec"由Gorestful与webservice /api/v1upgradeaware.go:261]连接到后端代理(拦截重定向)https://192.168.205.11:10250/exec/default/exec-test-nginx -6558988d5-fgxgg/exec-test- nginx?command = sh&输入= 1&输出= 1& tty = 1headers:map [连接:[升级] content-length:[0]升级:[spdy / 3.1]用户代理:[kubectl / v1.12.10(达尔文/ amd64)Kubernetes / E3C1340] X-Forthed-for:[192.168.205.1] x-stream-protocol-version:[v4.channel.k8s.io v3.channel.k8s.io v2.channel.k8s.io频道.k8s.io]]
请注意,HTTP请求包括协议升级请求。 SPDY允许单独的stdin / stdout / stderr / spdy-error“Streams”在单个TCP连接上复用。
为了能够采取必要的操作,API-Server需要知道它应该联系的位置。
这些连接终止于Kubelet的HTTPS端点。默认情况下,APIServer不会验证Kubelet的服务证书,这使得连接受到中间人攻击的连接,并不足以运行不受信任和/或公共网络。
//任何机器$ kubectl获取节点K8S-Node-1 -o LideName状态角色年龄版本IP IP外部IP OS-Image Kernel-Version Container-RuntimeK8S-Node-1就绪< none> 9h v1.15.3 192.168.205.11< none> Ubuntu 16.04.6 LTS 4.4.0-159通用Docker://17.3.3
然后检查网络。是否有与工作节点的连接(192.168.205.11)? Connecti̇on在那里。当我杀死exec进程时,它会消失,所以我知道它是由于我的exec命令为api-server设置的。
现在kubectl和api-server之间的连接仍然打开,API-Server和Kubelet之间存在另一个连接。
让我们继续连接到工人节点并检查工作节点上的内容。
首先,我们也可以在这里观察联系。第二行。 192.168.205.10是主节点的IP。
//工作人员节点$ netstat -ATN | Grep 10250 TCP6 0 0 ::: 10250 ::: *听TCP6 0 0 192.168.205.11:10250 192.168.205.10:37870成立 //工作人员节点$ ps-afx ... 31463? SL 0:00 \ _ Docker-Containerd-Shim 7D974065BBB3107074CE31C51F5EF40AEA8DCD535AE11A7B8F2DD180B8ED583A / var / run / Docker / libcontainerd / 7d974065bbb3107074ce31c51 31478 pts / 0 ss 0:00 \ _ sh 31485 pts / 0 s + 0:00 \ _睡眠5000 ... 不要混淆。 它不会返回命令的结果。 它返回通信的端点。 如果是这样,我们需要观察Kubelet和集装箱运行时之间的连接。 正确的? 让我们检查。 在运行exec命令之前和之后运行此命令并检查diff。 这个是我案件中的差异。 //工作人员节点$ ss -a-a -p | grep kubelet ... u_str estab 0 0 * 157937 * 157387用户:((" kubelet" pid = 5714,fd = 33))...... Hımmm。 通过Kubelet(PID = 5714)之间的UNIX套接字有一个新的连接。 谁可以成为? 是的。 它是Docker(PID = 1186)。
//工作人员节点$ ss -a -p | grep 157387 ... u_str estab 0 0 * 157937 * 157387用户:((" kubelet" pid = 5714,fd = 33))U_str Estab 0 0 /var/run/docker.sock 157387 * 157937用户:((" dockerd" pid = 1186,fd = 14))...... //工作人员节点。$ ps-afx ... 1186? SSL 0:55 / USR / BIN / DOCKERD -H FD:// 17784? SL 0:00 \ _ 泊坞窗 , containerd - 垫片 53a0a08547b2f95986402d7f3b3e78702516244df049ba6c5aa012e81264aa3c 在/ var / 运行 / 泊坞窗 / libcontainerd / 53a0a08547b2f95986402d7f317801 PTS / 2 SS 0:00 \ _ sh17827 PTS / 2 S + 0:00 \ _ 睡眠 ... 5000 让我们来检查CRI-O的源代码以了解它如何发生。 Docker中逻辑类似。 在链条的末尾,Container Runtime在工作节点中执行命令。 Kubectl或API-Server无法在工作节点中运行任何内容。 Kubelet可以运行,但它也与这种动作的集装箱运行时交互。