1. 程式人生 > >K8S 原始碼探祕 之 kubeadm join 執行流程分析

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 可以被信任。

驗證通過後,通過該 kubeconfig,可以獲取 CA 相關資訊,據此就可以建立安全的 client 了。kubeadm 會使用安全的 client 二次獲取 kube-public/cluster-info,並與之前獲得的比較是否相同,據此驗證該 TLS 連線的有效性。

        如果 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;