kubeadm构建k8s源码阅读环境
目标
前面看了minikube
的源码了解到其本质是调用了kubeadm
来启动k8s
集群,并没有达到最初看代码的目的。 所以继续看看kubeadm
的代码,看看能否用来方便地构建源码调试环境。
k8s源码编译
kubeadm
源码在k8s
源码库中,所以要先克隆k8s
源码。之前用minikube
创建的k8s
集群是v1.32.0
所以克隆v1.32.0
版本的代码
git clone --branch v1.32.0 --single-branch https://github.com/kubernetes/kubernetes.git
考虑到后续可能要改改源码并保存下来,所以我fork
了master
分支去编译。
在Makefile
中可以看到如何编译
在编译前先修改.go-version
文件中go的版本, 默认里面指定的是1.23.4
。k8s
源码中要求go
版本是1.23.0
以上就可以了,我的是1.23.3
不想重新下载go
压缩包了,所以改了。
修改shell
脚本让其输出编译的命令,看不到命令我不是很放心
通过环境变量指定版本号,修改完版本后执行编译命令编译kubeadm
export KUBE_GIT_VERSION=v1.32.0
export KUBE_GIT_COMMIT=$(git rev-parse --short HEAD)
export KUBE_GIT_TREE_STATE=clean
make all DBG=1 WHAT=cmd/kubelet
可以看到编译的命令已经带上了禁用优化的参数了
kubeadm
在一开始检查的过程中会调用kubelet
获取版本号,所以我把全部二进制文件都编译了
export KUBE_GIT_VERSION=v1.32.0
export KUBE_GIT_COMMIT=$(git rev-parse --short HEAD)
export KUBE_GIT_TREE_STATE=clean
make all DBG=1
调试命令如下
dlv --headless --listen=:8005 --api-version=2 --accept-multiclient --log exec /root/kubernetes/_output/bin/kubeadm -- init --cri-socket unix:///run/containerd/containerd.sock
vscode
配置如下
{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "kubeadm","type": "go","request": "attach","mode": "remote","remotePath": "/root/kubernetes","port": 8005,"host": "4c","showLog": true,"trace": "verbose","substitutePath": [{"from": "${workspaceFolder}","to": "/root/kubernetes"},{"from": "/Users/wy/wy/workspace_go/pkg/mod", // 本地路径"to": "/root/go_path/pkg/mod" // 远程路径},]}]
}
调试源码前准备工作
PATH环境变量
将前面编译源码生成二进制文件的目录添加到PATH
环境变量中,因为kubeadm
需要调用kubelet
containerd启用cri插件
kubeadm
中,contianerd
是默认的容器运行时,containerd
需要启动cri
插件,随docker
启动的contianerd
默认是禁用了cri
插件的。
containerd
配置cri
插件官方文档地址:
https://github.com/containerd/containerd/blob/main/docs/cri/config.md
docker version
命令查看docker
版本是27.5.0
, containerd
对应的版本是1.7.25
containerd
配置文件默认位置是/etc/containerd/config.toml
在配置文档中有完整的配置文件样例且有大量的注释,有需要的时候再来看,但这不是我们目前要关注的
使用命令生成默认配置
# 备份旧配置
cp /etc/containerd/config.toml /etc/containerd/config.toml.bak
# 生成默认配置
containerd config default > /etc/containerd/config.toml
修改的值如下,v1.32.0
版本k8s
要求是3.10
版本,没有的话会触发下载镜像的操作
SystemdCgroup = true
sandbox_image = "registry.k8s.io/pause:3.10"
需要重启containerd
。由于我docker
服务是apt
安装的,估计是自动装的containerd
,是由systemd
托管的。所以重启命令如下
sudo systemctl restart containerd
下载k8s相关镜像
由于网络问题,你得先下载k8s的镜像
# 查看需要下载的镜像
kubeadm config images list
镜像清单如下
registry.k8s.io/kube-apiserver:v1.32.1
registry.k8s.io/kube-controller-manager:v1.32.1
registry.k8s.io/kube-scheduler:v1.32.1
registry.k8s.io/kube-proxy:v1.32.1
registry.k8s.io/coredns/coredns:v1.12.0
registry.k8s.io/pause:3.10
registry.k8s.io/etcd:3.5.17-0
然后用github action
大法下载镜像,下载完成后,检查镜像
ctr --namespace k8s.io images list | awk '{print $1}'
镜像已经拉取成功了
配置kubelet
kubeadm init
命令会使用systemctl
命令重启kubelet
,所以需要编写 /etc/systemd/system/kubelet.service
但是具体怎么写,需要通过官方提供的apt
命令安装kubeadm
后,使用kubeadm
命令安装一次k8s
,然后查看kubelet.service
可以看到具体的脚本是怎么写的
可以看到需要编写两个文件,分别是kubelet.service
以及 10-kubeadm.conf
编写/etc/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/home/
Wants=network-online.target
After=network-online.target[Service]
ExecStart=/root/kubernetes/_output/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10
KillMode=process
Delegate=yes[Install]
WantedBy=multi-user.target
编写/etc/systemd/system/kubelet.service.d/10-kubeadm.conf
,可以看到这里指定了config.yaml
文件
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/default/kubelet
ExecStart=
ExecStart=/root/kubernetes/_output/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
然后启用该service
systemctl enable kubelet.service
调试源码
主要是想搞清kubeadm
是怎么部署k8s集群的,看看能不能用来调试代码。
代码入口是/cmd/kubeadm/kubeadm.go
kubeadm源码调试
kebeadm
中将部署集群的每个步骤抽象成phase
组成一个数组,然后遍历这个数组,运行每个phase
对应的函数,当phase
数组遍历完了,kubeadm init
命令就完成了
在cmd
命令初始化的时候,可以看到有哪些phase
其实在磊哥的《深入剖析Kubernetes》中有写了kubeadm
的部署原理,只是有些东西还是得自己看看才知道
很明显,kubelet
的启动对应是NewKubeletStartPhase
,随后的NewWaitControlPlanePhase
中等待apiserver
启动完成。
... 省略
initRunner.AppendPhase(phases.NewKubeletStartPhase())
initRunner.AppendPhase(phases.NewWaitControlPlanePhase())
... 省略
当 Kubelet
运行时,它会持续监视参数staticPodPath
指定的目录,如果有新的 Pod
配置文件加入,Kubelet
会自动创建 Pod
。这种启动Pod的方式叫静态启动,该过程不需要 apiserver
参与调度。
kubeadm
生成的kubelet
的配置文件中有个staticPodPath
选项,值如下
staticPodPath: /etc/kubernetes/manifests
该目录下的yaml
都是kubeadm
生成的,共四个yaml
文件,分别是
etcd.yaml
kube-apiserver.yaml
kube-controller-manager.yaml
kube-scheduler.yaml
kubelet源码调试
正常情况下,kubelet
是不会有问题的,如果在kubeadm init
命令执行过程提示 kubelet
失败,得看kubelet
到底报啥错了。查看kubelet
日志
journalctl -u kubelet
如果从日志上没看出是啥问题,可以调试下源码看看。当代码运行到启动kubelet
时,启动所需要的配置文件都已经生成了,所以调试kubelet
的时候,可以先退出kubeadm
的调试。
调试kubelet
需要先把kubeadm init
的代码运行到下图中的位置,然后kill
掉调试kubeadm init
的dlv
进程,然后调试kubelet
进程
调试前需要先停止kubelet
,并禁用自动重启
systemctl disable kubelet.service
systemctl stop kubelet
用下面的命令调试kubelet
源码
KUBELET_CONFIG_ARGS="--config=/var/lib/kubelet/config.yaml"
KUBELET_KUBECONFIG_ARGS="--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
KUBELET_KUBEADM_ARGS="--container-runtime-endpoint=unix:///run/containerd/containerd.sock --pod-infra-container-image=registry.k8s.io/pause:3.10"
dlv --headless --listen=:8005 --api-version=2 --accept-multiclient --log exec /root/kubernetes/_output/bin/kubelet -- $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS
变量$KUBELET_EXTRA_ARGS
是由文件/etc/default/kubelet
中定义的,默认是空值,所以我没有赋值。
读取pod
文件的代码位置如下,config.NewSourceFile
中会启动goroutinue
监听/etc/kubernetes/manifests
的文件,如果文件有改动,会往一个 channel
发送数据
最后在kubelet
的主循环中处理channel
中的数据,创建、更新或者删除pod
启动的代码东西太多了,等需要的时候再回来看,此处只是记录下代码的位置
kube-scheduler源码调试
回到主题上,k8s
相关的组件都是通过静态pod
的方式启动的,要了解一个pod
,就得看它的yaml
文件,以kube-scheduler
组件为例
可以看到是使用宿主机的网络命名空间,那么就可以直接使用执行源码编译的二进制文件启动kube-schedualer
代替静态pod
的方式来实现断点调试了。
先用kubeadm init
命令把k8s部署成功,默认情况下,出于安全原因,不会在控制平面节点上调度 Pod。想要在控制平面节点上调度需要执行下面的命令
kubectl taint nodes --all node-role.kubernetes.io/control-plane-
然后删除对应的kube-scheduler.yaml
,由于kubelet
是持续监视着/etc/kubernetes/manifests
的,如果文件有变动,则执行对应的操作,例如我删除了yaml
文件,kubelet
会删除掉对应的pod
删除yaml
文件后已经看不到kube-scheduler
了,coredns是要等到CNI插件安装成功后才会启动,这里先不管
参考yaml
中的启动命令,使用下面的命令调试
dlv --headless --listen=:8005 --api-version=2 --accept-multiclient --log exec /root/kubernetes/_output/bin/kube-scheduler -- --authentication-kubeconfig=/etc/kubernetes/scheduler.conf --authorization-kubeconfig=/etc/kubernetes/scheduler.conf --bind-address=127.0.0.1 --kubeconfig=/etc/kubernetes/scheduler.conf --leader-elect=false
参数说明
--authentication-kubeconfig
负责身份认证,确保kube-scheduler
可以连接 API Server。--authorization-kubeconfig
负责权限授权,确保kube-scheduler
有权限调度 Pod。--leader-elect=false
因为没有多个节点,所以把leader
选举关掉
可以看到已经能够成功断点调试了,SchedulerOne
函数就是对Pod
进行调度的入口函数。
相关文章:

kubeadm构建k8s源码阅读环境
目标 前面看了minikube的源码了解到其本质是调用了kubeadm来启动k8s集群,并没有达到最初看代码的目的。 所以继续看看kubeadm的代码,看看能否用来方便地构建源码调试环境。 k8s源码编译 kubeadm源码在k8s源码库中,所以要先克隆k8s源码。之…...

【Flink快速入门-1.Flink 简介与环境配置】
Flink 简介与环境配置 实验介绍 在学习一门新的技术之前,我们首先要了解它的历史渊源,也就是说它为什么会出现,它能够解决什么业务痛点。所以本节我们的学习目的是了解 Flink 的背景,并运行第一个 Flink 程序,对它有…...

硬盘修复后,文件隐身之谜
在数字时代,硬盘作为数据存储的重要载体,承载着无数珍贵的信息与回忆。然而,当硬盘遭遇故障并经过修复后,有时我们会遇到这样一个棘手问题:硬盘修复后,文件却神秘地“隐身”,无法正常显示。这一…...
如何处理网络连接错误导致的fetch失败?
处理由于网络连接错误导致的 fetch 失败通常涉及捕获网络错误并提供适当的用户反馈。以下是如何在 Vue 3 中实现这一点的步骤和示例。 一、更新 useFetch 函数 在 useFetch 函数中,需要捕获网络错误,并设置相应的错误信息。网络错误通常会抛出一个 TypeError,可以根据这个…...

Qt之设置QToolBar上的按钮样式
通常给QAction设置icon后,菜单栏的菜单项和工具栏(QToolBar)上对应的按钮会同时显示该icon。工具栏还可以使用setToolButtonStyle函数设置按钮样式,其参数为枚举值: enum ToolButtonStyle {ToolButtonIconOnly,ToolButtonTextOnly,ToolButtonTextBesideIcon,ToolButtonTe…...
责任链模式(Chain Responsibility)
一、定义:属于行为型设计模式,包含传递的数据、创建处理的抽象和实现、创建链条、将数据传递给顶端节点; 二、UML图 三、实现 1、需要传递处理的数据类 import java.util.Date;/*** 需要处理的数据信息*/ public class RequestData {priva…...
docker安装 mongodb
1、拉取镜像 docker run -dit --name mongo \ -p 17017:27017 \ -e MONGO_INITDB_ROOT_USERNAMEadmin \ -e MONGO_INITDB_ROOT_PASSWORD2018 \ --restartalways \ mongo2、进入容器 docker exec -it mongo bash 3、进入mongo ./bin/mongosh -u admin -p 2018 --authenticat…...

RabbitMQ 从入门到精通:从工作模式到集群部署实战(五)
#作者:闫乾苓 系列前几篇: 《RabbitMQ 从入门到精通:从工作模式到集群部署实战(一)》:link 《RabbitMQ 从入门到精通:从工作模式到集群部署实战(二)》: lin…...

salesforce SF CLI 数据运维经验分享
SF CLI data默认使用bulk api v2, 数据操作效率有了极大的提高。 Bulk api v2的优点: 执行结果可以很直观的从Bulk Data Load Jobs中看到。相较于bulk api v1,只能看到job执行in progress,或者closed的状态,有了很大的改善。执行…...

5.2Internet及其作用
5.2.1Internet概述 Internet称为互联网,又称英特网,始于1969年的美国ARPANET(阿帕网),是全球性的网络。 互连网指的是两个或多个不同类型的网络通过路由器等网络设备连接起来,形成一个更大的网络结构。互连…...

【蓝桥杯—单片机】第十一届省赛真题代码题解题笔记 | 省赛 | 真题 | 代码题 | 刷题 | 笔记
第十一届省赛真题代码部分 前言赛题代码思路笔记竞赛板配置内部振荡器频率设定键盘工作模式跳线扩展方式跳线 建立模板明确设计要求和初始状态显示功能部分数据界面第一部分第二部分第三部分调试时发现的问题 参数设置界面第一部分第二部分和第四部分第三部分和第五部分 按键功…...

数据分析:企业数字化转型的金钥匙
引言:数字化浪潮下的数据金矿 在数字化浪潮席卷全球的背景下,有研究表明,只有不到30%的企业能够充分利用手中掌握的数据,这是否让人深思?数据已然成为企业最为宝贵的资产之一。然而,企业是否真正准备好从数…...

网络工程师 (23)OSI模型层次结构
前言 OSI(Open System Interconnect)模型,即开放式系统互联模型,是一个完整的、完善的宏观模型,它将计算机网络体系结构划分为7层。 OSI七层模型 1. 物理层(Physical Layer) 功能:负…...

DeepSeek添加知识库
1、下载dify 项目地址:https://github.com/langgenius/dify 2、通过docker安装 端口报错 修改端口 .env文件下所有80端口替换成了其它端口 执行正常了 查看 docker容器 <...

2、k8s的cni网络插件和基本操作命令
kube-prxoy属于节点组件,网络代理,实现服务的自动发现和负载均衡。 k8s的内部网络模式 1、pod内的容器于容器之间的通信。 2、一个节点上的pod之间的通信,docker0网桥直接通信。 3、不同节点上的pod之间的通信: 通过物理网卡的…...
Next.js简介:现代 Web 开发的强大框架(ChatGPT-4o回答)
prompt: 你是一位专业的技术博客撰稿人,你将写一篇关于介绍next.js这个开发框架的技术博文,语言是中文,风格专业严谨,用词自然、引人入胜且饶有趣味 在现代 Web 开发的世界中,选择合适的框架可以显著提升开发效率和应用…...
【DeepSeek:国产大模型的崛起与ChatGPT的全面对比】
DeepSeek:国产大模型的崛起与ChatGPT的全面对比 目录 引言DeepSeek的技术架构 2.1 混合专家(MoE)架构2.2 动态路由机制2.3 训练数据与成本 ChatGPT的技术架构 3.1 Transformer架构3.2 训练数据与成本 性能对比 4.1 推理能力4.2 语言处理4.3…...
input 超出maxlength限制后,输入框变红
一、前言 最近收到产品的一个需求:输入框限制了maxlength“11”,需要在输入第12位时,输入框变红;当然,第12位是不能真正输入到输入框中的。 二、实现难点 其实,单纯的要监听 字母和数字以及字符 还是比较容…...
Docker 构建镜像并搭建私人镜像仓库教程
构建镜像教程 步骤 1:安装 Docker #在安装 Docker 之前,建议先更新系统软件包。 sudo yum update -y # 移除旧的Docker版本和Podman、runc软件包及其相关依赖。 yum remove -y docker docker-client docker-client-latest docker-ce-cli docker-commo…...
doris:MySQL Dump
Doris 在 0.15 之后的版本已经支持通过 mysqldump 工具导出数据或者表结构 使用示例 导出 导出 test 数据库中的 table1 表:mysqldump -h127.0.0.1 -P9030 -uroot --no-tablespaces --databases test --tables table1 导出 test 数据库中的 table1 表结构&am…...
OpenBMC:通过qemu-system-arm运行编译好的image
OpenBMC:编译_openbmc meson.build file-CSDN博客 讲述了如何编译生成openbmc的image 完成编译后可以通过qemu-system-arm进行模拟加载,以便在没有BMC硬件的情况下进行调试 1.下载qemu-system-arm 在openbmc的上级目录上执行 wget https://jenkins.op…...

STM32的HAL库开发---通用定时器(TIMER)---定时器脉冲计数
一、脉冲计数实验原理 1、 外部时钟模式1:核心为蓝色部分的时基单元,时基单元的时钟源可以来自四种,分别是内部时钟PCLK、外部时钟模式1,外部时钟模式2、内部定时器触发(级联)。而脉冲计数就是使用外部时钟…...

动态规划LeetCode-121.买卖股票的最佳时机1
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。…...
网安三剑客:DNS、CDN、VPN
DNS(网络地址转换系统)的技术原理与安全应用 1. 网络地址转换系统的基本原理 DNS通过解析用户的访问URL(超链接),将其映射到服务器上存储的信息。具体来说: 解析URL:DNS从URL中提取出 hostna…...
Linux在x86环境下制作ARM镜像包
在x86环境下制作ARM镜像包(如qemu.docker),可以通过QEMU和Docker的结合来实现。以下是详细的步骤: 安装QEMU-user-static QEMU-user-static是一个静态编译的QEMU二进制文件,用于在非目标架构上运行目标架构的二进制文…...

Vue3+codemirror6实现公式(规则)编辑器
实现截图 实现/带实现功能 插入标签 插入公式 提示补全 公式验证 公式计算 需要的依赖 "codemirror/autocomplete": "^6.18.4","codemirror/lang-javascript": "^6.2.2","codemirror/state": "^6.5.2","cod…...
Lua中文语言编程源码-第十一节,其它小改动汉化过程
__tostring 汉化过程 liolib.c metameth[] {"__转换为字符串", f_tostring}, lauxlib.c luaL_callmeta(L, idx, "__转换为字符串") lua.c luaL_callmeta(L, 1, "__转换为字符串") __len 汉化过程 ltm.c luaT_eventname[] ltablib.c c…...
Safari常用快捷键
一、书签边栏 1、显示或隐藏书签边栏:Control-Command-1 2、选择下一个书签或文件夹:向上头键或向下头键 3、打开所选书签:空格键 4、打开所选文件夹:空格键或右箭头键 5、关闭所选文件夹:空格键或左箭头键 6、更…...
Git登录并解决 CAPTCHA
修改公司域账户密码之后,导致今天pull代码时显示:remote error: CAPTCHA required 本文将介绍如何解决 Git 中的常见错误“fatal: Authentication failed for git”。该问题通常出现在尝试访问远程 Git 仓库时,表示身份验证失败。以下是几种常…...

Websocket从原理到实战
引言 WebSocket 是一种在单个 TCP 连接上进行全双工通信的网络协议,它使得客户端和服务器之间能够进行实时、双向的通信,既然是通信协议一定要从发展历史到协议内容到应用场景最后到实战全方位了解 发展历史 WebSocket 最初是为了解决 HTTP 协议在实时…...