解读Kubeadm源码

kubeadm init过程

官网教程:https://kubernetes.io/zh-cn/docs/reference/setup-tools/kubeadm/kubeadm-init/

1. Node环境检查(pre-fight-check)

生成的checks列表的对象,都实现了check接口,通过调用Check()进行

  1. 通过与prefight前检查独立存在
  2. 检查mainfestDir目录,K8s默认组件使用static pod
  3. NumCPUCheck检查CPU 最低2C,可以通过--ignore-prefight-errors=NumCPU进行忽略
  4. MemCheck检查检查,最低2G
  5. 进行kubectl、kubelet的版本匹配检查
  6. 检查FirewaldCheck检查防火墙
  7. 端口检查
  8. ……
  9. 同时还有RunPullImageCheck检查镜像是否存在

func InitNodeChecks(execer utilsexec.Interface, cfg *kubeadmapi.InitConfiguration, ignorePreflightErrors sets.Set[string], isSecondaryControlPlane bool, downloadCerts bool) ([]Checker, error) {
if !isSecondaryControlPlane {
// First, check if we're root separately from the other preflight checks and fail fast
if err := RunRootCheckOnly(ignorePreflightErrors); err != nil {
return nil, err
}
}

manifestsDir := filepath.Join(kubeadmconstants.KubernetesDir, kubeadmconstants.ManifestsSubDirName)
checks := []Checker{
//CPU检查 2G
NumCPUCheck{NumCPU: kubeadmconstants.ControlPlaneNumCPU},
// Linux only
// TODO: support other OS, if control-plane is supported on it.
// 内存检查 170
MemCheck{Mem: kubeadmconstants.ControlPlaneMem},
KubernetesVersionCheck{KubernetesVersion: cfg.KubernetesVersion, KubeadmVersion: kubeadmversion.Get().GitVersion},
// 防火墙检查
FirewalldCheck{ports: []int{int(cfg.LocalAPIEndpoint.BindPort), kubeadmconstants.KubeletPort}},
PortOpenCheck{port: int(cfg.LocalAPIEndpoint.BindPort)},
PortOpenCheck{port: kubeadmconstants.KubeSchedulerPort},
PortOpenCheck{port: kubeadmconstants.KubeControllerManagerPort},
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeAPIServer, manifestsDir)},
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeControllerManager, manifestsDir)},
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.KubeScheduler, manifestsDir)},
FileAvailableCheck{Path: kubeadmconstants.GetStaticPodFilepath(kubeadmconstants.Etcd, manifestsDir)},
HTTPProxyCheck{Proto: "https", Host: cfg.LocalAPIEndpoint.AdvertiseAddress},
}

// File content check for IPV4 and IPV6 are needed if it is:
// (dual stack) `--service-cidr` or `--pod-network-cidr` is set with an IPV4 and IPV6 CIDR, `--apiserver-advertise-address` is optional as it can be auto-detected.
// (single stack) which is decided by the `--apiserver-advertise-address`.
// Note that for the case of dual stack, user might only give IPV6 CIDR for `--service-cidr` and leave the `--apiserver-advertise-address` a default value which will be
// auto-detected and properly bound to an IPV4 address, this will make the cluster non-functional eventually. The case like this should be avoided by the validation instead,
// i.e. We don't care whether the input values for those parameters are set correctly here but if it's an IPV4 scoped CIDR or address we will add the file content check for IPV4,
// as does the IPV6.
IPV4Check := false
IPV6Check := false
cidrs := strings.Split(cfg.Networking.ServiceSubnet, ",")
for _, cidr := range cidrs {
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
if !IPV4Check && netutils.IsIPv4CIDRString(cidr) {
IPV4Check = true
}
if !IPV6Check && netutils.IsIPv6CIDRString(cidr) {
IPV6Check = true
}

}
cidrs = strings.Split(cfg.Networking.PodSubnet, ",")
for _, cidr := range cidrs {
checks = append(checks, HTTPProxyCIDRCheck{Proto: "https", CIDR: cidr})
if !IPV4Check && netutils.IsIPv4CIDRString(cidr) {
IPV4Check = true
}
if !IPV6Check && netutils.IsIPv6CIDRString(cidr) {
IPV6Check = true
}
}

if !isSecondaryControlPlane {
checks = addCommonChecks(execer, cfg.KubernetesVersion, &cfg.NodeRegistration, checks)

// Check if Bridge-netfilter and IPv6 relevant flags are set
if ip := netutils.ParseIPSloppy(cfg.LocalAPIEndpoint.AdvertiseAddress); ip != nil {
if !IPV4Check && netutils.IsIPv4(ip) {
IPV4Check = true
}
if !IPV6Check && netutils.IsIPv6(ip) {
IPV6Check = true
}
}

if IPV4Check {
checks = addIPv4Checks(checks)
}
if IPV6Check {
checks = addIPv6Checks(checks)
}

// if using an external etcd
if cfg.Etcd.External != nil {
// Check external etcd version before creating the cluster
checks = append(checks, ExternalEtcdVersionCheck{Etcd: cfg.Etcd})
}
}

if cfg.Etcd.Local != nil {
// Only do etcd related checks when required to install a local etcd
checks = append(checks,
PortOpenCheck{port: kubeadmconstants.EtcdListenClientPort},
PortOpenCheck{port: kubeadmconstants.EtcdListenPeerPort},
DirAvailableCheck{Path: cfg.Etcd.Local.DataDir},
)
}

if cfg.Etcd.External != nil && !(isSecondaryControlPlane && downloadCerts) {
// Only check etcd certificates when using an external etcd and not joining with automatic download of certs
if cfg.Etcd.External.CAFile != "" {
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.CAFile, Label: "ExternalEtcdClientCertificates"})
}
if cfg.Etcd.External.CertFile != "" {
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.CertFile, Label: "ExternalEtcdClientCertificates"})
}
if cfg.Etcd.External.KeyFile != "" {
checks = append(checks, FileExistingCheck{Path: cfg.Etcd.External.KeyFile, Label: "ExternalEtcdClientCertificates"})
}
}
return checks, nil
}

2.NewCertsPhase

在这个阶段,生成了通过自签的CA证书为每一个组件建立身份标识,可以通过其放入--cert-dir(默认/etc/kubernets/pki),来提供它们的CA证书和密钥。

ApiServer证书为 apiserver-cert-extra-sans参数值提供附加的SAN条目

对DNS进行x509证书签发

3.NewKubeConfigPhase

将kubeconfig文件写入/etc/kubernetes/目录,让kubelet、控制器管理和调度器来连接到API服务器,它们有自己的标识,同时生成一个admin.conf独立的kubeconfig文件,用于管理操作

4.NewEtcdPhase

一些etcd的准备工作和生成配置文件

5.NewControlPlanePhase

为控制节点的组件和创建静态pod以及生成文件放在/etc/kubernetes/mainfests下面

6. NewKubeletStartPhase

  1. 将env的变量写入到/var/lib/kubelet/kubeadm-flags.env
  2. 配置写入到/var/lib/kubelet/config.yaml
  3. 启动kubelet

7.NewWaitControlPlanePhase

  1. 监听/etc/kubernetes/manifest目录,为了创建的时候启动Pod
  2. 控制面的Pod起来之后,kubeadm init继续执行

8.NewUploadConfigPhase

把配置文件上传到K8s ConfigMap )admin.conf文件

9.*NewUploadCertsPhase

  1. 需要执行的时候添加--config=kubeadm-config.yaml --upload-certs才会执行这个函数

10.NewMarkControlPlanePhase

  1. 主要是对控制面的节点应用标签和污点的管理,以便在它上面不会运行一些其他的工作负载均衡

11.NewBootstrapTokenPhase

  1. 生成token
  2. 配置configmap,RBAC角色
  3. 配置RBAC,允许节点Bootstrap令牌获取节点
  4. 配置RBAC,允许节点Boorstrap令牌发布csr,以便节点获得长期证书
  5. 配置RBAC,允许csrapprover控制器节点从节点引导令牌自动批准
  6. 配置RBAC,允许集群中所有的节点客户端证书的轮换
  7. 在kube-public命名空间中创建cluster-info ConfigMap

12.NewKubeletFinalizePhase

  1. 更新/etc/kubernetes/kubelet.conf指向可运行的kubeley客户端证书和密钥

13.NewAddonPhase

  1. 调用runKubeProxyAddon将KubeProxy插件安装到Kubernetes集群
  2. 调用runCoreDNSAddon将CoreDNS插件安装到Kubernetes集群

14.NewShowJoinCommandPhase

  1. 打印Join信息

kubeadm Join过程

官网教程:https://kubernetes.io/zh-cn/docs/reference/setup-tools/kubeadm/kubeadm-join/

1.NewPreflightPhase

2.NewControlPlanePreparePhase

3.NewCheckEtcdPhase

4.NewKubeletStartPhase

  1. 把配置文件写入/var/lib/kubelet/config.yaml
  2. 把变量文件flags写入/var/lib/kubelet/kubeadm-flags.env
  3. 启动kubelet
  4. 等待kubelet执行TLS Bootstrap

5.NewControlPlaneJoinPhase