我的编程空间,编程开发者的网络收藏夹
学习永远不晚

源码解析 Kubectl Port-Forward 工作原理

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

源码解析 Kubectl Port-Forward 工作原理

通过 port-forward 流程的分析,梳理出 kubectl -> api-server -> kubelet -> 容器运行时 的交互,了解 cri 的工作方式。

kubectl-port-forward

kubectl

简单创建个 pod:

kubectl run pipy --image flomesh/pipy:latest -n default

在执行 kubectl forward 时添加参数 -v 9 打印日志。

kubectl port-forward pipy 8080 -v 9
...
I0807 21:45:58.457986 14495 round_trippers.go:466] curl -v -XPOST -H "User-Agent: kubectl/v1.24.3 (darwin/arm64) kubernetes/aef86a9" -H "X-Stream-Protocol-Version: portforward.k8s.io" 'https://192.168.1.12:6443/api/v1/namespaces/default/pods/pipy/portforward'
I0807 21:45:58.484013 14495 round_trippers.go:553] POST https://192.168.1.12:6443/api/v1/namespaces/default/pods/pipy/portforward 101 Switching Protocols in 26 milliseconds
I0807 21:45:58.484029 14495 round_trippers.go:570] HTTP Statistics: DNSLookup 0 ms Dial 0 ms TLSHandshake 0 ms Duration 26 ms
I0807 21:45:58.484035 14495 round_trippers.go:577] Response Headers:
I0807 21:45:58.484040 14495 round_trippers.go:580] Upgrade: SPDY/3.1
I0807 21:45:58.484044 14495 round_trippers.go:580] X-Stream-Protocol-Version: portforward.k8s.io
I0807 21:45:58.484047 14495 round_trippers.go:580] Date: Sun, 07 Aug 2022 13:45:58 GMT
I0807 21:45:58.484051 14495 round_trippers.go:580] Connection: Upgrade
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080

从日志可以看到请求的地址为 /api/v1/namespaces/default/pods/pipy/portforward,其中 portforward 为 pod 资源的子资源。

这里使用的协议是 spdy。

kubectl 此时会监听本地端口,同时使用 pod 子资源 portforward 的 url 创建到 api-server 的连接。

当本地端口有连接接入时,kubectl 会不断地在两个连接间拷贝数据。

参考源码:

  • staging/class="lazy" data-src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go:389[1]
  • staging/class="lazy" data-src/k8s.io/client-go/tools/portforward/portforward.go:242[2]
  • staging/class="lazy" data-src/k8s.io/client-go/tools/portforward/portforward.go:330[3]

api-server

pod 的三个子资源 exec、attach 和 portforward,对这三个资源的操作都会代理有对应 node 的 kubetlet server 进行处理。

api-server 在接收到访问 pod 子资源 portforward 的请求后,通过 pod 及其所在 node 的信息,获取访问该 node 上 kubelet server 的 url。

然后将访问 pod 的 portforward 的请求,代理到 kubelet server。

参考源码

  • pkg/registry/core/pod/rest/subresources.go:185[4]

kubelet

portforward 请求来到了 pod 所在节点的 kubelet server,在 kubelet server 中,有几个用于调试的 endpoint,portforward 便是其中之一:

  • /run/{podNamespace}/{podID}/{containerName}
  • /exec/{podNamespace}/{podID}/{containerName}
  • /attach/{podNamespace}/{podID}/{containerName}
  • /portforward/{podNamespace}/{podID}
  • /containerLogs/{podNamespace}/{podID}/{containerName}
  • /runningpods/

kubelet server 收到请求后,首先会通过 RuntimeServiceClient 发送 gRCP 请求到容器运行时的接口(/runtime.v1alpha2.RuntimeService/PortForward)获取容器运行时 streaming server 处理 pordforward 请求的 url。

拿到 portforward streaming 的 url 之后,kubelet server 将请求代理到该 url。

参考源码

  • pkg/kubelet/server/server.go:463[5]
  • pkg/kubelet/server/server.go:873[6]
  • pkg/kubelet/cri/streaming/portforward/portforward.go:46[7]
  • pkg/kubelet/cri/streaming/server.go:111[8]

cri

这里以 Containerd 为例。

Containerd 在启动时会启动 runtime service 和 image service。前者是负责容器相关的操作,后者负责镜像相关的操作。

