kubeadm工作原理-kubeadminit原理分析-kubeadmjoin原理分析(代码片段)

良凯尔 良凯尔     2022-10-21     745

关键词:

kubeadm工作原理-kubeadm init原理分析-kubeadm join原理分析。kubeadm是社区维护的Kubernetes集群一键部署利器,使用两条命令即可完成k8s集群中master节点以及node节点的部署,其底层原理是利用了k8s TLS bootstrap特性。

kubeadm概述

kubeadm是社区维护的Kubernetes集群一键部署利器,使用两条命令即可完成k8s集群中master节点以及node节点的部署,其底层原理是利用了k8s TLS bootstrap特性。

kubeadm部署k8s集群示例

(1)k8s master节点部署:

$ kubeadm init

此外,我们也可以自己编写yaml文件来自定义kubeadm的启动过程和一些组件的启动参数等等

$ kubeadm init --config xxx.yaml

(2)k8s node节点部署(将一个node节点加入到已有集群当中):

$ kubeadm join <kube-apiserver的ip + 端口> --token <token>

此外,我们也可以自己编写yaml文件来自定义kubeadm的启动过程和一些组件的启动参数,包括kube-apiserver的ip与端口、token等

$ kubeadm join --config xxx.yaml

关于自定义yaml文件以及更多的kubeadm用法请参考:https://kubernetes.io/zh/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/

k8s TLS bootstrap概述

当k8s集群开启了TLS认证后,每个节点的kubelet组件都要使用由kube-apiserver的CA签发的有效证书才能与kube-apiserver通信;当节点非常多的时候,为每个节点都单独签署证书是一件非常繁琐而又耗时的事情。

此时k8s TLS bootstrap功能应运而生。

k8s TLS bootstrap功能就是让kubelet先使用一个预先商定好的低权限token连接到kube-apiserver,向kube-apiserver申请证书,然后kube-controller-manager给kubelet动态签署证书,后续kubelet都将通过动态签署的证书与kube-apiserver通信。

关于k8s TLS bootstrap的详细分析这里暂时不展开。

kubeadm原理解析

大致流程

在k8s master中,会先启动一个kubelet,控制面组件通过kubelet static pod特性启动,在k8s master控制面组件启动成功后,其他节点需要加入到k8s集群时,使用TLS bootstrap来简化加入的过程,先通过bootstrap-token与kube-apiserver通信,自动从kube-controller-manager处签发拿到与kube-apiserver通信的证书,然后自动生成与kube-apiserver通信的kubeconfig文件,后续将使用kubeconfig文件与kube-apiserver进行通信。

详细流程解析

1.kubeadm init

kubeadm init的结果是完成一个k8s master节点的部署,包括kube-apiserver、kube-controller-manager、kube-scheduler、etcd等控制面组件以及kubelet数据面组件,即该master节点既是控制面又是数据面,所以master节点上也是可以运行pod的;

以下为kubeadm init的处理流程代码(基于k8s v1.17.4版本),一共13步:

// cmd/kubeadm/app/cmd/init.go-NewCmdInit()
    ...
    // initialize the workflow runner with the list of phases
	initRunner.AppendPhase(phases.NewPreflightPhase()) // 1.环境检查
	initRunner.AppendPhase(phases.NewKubeletStartPhase()) // 2.配置并启动kubelet
	initRunner.AppendPhase(phases.NewCertsPhase()) // 3.证书生成
	initRunner.AppendPhase(phases.NewKubeConfigPhase()) // 4.kubeconfig文件生成
	initRunner.AppendPhase(phases.NewControlPlanePhase()) // 5.控制面组件yaml生成
	initRunner.AppendPhase(phases.NewEtcdPhase()) // 6.etcd组件yaml生成
	initRunner.AppendPhase(phases.NewWaitControlPlanePhase()) // 7.等待控制面组件运行
	initRunner.AppendPhase(phases.NewUploadConfigPhase()) // 8.上传配置
	initRunner.AppendPhase(phases.NewUploadCertsPhase()) // 9.上传CA证书/私钥
	initRunner.AppendPhase(phases.NewMarkControlPlanePhase()) // 10.master节点打污点
	initRunner.AppendPhase(phases.NewBootstrapTokenPhase()) // 11.生成bootstrap token和ca证书configmap
	initRunner.AppendPhase(phases.NewKubeletFinalizePhase()) // 12.更换kubelet证书
	initRunner.AppendPhase(phases.NewAddonPhase()) // 13.安装Addon
	...

