這是Google Developer Advocate Sandeep Dinesh 關於如何充分利用Kubernetes環境的七部分影片和部落格系列的第一部分。 主要講保持容器映象盡可能小的理論和實用性。
Docker使構建容器映象變得輕而易舉。只需將標準 Dockerfile 放入您的檔案夾,執行 docker build 命令,然後執行,芝麻開門!您的容器映象已構建成功!
這種簡單性的缺點是,很容易構建出大體積的容器映象,其中包含您不需要的東西——包括潛在的安全漏洞。
在本期“Kubernetes最佳實踐”中,讓我們探討如何使用Alpine Linux 和 Docker builder 樣式建立生產就緒的容器映象,再做一些基準測試,然後確定這些容器在Kubernetes叢集中執行方式。
根據您使用的是解釋型語言還是編譯型語言,建立容器映象的過程會有所不同。讓我們一起來深入瞭解!
解釋型語言,如Ruby,Python,Node.js,PHP和其他語言透過傳送原始碼到直譯器來執行程式碼。 這樣的好處是可以跳過編譯步驟,但其缺點是要求您將直譯器與程式碼一起丟進去。
幸運的是,大多數這些語言都提供了預構建的Docker容器,其中包含一個輕量級環境,允許您執行更小的容器。
我們來看一個Node.js應用程式並對其進行容器化。 首先,讓我們使用node:onbuild映象作為基礎。 Docker容器的onbuild版本預先打包了您需要的所有內容,因此無需執行大量配置即可搞定。 這意味著Dockerfile非常簡單(只有兩行!)。 但是你要付出的磁碟大小代價——差不多700MB!
dockerfile
FROM node:onbuild
EXPOSE 8080
透過使用較小的基礎映象(如Alpine),您可以顯著減少容器的大小。Alpine Linux是一款體積小,輕量級的Linux發行版,在Docker使用者中非常受歡迎,因為它與許多應用程式相容,同時仍然保持小體積。
幸運的是,Node.js(以及其他流行語言)有一個官方的Alpine影象,可以滿足您的一切需求。與預設的node映象不同,node:alpine會刪除許多檔案和程式,只留下足以執行您的應用程式的部分。
基於Alpine Linux的Dockerfile建立起來有點複雜,因為你必須執行一些針對onbuild的命令。
dockerfile
FROM node:alpine
WORKDIR /app
COPY package.json /app/package.json
RUN npm install
COPY server.js /app/server.js
EXPOSE 8080
CMD npm start
諸如Go,C,C ++,Rust,Haskell等編譯型語言可以建立在沒有許多外部依賴性的情況下執行的二進位制檔案。 這意味著你可以提前構建二進位制檔案並將其投入生產,而無需把建立二進位制檔案(如編譯器)放進去。
藉助Docker對多階段構建的支援,您可以輕鬆地打包二進位制檔案和最少量的腳手架。 讓我們學習一下怎麼做。
讓我們採用Go應用程式並使用此樣式對其進行容器化。 首先,讓我們使用golang:onbuild映象作為基礎。 和以前一樣,Dockerfile只有兩行,但你再次付出磁碟大小超過700MB的代價!
dockerfile
FROM golang:onbuild
EXPOSE 8080
下一步是使用更小的基礎映象,也就是golang:alpine映象。 到目前為止,這與我們針對解釋型語言所遵循的過程相同。
同樣,使用Alpine基礎映象建立Dockerfile有點複雜,因為您必須執行一些執行onbuild映象相關的命令。
dockerfile
FROM golang:alpine
WORKDIR /app
ADD . /app
RUN cd /app && go build -o goapp
EXPOSE 8080
ENTRYPOINT ./goapp
但同樣,由此產生的映象要小得多,大小隻有256MB!
但是,我們可以使映象更小:您不需要Go附帶的任何編譯器或其他構建和除錯工具,因此您可以從最終容器中刪除它們。
讓我們使用多階段構建來獲取由golang:alpine容器建立的二進位制檔案並將其自行打包。
dockerfile
FROM golang:alpine AS build-env
WORKDIR /app
ADD . /app
RUN cd /app && go build -o goapp
FROM alpine
RUN apk update && \
apk add ca-certificates && \
update-ca-certificates && \
rm -rf /var/cache/apk
在構建此容器時,您可能會註意到Dockerfile會執行一些奇怪的操作,例如手動將HTTPS證書安裝到容器中。這是因為基礎的Alpine Linux幾乎沒有預安裝任何東西。 因此,即使您需要手動安裝任何依賴項,最終結果也還是超小容器映象!
註意:如果您想節省更多空間,可以靜態編譯應用程式並使用scratch容器映象。使用scratch作為基礎容器映象意味著您從頭開始,根本沒有基礎層。 但是,我建議使用Alpine作為基礎映象而不是scratch,因為Alpine映象中的僅僅增加少量額外MB的大小卻可以使得使用標準工具和安裝依賴項變得更加容易。
為了構建和儲存映象,我強烈推薦Google Container Builder和Google Container Registry的組合。 Google Container Builder非常快,並自動將映象推送到Google Container Registry。 大多數開發人員應該可以輕鬆地在GCP的免費套餐中完成所有工作,而Google Container Registry與原始Google雲端儲存的價格相同(便宜!)。
Google Kubernetes Engine等平臺可以安全地從Google Container Registry中拉取映象而無需任何其他配置,讓您輕鬆上手!
此外,Google Container Registry還為您提供漏洞掃描工具和開箱即用的IAM支援。 這些工具可以使您更輕鬆地保護和鎖定容器。
人們聲稱小體積容器的巨大優勢是縮短了時間——建立時間和拉取時間。 讓我們測試一下,使用onbuild建立的容器,對比在多階段過程中使用Alpine建立的容器,看看真實情況如何。
TL;DR:對於功能強大的計算機或Container Builder沒有顯著差異,但對於效能沒有那麼強大的計算機和共享系統(如許多CI/CD系統)而言則有明顯差異。 就絕對效能而言,小映象總是更好。
對於第一次測試,我將使用膝上型電腦進行構建。 我正在使用我們的辦公室WiFi,所以下載速度非常快!
對於每次構建,我都會刪除快取中的所有Docker映象。
Go Onbuild: 35 Seconds
Go Multistage: 23 Seconds
對於較大的容器映象,構建需要的時間大約是10秒左右。 雖然這個代價僅在初始構建時需要付出,但是如果您使用持續整合系統,則在每次構建時都要付出這個代價。
下一個測試是將容器映象推送到遠端映象倉庫。 對於此測試,我使用Google Container Registry來儲存映象。
Go Onbuild: 15 Seconds
Go Multistage: 14 Seconds
這很有趣! 為什麼需要花費相同的時間來推送12MB映象和700MB映象? 事實證明,Google Container Registry在幕後使用了很多技巧,包括許多流行基礎映象的全域性快取。
最後,我想測試將映象從遠端映象倉庫庫拉到本地計算機所需的時間。
Go Onbuild: 26 Seconds
Go Multistage: 6 Seconds
20秒的差距,這是使用兩個不同容器映象之間的最大差異。 您可以開始看到使用較小映象的優勢,尤其是在經常拉取映象時。
您還可以使用Google Container Builder在雲中構建容器映象,這樣可以自動將它們儲存在Google Container Registry中。
Go Onbuild: 25 Seconds
Go Multistage: 20 Seconds
再次證明,使用較小的映象有一點小優勢,沒有我想象的那麼大。
如果是在小型機器上構建映象,那麼使用較小的容器映象是否有優勢呢? 如果你有一個功能強大的膝上型電腦與快速網際網路連線和/或容器生成器,優勢並不明顯。 但是,如果您使用功能較弱的機器,故事就會發生變化。 為了模擬這一點,我使用了一個Google Compute Engine f1-micro VM來構建,推送和拉取這些映象,結果非常驚人!
Go Onbuild: 52 seconds
Go Multistage: 6 seconds
Go Onbuild: 54 seconds
Go Multistage: 28 seconds
Go Onbuild: 48 Seconds
Go Multistage: 16 seconds
雖然您可能不關心構建和推送容器映象所需的時間,但您應該非常關心拉取容器映象所需的時間。 對於Kubernetes,這可能是您的生產叢集最重要的指標。
例如,假設您有一個三節點叢集,其中一個節點崩潰。 如果您使用的是像Kubernetes Engine這樣的託管系統,系統會自動生成一個新節點來代替它。
但是,這個新節點將是全新的,並且必須先拉取所有容器映象才能開始工作。 拉取容器映象所需的時間越長,叢集執行的時間就越長!
當您增加群集大小(例如,使用Kubernetes Engine Autoscaling)或將節點升級到新版本的Kubernetes時,可能會發生這種情況(接下來的幾集中會關註這個問題)。
我們可以看到來自多個部署的多個容器的拉取效能可以在這裡真正體現出來,使用小容器可能會浪費幾分鐘的部署時間!
除了效能之外,使用較小的容器映象還有很大的安全性提升。 與使用大基礎映象的容器映象相比,小容器映象通常具有較小的攻擊面。
幾個月前,我構建了Go onbuild和multi-age容器映象,因此它們可能包含一些已被髮現的漏洞。 使用Google Container Registry的內建漏洞掃描,可以輕鬆掃描容器中的已知漏洞。 讓我們看看我們能找到些什麼。
哇,這次兩者之間有很大的不同! 較小容器映象中只有三個“中級”漏洞,而較大容器映象中有16個嚴重漏洞和300多個其他漏洞。
您可以看到大多數存在的問題與我們的應用程式無關,甚至沒有我們的應用程式! 因為多階段構建使用的是更小的基礎映象,所以可以產生漏洞的東西更少。
使用小容器映象的效能和安全優勢不言而喻。使用小的基礎映象和builder pattern可以更容易地構建小映象,並且還有許多其他技術可用於單個技術棧和程式語言,以最小化容器體積。 無論你做什麼,你都可以確信你保持容器映象最小化的努力是值得的!
預告:下一篇中我們將討論如何使用Kubernetes名稱空間來隔離叢集。
原文連結:https://cloudplatform.googleblog.com/2018/04/Kubernetes-best-practices-how-and-why-to-build-small-container-images.html
基於Kubernetes的DevOps實踐培訓將於2018年8月24日在北京開課,3天時間帶你係統掌握Kubernetes。本次培訓包括:容器特性、映象、網路;Kubernetes架構、核心元件、基本功能;Kubernetes設計理念、架構設計、基本功能、常用物件、設計原則;Kubernetes的資料庫、執行時、網路、外掛已經落地經驗;微服務架構、元件、監控方案等,點選下方圖片檢視詳情。
長按二維碼向我轉賬
受蘋果公司新規定影響,微信 iOS 版的贊賞功能被關閉,可透過二維碼轉賬支援公眾號。
微信掃一掃
使用小程式