作者 | fanux.中弈
什麼是叢集鏡像
顧名思義,和作業系統 .iso 鏡像或 Docker 鏡像類似,叢集鏡像是用一定的技術手段把整個叢集的所有檔案以一定格式打成的一個資源包。

對比單機和叢集會發現一些的有趣現象:
- 單機有計算、存儲、網絡等驅動;叢集有 CNI/CSI/CRI 實作像是叢集的驅動。
- 單機有 ubuntu centos 作業系統;叢集中可以把 Kubernetes 看成雲作業系統。
- 單機上可以運作 docker 容器或虛拟機;相當于一個運作的執行個體,叢集上也有運作着 K8s 的執行個體。
- 單機上有虛拟機鏡像,docker 鏡像;随着雲計算技術的發展,叢集上也會抽象出類似的鏡像技術。
以基于 Kubernetes 的叢集鏡像為例,裡面包含了除作業系統以外的所有檔案:
- docker 依賴的二進制與 systemd 配置、dockerd 配置,以及一個私有的容器鏡像倉庫。
- Kubernetes 核心元件二進制、容器鏡像、kubelet system 配置等。
- 應用需要用到的 yaml 配置或 helm chart,以及應用的容器鏡像。
- 其它腳本、配置與二進制工具等應用運作需要的所有依賴。
同樣,叢集鏡像運作時肯定不是起一個容器或者裝在一台機器上,而是這個鏡像可以直接安裝到多台伺服器上或者直接對接到公有雲的基礎設施上。
sealer 介紹
sealer是阿裡巴巴開源的叢集鏡像的一個實作方式,項目位址:
https://github.com/alibaba/sealerDocker 解決了單個容器的鏡像化問題,而 sealer 通過把整個叢集打包,實作了分布式軟體的 Build Share Run!!!
試想我們要去傳遞一個 SaaS 應用,它依賴了 MySQL/ES/Redis 這些資料庫和中間件,所有東西都在 Kubernetes 上進行編排,如果沒有叢集鏡像時,要做如下操作:
- 找個工具去安裝 K8s 叢集
- helm install mysql es redis... 如果是離線環境可能還需要導入容器鏡像
- kubectl apply yoursaas
看似好像也沒那麼複雜,但其實從整個項目傳遞的角度來說,以上操作是面向過程極易出錯的。
現在如果提供另外一個方式,隻需一條指令就可解決上面的問題,你會不會用?
sealer run your-saas-application-with-mysql-redis-es:latest
可以看到,隻需要 run 一個叢集鏡像,整個叢集就被傳遞了,細節複雜的操作都被屏蔽掉了,而且任何應用都可以使用相同的方式運作。這個叢集鏡像是怎麼來的呢?

