sealer,“集羣” 版本的 Docker,交付複雜度的終結者

背景

隨着時代的發展,單機上跑的單體應用已經越來越少了,分佈式應用幾乎已經無處不在。Docker 很好的對單機應用進行了鏡像化的封裝,實現在單機上 Build Ship Run, 從此單機上應用的運行沒有什麼是一個 docker run 解決不了的。

docker 對比 rpm 之類的工具顯然一致性好很多,原因是 docker 把 rootfs 同樣封裝到了鏡像之中,也就是所有的依賴都在鏡像中。

再看集羣和分佈式應用,以前 IaaS 主導的雲計算只對資源進行了抽象,顯然一個操作系統是承上啓下的作用,向上需要有很好的應用管理能力,kubernetes 很符合這一定義。

所以現在假設 kubernetes 是管理所有服務器的操作系統,在這個前提下我們要設計一個 “集羣” 版本的 Docker,這就是我們今天的主角 sealer

目前 sealer 也捐獻給了 CNCF 基金會,項目地址:https://github.com/sealerio/sealer

快速開始


聯想一下 Docker 我們需要啓動一個 centos 容器:

docker run centos

所以要用 sealer 啓動一個 kubernetes 集羣,只需要:

sealer run kubernetes:v1.19.8 \
    --masters 192.168.0.2,192.168.0.3,192.168.0.4 \
    --nodes 192.168.0.5,192.168.0.6,192.168.0.7 --passwd xxx

這樣一個六節點的集羣就起來了,當然 sealer 同樣支持單節點。

同理,我們可以運行分佈式軟件如:

sealer run mysql-cluster:8.0
sealer run redis:5.0

各種分佈式軟件一鍵安裝交付。

交付的痛點

想象沒有 sealer 交付的故事是什麼樣的?假設你已經使用了 kubernetes helm 這些工具,當然沒使用的只會比以下步驟更痛苦。

  1. 找一個能在離線環境中安裝 kubernetes 本身的工具

  2. 加載你事先打包好的所有 docker 鏡像

  3. 啓動一個私有鏡像倉庫

  4. 把所有鏡像推送到私有鏡像倉庫中

  5. 修改編排文件中鏡像倉庫地址

  6. 執行所有的 helm chart

而使用 sealer 交付故事是:

  1. 加載集羣鏡像

  2. sealer run [集羣鏡像]

如果的交付文檔很長,整個交付面向過程,那就很適合使用 sealer,可以在整個集羣一致性上保證交付成功。

那麼如何去構建一個自定義的集羣鏡像呢?

Build 集羣鏡像

sealer 運行分佈式應用很簡單,同樣要去自定義一個集羣鏡像也需要很簡單,這裏採用與 Docker 鏡像幾乎相同的方式進行構建。

這裏以構建一個 dashboard 的集羣鏡像爲例子:

  1. 編寫一個類似 Dockerfile 的文件,我們叫 Kubefile
FROM kubernetes:v1.19.8
RUN wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
CMD kubectl apply -f recommended.yaml

第一行 FROM kubernetes:v1.19.8 可以選擇你想要的基礎鏡像。

RUN 指令只會在 Build 的時候執行,去下載 dashboard 的 yaml 文件。

CMD 指令會在集羣啓動後執行,所以這裏並不關心用戶使用什麼編排工具,比如 sealer 可以很好的與 helm 搭配使用。

  1. build
sealer build -t dashboard:latest .

這裏 sealer 不僅只是把 RUN 命令執行了一下,還會去掃描裏面包含的所有 docker 鏡像並緩存到集羣鏡像中,這樣啓動的時候會直接從緩存的私有鏡像倉庫中去下載鏡像。

  1. Run
sealer run dashboard:latest --masters 192.168.0.2 --passwd xxx
kubectl get pod -A|grep dashboard

現在我們就可以運行這個集羣鏡像,sealer 會先拉起一個 kubernetes 集羣,再在其上面部署 dashboard。

這裏神奇的地方是雖然 dashboard 編排文件裏面寫的是 gcr 倉庫的鏡像地址,sealer 並不會從公網去拉取,而會檢測私有鏡像倉庫是是否存在該鏡像,有的話直接從私有鏡像倉庫中拉取。如此 即便在離線環境中也可以正常拉到鏡像,而且整個過程什麼也不需要修改。

  1. Push
sealer push registry.cn-qingdao.aliyuncs.com/sealer-io/dashboard:latest

可以把剛纔的集羣鏡像 push 到任意的 registry 中,比如 docker hub。

配置管理

看到上面你可能會感覺確實簡單,但是功能好像不太滿足,因爲一次交付,幾乎會有非常多的配置文件需要管理與調整,這在 sealer 裏面如何處理?

sealer 對這塊的設計也有充分考慮,答案是使用 Clusterfile。

Clusterfile 說白了是就告訴 sealer 啓動整個集羣需要的配置是怎樣的。

apiVersion: sealer.cloud/v2
kind: Cluster
metadata:
  name: default-kubernetes-cluster
spec:
  image: kubernetes:v1.19.8
  ssh:
    passwd: xxx
  hosts:
    - ips: [ 192.168.0.2,192.168.0.3,192.168.0.4 ]
      roles: [ master ]
    - ips: [ 192.168.0.5 ]
      roles: [ node ]

sealer apply -f Clusterfile 即可啓動整個集羣。

常見需求,比如想修改一個 podsubnet, sealer 支持 merge 所有 kubeadm 配置文件:

---
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration
networking:
  podSubnet: 100.64.0.0/10

你不需要把所有配置寫全,只需要寫你關心的字段,會自動合併到默認配置中。

業務配置使用更通用的做法:

---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Config
metadata:
  name: mysql-config
spec:
  path: etc/mysql.yaml
  data: |
       mysql-user: root
       mysql-passwd: xxx

data 裏面的內容會覆蓋鏡像內部的 path, 指定的文件,同樣支持是直接覆蓋還是合併等一些策略,那麼這裏的內容就很適合是 helm values.

sealer 同樣支持用環境變量管理少量配置:

apiVersion: sealer.cloud/v2
kind: Cluster
metadata:
  name: my-cluster
spec:
  image: kubernetes:v1.19.8
  env:
    docker-dir: /var/lib/docker
  hosts:
    - ips: [ 192.168.0.2 ]
      roles: [ master ] # add role field to specify the node role
      env: # overwrite some nodes has different env config
        docker-dir: /data/docker
    - ips: [ 192.168.0.3 ]
      roles: [ node ]

鏡像內部的腳本就可以直接使用 docker-dir 環境變量:

#!/bin/bash
echo $docker-dir

插件機制

插件可以幫助用戶做一些之外的事情,比如更改主機名,升級內核,或者添加節點標籤等……

主機名插件

如果你在 Clusterfile 後添加插件配置並應用它,sealer 將幫助你更改所有的主機名:

---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: hostname
spec:
  type: HOSTNAME
  data: |
    192.168.0.2 master-0
    192.168.0.3 master-1
    192.168.0.4 master-2
    192.168.0.5 node-0
    192.168.0.6 node-1
    192.168.0.7 node-2

Hostname Plugin 將各個節點在安裝集羣前修改爲對應的主機名。

腳本插件

如果你在 Clusterfile 後添加 Shell 插件配置並應用它,sealer 將幫助你執行 shell 命令 (執行路徑爲鏡像 Rootfs 目錄):

---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: shell
spec:
  type: SHELL
  action: PostInstall
  'on': node-role.kubernetes.io/master=
  data: |
    kubectl taint nodes node-role.kubernetes.io/master=:NoSchedule
action : [PreInit| PostInstall] # 指定執行shell的時機
  在初始化之前執行命令      |  action: PreInit
  在添加節點之前執行命令    |  action: PreJoin
  在添加節點之後執行命令    |  action: PostJoin
  在執行Kubefile CMD之前  |  action: PreGuest
  在安裝集羣之後執行命令    |  action: PostInstall
  在清理集羣前執行命令      |  action: PreClean
  在清理集羣后執行命令      |  action: PostClean
  組合使用                |  action: PreInit|PreJoin
on     : #指定執行命令的機器
  爲空時默認在所有節點執行
  在所有master節點上執行   | 'on': master
  在所有node節點上執行     | 'on': node
  在指定IP上執行          | 'on': 192.168.56.113,192.168.56.114,192.168.56.115,192.168.56.116
  在有連續IP的機器上執行    | 'on': 192.168.56.113-192.168.56.116
  在指定label節點上執行(action需爲PostInstall或PreClean)  | 'on': node-role.kubernetes.io/master=
data   : #指定執行的shell命令

標籤插件

如果你在 Clusterfile 後添加 label 插件配置並應用它,sealer 將幫助你添加 label:

apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: label
spec:
  type: LABEL
  action: PreGuest
  data: |
    192.168.0.2 ssd=true
    192.168.0.3 ssd=true
    192.168.0.4 ssd=true
    192.168.0.5 ssd=false,hdd=true
    192.168.0.6 ssd=false,hdd=true
    192.168.0.7 ssd=false,hdd=true

節點 ip 與標籤之前使用空格隔開,多個標籤之間使用逗號隔開。

集羣檢測插件

由於服務器以及環境因素 (服務器磁盤性能差) 可能會導致 sealer 安裝完 kubernetes 集羣后,立即部署應用服務,出現部署失敗的情況。cluster check 插件會等待 kubernetes 集羣穩定後再部署應用服務。

apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: checkCluster
spec:
  type: CLUSTERCHECK
  action: PreGuest

污點插件

如果你在 Clusterfile 後添加 taint 插件配置並應用它,sealer 將幫助你添加污點和去污點:

apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: taint
spec:
  type: TAINT
  action: PreGuest
  data: |
    192.168.56.3 key1=value1:NoSchedule
    192.168.56.4 key2=value2:NoSchedule-
    192.168.56.3-192.168.56.7 key3:NoSchedule
    192.168.56.3,192.168.56.4,192.168.56.5,192.168.56.6,192.168.56.7 key4:NoSchedule
    192.168.56.3 key5=:NoSchedule
    192.168.56.3 key6:NoSchedule-
    192.168.56.4 key7:NoSchedule-

data 寫法爲 ips taint_argument ips  : 多個 ip 通過 , 連接,連續 ip 寫法爲 首 ip - 末尾 ip taint_argument: 同 kubernetes 添加或去污點寫法 (key=value:effect #effect 必須爲:NoSchedule, PreferNoSchedule 或 NoExecute)。

插件使用步驟

Clusterfile 內容:

apiVersion: sealer.aliyun.com/v1alpha1
kind: Cluster
metadata:
  name: my-cluster
spec:
  image: registry.cn-qingdao.aliyuncs.com/sealer-io/kubernetes:v1.19.8
  provider: BAREMETAL
  ssh:
    # ssh的私鑰文件絕對路徑,例如/root/.ssh/id_rsa
    pk: xxx
    # ssh的私鑰文件密碼,如果沒有的話就設置爲""
    pkPasswd: xxx
    # ssh登錄用戶
    user: root
    # ssh的登錄密碼,如果使用的密鑰登錄則無需設置
    passwd: xxx
  network:
    podCIDR: 100.64.0.0/10
    svcCIDR: 10.96.0.0/22
  certSANS:
    - aliyun-inc.com
    - 10.0.0.2
  masters:
    ipList:
     - 192.168.0.2
     - 192.168.0.3
     - 192.168.0.4
  nodes:
    ipList:
     - 192.168.0.5
     - 192.168.0.6
     - 192.168.0.7
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: hostname
spec:
  type: HOSTNAME
  data: |
     192.168.0.2 master-0
     192.168.0.3 master-1
     192.168.0.4 master-2
     192.168.0.5 node-0
     192.168.0.6 node-1
     192.168.0.7 node-2
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: taint
spec:
  type: SHELL
  action: PostInstall
  on: node-role.kubernetes.io/master=
  data: |
     kubectl taint nodes node-role.kubernetes.io/master=:NoSchedule
sealer apply -f Clusterfile #plugin僅在安裝時執行,後續apply不生效。

執行上述命令後 hostname,shell plugin 將修改主機名並在成功安裝集羣后執行 shell 命令。

在 Kubefile 中定義默認插件

很多情況下在不使用 Clusterfile 的情況下也能使用插件,本質上 sealer 會先把 Clusterfile 中的插件配置先存儲到 rootfs/plugins 目錄,再去使用,所以我們可以在製作鏡像時就定義好默認插件。

插件配置文件 shell.yaml:

apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
name: taint
spec:
type: SHELL
action: PostInstall
on: node-role.kubernetes.io/master=
data: |
  kubectl get nodes
---
apiVersion: sealer.aliyun.com/v1alpha1
kind: Plugin
metadata:
  name: SHELL
spec:
  action: PostInstall
  data: |
    if type yum >/dev/null 2>&1;then
    yum -y install iscsi-initiator-utils
    systemctl enable iscsid
    systemctl start iscsid
    elif type apt-get >/dev/null 2>&1;then
    apt-get update
    apt-get -y install open-iscsi
    systemctl enable iscsid
    systemctl start iscsid
    fi

Kubefile:

FROM kubernetes:v1.19.8
COPY shell.yaml plugin

構建一個包含安裝 iscsi 的插件 (或更多插件) 的集羣鏡像:

sealer build -m lite -t kubernetes-iscsi:v1.19.8 .

通過鏡像啓動集羣后插件也將被執行,而無需在 Clusterfile 中定義插件: sealer run kubernetes-iscsi:v1.19.8 -m x.x.x.x -p xxx

總結

以上對 sealer 的核心能力有了一個整體的介紹,目前 sealer 已經在多家企業中生產落地,阿里內部也有非常多的實踐,sealer 未來會重點在性能上做進一步突破,加強生態集羣鏡像製作,幫助企業和開發者更快進行交付。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/81Gl0b8s3OfWWVCLR_SmLQ