Kubernetes一鍵部署利器:kubeadm

要真正發揮容器技術的實力,你就不能僅僅侷限於對 Linux 容器自己的鑽研和使用。 這些知識更適合做爲你的技術儲備,以便在須要的時候能夠幫你更快的定位問題,並解決問題。 而更深刻的學習容器技術的關鍵在於,如何使用這些技術來「容器化」你的應用。 好比,咱們的應用既多是 Java Web 和 MySQL 這樣的組合,也多是 Cassandra 這樣的分佈式 系統。而要使用容器把後者運行起來,你單單經過 Docker 把一個 Cassandra 鏡像跑起來是沒用 的。node

要把 Cassandra 應用容器化的關鍵,在於如何處理好這些 Cassandra 容器之間的編排關係。比 如,哪些 Cassandra 容器是主,哪些是從?主從容器如何區分?它們之間又如何進行自動發現和通 信?Cassandra 容器的持久化數據又如何保持,等等。 這也是爲何咱們要反覆強調 Kubernetes 項目的主要緣由:這個項目體現出來的容器化「表達能 力」,具備獨有的先進性和完備性。docker

這就使得它不只能運行 Java Web 與 MySQL 這樣的常規組 合,還可以處理 Cassandra 容器集羣等複雜編排問題。因此,對這種編排能力的剖析、解讀和最佳 實踐,將是本專欄最重要的一部份內容。 不過,萬事開頭難。 做爲一個典型的分佈式項目,Kubernetes 的部署一直以來都是擋在初學者前面的一隻「攔路虎」。 尤爲是在 Kubernetes 項目發佈初期,它的部署徹底要依靠一堆由社區維護的腳本。bootstrap

其實,Kubernetes 做爲一個 Golang 項目,已經免去了不少相似於 Python 項目要安裝語言級別依 賴的麻煩。可是,除了將各個組件編譯成二進制文件外,用戶還要負責爲這些二進制文件編寫對應 的配置文件、配置自啓動腳本,以及爲 kube-apiserver 配置受權文件等等諸多運維工做。 目前,各大雲廠商最經常使用的部署的方法,是使用 SaltStack、Ansible 等運維工具自動化地執行這些 步驟。api

但即便這樣,這個部署過程依然很是繁瑣。由於,SaltStack 這類專業運維工具自己的學習成本,就 可能比 Kubernetes 項目還要高。 難道 Kubernetes 項目就沒有簡單的部署方法了嗎? 這個問題,在 Kubernetes 社區裏一直沒有獲得足夠重視。直到 2017 年,在志願者的推進下,社 區才終於發起了一個獨立的部署工具,名叫:kubeadm。 這個項目的目的,就是要讓用戶可以經過這樣兩條指令完成一個 Kubernetes 集羣的部署:安全

# 建立一個 Master 節點
$ kubeadm init

# 將一個 Node 節點加入到當前集羣中
$ kubeadm join <Master 節點的 IP 和端口 >

是否是很是方便呢? 不過,你可能也會有所顧慮:Kubernetes 的功能那麼多,這樣一鍵部署出來的集羣,能用於生產 環境嗎? 爲了回答這個問題,在今天這篇文章,我就先和你介紹一下 kubeadm 的工做原理吧。 kubeadm 的工做原理 在上一篇文章《從容器到容器雲:談談 Kubernetes 的本質》中,我已經詳細介紹了 Kubernetes 的架構和它的組件。在部署時,它的每個組件都是一個須要被執行的、單獨的二進制文件。因此 不難想象,SaltStack 這樣的運維工具或者由社區維護的腳本的功能,就是要把這些二進制文件傳輸 到指定的機器當中,而後編寫控制腳原本啓停這些組件。 不過,在理解了容器技術以後,你可能已經萌生出了這樣一個想法,爲何不用容器部署 Kubernetes 呢?服務器

這樣,我只要給每一個 Kubernetes 組件作一個容器鏡像,而後在每臺宿主機上用 docker run 指令啓 動這些組件容器,部署不就完成了嗎? 事實上,在 Kubernetes 早期的部署腳本里,確實有一個腳本就是用 Docker 部署 Kubernetes 項 目的,這個腳本相比於 SaltStack 等的部署方式,也的確簡單了很多。網絡

可是,這樣作會帶來一個很麻煩的問題,即:如何容器化 kubelet。 我在上一篇文章中,已經提到 kubelet 是 Kubernetes 項目用來操做 Docker 等容器運行時的核心 組件。但是,除了跟容器運行時打交道外,kubelet 在配置容器網絡、管理容器數據卷時,都須要直 接操做宿主機。 而若是如今 kubelet 自己就運行在一個容器裏,那麼直接操做宿主機就會變得很麻煩。對於網絡配 置來講還好,kubelet 容器能夠經過不開啓 Network Namespace(即 Docker 的 host network 模式)的方式,直接共享宿主機的網絡棧。但是,要讓 kubelet 隔着容器的 Mount Namespace 和 文件系統,操做宿主機的文件系統,就有點兒困難了。架構

好比,若是用戶想要使用 NFS 作容器的持久化數據卷,那麼 kubelet 就須要在容器進行綁定掛載 前,在宿主機的指定目錄上,先掛載 NFS 的遠程目錄。 但是,這時候問題來了。因爲如今 kubelet 是運行在容器裏的,這就意味着它要作的這個「mount -F nfs」命令,被隔離在了一個單獨的 Mount Namespace 中。即,kubelet 作的掛載操做,不能 被「傳播」到宿主機上。 對於這個問題,有人說,可使用 setns() 系統調用,在宿主機的 Mount Namespace 中執行這些 掛載操做;也有人說,應該讓 Docker 支持一個–mnt=host 的參數。  app

可是,到目前爲止,在容器裏運行 kubelet,依然沒有很好的解決辦法,我也不推薦你用容器去部署 Kubernetes 項目。運維

正由於如此,kubeadm 選擇了一種妥協方案: 因此,你使用 kubeadm 的第一步,是在機器上手動安裝 kubeadm、kubelet 和 kubectl 這三個二 進制文件。固然,kubeadm 的做者已經爲各個發行版的 Linux 準備好了安裝包,因此你只須要執 行:

$ apt-get install kubeadm

就能夠了。 接下來,你就可使用「kubeadm init」部署 Master 節點了。 kubeadm init 的工做流程 當你執行 kubeadm init 指令後,kubeadm 首先要作的,是一系列的檢查工做,以肯定這臺機器 能夠用來部署 Kubernetes。這一步檢查,咱們稱爲「Preflight Checks」,它能夠爲你省掉不少後 續的麻煩。 其實,Preflight Checks 包括了不少方面,好比: 在經過了 Preflight Checks 以後,kubeadm 要爲你作的,是生成 Kubernetes 對外提供服務所 需的各類證書和對應的目錄。

Kubernetes 對外提供服務時,除非專門開啓「不安全模式」,不然都要經過 HTTPS 才能訪問 kube-apiserver。這就須要爲 Kubernetes 集羣配置好證書文件。 kubeadm 爲 Kubernetes 項目生成的證書文件都放在 Master 節點的 /etc/kubernetes/pki 目錄 下。在這個目錄下,最主要的證書文件是 ca.crt 和對應的私鑰 ca.key。

此外,用戶使用 kubectl 獲取容器日誌等 streaming 操做時,須要經過 kube-apiserver 向 kubelet 發起請求,這個鏈接也必須是安全的。kubeadm 爲這一步生成的是 apiserver-kubeletclient.crt 文件,對應的私鑰是 apiserver-kubelet-client.key。 除此以外,Kubernetes 集羣中還有 Aggregate APIServer 等特性,也須要用到專門的證書,這裏 我就再也不一一列舉了。

須要指出的是,你能夠選擇不讓 kubeadm 爲你生成這些證書,而是拷貝現 有的證書到以下證書的目錄裏:  

/etc/kubernetes/pki/ca.{crt,key}

  

這時,kubeadm 就會跳過證書生成的步驟,把它徹底交給用戶處理。 證書生成後,kubeadm 接下來會爲其餘組件生成訪問 kube-apiserver 所需的配置文件。這些文 件的路徑是:/etc/kubernetes/xxx.conf:

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

  

這些文件裏面記錄的是,當前這個 Master 節點的服務器地址、監聽端口、證書目錄等信息。這 樣,對應的客戶端(好比 scheduler,kubelet 等),能夠直接加載相應的文件,使用裏面的信息與 kube-apiserver 創建安全鏈接。 接下來,kubeadm 會爲 Master 組件生成 Pod 配置文件。我已經在上一篇文章中和你介紹過 Kubernetes 有三個 Master 組件 kube-apiserver、kube-controller-manager、kubescheduler,而它們都會被使用 Pod 的方式部署起來。

你可能會有些疑問:這時,Kubernetes 集羣尚不存在,難道 kubeadm 會直接執行 docker run 來 啓動這些容器嗎? 固然不是。 在 Kubernetes 中,有一種特殊的容器啓動方法叫作「Static Pod」。它容許你把要部署的 Pod 的 YAML 文件放在一個指定的目錄裏。這樣,當這臺機器上的 kubelet 啓動時,它會自動檢查這個目 錄,加載全部的 Pod YAML 文件,而後在這臺機器上啓動它們。

從這一點也能夠看出,kubelet 在 Kubernetes 項目中的地位很是高,在設計上它就是一個徹底獨 立的組件,而其餘 Master 組件,則更像是輔助性的系統容器。 在 kubeadm 中,Master 組件的 YAML 文件會被生成在 /etc/kubernetes/manifests 路徑下。比 如,kube-apiserver.yaml:

apiVersion: v1
kind: Pod
metadata:
  annotations:
    scheduler.alpha.kubernetes.io/critical-pod: ""
  creationTimestamp: null
  labels:
    component: kube-apiserver
    tier: control-plane
  name: kube-apiserver
  namespace: kube-system
spec:
  containers:
  - command:
    - kube-apiserver
    - --authorization-mode=Node,RBAC
    - --runtime-config=api/all=true
    - --advertise-address=10.168.0.2
    ...
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    image: k8s.gcr.io/kube-apiserver-amd64:v1.11.1
    imagePullPolicy: IfNotPresent
    livenessProbe:
      ...
    name: kube-apiserver
    resources:
      requests:
        cpu: 250m
    volumeMounts:
    - mountPath: /usr/share/ca-certificates
      name: usr-share-ca-certificates
      readOnly: true
    ...
  hostNetwork: true
  priorityClassName: system-cluster-critical
  volumes:
  - hostPath:
      path: /etc/ca-certificates
      type: DirectoryOrCreate
    name: etc-ca-certificates
  ...

關於一個 Pod 的 YAML 文件怎麼寫、裏面的字段如何解讀,我會在後續專門的文章中爲你詳細分 析。在這裏,你只須要關注這樣幾個信息:

  • 1. 這個 Pod 裏只定義了一個容器,它使用的鏡像是:k8s.gcr.io/kube-apiserveramd64:v1.11.1 。這個鏡像是 Kubernetes 官方維護的一個組件鏡像。
  • 2. 這個容器的啓動命令(commands)是 kube-apiserver --authorization-mode=Node,RBAC …,這樣一句很是長的命令。其實,它就是容器裏 kube-apiserver 這個二進制文件再加上指定的 配置參數而已。
  • 3. 若是你要修改一個已有集羣的 kube-apiserver 的配置,須要修改這個 YAML 文件。
  • 4. 這些組件的參數也能夠在部署時指定,我很快就會講解到。 在這一步完成後,kubeadm 還會再生成一個 Etcd 的 Pod YAML 文件,用來經過一樣的 Static Pod 的方式啓動 Etcd。

因此,最後 Master 組件的 Pod YAML 文件以下所示:  

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

  

而一旦這些 YAML 文件出如今被 kubelet 監視的 /etc/kubernetes/manifests 目錄下,kubelet 就 會自動建立這些 YAML 文件中定義的 Pod,即 Master 組件的容器。 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 上,這樣一個新的節點就部署完成了。 接下來,你只要在其餘節點上重複這個指令就能夠了。 配置 kubeadm 的部署參數 我在前面講解了 kubeadm 部署 Kubernetes 集羣最關鍵的兩個步驟,kubeadm init 和 kubeadm join。相信你必定會有這樣的疑問:kubeadm 確實簡單易用,但是我又該如何定製個人集羣組件參 數呢?

 

$ kubeadm init --config kubeadm.yaml

  

這時,你就能夠給 kubeadm 提供一個 YAML 文件(好比,kubeadm.yaml),它的內容以下所示 (我僅列舉了主要部分):

apiVersion: kubeadm.k8s.io/v1alpha2
kind: MasterConfiguration
kubernetesVersion: v1.11.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
  ...

  

經過制定這樣一個部署參數配置文件,你就能夠很方便地在這個文件裏填寫各類自定義的部署參數 了。好比,我如今要指定 kube-apiserver 的參數,那麼我只要在這個文件里加上這樣一段信息:

...
apiServerExtraArgs:
  advertise-address: 192.168.0.103
  anonymous-auth: false
  enable-admission-plugins: AlwaysPullImages,DefaultStorageClass
  audit-log-path: /home/johndoe/audit.log

  

而後,kubeadm 就會使用上面這些信息替換 /etc/kubernetes/manifests/kube-apiserver.yaml 裏的 command 字段裏的參數了。 而這個 YAML 文件提供的可配置項遠不止這些。好比,你還能夠修改 kubelet 和 kube-proxy 的配 置,修改 Kubernetes 使用的基礎鏡像的 URL(默認的k8s.gcr.io/xxx鏡像 URL 在國內訪問是 有困難的),指定本身的證書文件,指定特殊的容器運行時等等。這些配置項,就留給你在後續實 踐中探索了。 總結 在今天的此次分享中,我重點介紹了 kubeadm 這個部署工具的工做原理和使用方法。緊接着,我 會在下一篇文章中,使用它一步步地部署一個完整的 Kubernetes 集羣。 從今天的分享中,你能夠看到,kubeadm 的設計很是簡潔。而且,它在實現每一步部署功能時,都 在最大程度地重用 Kubernetes 已有的功能,這也就使得咱們在使用 kubeadm 部署 Kubernetes 項目時,很是有「原生」的感受,一點都不會感到突兀。 而 kubeadm 的源代碼,直接就在 kubernetes/cmd/kubeadm 目錄下,是 Kubernetes 項目的一 部分。其中,app/phases 文件夾下的代碼,對應的就是我在這篇文章中詳細介紹的每個具體步 驟。

相關文章
相關標籤/搜索