kubeadm 的工作原理


kubeadm 的工作原理

作者:張首富
時間:2020-06-04
w x:y18163201

相信使用二進制部署過 k8s 集群的同學們都知道,二進制部署集群太困難了,有點基礎的人部署起來還有成功的希望,要不然只能跟着別人的教程一步一步的去部署,部署的時候完全不知道這樣操作的意義是啥?出問題了無從下手解決。對於初學者來說真的是浪費生命,那有沒有什么簡單的方式來部署集群呢?這個問題在前幾年可能沒有很好的答案,但是在現在,答案簡直太多了,比如 kubeadm,rke 等方式,我們今天就來介紹下 kubeadm 部署集群的工作原理。

這里默認你有點 k8s 基礎,知道他們都是有哪些組件構成的。

在集群部署的時候,他的每一個組件都是一個需要被執行的,單獨的二進制文件,在現在容器化那么發達的時期,我們肯定來用 docker 來簡化部署。但是容器化部署的時候會有一個很大的問題,如何容器化 kubelet

我們知道 kubelet 是 kubernetes 項目用來操作 Docker 等容器運行時的核心組件,在每個 節點上都存在,可以除了跟容器運行時打交道外,kubelet 在配置容器網絡、管理容器數據卷事 時,他都需要直接操作宿主機。

如果現在 kubelet 本身就運行在一個容器里,那么直接操作宿主機就會變得很麻煩。對於網絡配置來說還好,kubelet 容器可以通過不開啟 Network Namespace(--net host)的方式,直接共享宿主機的網絡棧。可是,要讓 kubelet 隔着容器的 Mount Namespace 和文件系統,操作宿主機的文件系統,就有點兒困難了。

比如,如果用戶想要使用 NFS 做容器的持久化數據卷,那么 kubelet 就需要在容器進行綁定掛載前,在宿主機的指定目錄上,先掛載 NFS 的遠程目錄。

可是,這時候問題來了。由於現在 kubelet 是運行在容器里的,這就意味着它要做的這個“mount -F nfs”命令,被隔離在了一個單獨的 Mount Namespace 中。即,kubelet 做的掛載操作,不能被“傳播”到宿主機上。

對於這個問題,有人說,可以使用 setns() 系統調用,在宿主機的 Mount Namespace 中執行這些掛載操作;也有人說,應該讓 Docker 支持一個–mnt=host 的參數。但是,到目前為止,在容器里運行 kubelet,依然沒有很好的解決辦法,我也不推薦你用容器去部署 Kubernetes 項目。

因此為了解決上面這個問題,kubeadm 選擇了一種方案:

  • 把 kubelet 直接部署在宿主機上,然后使用容器部署其他的 kubernetes組件

所以,我們使用 kubeadm 安裝集群的第一步 就是在所有的機器上手動安裝 kubeadm、kubelet 和 kubectl 這三個二進制文件。

centos/Redhat 安裝:

cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

yum -y install kubectl-1.14.0 
yum -y install kubelet-1.14.0 
yum -y install kubeadm-1.14.0
systemctl enable kubelet  #必須要設置,

注意: 如果你這個時候啟動 kubelet 肯定會發現一個報錯,提示缺少文件,這個時候不用管它,我們一會使用 kubeadm init 之后初始化集群就正常了

然后我們需要創建 kubeadm 的配置文件,指定我們集群信息。舉個例子

cat > kubeadm-config.yaml <<-'EOF'

apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.16.0
api:
  advertiseAddress: 192.168.0.102
  bindPort: 6443
  ...
etcd:
  local:
    dataDir: /var/lib/etcd
    image: ""
imageRepository: k8s.gcr.io
kubeProxy:
  config:
    bindAddress: 0.0.0.0
    ...
kubeletConfiguration:
  baseConfig:
    address: 0.0.0.0
    ...
networking:
  dnsDomain: cluster.local
  podSubnet: ""
  serviceSubnet: 10.96.0.0/12
nodeRegistration:
  criSocket: /var/run/dockershim.sock
  ...
EOF

具體可以參考:https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/

接下來我們就可以使用kubeadm init來部署 Master 節點了。

kubeadm init 的工作流程

1,Prefligth Checks 檢查

kubeadm 首先要做的,是一系列的檢查工作,以確定這台機器可以用來部署 Kubernetes。這一步檢查,我們稱為“Preflight Checks”,它可以為你省掉很多后續的麻煩。

其實,Preflight Checks 包括了很多方面,比如:

  • Linux 內核的版本必須是否是 3.10以上?
  • Linux Cgroups 模塊是否可用
  • 機器的 hostname 是否標准?在 Kubernetes 項目里,機器的名字以及一切存儲在 Etcd 中的 API 對象,都必須使用標准的 DNS 命名(RFC 1123)。
  • 用戶安裝的 kubeadm 和 kubelet 的版本是否匹配?
  • 機器上是不是已經安裝了 Kubernetes 的二進制文件?
  • Kubernetes 的工作端口 10250/10251/10252 端口是不是已經被占用?
  • ip、mount 等 Linux 指令是否存在?
  • Docker 是否已經安裝?
  • Docker 和 kubelet 使用的驅動程序是否相同?
  • 。。。。

上面這些檢查中,一些檢查項目僅僅觸發警告,其它的則會被視為錯誤並且退出 kubeadm,除非問題得到解決或者用戶指定了 --ignore-preflight-errors=<list-of-errors> 參數。

2,生成自簽證書

在檢查通過之后,kubeadm 會為你生成 kubernetes對外提供服務所需的各種證書和對應的目錄。

如果用戶已經通過 --cert-dir 配置的證書目錄(默認為 /etc/kubernetes/pki)提供了他們自己的 CA 證書以及/或者密鑰, 那么將會跳過這個步驟。

kubernetes 對外提供服務時,除非專門開啟“不安全模式”,否則都要通過 HTTPS 才能訪問 Kube-apiserver。這就需要為 Kubernetes 集群配置好證書文件。

kubeadm 為 Kubernetes 項目生成的證書文件都放在 Master 節點的 /etc/kubernetes/pki 目錄下。在這個目錄下,最主要的證書文件是 ca.crt 和對應的私鑰 ca.key。

此外,用戶使用 kubectl 獲取容器日志等 streaming 操作時,需要通過 kube-apiserver 向 kubelet 發起請求,這個連接也必須是安全的。kubeadm 為 這一步生成的事 apiserver-kubelet-client.out 文件,對應的私鑰是 apiserver-kubelet-client.key。

除此之外,Kubernetes 集群中還有 Aggregate APIServer 等特性,也需要用到專門的證書,這里我就不再一一列舉了。可以參考這個文件:https://www.cnblogs.com/shoufu/p/12963081.html 需要指出的是,你可以選擇不讓 kubeadm 為你生成這些證書,而是拷貝現有的證書到如下證書的目錄里:

/etc/kubernetes/pki/ca.{crt,key}
[root@zsf-test pki]# tree
.
├── 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
│   ├── ca.crt
│   ├── ca.key
│   ├── healthcheck-client.crt
│   ├── healthcheck-client.key
│   ├── peer.crt
│   ├── peer.key
│   ├── server.crt
│   └── server.key
├── front-proxy-ca.crt
├── front-proxy-ca.key
├── front-proxy-client.crt
├── front-proxy-client.key
├── sa.key
└── sa.pub

3, 生成其他組件訪問 kube-apiserver 所需要的配置文件

這些文件的路徑是:/etc/kubernetes/xxx.conf

ls /etc/kubernetes/*.conf
/etc/kubernetes/admin.conf  /etc/kubernetes/controller-manager.conf  /etc/kubernetes/kubelet.conf  /etc/kubernetes/scheduler.conf

這些文件里面記錄的是,當前這個 Master 節點的服務器地址、監聽端口。證書目錄等信息。這樣,對應的客戶端(比如 scheduler,kubelet 等),可以直接加載相應的文件,使用里面的信息與 kube-apiserver建立安全連接。

4, 為 Master 組件生成 Pod 配置文件

在 Kubernetes 中,有一種特殊的容器啟動方法叫做“Static Pod”。它允許你把要部署的 Pod 的 YAML 文件放在一個指定的目錄里。這樣,當這台機器上的 kubelet 啟動時,它會自動檢查這個目錄,加載所有的 Pod YAML 文件,然后在這台機器上啟動它們。

從這一點也可以看出,kubelet 在 Kubernetes 項目中的地位非常高,在設計上它就是一個完全獨立的組件,而其他 Master 組件,則更像是輔助性的系統容器。

cd /etc/kubernetes/manifests
├── etcd.yaml
├── kube-apiserver.yaml
├── kube-controller-manager.yaml
└── kube-scheduler.yaml

然后 kubeadm 會調用 kubelet 運行這個 yml 文件,等到 Master 容器啟動后,kubeadm 會通過檢查localhost:6443/healthz 這個 Master 組件的健康檢查 url,等待 Master 組件完全運行起來。

然后,kubeadm 就會為集群生成一個 bootstrap token。在后面,只要持有這個 token,任何一個安裝了 kubelet 和 kubadm 的節點,都可以通過 kubeadm join 加入到這個集群當中。

這個 token 的值和使用方法,會在 kubeadm init 結束后被打印出來。

在 token 生成之后,kubeadm 會將 ca.crt 等 Master 節點的重要信息,通過 ConfigMap 的方式保存在 Etcd 當中,供后續部署 Node 節點使用。這個 ConfigMap 的名字是 cluster-info。

kubeadm init 的最后一步,就是安裝默認插件。Kubernetes 默認 kube-proxy 和 DNS 這兩個插件是必須安裝的。它們分別用來提供整個集群的服務發現和 DNS 功能。其實,這兩個插件也只是兩個容器鏡像而已,所以 kubeadm 只要用 Kubernetes 客戶端創建兩個 Pod 就可以了。

kubeadm join 的工作流程

這個流程其實非常簡單,kubeadm init 生成 bootstrap token 之后,你就可以在任意一台安裝了 kubelet 和 kubeadm 的機器上執行 kubeadm join 了。

可是,為什么執行 kubeadm join 需要這樣一個 token 呢?

因為,任何一台機器想要成為 Kubernetes 集群中的一個節點,就必須在集群的 kube-apiserver 上注冊。可是,要想跟 apiserver 打交道,這台機器就必須要獲取到相應的證書文件(CA 文件)。可是,為了能夠一鍵安裝,我們就不能讓用戶去 Master 節點上手動拷貝這些文件。

所以,kubeadm 至少需要發起一次“不安全模式”的訪問到 kube-apiserver,從而拿到保存在 ConfigMap 中的 cluster-info(它保存了 APIServer 的授權信息)。而 bootstrap token,扮演的就是這個過程中的安全驗證的角色。

只要有了 cluster-info 里的 kube-apiserver 的地址、端口、證書,kubelet 就可以以“安全模式”連接到 apiserver 上,這樣一個新的節點就部署完成了。

接下來,你只要在其他節點上重復這個指令就可以了。

具體安裝可以查看文章:

https://zhangguanzhang.github.io/2019/11/24/kubeadm-base-use/#kubeadm%E9%83%A8%E7%BD%B2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM