看到一篇关于 Kubectl 运行的机制,觉得写得非常不错,图文并茂很形象,就翻译成了中文记录一下,原文地址:

  • https://erkanerol.github.io/post/how-kubectl-exec-works/[1]

上周五,我的一位同事问了一个有关如何使用 go-client 在 Pod 中执行命令的问题。我不知道答案,我注意到我从未想过“ kubectl exec”中的机制。我有一些想法,但是我不 100%确定。我需要通过实践来找到答案,在阅读了一些博客,文档和源代码后,我学到了很多东西。在这篇博客中,我将分享我的理解和发现。

Setup

我克隆了https://github.com/ecomm-integration-ballerina/kubernetes-cluster,以便在MacBook中创建k8s集群。我修改Kubelet配置中节点的IP地址,因为默认配置不允许我运行kubectl exec。您可以在这里[2]找到根本原因。

下文提到的关于机器的对应关系如下:

  • any machine = MacBook

  • master IP = 192.168.205.10

  • work IP = 192.168.205.11

  • API server 端口 = 6443

Component

  • kubectl exec:当我们在机器上运行“ kubectl exec…”时,可以在任何有权限访问 K8s API 服务上运行。

  • API Server[3]:API Server上的组件,用于公开 Kubernetes API。它是 Kubernetes 控制平面的前端。

  • kubelet[4]:在集群中每个节点上运行的代理。确保容器在容器中运行。

  • container runtime[5]:负责运行容器的软件。例如:docker,cri-o,containerd…

  • kernel:工作节点中操作系统的内核,负责管理进程。

  • target container:作为 Pod 的一部分并在其中一个工作程序节点上运行的容器。

Findings

1. Client 端

在默认名称空间中创建容器

# any machine
$ kubectl run exec-test-nginx --image=nginx

然后运行 exec 命令并sleep 5000进行观察

# any machine
$ kubectl exec -it exec-test-nginx-6558988d5-fgxgg -- sh
# sleep 5000

我们可以观察到 kubectl 过程(在这种情况下为 pid = 8507)

# any machine
$ ps -ef |grep kubectl
501  8507  8409   0  7:19PM ttys000    0:00.13 kubectl exec -it exec-test-nginx-6558988d5-fgxgg -- sh

当我们检查该进程的网络活动时,我们可以看到它与 API Server(192.168.205.10.6443)有连接

# any machine
$ netstat -atnv |grep 8507
tcp4       0      0  192.168.205.1.51673    192.168.205.10.6443    ESTABLISHED 131072 131768   8507      0 0x0102 0x00000020
tcp4       0      0  192.168.205.1.51672    192.168.205.10.6443    ESTABLISHED 131072 131768   8507      0 0x0102 0x00000028

让我们检查一下代码。kubectl 使用子资源创建一个 POST 请求,exec并发送一个 rest 请求。

2. API Server 端

我们可以在 API 服务端观察请求。

handler.go:143] kube-API Server: POST "/api/v1/namespaces/default/pods/exec-test-nginx-6558988d5-fgxgg/exec" satisfied by gorestful with webservice /api/v1
upgradeaware.go:261] Connecting to backend proxy (intercepting redirects) https://192.168.205.11:10250/exec/default/exec-test-nginx-6558988d5-fgxgg/exec-test-nginx?command=sh&input=1&output=1&tty=1
Headers: map[Connection:[Upgrade] Content-Length:[0] Upgrade:[SPDY/3.1] User-Agent:[kubectl/v1.12.10 (darwin/amd64) kubernetes/e3c1340] X-Forwarded-For:[192.168.205.1] X-Stream-Protocol-Version:[v4.channel.k8s.io v3.channel.k8s.io v2.channel.k8s.io channel.k8s.io]]

请注意,http 请求包括协议升级请求。SPDY[6]允许将单独的 stdin / stdout / stderr / spdy-error 流通过单个 TCP 连接进行多路复用。

API 服务收到请求并将其绑定到 PodExecOptions

为了能够采取必要的措施,API Server 需要知道应该请求哪个 node。

当然,端点是从节点信息派生的。

发现了,Kubelet 具有可node.Status.DaemonEndpoints.KubeletEndpoint.Port连接 API 服务的端口。

master/node 之间的通信 > master 集群通信 > API Server 到 kubelet[7]

这些连接在 kubelet 的 HTTPS 端点处终止。默认情况下,API 服务不验证 kubelet 的服务证书,这使得连接容易遭受中间人攻击,不安全的公共网络。

现在,API 服务知道了端点并打开了连接。

让我们检查 master 上发生了什么。

首先,得到 worker 节点的 ip。正是192.168.205.11在这种情况下。

# any machine
$ kubectl get nodes k8s-node-1 -o wide
NAME         STATUS   ROLES    AGE   VERSION   INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
k8s-node-1   Ready    <none>   9h    v1.15.3   192.168.205.11   <none>        Ubuntu 16.04.6 LTS   4.4.0-159-generic   docker://17.3.3

然后获取 kubelet 端口。在这个例子中是10250

