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

考虑到后续可能要改改源码并保存下来,所以我forkmaster分支去编译。

Makefile中可以看到如何编译
在这里插入图片描述

在编译前先修改.go-version文件中go的版本, 默认里面指定的是1.23.4k8s源码中要求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 initdlv进程,然后调试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进行调度的入口函数。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/965934.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

BFS算法篇——广度优先搜索,探索未知的旅程(上)

文章目录 前言一、BFS的思路二、BFS的C语言实现1. 图的表示2. BFS的实现 三、代码解析四、输出结果五、总结 前言 广度优先搜索(BFS)是一种广泛应用于图论中的算法,常用于寻找最短路径、图的遍历等问题。与深度优先搜索(DFS&…

baigeiRSA

baigeiRSA 打开附件有两个: 1.import libnumfrom Crypto.Util import numberfrom secret import flag​size 128e 65537p number.getPrime(size)q number.getPrime(size)n p*q​m libnum.s2n(flag)c pow(m, e, n)​print(n %d % n)print(c %d % c)​​2.n…

脚本一键生成管理下游k8s集群的kubeconfig

一、场景 1.1 需要管理下游k8s集群的场景。 1.2 不希望使用默认的cluster-admin权限的config. 二、脚本 **重点参数: 2.1 配置变量。 1、有单独namespace的权限和集群只读权限。 2、自签名的CA证书位置要正确。 2.2 如果配置错误,需要重新…

camera光心检测算法

1.概要 光心检测算法,基于opencv c实现,便于模组厂快速集成到软件工具中,适用于camera模组厂算法评估组装制程镜头与sensor的偏心程度,便于工程师了解制程的问题找出改善方向。 2.技术介绍 下图为camera模组厂抓取的bayer-raw经过…

基于logback+fastjson实现日志脱敏

一、需求背景 日常工作中,必不可免的会将一些敏感信息,如用户名、密码、手机号、身份证号、银行账号等等打印出来,但往往为了安全,这些信息都需要进行脱敏。脱敏实际就是用一些特殊字符来替换部分值。 JSON 和 JSONObject Fastj…

RC5分组加密算法

目录 (1)RC5密钥扩展算法 (2)RC5加密算法 (3)RC5解密算法 RC5分组加密算法 RC5分组密码算法是1994年RSA实验室的RonaldL.Rivest教授发明的。它是参数可变的分组密码算法,三个可变的参数是&a…

GPU — 8 卡 GPU 服务器与 NVLink/NVSwitch 互联技术

目录 文章目录 目录8 卡 GPU 服务器GPU 互联技术分类PCIe 直连PCIe Switch 互联NVLink 互联NVLink 1.0 与 DGX-1 系统NVLink 2.0 与 DGX-1 系统NVSwitch 全互联NVSwitch 1.0 与 DGX-2 系统NVLink 3.0、NVSwitch 2.0 与 DGX A100NVLink 4.0、NVSwitch 3.0 与 DGX H100NVSwitch v…

idea——IDEA2024版本创建Sping项目无法选择Java 8

目录 一、背景二、解决方式(替换创建项目的源地址) 一、背景 IDEA2024创建一个springboot的项目,本地安装的是1.8,但是在使用Spring Initializr创建项目时,发现版本只有17、21、23。 二、解决方式(替换创…

STM32 串口发送与接收

接线图 代码配置 根据上一章发送的代码配置,在GPIO配置的基础上需要再配置PA10引脚做RX接收,引脚模式可以选择浮空输入或者上拉输入,在USART配置串口模式里加上RX模式。 配置中断 //配置中断 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE…

储能系统-系统架构

已更新系列文章包括104、61850、modbus 、单片机等,欢迎关注 IEC61850实现方案和测试-1-CSDN博客 快速了解104协议-CSDN博客 104调试工具2_104协议调试工具-CSDN博客 1 电池储能系统(BESS) 架构 电池储能系统主要包括、电池、pcs、本地控制…

TOTP实现Google Authenticator认证工具获取6位验证码

登录遇到Google认证怎么办? TOTP是什么?(Google Authenticator) TOTP(Time-based One-Time Password)是一种基于时间的一次性密码算法,主要用于双因素身份验证。其核心原理是通过共享密钥和时间同步生成动态密码,具体步骤如下: 共享密钥:服务端与客户端预先共享一个…

清理服务器/docker容器

清理服务器 服务器或docker容器清理空间。 清理conda环境 删除不用的conda虚拟环境: conda env remove --name python38 conda env remove --name python310清理临时目录:/tmp du -sh /tmp # 查看/tmp目录的大小/tmp 目录下的文件通常是可以直接删除…

Naive UI去掉n-select下拉框边框,去掉n-input输入框边框

<template><div><div style"margin-top:10px;width: 100%;"><dade-descriptions><tr><dade-descriptions-item label"代理名称"><dade-input placeholder"代理名称"></dade-input></dade-de…

【完整版】DeepSeek-R1大模型学习笔记(架构、训练、Infra)

文章目录 0 DeepSeek系列总览1 模型架构设计基本参数专家混合模型&#xff08;MoE&#xff09;[DeepSeek-V2提出, DeepSeek-V3改良]多头潜在注意力&#xff08;MLA&#xff09;[DeepSeek-V2提出]多token预测&#xff08;MTP&#xff09;[DeepSeek-V3提出] 2 DeepSeek-R1-Zero及…

如何使用 Python 和 SQLAlchemy 结合外键映射来获取其他表中的数据

在使用 Python 和 SQLAlchemy 时&#xff0c;结合外键映射可以让你在查询时轻松地获取其他表中的数据。SQLAlchemy 提供了丰富的 ORM&#xff08;对象关系映射&#xff09;功能&#xff0c;可以让你通过定义外键关系来查询并获取关联的数据。下面我会演示如何设置外键关系&…

Python爬虫:1药城店铺爬虫(完整代码)

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

游戏引擎学习第91天

黑板&#xff1a;澄清线性独立性 首先&#xff0c;提到线性独立时&#xff0c;之前讲解过的“最小”的概念实际上是在表达线性独立。对于二维坐标系来说&#xff0c;两个基向量是最小的&#xff0c;这两个向量是线性独立的。如果超过两个基向量&#xff0c;就会变得冗余&#…

学习率调整策略 | PyTorch 深度学习实战

前一篇文章&#xff0c;深度学习里面的而优化函数 Adam&#xff0c;SGD&#xff0c;动量法&#xff0c;AdaGrad 等 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于 强化学习必修课&#xff1a;引…

在 Flownex 中创建自定义工作液

在这篇博文中&#xff0c;我们将了解如何在 Flownex 中为流网添加和定义一种新的流体温度相关工作材料。 Flownex 物料管理界面 在 Flownex 中使用与温度相关的流体材料时&#xff0c;了解其特性与温度的关系非常重要。这种了解可确保准确预测各种热条件下的流体行为&#xff0…

记一次golang环境的变化

前两天编译打包了了个文件&#xff0c;把env的 goos 搞坏了 导致运行项目一直报错 先是这样 go: unsupported GOOS/GOARCH pair windows/amd64再是这样 /amd64supported GOOS/GOARCH pair linux咱就说&#xff0c;咱也是知道环境配置的有问题 &#xff08; go env GOOS &…