(1)环境检查。检查项包括操作系统内核版本、k8s组件暴露服务的指定端口是否被占用、docker是否安装、iptables命令是否安装等等,其实这一步还包括了拉取kubeadm部署所需的镜像;

(2)配置并启动kubelet。创建kubelet启动所需的配置文件,并启动kubelet,kubeadm使用了systemd的方式部署启动kubelet;

# systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/usr/lib/systemd/system/kubelet.service; disabled; vendor preset: enabled)
  Drop-In: /usr/lib/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) ...

为什么master上还需要配置启动kubelet呢?

因为kubeadm init的时候需要将master控制面组件kube-apiserver、kube-controller-manager、kube-scheduler、etcd以pod的方式运行起来,而现在又没有在运行的控制面以及kubelet,怎么办呢,kubeadm的做法是,给master节点上也安装启动kubelet,然后使用kubelet static pod特性将master控制面组件运行起来。

关于static pod,详细内容可参考:https://kubernetes.io/zh/docs/tasks/configure-pod-container/static-pod/

(3)证书生成。即生成kubernetes对外提供服务所需的各种证书,放到/etc/kubernetes/pki目录下;

# ls /etc/kubernetes/pki
apiserver.crt  apiserver-etcd-client.crt  apiserver-etcd-client.key  apiserver.key  apiserver-kubelet-client.crt  apiserver-kubelet-client.key	ca.crt	ca.key	etcd  front-proxy-ca.crt  front-proxy-ca.key  front-proxy-client.crt  front-proxy-client.key  sa.key  sa.pub

(4)kubeconfig配置文件生成。即生成master节点上kube-controller-manager、kube-scheduler、kubelet组件等访问kube-apiserver的kubeconfig文件,放到/etc/kubernetes目录下,文件包含了apiserver的地址、监听端口、证书等信息,使用该kubeconfig文件即可直接与kube-apiserver通信;

# ls /etc/kubernetes
admin.conf  controller-manager.conf  kubelet.conf  manifests  pki  scheduler.conf

master上的kubelet启动后,使用kubeadm生成的kubeconfig与kube-apiserver进行通信,通过证书轮换,向kube-apiserver申请新的证书,由kube-controller-manager签发证书返回。

注意:这里master上的kubelet不会使用TLS bootstrap特性。

(5)控制面组件yaml文件生成。即kubeadm为4个控制面组件kube-apiserver、kube-controller-manager、kube-scheduler生成pod yaml文件,放到/etc/kubernetes/manifests目录下,然后kubelet会根据static pod特性,使用pod的方式将它们部署起来;

# ls /etc/kubernetes/manifests
kube-apiserver.yaml	kube-controller-manager.yaml  kube-scheduler.yaml

(6)etcd组件yaml文件生成。即kubeadm为etcd组件生成pod yaml文件,放到/etc/kubernetes/manifests目录下,然后kubelet会根据static pod特性,使用pod的方式将etcd部署起来;

# ls /etc/kubernetes/manifests
etcd.yaml  kube-apiserver.yaml	kube-controller-manager.yaml  kube-scheduler.yaml

(7)等待控制面组件运行。kubeadm会不间断检查localhost:6443/healthz这个url,等待master组件完全启动;

(8)上传配置。这里会创建2个configmap有,都创建在kube-system命名空间下,名称分别是kubeadm-config、kubelet-config-xxx(k8s版本),分别存储着kubeadm的集群配置信息、kubelet的配置信息;

(9)上传CA证书/私钥。该步骤默认不执行,通过增加——upload-certs参数启用,它会将相关的CA证书/私钥加密后作为data,在kube-system命名空间下创建名称为kubeadm-certs的secret,给后续的master节点kubeadm join使用,这样join时可以直接从secret中解密出CA证书/私钥,然后签发其他证书,而无需手工复制相关CA证书/私钥;

kubeadm init执行完成后,会输出一个名称为certificateKey的值,然后在其他master节点join时,加上--certificate-key参数即可。

certificateKey是在添加新的master节点时用来解密kubeadm-certs secret中的证书的秘钥。

kubeadm-certs示例如下,其中的证书和私钥均已加密,通过certificateKey解密即可使用:

apiVersion: v1
data:
  ca.crt: KfdZpEDF1wJfaexXls5...
  ca.key: VXfm7luIyM3QT+Rd04+...
  etcd-ca.crt: wwSzqCcltkrP26...
  etcd-ca.key: gqusZazZLF33Ip...
  front-proxy-ca.crt: EmfgKP6...
  front-proxy-ca.key: wKMYSrk...
  sa.key: pscxeFTGoCFZ6hrE1XK...
  sa.pub: keey1WPkWdj2TjEb/oM...
kind: Secret
metadata:
  name: kubeadm-certs
  namespace: kube-system
  ownerReferences:
  - apiVersion: v1
    blockOwnerDeletion: true
    controller: true
    kind: Secret
    name: bootstrap-token-xxxxxx
    ...
  ...
type: Opaque

注意:secret kubeadm-certs和解密密钥certificateKey会在两个小时后失效。

(10)master节点打污点。将该master节点打上污点,不作为计算节点数据面使用;

(11)生成bootstrap token和ca证书configmap。

kubeadm会为该k8s集群生成一个bootstrap token并打印出来,后续的node节点通过这个token,通过kubeadm join命令,使用TLS bootstrap特性即可加入到这个k8s集群中,当然,这里还包括了为该token创建RBAC的各个对象,赋予该token创建CSR证书签名请求的权限、自动批复CSR请求的权限、轮换证书请求自动批复的权限等,这里不展开介绍,后续分析k8s TLS bootstrap原理时再做分析;

kubeadm init执行完成后,也可以通过以下命令获取token:

# kubeadm token list

kubeadm还会将ca.crt、apiserver url等信息,保存到一个configmap当中,给后续加入该k8s集群的node节点使用,configmap名称为cluster-info,位于kube-public命名空间下;

# kubectl get configmap -n kube-public -o yaml cluster-info
apiVersion: v1
data:
  kubeconfig: |
    apiVersion: v1
    clusters:
    - cluster:
        certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0F...
        server: https://192.168.1.10:6443
      name: ""
    contexts: null
    current-context: ""
    kind: Config
    preferences: 
    users: null
kind: ConfigMap
metadata:

(12)更换kubelet证书。前面说过,master上的kubelet启动后,使用kubeadm生成的kubeconfig与kube-apiserver进行通信,通过证书轮换,向kube-apiserver申请新的证书,由kube-controller-manager签发证书返回。而这里说的更换kubelet证书,其实就是将kubelet与kube-apiserver通信的kubeconfig文件中的证书替换成由kube-controller-manager签发返回的证书,即将kubeconfig文件中的client-certificateclient-key的值都替换成/var/lib/kubelet/pki/kubelet-client-current.pem

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0F...
    server: https://192.168.1.10:6443
  name: test-cluster
contexts:
- context:
    cluster: test-cluster
    user: system:node:test-cluster-master-1
  name: system:node:test-cluster-master-1
current-context: system:node:test-cluster-master-1
kind: Config
preferences: 
users:
- name: system:node:test-cluster-master-1
  user:
    client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
    client-key: /var/lib/kubelet/pki/kubelet-client-current.pem

(13)安装Addon。安装coredns与kube-proxy,kubeadm init流程结束。

2.kubeadm join

kubeadm join的结果是完成一个k8s master节点或node节点加入一个已有的k8s集群。

以下为kubeadm join的处理流程代码(基于k8s v1.17.4版本),一共5步:

// cmd/kubeadm/app/cmd/join.go-NewCmdInit()
    ...
    joinRunner.AppendPhase(phases.NewPreflightPhase()) // 1.环境检查
	joinRunner.AppendPhase(phases.NewControlPlanePreparePhase()) // 2.控制面准备
	joinRunner.AppendPhase(phases.NewCheckEtcdPhase()) // 3.检查etcd是否健康
	joinRunner.AppendPhase(phases.NewKubeletStartPhase()) // 4.启动kubelet
	joinRunner.AppendPhase(phases.NewControlPlaneJoinPhase()) // 5.控制面操作
	...

(1)环境检查。检查项包括操作系统内核版本、k8s组件暴露服务的指定端口是否被占用、docker是否安装、iptables命令是否安装等等,但这里的环境检查与kubeadm init时的检查有点不同,这里会区分是join的master节点还是node节点,如果是node节点,则仅仅进行node相关的检查;

另外,这里还会获取kube-public命名空间下的configmap对象cluster-info,从中CA、master api等信息;

(2)控制面准备。如果是node的join,这一步的逻辑不会执行。这里会从kube-system命名空间中加载名称为kubeadm-certs的secret对象,然后生成控制面组件kube-apiserver、kube-controller-manager、kube-scheduler所需的证书,最后生成它们的部署yaml,放置到kubelet的static pod目录下,被kubelet使用static pod特性启动;

(3)检查etcd是否健康。

(4)启动kubelet。根据CA、bootstrap token等信息生成/etc/kubernetes/bootstrap-kubelet.conf文件,通过TLS bootstrap机制,kubelet使用bootstrap token来向kube-apiserver申请证书,由kube-controller-manager签发证书返回,然后kubelet根据返回的证书生成kubeconfig文件并写入到/etc/kubernetes/kubelet.conf文件,后续kubelet将会使用该kubeconfig文件来与kube-apiserver通信;

# cat /etc/kubernetes/kubelet.conf
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0F...
    server: https://192.168.1.10:6443
  name: default-cluster
contexts:
- context:
    cluster: default-cluster
    namespace: default
    user: default-auth
  name: default-context
current-context: default-context
kind: Config
preferences: 
users:
- name: default-auth
  user:
    client-certificate: /var/lib/kubelet/pki/kubelet-client-current.pem
    client-key: /var/lib/kubelet/pki/kubelet-client-current.pem

注意:bootstrap-kubelet.conf文件会在kubelet.conf文件生成后,被kubeadm删除掉;

(5)控制面操作。如果是node的join,这一步的逻辑不会执行。控制面操作包括生成etcd的static pod yaml、更新kube-system命名空间下的configmap对象kubeadm-config,将该控制节点信息更新进去、将该master节点打上污点,不作为计算节点数据面使用;至此,kubeadm join流程结束。

kuberneteskubeadminit与join原理分析(代码片段)

...、kubeadm部署k8s集群示例        1、k8smaster节点部署$kubeadminit        此外,我们也可以自己编写yaml文件来自定义kubeadm的启动过程和一些组件的启动参数等等$kubeadminit--configxxx.yaml    2、​k8snode节点部署(将一个... 查看详情

kubernetes一键部署利器:kubeadm(代码片段)

文章目录集群部署痛点kubeadm的工作原理kubeadminit的工作流程kubeadmjoin的工作流程配置kubeadm的部署参数集群部署痛点Kubernetes的部署一直以来都是挡在初学者前面的一只“拦路虎”。尤其是在Kubernetes项目发布初期,它的部署完... 查看详情

Kubernetes1.9.0 kubeadm init - 在系统路径中找不到 crictl

】Kubernetes1.9.0kubeadminit-在系统路径中找不到crictl【英文标题】:Kubernetes1.9.0kubeadminit-crictlnotfoundinsystempath【发布时间】:2018-06-0303:39:26【问题描述】:我在Centos7机器上设置kubernetes集群,kubeadminit命令给了我以下警告信息。[init]Usi... 查看详情

kubeadm init 在初始化 Kubernetes 集群时失败 [关闭]

】kubeadminit在初始化Kubernetes集群时失败[关闭]【英文标题】:kubeadminitfailingwhileinitializingaKubernetescluster[closed]【发布时间】:2021-08-0821:56:47【问题描述】:来自kubeadminit的执行日志VM操作系统版本-RHEL8.2(4.18.0-193.el8.x86_64)Docker版本-19.... 查看详情

Kubeadm Init 在启动控制平面时失败(kubelet 未运行或健康)

】KubeadmInit在启动控制平面时失败(kubelet未运行或健康)【英文标题】:KubeadmInitfailedatbootupcontrolplane(kubeletisn\'trunningorhealthy)【发布时间】:2021-03-0704:10:13【问题描述】:我正在使用centos7并使用以下命令在主节点中引导Kubernetes... 查看详情

调用 kubeadm init 时,kubeadm 无法初始化

】调用kubeadminit时,kubeadm无法初始化【英文标题】:kubeadmfailstoinitializewhenkubeadminitiscalled【发布时间】:2019-08-2703:32:41【问题描述】:我是kubernetes新手,正在尝试配置kubernetes主节点,我已经安装了kubeadm、kubectl和kubelethttps://kubern... 查看详情

kubeadm:主节点从未准备好

...创建的Virtualbox,并按照说明进行操作。我最初只是做了kubeadminit,但它不起作用(主NotReady)。所以我想也许旧版本可能会更好。原来如此kubea 查看详情

K8S:将“kubeadm init”命令行参数转换为“--config”YAML

】K8S:将“kubeadminit”命令行参数转换为“--config”YAML【英文标题】:K8S:convert"kubeadminit"command-lineargumentsto"--config"YAML【发布时间】:2020-02-0504:29:10【问题描述】:背景我正在尝试通过kubeadm配置集群。我通常通过以... 查看详情

想自学java的速来!docker原理阮一峰

...要概念3、部署kubernetesCluster(安装docker+安装kubelet.kubeadm和kubectll+用kubeadm创 查看详情

kubeadm入门

...。客户端将与API通信,以调度工作负载和管理集群的状态kubeadminit--token=102952.1a7dd4cc8d1f4cc5--kubernetes-versionsion-oshort)在生产环境中,建议排除明文令牌,kubeadm会生成一个令牌。要管理Kubernetes集群,需要客户端配置和证书。这个配... 查看详情

尝试 Kubeadm init 时在 SLES 中给出错误提示“不支持的图形驱动程序:btrfs”

】尝试Kubeadminit时在SLES中给出错误提示“不支持的图形驱动程序:btrfs”【英文标题】:Givingerrorsaying"unsupportedgraphdriver:btrfs"inSLESwhentrytoKubeadminit【发布时间】:2019-08-2110:06:39【问题描述】:我尝试在SLES上安装Kubernetes集群... 查看详情

快速搭建kubernetes容器集群平台(kubeadm)

...指令完成一个kubernetes集群的部署: #创建一个Master节点kubeadminit#将一个Node节点加入到当前集群中kubeadmjoin<Master节点的IP和端口> 1.安装要求在开始之前,部署Kubernetes集群机器需要满足以下几个条件: 一台或多 查看详情

初始化 master 后找不到 kubeadm 令牌

...ter【发布时间】:2017-02-2122:02:26【问题描述】:当我运行kubeadminit时,它会显示一个令牌,我应该使用该令牌从其他主机连接到该主机。该令牌存储在哪里?我试图通过在Terraform中添加kubeadm来找出更多自动化方法。感谢您的帮助... 查看详情

https工作原理

https工作原理 查看详情

如何在 master 上找到 kubeadm 的 join 命令?

...发布时间】:2018-12-1002:10:44【问题描述】:当我之前运行kubeadminit时,我丢失了原始的“kubeadmjoin”命令。如何再次检索此值?【问题讨论】:【参考方案1】:kubeadmtokencreate--print-join-command【讨论 查看详情

kubeadm搭建高可用k8s集群

...ster2和master3安装docker、kubeadm、kubectl、flannel,但不要执行kubeadminit。(如果执行了kubeadminit也没关系,再执行kubeadmreset就行了)。然后在master1节点/etc/kubernetes/目录下执行tar-czvfpki.tar.gzpki对pki目录进行压缩生成pki.tar.gz文件。将pki.t... 查看详情

kubeadm init 显示 kubelet 没有运行或健康

】kubeadminit显示kubelet没有运行或健康【英文标题】:kubeadminitshowskubeletisn\'trunningorhealthy【发布时间】:2019-02-0618:05:31【问题描述】:我正在尝试运行Kubernetes并尝试使用sudokubeadminit。根据官方文档的建议,Swap已关闭。问题是它显... 查看详情

kubeadm生成的token过期后,集群增加节点

...,都会提供node加入的token。[[email protected]-1kubernetes]#kubeadminit--config./kubeadm-init.yaml--skip-preflight-checks[kubeadm]WARNING:kubeadmisinbeta,pleasedonotuseitforproductionclusters.[init]UsingKubernetesversion:v1.8.1[init]UsingAuthorizationmodes:[NodeRBAC][preflight]Skippingp... 查看详情