# any machine
$ kubectl get nodes k8s-node-1 -o jsonpath='{.status.daemonEndpoints.kubeletEndpoint}'
map[Port:10250]

然后检查网络。是否存在到工作节点(192.168.205.11)的连接?可以看到,当我杀死 exec 进程时,它消失了,所以我知道它正是由于 exec 命令而由 API Server 设置的

# master node
$ netstat -atn |grep 192.168.205.11
tcp        0      0 192.168.205.10:37870    192.168.205.11:10250    ESTABLISHED
...

API 服务到 Kubelet

现在,kubectl 和 API Server 之间的连接仍然打开,并且 API Server 和 kubelet 之间还有另一个连接。

3. Worker 节点

让我们通过连接到 Worker 节点并检查正在发生的事情。

首先,我们也可以在此处观察连接。第二行。192.168.205.10是 master 的 IP。

# worker node
$ netstat -atn |grep 10250
tcp6       0      0 :::10250                :::*                    LISTEN
tcp6       0      0 192.168.205.11:10250    192.168.205.10:37870    ESTABLISHED

那我们的 sleep 命令呢?可以通过 ps 命令找到!!!

# worker node
$ 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              \_ sleep 5000
...
  • kubelet 如何做到的?

  • kubelet 有一个守护程序,该守护程序通过 10250 端口与 API Server 通信。

  • kubelet 计算执行请求的响应端点。

不要混淆。它不返回命令的结果。它返回一个通信端点。

kubelet 实现的RuntimeServiceClient接口是 Container Runtime Interface 的一部分。

它仅使用 gRPC 通过 Container Runtime Interface 调用方法。

container runtime 负责实施 RuntimeServiceServer

Kubelet到容器运行时

如果是这样,我们需要观察 kubelet 与容器运行时之间的联系。对?让我们检查。

在运行 exec 命令之前和之后运行此命令,并检查 diff。

# worker node
$ ss -a -p |grep kubelet
...
u_str  ESTAB      0      0       * 157937                * 157387                users:(("kubelet",pid=5714,fd=33))
...

嗯 在 kubelet(pid = 5714)与某个组件通过 UNIX 套接字建立了新连接。正是 DOCKER(pid = 1186)。

# worker node
$ ss -a -p |grep 157387
...
u_str  ESTAB      0      0       * 157937                * 157387                users:(("kubelet",pid=5714,fd=33))
u_str  ESTAB      0      0      /var/run/docker.sock 157387                * 157937                users:(("dockerd",pid=1186,fd=14))
...

这是运行我们的命令的 docker 守护进程(pid = 1186)。

# worker node.
$ ps -afx
...1186 ?        Ssl    0:55 /usr/bin/dockerd -H fd://
17784 ?        Sl     0:00      \_ docker-containerd-shim 53a0a08547b2f95986402d7f3b3e78702516244df049ba6c5aa012e81264aa3c /var/run/docker/libcontainerd/53a0a08547b2f95986402d7f3
17801 pts/2    Ss     0:00          \_ sh
17827 pts/2    S+     0:00              \_ sleep 5000
...

4. Docker runtime

让我们检查 cri-o 的源代码以了解它如何发生。逻辑在 docker 中相似。

它具有一个实现 RuntimeServiceServer 的服务器。

在链的最后, container runtime 在 work 节点中执行命令。

容器运行时到内核

最后,kernel 执行命令

内核输入

注意事项

  • API Server 也可以初始化与 kubelet 的连接。

  • 这些连接将一直持续到交互式执行程序结束。

    • kubectl 和 API Server 之间的连接

    • API Server 和 kubelet 之间的连接

    • kubelet 与 container runtime 之间的连接

  • kubectl 或 API Server 无法在 work 节点中运行任何内容。kubelet 可以运行,但也可以与 container runtime 时交互以进行此类操作。

参考

  • https://groups.google.com/forum/#!topic/kubernetes-dev/Cjia36v39vM[8]

  • https://medium.com/@joatmon08/playing-with-kubeadm-in-vagrant-machines-part-2-bac431095706[9]

  • https://serverfault.com/questions/252723/how-to-find-other-end-of-unix-socket-connection[10]

引用链接

[1]

https://erkanerol.github.io/post/how-kubectl-exec-works/: https://erkanerol.github.io/post/how-kubectl-exec-works/

[2]

这里: https://medium.com/@joatmon08/playing-with-kubeadm-in-vagrant-machines-part-2-bac431095706

[3]

API Server: https://kubernetes.io/docs/concepts/overview/components/#kube-apiserver

[4]

kubelet: https://kubernetes.io/docs/concepts/overview/components/#kubelet

[5]

container runtime: https://kubernetes.io/docs/concepts/overview/components/#container-runtime

[6]

SPDY: https://www.wikiwand.com/en/SPDY

[7]

master/node 之间的通信 > master 集群通信 > API Server 到 kubelet: https://kubernetes.io/docs/concepts/architecture/master-node-communication/#apiserver-to-kubelet

[8]

https://groups.google.com/forum/#!topic/kubernetes-dev/Cjia36v39vM: https://groups.google.com/forum/#!topic/kubernetes-dev/Cjia36v39vM

[9]

https://medium.com/@joatmon08/playing-with-kubeadm-in-vagrant-machines-part-2-bac431095706: https://medium.com/@joatmon08/playing-with-kubeadm-in-vagrant-machines-part-2-bac431095706

[10]

https://serverfault.com/questions/252723/how-to-find-other-end-of-unix-socket-connection: https://serverfault.com/questions/252723/how-to-find-other-end-of-unix-socket-connection

原文链接:https://izsk.me/2021/01/10/Kubernetes-how-does-kubectl-work/

你可能还喜欢

点击下方图片即可阅读

记一次 Kubernetes 中严重的安全问题

云原生是一种信仰 

你知道 kubectl exec 的运行机制是什么吗?相关推荐

  1. kubelet运行机制及架构分析

    背景 在对kubernetes 管理的容器进行监控时涉及到了cAdvisor,而cAdvisor 又运行在kublet中,在这里记录一下kubelet 相关的介绍 简介 kubelet 是在每个 No ...

  2. qt ui界面加入qsplitter_UI 文件设计与运行机制

    上一篇通过一个 "Hello World" 实例,演示了在 Qt Creator 里创建应用程序.设计窗体界面.编译和运行程序的基本过程.这一篇将介绍可视化设计的 UI 界面文件的 ...

  3. 傻傻分不清的javascript运行机制

    学习到javascript的运行机制时,有几个概念经常出现在各种文章中且容易混淆.Execution Context(执行环境或执行上下文),Context Stack (执行栈),Variable ...

  4. 从hello world 说程序运行机制

    http://www.cnblogs.com/yanlingyin/archive/2012/03/05/2379199.html 开篇 学习任何一门编程语言,都会从hello world 开始.对于 ...

  5. js 多个定时器_从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理(二)

    作者:撒网要见鱼   https://segmentfault.com/a/1190000012925872 本文接上篇 <从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理(一)> ...

  6. session对象运行机制

    当你看到 "会话" 这个词的时候,你会怎么理解呢?是交流.对话的意思吗?那毫无疑问绝对是的啦,只不过那是传统意义上的,或者说是日常生活中的意思,在计算机科学领域,它的意思就要引申一 ...

  7. http和https的区别 与 SSL/TLS协议运行机制的概述

    http和https的区别 与 SSL/TLS协议运行机制的概述 参考1 1 http 是不使用的SSL/TSL的通信通道 窃听风险:第三方获取通信内容 篡改风险:修改通信内容 冒充风险:冒充他人身份 ...

  8. 第3课:SparkStreaming 透彻理解三板斧之三:解密SparkStreaming运行机制和架构进阶之Job和容错...

    本期内容: 解密Spark Streaming Job架构和运行机制 解密Spark Streaming容错架构和运行机制 理解SparkStreaming的Job的整个架构和运行机制对于精通Spar ...

  9. 浅谈SQL Server内部运行机制

    原文:浅谈SQL Server内部运行机制 对于已经很熟悉T-SQL的读者,或者对于较专业的DBA来说,逻辑的增删改查,或者较复杂的SQL语句,都是非常简单的,不存在任何挑战,不值得一提,那么,SQL ...

最新文章

  1. 解决Vs输出中文乱码的问题
  2. linux下eclipse cdt引用函数库设置问题
  3. SpringMVC的环境搭建
  4. 如何调用华为云api_postman调用华为云接口添加资源
  5. web.xml 通过contextConfigLocation配置spring 的方式
  6. JVM思维导图、正则表达式符号图、企业内部开发流程图
  7. 【原创】请不要对Boost Format使用Byte作为参数
  8. string转short java_[Java基础]之 数据类型转换
  9. Iterator图解
  10. GZNT模版文件说明
  11. 图片版坦克大战源代码之坦克类(二)
  12. Jmeter--压力测试工具
  13. linux查看固态硬盘寿命,CentOS下查看 ssd 寿命
  14. 调用百度人体关键点识别API
  15. Springboot 序列化空对象报错解决办法
  16. CF1325C Ehab and Path-etic MEXs
  17. 电影推荐系统 python简书_基于Spark的电影推荐系统(实战简介)
  18. linux怎么修改ftp密码
  19. 期货是衍生产品(期货衍生产品法)
  20. mysql带有子查询的like查询

热门文章

  1. mvdbos php spider,Scrapy-Redis分布式爬取自如网(一)
  2. Seneca :NodeJS 微服务框架入门指南
  3. wireshark抓包分析SSL/TLS协议
  4. SSL/TLS 与 IPSec 对比
  5. 英语语法---宾语补足语详解
  6. 01_国家卫生部PACS相关标准
  7. A.O.史密斯创新精品净水热饮机 净水热饮无需等待
  8. 急!急!急!VMWare vSphere 6.X 标准技术支持快要结束了!!!(20221015)
  9. 【自然语言处理】【细粒度情感分析】细粒度情感分析:了解文本情感的What、How、Why
  10. 感觉这么多年喝的鸡汤都白补了,我想静静!