K8S 原始碼探祕 之 kubeadm join 執行流程分析
一、引言
本文將基於 Kubernetes 1.12 版本,分析 kubeadm join 的執行流程,希望對讀者理解 k8s 有幫助!
關於 init 流程請參考前文: K8S 原始碼探祕 之 kubeadm init 執行流程分析
二、流程介紹
2.1 首先,上一張整體執行流程圖(可以點選看大圖!!!):
kubeadm 在執行 join 的過程中,主要包含:配置載入、環境檢測、獲取和驗證kubeconfig、配置本地 kubelet 服務等步驟,其間還穿插著對於當加入節點為 Master 時的一些額外操作。
配置初始化的過程與 init 時基本是一樣的,都包含載入系統預設引數、解析和應用使用者指定的配置、設定動態配置項(如節點名稱、節點 IP 等)以及驗證配置有效性等過程,不再贅述。
環境檢測的過程與 init 十分類似,只不過檢測專案稍有差異,專案列表見 2.2。
獲取和驗證 kubeconfig 配置在 join 過程中非常關鍵,之後的配置過程都依賴該步驟的產出。獲取 kubeconfig 目前支援三種方式:通過檔案載入;通過網路載入;通過 token 從 apiserver 讀取。通過檔案和網路載入相對比較簡單,這裡重點介紹第三種也是最常見的 join 方式:通過 token 讀取 kubeconfig。首先,kubeadm 會基於 APIServer EndPoint、token-bootstrap-client 使用者、kubernetes 叢集名以及空的證書資料建立一個不安全的 client,連線 API Server,讀取 kube-public/cluster-info ConfigMap,該 ConfigMap 是在 init 的過程中建立好的,匿名即可訪問。再讀取該 ConfigMap 中儲存的 kubeconfig 項、jws-kubeconfig-<token.ID> 項。其中,kubeconfig 項即儲存的 kubeconfig 內容,jws-kubeconfig-<token.ID> 項儲存的使用該 token 對該 kubeconfig 的簽名結果。kubeadm join 的驗簽過程即使用使用者提供的 token、kube-public/cluster-info 中儲存的 kubeconfig 資訊進行 jws 簽名,將簽名結果與 jws-kubeconfig-<token.ID> 項的內容對比,相同則驗證通過,認為該 APIServer 可以被信任。
如果 join 的節點角色為 Control Plane Instance,則需要進行一些額外配置。主要過程包括:連線API Server,讀取 kube-system/kubeadm-config ConfigMap,據此生成 InitConfiguration,進行 Master 加入相關檢查(包括是否使用 Local etcd、是否使用固定 endpoint、是否啟用了 self-hosted、證書是否配置正確等),執行 kubeadm init 系列檢查,生成證書以及 manifest 檔案(kube-apiserver、kube-controller-manager、kube-scheduler)。
配置本地 kubelet 服務無論在 init 還是 join 都是重要的一步。主要過程包括:生成相關配置,主要指 kubelet 執行需要的配置檔案;重啟 kubelet 服務自動完成 TLS Bootstrap,將 bootstrap-kubelet.conf 轉為 kubelet.conf;補充節點的相關屬性 Annotation、配置 DynamicKubeletConfig 等。
完成前的操作:如果加入的是 Control Plane Instance,則更新 kubeadm-config ConfigMap,同時給節點新增正確的標籤。最後打印出 join 成功描述。
2.2 預檢專案
1) 檢查執行 init 命令的使用者是否為 root,如果不是 root,直接快速失敗(fail fast);
2) 檢查 /etc/kubernetes/manifests/ 是否為空;
3) 檢查 /etc/kubernetes/bootstrap-kubelet.conf 是否不存在;
4) 檢查核心是否包含 ipvs 模組;
5) 檢查容器執行時,使用 CRI 還是 Docker,如果是 Docker,進一步檢查 Docker 服務是否已啟動,是否設定了開機自啟動;
6) 對於 Linux 系統,會額外檢查以下內容:
6.1) 檢查以下命令是否存在:crictl、ip、iptables、mount、nsenter、ebtables、ethtool、socat、tc、touch;
6.2) 檢查 /proc/sys/net/bridge/bridge-nf-call-iptables、/proc/sys/net/ipv4/ip-forward 內容是否為 1;
6.3) 檢查 swap 是否是關閉狀態;
7) 檢查核心是否被支援,Docker 版本及後端儲存 GraphDriver 是否被支援;
對於 Linux 系統,還需檢查 OS 版本和 cgroup 支援程度(支援哪些資源的隔離);
8) 檢查主機名訪問可達性;
9) 檢查 kubelet 版本,要高於 kubeadm 需要的最低版本,同時不高於待安裝的 k8s 版本;
10) 檢查 kubelet 服務是否開機自啟動;
11) 檢查 10250 埠是否被佔用;
12) 檢查 /etc/kubernetes/pki/ca.crt (非加入 Master,不應存在);
13) 檢查訪問 apiserver 是否通過了代理;
14) 如果使用 IPv6
檢查 /proc/sys/net/bridge/bridge-nf-call-iptables、/proc/sys/net/ipv6/conf/default/forwarding 內容是否為 1;