做者:張首富 時間:2020-06-04 w x:y18163201
相信使用二進制部署過 k8s 集羣的同窗們都知道,二進制部署集羣太困難了,有點基礎的人部署起來還有成功的但願,要否則只能跟着別人的教程一步一步的去部署,部署的時候徹底不知道這樣操做的意義是啥?出問題了無從下手解決。對於初學者來講真的是浪費生命,那有沒有什麼簡單的方式來部署集羣呢?這個問題在前幾年可能沒有很好的答案,可是在如今,答案簡直太多了,好比 kubeadm,rke 等方式,咱們今天就來介紹下 kubeadm 部署集羣的工做原理。html
這裏默認你有點 k8s 基礎,知道他們都是有哪些組件構成的。 node
在集羣部署的時候,他的每個組件都是一個須要被執行的,單獨的二進制文件,在如今容器化那麼發達的時期,咱們確定來用 docker 來簡化部署。可是容器化部署的時候會有一個很大的問題,如何容器化 kubelet。git
咱們知道 kubelet 是 kubernetes 項目用來操做 Docker 等容器運行時的核心組件,在每一個 節點上都存在,能夠除了跟容器運行時打交道外,kubelet 在配置容器網絡、管理容器數據卷事 時,他都須要直接操做宿主機。github
若是如今 kubelet 自己就運行在一個容器裏,那麼直接操做宿主機就會變得很麻煩。對於網絡配置來講還好,kubelet 容器能夠經過不開啓 Network Namespace(--net host)的方式,直接共享宿主機的網絡棧。但是,要讓 kubelet 隔着容器的 Mount Namespace 和文件系統,操做宿主機的文件系統,就有點兒困難了。docker
好比,若是用戶想要使用 NFS 作容器的持久化數據卷,那麼 kubelet 就須要在容器進行綁定掛載前,在宿主機的指定目錄上,先掛載 NFS 的遠程目錄。bootstrap
但是,這時候問題來了。因爲如今 kubelet 是運行在容器裏的,這就意味着它要作的這個「mount -F nfs」命令,被隔離在了一個單獨的 Mount Namespace 中。即,kubelet 作的掛載操做,不能被「傳播」到宿主機上。centos
對於這個問題,有人說,可使用 setns() 系統調用,在宿主機的 Mount Namespace 中執行這些掛載操做;也有人說,應該讓 Docker 支持一個–mnt=host 的參數。可是,到目前爲止,在容器裏運行 kubelet,依然沒有很好的解決辦法,我也不推薦你用容器去部署 Kubernetes 項目。api
所以爲了解決上面這個問題,kubeadm 選擇了一種方案:安全
因此,咱們使用 kubeadm 安裝集羣的第一步 就是在全部的機器上手動安裝 kubeadm、kubelet 和 kubectl 這三個二進制文件。bash
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 首先要作的,是一系列的檢查工做,以肯定這臺機器能夠用來部署 Kubernetes。這一步檢查,咱們稱爲「Preflight Checks」,它能夠爲你省掉不少後續的麻煩。
其實,Preflight Checks 包括了不少方面,好比:
上面這些檢查中,一些檢查項目僅僅觸發警告,其它的則會被視爲錯誤而且退出 kubeadm,除非問題獲得解決或者用戶指定了 --ignore-preflight-errors=<list-of-errors>
參數。
在檢查經過以後,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 等特性,也須要用到專門的證書,這裏我就再也不一一列舉了。能夠參考這個文件:http://www.javashuo.com/article/p-bdgutsqg-nx.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
這些文件的路徑是:/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創建安全鏈接。
在 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 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
參考:極客時間 張磊的 kubernetes 專欄