kubelet 获取用于端口转发的 streaming url,就是调用了 runtime service 的 gRPC 接口完成的。

除了两个 gRPC service 以外,还加载了一系列插件。这些插件中,其中有一个是 cri service。

cri service 会启动 streaming server。这个 server 会响应 /exec、/attach 和 /portforward 的 stream 请求。

portforward 支持两种操作系统 linux 和 windows:sandbox_portforward_linux.go 和 sandbox_portforward_windows.go。

在 linux 上,在 pod 所在的 network namespace 中使用地址 localhost 创建到目标端口的连接。然后在 streaming server 的连接和该连接之间拷贝数据,完成数据的传递。

在 windows 上,是通过 wincat.exe 使用地址 127.0.0.1 创建到目标端口的连接。

参考源码

  • pkg/cri/streaming/server.go:149[9]
  • pkg/cri/server/streaming.go:69[10]
  • pkg/cri/server/service.go:138[11]
  • pkg/cri/server/sandbox_portforward_linux.go:34[12]

总结

结合源码分析对 port-foward 工作原理的梳理,相信对 cri 的工作方式也有了一定的了解。本文是以容器运行时 Containerd 为例,不同的容器运行时虽然实现了 cri,但是实现的细节上也会有所差异。

比如在 port-forward 的实现上,Kubernetes v1.23.0 版本中的 docker shim(1.24 中被移除)[13] 中,是使用nsenter 进入 pod 所在的 network namespace 中通过 socat 完成的端口转发。

参考资料

[1] staging/class="lazy" data-src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go:389: https://github.com/kubernetes/kubernetes/tree/release-1.24/staging/class="lazy" data-src/k8s.io/kubectl/pkg/cmd/portforward/portforward.go#L389

[2] staging/class="lazy" data-src/k8s.io/client-go/tools/portforward/portforward.go:242: https://github.com/kubernetes/kubernetes/tree/release-1.24/staging/class="lazy" data-src/k8s.io/client-go/tools/portforward/portforward.go#L242

[3] staging/class="lazy" data-src/k8s.io/client-go/tools/portforward/portforward.go:330: https://github.com/kubernetes/kubernetes/tree/release-1.24/staging/class="lazy" data-src/k8s.io/client-go/tools/portforward/portforward.go#L330

[4] pkg/registry/core/pod/rest/subresources.go:185: https://github.com/kubernetes/kubernetes/tree/release-1.24/pkg/registry/core/pod/rest/subresources.go#L185

[5] pkg/kubelet/server/server.go:463: https://github.com/kubernetes/kubernetes/tree/release-1.24/pkg/kubelet/server/server.go#L463

[6] pkg/kubelet/server/server.go:873: https://github.com/kubernetes/kubernetes/tree/release-1.24/pkg/kubelet/server/server.go#L873

[7] pkg/kubelet/cri/streaming/portforward/portforward.go:46: https://github.com/kubernetes/kubernetes/tree/release-1.24/pkg/kubelet/cri/streaming/portforward/portforward.go#L46

[8] pkg/kubelet/cri/streaming/server.go:111: https://github.com/kubernetes/kubernetes/tree/release-1.24/pkg/kubelet/cri/streaming/server.go#L111

[9] pkg/cri/streaming/server.go:149: https://github.com/containerd/containerd/tree/release/1.5/pkg/cri/streaming/server.go#L149

[10] pkg/cri/server/streaming.go:69: https://github.com/containerd/containerd/tree/release/1.5/pkg/cri/server/streaming.go#L69

[11] pkg/cri/server/service.go:138: https://github.com/containerd/containerd/tree/release/1.5/pkg/cri/server/service.go#L138

[12] pkg/cri/server/sandbox_portforward_linux.go:34: https://github.com/containerd/containerd/tree/release/1.5/pkg/cri/server/sandbox_portforward_linux.go#L34

[13] Kubernetes v1.23.0 版本中的 docker shim(1.24 中被移除): https://github.com/kubernetes/kubernetes/blob/release-1.23/pkg/kubelet/dockershim/docker_streaming_others.go#L43

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

源码解析 Kubectl Port-Forward 工作原理

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

源码解析 Kubectl Port-Forward 工作原理

本文的源码基于 Kubernetes v1.24.0,容器运行时使用 Containerd 1.5,从源码来分析 kubectl port-forward 的工作原理。

【mybatis】mybatis 拦截器工作原理源码解析

mybatis 拦截器工作原理(JDK动态代理)1. mybatis 拦截器案例场景:分页查询,类似成熟产品:pagehelper, 这里只做简单原理演示1.0 mybatis全局配置 SqlMapConfig.xml
【mybatis】mybatis 拦截器工作原理源码解析
2015-01-18

axios拦截器工作方式及原理源码解析

这篇文章主要为大家介绍了axios拦截器工作原理源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-10

【mybatis】 mybatis 工作原理底层源码全流程解析

mybatis 工作原理1. SqlSessionFactory 初始化作用:加载Mybatis配置,用于生成SqlSession用于数据库操作// 加载mybatis全局配置文件,生成SqlSessionFactoryInputStream inputStr
【mybatis】 mybatis 工作原理底层源码全流程解析
2019-01-10

从源码角度解析Golang错误处理方式的工作原理

Golang作为一门被广泛应用于云计算、分布式系统等领域的编程语言,其设计简洁、高效而且易用,其中错误处理机制也是其设计之一。本文将从源码角度分析Golang错误处理方式的工作原理,并结合具体的代码示例进行说明。一、Golang错误处理的
从源码角度解析Golang错误处理方式的工作原理
2024-03-14

Android源码进阶之LiveData工作原理详解

LiveData 是一种可观察的数据存储器类。与常规的可观察类不同,LiveData 具有生命周期感知能力,意指它遵循其他应用组件(如 Activity、Fragment 或 Service)的生命周期。

解析DNS工作原理

  DNS是互连网核心协议之一,不管是上网浏览,还是编程开发,都需要了解一点它的知识。本文就来学习DNS工作原理,希望您读完本文也对它有所了解。  DNS(Domain Name System)是“域名系统”的英文缩写,是一种组织成域层次结构的计算机和网络服务命名系统,它用于TCP/IP,所提供
解析DNS工作原理
2024-04-18

Android源码进阶之深入理解Retrofit工作原理

Retrofit是一个基于AOP思想,对RestfulApi注解进行动态代理的网络框架;今天我们就来探讨下实现原理,一起进步。

SpringbootFatJa原理机制源码解析

这篇文章主要为大家介绍了SpringbootFatJa原理机制源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-12-26

Android Handler工作原理解析

简介在Android 中,只有主线程才能操作 UI,但是主线程不能进行耗时操作,否则会阻塞线程,产生 ANR 异常,所以常常把耗时操作放到其它子线程进行。如果在子线程中需要更新 UI,一般是通过 Handler 发送消息,主线程接受消息并且
2022-06-06

ResponseBodyAdvice的使用原理源码解析

这篇文章主要为大家介绍了ResponseBodyAdvice的使用原理源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-03-13

Vue3.5 源码解析, useTemplateRef 实现原理

useTemplateRef 的实现并不复杂,本质上 依然是基于 ref 的实现,只不过是在 ref 上进行了封装。访问 vue-next-3.5.0-master/packages/runtime-core/src/helpers/use
Vue3.5源码API2024-11-29

async-validator实现原理源码解析

这篇文章主要为大家介绍了async-validator实现原理源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-11

Gorm 框架原理&源码解析

gorm 框架通过一个 gorm.DB 实例来指代我们所操作的数据库. 使用 gorm 的第一步就是要通过 Open 方法创建出一个 gorm.DB 实例,其中首个入参为连接器 dialector,本身是个抽象的 interface,其实现

解析OSPF协议工作原理

  在如今的计算机网络中,当两台非直接连接的计算机需要经过几个网络通信时,通常就需要路由器。路由器提供一种方法来开辟通过一个网状连接的路径。那么路径是怎么建立的呢?路由器提供协议的任务是,为路由器提供他们建立网状网络最佳路径所需要的相互共享的路由信息。在众多的路由技术中,OSPF协议已成为目前Internet广域网和I
解析OSPF协议工作原理
2024-04-18

大牛深入解析SpringBoot核心运行原理和运作原理源码

本章会带领大家通过源码学习 Spring Boot 的核心运作原理,内容涉及自动配置的运作原理、核心功能模块、核心注解以及使用到的核心源代码分析。

Android Framework原理Binder驱动源码解析

这篇文章主要为大家介绍了Android Framework原理Binder驱动源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-01-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录