如上圖所示:我們隻需要定義一個類似 Dockerfile 的檔案,将其稱之為 Kubefile, 然後執行 build 指令即可:
sealer build -t your-saas-application-with-mysql-redis-es:latest .
從單機和叢集兩個緯度進行對比,就可以一目了然:
- docker 通過 Dockerfile 建構一個 docker 鏡像,使用 compose 就可以運作容器。
- sealer 通過 Kubefile 建構一個 CloudImage,使用 Clusterfile 啟動整個叢集。
快速體驗
下面我們一起制作和運作一個 Kubernetes dashboard 的叢集鏡像,來體驗一個完整的流程。
編寫 Kubefile:
# 基礎鏡像,已經被制作好了裡面包含所有的kubernetes啟動相關的依賴
FROM registry.cn-qingdao.aliyuncs.com/sealer-io/cloudrootfs:v1.16.9-alpha.7
# 下載下傳官方的dashboard yaml編排檔案,已經下載下傳了可以使用COPY指令
RUN wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.2.0/aio/deploy/recommended.yaml
# 指定運作方式,可以使用kubectl helm kustomiz等
CMD kubectl apply -f recommended.yaml
build dashboard 叢集鏡像:
sealer build -t kubernetes-with-dashobard:latest .
運作叢集鏡像:
# 下面指令會在伺服器上安裝k8s叢集并apply dashboard, passwd指定伺服器ssh密碼,也可以使用密鑰
sealer run kubernetes-with-dashobard:latest \
--master 192.168.0.2,192.168.0.3,192.168.0.4 \
--node 192.168.0.5,192.168.0.6 \
--passwd xxx
# 檢查pod
kubectl get pod -A |grep dashboard
把制作好的鏡像推送到鏡像倉庫,相容 docker registry:
sealer tag kubernetes-with-dashobard:latest docker.io/fanux/dashobard:latest
sealer push docker.io/fanux/dashobard:latest
這樣就可以把制作好的鏡像傳遞出去或者提供給别人複用。
使用場景
sealer 具體能幫我們做哪些事呢?下面列舉幾個主要場景:
安裝 Kubernetes 與叢集生命周期管理(更新/備份/恢複/伸縮)
這是個最簡單的場景,不管你是需要在單機上安裝個開發測試環境,還是在生産環境中安裝一個高可用叢集;不管是裸機還是對接公有雲,或者各種體系結構作業系統,都可以使用 sealer 進行安裝,這裡隻安裝 Kubernetes 的話就選擇個基礎鏡像即可。
與其它的安裝工具對比,sealer 優勢在于:
- 簡單到令人發指:sealer run 一條指令結束。
- 速度快到令人窒息:3min 裝完 6 節點,可能你使用别的工具時還沒下載下傳完 sealer 就已經裝完了,不僅如此,後續我們還有黑科技優化到 2min 甚至 1min 以内。
- 相容性與穩定性:相容各種作業系統,支援 x86 arm 等體系結構。
- 一緻性設計:會讓叢集保持 Clusterfile 中的定義狀态,以更新為例,隻需要改一下 Clusterfile 中的版本号即可實作更新。
速度快是因為首先是 golang 實作,意味着我們可以對衆多很細緻的地方做并發的處理,這相比 ansible 就有了更多優勢;而且還可以做更細緻的錯誤處理,然後在鏡像分發上抛棄以前 load 的方式;後續在檔案分發上也會做優化,達到安裝性能上的極緻。
相容性上,docker kubelet 采用了二進制+systemd 安裝核心元件全容器化,這樣不用再去依賴 yum/apt 這類感覺作業系統的安裝工具。ARM 和 x86 采用不同的鏡像支援與 sealer 本身解耦開,對公有雲的适配也抽離單獨子產品進行實作,這裡我們沒去對接 terraform,原因還是為了性能。在我們的場景下,terraform 啟動基礎設施将近 3min,而我們通過退避重試把基礎設施啟動優化到了 30s 以内,除此之外,在叢集鏡像場景下,不需要這麼複雜的基礎設施管理能力,我們不想讓 sealer 變重也不想依賴一個指令行工具。
一緻性的設計理念是 sealer 中值得一提的,叢集鏡像與 Clusterfile 決定了叢集是什麼樣子,相同的鏡像與 Clusterfile 就能 run 出個一樣的叢集。變更要麼變更 Clusterfile,如增加節點、改變節點規格或者換鏡像,換鏡像時,由于叢集鏡像也是分層結構,是以 hash 值不變的 layer 不會發生變更,而 hash 發生變化會幫助重新 apply 該層。
雲原生生态軟體的打包/安裝等,如 prometheus mysql 叢集
sealer run prometheus:latest 就可以建立一個帶有 prometheus 的叢集,或者在一個已有的叢集中安裝 prometheus。
那麼問題來了:它和 helm 啥差別?
- sealer 不關心編排,更注重打包,上面例子 prometheus 可以用 helm 編排,sealer 會把 chart 和 chart 裡需要的所有容器鏡像打包起來,這是在 build 的過程中通過黑科技做到的,因為 build 過程會像 docker build 一樣起臨時的 Kubernetes 叢集,然後我們就知道叢集依賴了哪些容器鏡像,最後把這些容器鏡像打包。
- 和 Kubernetes 一起打包,拿了一個 chart 它未必能安裝成功,比如使用了廢棄的 api 版本,但是做成鏡像把 Kubnernetes 也包在一起了,隻要 build 沒問題,run 就沒問題,這點和 docker 把作業系統 rootfs 打包在一起有異曲同工之妙。
- 內建性,叢集鏡像更關注整個分布式應用叢集整體打包,如把 prometheus ELK mysql 叢集做成一個鏡像服務與業務。
是以 sealer 與helm是協作關系,分工明确。
後續可以在 sealer 的官方鏡像倉庫中找到這些通用的叢集鏡像,直接使用即可。
SaaS 軟體整體打包/傳遞 專有雲離線傳遞
從分布式應用的視角看,通常從上往下,少則幾個多則上百的元件,現有整體傳遞方式大多都是面向過程的,中間需要很多進行幹預的事,sealer 就可以把這些東西統統打包在一起進行一鍵傳遞。
可能你會問:我們做個 tar.gz 再加個 ansible 腳本不也能一鍵化嗎?答案是肯定的。就和 docker 鏡像出現之前,大家也通過 tar.gz 傳遞一樣,你會發現标準和技術的出現解決了人與人之間的協作問題, 有了叢集鏡像就可以直接複用别人的成果,也能制作好東西供别人使用。
專有雲場景就非常适合使用 sealer,很多客戶機房都是離線的,而叢集鏡像會把所有依賴打到鏡像中,隻要鏡像制作得好,那麼所有局點都能以相同的方式進行一鍵傳遞,獲得極佳的一緻性體驗。
在公有雲上實踐上述場景
sealer 自帶對接公有雲屬性,很多情況下對接公有雲會有更好的使用體驗,比如安裝叢集時,隻需要指定伺服器數量和規格而不用關心 IP,伸縮直接修改 Clusterfile 中定義的數字即可。
技術原理簡介
寫時複制
叢集鏡像的存儲也是通過寫時複制的方式實作的。這樣做有兩個好處:我們可以把同一叢集中不同的分布式軟體打在不同層,以實作複用;還可以實作直接把叢集鏡像 push 到 docker 鏡像倉庫中。
容器鏡像緩存
build 的過程中 sealer 是如何知道待建構的叢集鏡像裡有哪些容器鏡像,以及怎麼把容器鏡像存儲下來呢?其中有一些難點問題:
- 如何知道分布式軟體中有哪些容器鏡像?因為我們需要把這些鏡像緩存下來,不管是掃描使用者的 yaml 檔案還是用 helm template 之後掃描都是不完美的。首先不能确定使用者的編排方式是什麼,其次有些軟體不把鏡像位址寫在編排檔案中,而是通過自己的程式去拉起,無法保證 build 成功運作就一定沒問題。
- 容器鏡像是需要被存儲到私有倉庫中打包在叢集鏡像裡,那容器鏡像倉庫位址勢必和編排檔案中寫的不一樣,特别是怎麼保證使用者 alwayPull 的時候還是能夠在私有倉庫中下載下傳到鏡像?
對待第一個問題,sealer 解決方式是:sealer build 的過程中和 Docker build 一樣,會拉起一個臨時的 Kubernetes 叢集,并執行使用者在 Kubefile 中定義的 apply 指令。
如上圖所示,這樣就可以保證使用者依賴的所有鏡像都被打包進去,無論使用者使用什麼樣的編排方式。
第二個問題,我們打包容器鏡像到私有鏡像倉庫中,怎樣使用這個私有鏡像也是個難題,假設私有鏡像倉庫名為 localhost:5000,肯定會和編排檔案中寫的不一緻,對此我們有兩種方式解決:
- 第一種是 hack 和 docker,做了一個隻要私有鏡像倉庫中有就直接從私有鏡像中拉取,沒有才去公網拉取鏡像的能力。
- 第二種方案是無侵入 docke r的 proxy,把 docker 請求全部打給代理,讓代理去決定如果私有倉庫有就從私有倉庫拉取。同時我們還增強了 registry 的能力讓 registry 可以 cache 多個遠端倉庫的能力。
sealer 的這種方案完美解決了離線場景鏡像打包的問題。
負載均衡
sealer 的叢集高可用使用了輕量級的負載均衡 lvscare。相比其它負載均衡,lvscare 非常小僅有幾百行代碼,而且 lvscare 隻做 ipvs 規則的守護,本身不做負載非常穩定,直接在 node 上監聽 apiserver,如果跪了就移除對應的規則,重新起來之後會自動加回,相當于是一個專用的負載均衡器,在 sealos 項目中也用了兩年多,有廣泛的實踐。
運作時
運作時就是支撐應用運作的環境,像 base on Kuberentes 的運作時 sealer 就可以透明地支援非常簡單,以 istio 為例,使用者隻需要:
FROM kubernetes:v1.18.3
RUN curl -L https://istio.io/downloadIstio | sh -
就可以 build 出一個 istio 的運作時供自己應用使用。
對于不是 base on Kuberentes 的運作時,如 k0s k3s,可以擴充 sealer.Runtime 中的接口,這樣以後就可以:
FROM k3s:v1.18.3
RUN curl -L https://istio.io/downloadIstio | sh -
更牛的擴充比如擴充 ACK 的 runtime:
FROM aliyum.com/ACK:v1.16.9
RUN curl -L https://istio.io/downloadIstio | sh -
這種鏡像會直接幫助使用者應用運作到 ACK 上。以上有些能力在 roadmap 中。
基礎設施
現在很多使用者都希望在雲端運作自己的叢集鏡像,sealer 自帶對接公有雲能力,sealer 自己實作的基礎設施管理器,得益于我們更精細的退避重試機制,30s 即可完成基礎設施建構(阿裡雲 6 節點)性能是同類工具中的佼佼者,且 API 調用次數大大降低,配置相容 Clusterfile。
總結
sealer 未來的一些願景與價值展現:
- sealer 可以以極其簡單的方式讓使用者自定義叢集,解決分布式軟體制作者與使用者的協作問題。
- 極其簡單友好的 User Interface,能屏蔽和相容各種底層技術細節,到處運作。
- 生态建設,官方倉庫裡将會涵蓋常用的分布式軟體。
最後我們總結下:
- 如果你要整體傳遞你的分布式 SaaS,請用 sealer。
- 如果你要內建多個分布式服務在一起,如資料庫消息隊列或者微服務運作時,請用 sealer。
- 如果你要安裝一個分布式應用如 mysql 主備叢集,請用 sealer。
- 如果你需要安裝/管理一個 Kubernetes 高可用叢集,請用 sealer。
- 如果你要初始化多個資料中心,保持多個資料中心狀态強一緻,請用 sealer。
- 如果你需要在公有雲上實作上述場景,請用 sealer。
sealer 将會在近期宣布開源,有興趣的可以關注:
如果對相關内容有疑問,歡迎加入釘釘交流群:
掃碼檢視更多中間件技術幹貨和案例: