10個小技巧提高 Kubernetes 容器效率
近年來,容器以及 Kubernetes 成為開發(fā)者以及企業(yè)用戶重點關(guān)注的技術(shù)趨勢,本文總結(jié)了構(gòu)建和管理容器的十個重要技巧來優(yōu)化 IT 成本并提高效率。
容器是 Kubernetes 中應(yīng)用程序的核心載體。當(dāng)創(chuàng)建 Kubernetes 工作負(fù)載,例如創(chuàng)建用于調(diào)度、擴容或者升級應(yīng)用程序的規(guī)則時,首先需要創(chuàng)建一個容器鏡像,然后通過該鏡像來運行服務(wù)或 Kubernetes 工作負(fù)載。在完成對鏡像的測試并與應(yīng)用程序其余代碼整合后,用戶通常會將鏡像推送到容器注冊中心。但在推送之前,仍然有很多實戰(zhàn)技巧可以幫助構(gòu)建和管理容器。
正文
通過 Kubernetes,用戶可以自動擴展業(yè)務(wù),而整個過程很少出現(xiàn)甚至零宕機,從而優(yōu)化 IT 成本并提高系統(tǒng)可靠性。
1、使用Kubernetes 模式
隨著 Kubernetes 不斷推出新功能,其應(yīng)用模式也在逐步改變。為了確保 Kubernetes 集群遵循當(dāng)前 Kubernetes 的應(yīng)用模式,用戶需要定期查閱Kubernetes 官方文檔以及每一個版本的發(fā)布說明。
2、復(fù)用基礎(chǔ)鏡像以節(jié)省時間
在 Kubernetes 集群中創(chuàng)建應(yīng)用容器時,用戶需要構(gòu)建一個 Docker 基礎(chǔ)鏡像,然后在此鏡像基礎(chǔ)上構(gòu)建部分或全部應(yīng)用容器。有很多應(yīng)用共享依賴項、庫和配置,因此可以在基礎(chǔ)鏡像完成對共享部分進行配置,從而實現(xiàn)復(fù)用。
Docker Hub和Google Container 注冊中心有數(shù)千個可供下載的基礎(chǔ)鏡像,這些鏡像已經(jīng)預(yù)先完成應(yīng)用配置,隨時可以投入使用,這可以節(jié)省大量時間。

3、不要輕易相信任何鏡像
盡管使用預(yù)先構(gòu)建的鏡像很方便,但要格外小心并確保對其運行特定漏洞掃描。
一些開發(fā)人員會從 Docker Hub 中獲取一個其他用戶創(chuàng)建的基礎(chǔ)鏡像,然后將這個容器推送到生產(chǎn)環(huán)境,而這一切只是因為乍一看這個鏡像包含了所需要的包。
這里有很多錯誤:鏡像中的代碼版本可能不正確;這些代碼可能有漏洞;或者更糟糕的情形是該項目可能已經(jīng)被故意綁定了惡意軟件。
為了緩解上述問題,用戶可以通過 Snyder 或 Twistlock 來運行靜態(tài)分析,然后將其整合到 CI/CD(持續(xù)集成和持續(xù)交付)管道中,進而掃描所有容器漏洞。
一般來說,一旦在基礎(chǔ)鏡像中發(fā)現(xiàn)漏洞,用戶就應(yīng)該重新構(gòu)建整個鏡像,而不是僅僅修復(fù)漏洞。容器應(yīng)該是不變的,因此,需要引入補丁重新構(gòu)建和部署鏡像。
4、優(yōu)化基礎(chǔ)鏡像
從最精簡、最可行的基礎(chǔ)鏡像開始,然后在此基礎(chǔ)上構(gòu)建軟件包。通過這種方式,可以準(zhǔn)確掌握容器中的全部內(nèi)容。
較小的基礎(chǔ)鏡像也可以減少開銷。例如,應(yīng)用可能只有 5MB 大小,如果要添加一個現(xiàn)成的 Node.js 鏡像,然后再安裝所有的庫,整個鏡像很可能會變成 600MB 大小,但實際上并不需要這些額外的庫。
因此,盡量保持最精簡的鏡像可以使:
- 構(gòu)建更快
- 存儲空間更小
- 鏡像拉取更快
- 潛在威脅面更小
5、確保容器只運行一個進程
同保持基礎(chǔ)鏡像最小化類似的是,確保每個容器只有一個進程。容器的生命周期與它托管的應(yīng)用程序相同,這意味著每個容器應(yīng)該只包含一個父進程。

按照Google Cloud的說法,把容器當(dāng)作虛擬機并同時運行多個進程是一個常見的錯誤。雖然容器可以實現(xiàn)這種方式,但這樣就無法使用 Kubernetes 的自我修復(fù)屬性。
通常,容器和應(yīng)用應(yīng)該同時啟動;同樣,當(dāng)應(yīng)用停止時,容器也應(yīng)該停止。如果在一個容器中有多個進程,可能會出現(xiàn)應(yīng)用程序狀態(tài)混雜的情形,這將導(dǎo)致 Kubernetes 無法確定一個容器是否健康。
6、正確處理 Linux 信號
容器通過 Linux 信號來控制其內(nèi)部進程的生命周期。為了將應(yīng)用的生命周期與容器聯(lián)系起來,需要確保應(yīng)用能夠正確處理 Linux 信號。
Linux 內(nèi)核使用了諸如 SIGTERM、SIGKILL 和 SIGINIT 等信號來終止進程。但是,容器內(nèi)的 Linux 會使用不同的方式來執(zhí)行這些常見信號,如果執(zhí)行結(jié)果同信號默認(rèn)結(jié)果不符,將會導(dǎo)致錯誤和中斷發(fā)生。
創(chuàng)建專門的 init 系統(tǒng)有助于解決此問題,比如專門針對容器的Linux Tini系統(tǒng)。這個工具正確注冊了信號處理程序(比如 PID),容器化應(yīng)用可以正確執(zhí)行 Linux 信號,從而正常關(guān)閉孤立進程和僵尸進程,完成內(nèi)存回收。
7、充分利用 Docker 的緩存構(gòu)建機制
容器鏡像由一系列鏡像層組成,這些鏡像層通過模板或 Dockerfile 中的指令生成。這些層以及構(gòu)建順序通常被容器平臺緩存。例如,Docker 就有一個可以被不同層復(fù)用的構(gòu)建緩存。這個緩存可以使構(gòu)建更快,但是要確保當(dāng)前層的所有父節(jié)點都保存了構(gòu)建緩存,并且這些緩存沒有被改變過。簡單來講,需要把不變的層放在前面,而把頻繁改變的層放在后面。
例如,假設(shè)有一個包含步驟 X、Y 和 Z 的構(gòu)建文件,對步驟 Z 進行了更改,構(gòu)建文件可以在緩存中重用步驟 X 和 Y,因為這些層在更改 Z 之前就已經(jīng)存在,這樣可以加速構(gòu)建過程。但是,如果改變了步驟 X,緩存中的層就不能再被復(fù)用。
雖然這是一種方便的行為,可以節(jié)省時間,但是必須確保所有鏡像層都是當(dāng)前的,而不是從舊的、過時的緩存構(gòu)建而成。
8、使用類似 Helm 的包管理器
Helm作為 Kubernetes 的非官方軟件包管理器,可以幫助安裝和更新集群中運行的共同負(fù)載和容器。Helm 可以使用Chart聲明自定義應(yīng)用程序依賴項,并提供滾動升級和回滾工具。
用戶可以通過現(xiàn)有基礎(chǔ)鏡像為 Kubernetes 集群提供通用服務(wù),如數(shù)據(jù)庫或 Web 服務(wù);也可以為內(nèi)部應(yīng)用程序創(chuàng)建自定義基礎(chǔ)鏡像,創(chuàng)建自定義的 Charts 可以簡化部署,減少開發(fā)團隊的工作負(fù)擔(dān)和重復(fù)性工作。
9、使用標(biāo)簽和語義化版本號
作為基本原則,用戶不應(yīng)該使用:latest標(biāo)記。對大多數(shù)開發(fā)人員來說,這是顯而易見的。如果不為容器添加自定義標(biāo)簽,它將嘗試從鏡像倉庫中拉取當(dāng)前版本,而容器可能并沒有包括需要的更改。
在創(chuàng)建自定義鏡像時,使用鏡像標(biāo)簽和語義化版本號來追蹤對 Docker 容器的更改。當(dāng)它們在 Kubernetes 集群中運行時,Kubernetes 通過鏡像標(biāo)簽確定應(yīng)該運行哪個版本。在選擇 Docker 鏡像版本機制時,應(yīng)該同時考慮生產(chǎn)負(fù)載和開發(fā)流程兩種情況,這樣才能在 Kubernetes 中獲得更好的效果。
10、安全
在很多情況下,當(dāng)構(gòu)建 Docker 鏡像時,需要讓容器內(nèi)的應(yīng)用程序訪問敏感數(shù)據(jù),例如 API 令牌、私鑰和數(shù)據(jù)庫連接字符串等。
將這些秘密信息嵌入到容器中并不是一個安全的解決方案,即使只是保存到一個私有容器鏡像中。將未加密的隱私數(shù)據(jù)作為 Docker 鏡像的一部分進行處理會面臨無數(shù)額外的安全風(fēng)險,包括網(wǎng)絡(luò)和鏡像注冊表的安全性,而 Docker 架構(gòu)本身也決定了無法對容器中未加密的敏感數(shù)據(jù)進行優(yōu)化。
相反,用戶可以通過使用Kubernetes Secrets 對象將隱私信息存儲在容器外面,這樣更簡單、安全。
Kubernetes 提供了一個 Secrets 抽象,允許在 Docker 鏡像或 Pod 定義之外存儲隱私數(shù)據(jù)。用戶可以通過掛載卷或環(huán)境變量的方式把這些信息加載到容器中。更新時,只需更換相關(guān)服務(wù)的 Pod 并使用新的證書即可。用戶也可以通過 Hashicorp Vault 以及Bitnami Sealed Secrets來保存隱私數(shù)據(jù)。