在使用容器化應用時,你遵循這些最佳實踐了嗎?git
用Kubernetes,你能夠自動化的且按需的、以極少的或者是零宕機時間來擴展業務,這優化了IT成本,而且增長了系統的可靠性。數據庫
對於Kubernetes中運行的應用來講,容器是其核心。當你建立Kubernetes工做負載(也就是用於調度、擴展和升級應用的規則)的時候,你啓動了一個運行着服務或者Kubernetes工做負載的容器鏡像。鏡像在測試以及與應用的代碼基的其餘部分集成之後,它一般被推送到容器倉庫。可是,在這個點以前,當你寫服務而且將其容器化的時候,有不少須要牢記在心的最佳實踐。緩存
一、跟上最新的Kubernets模安全
隨着Kubernets新特性的持續發佈,Kubernetes的使用模式可能會有所改變。爲了確保你的集羣遵循了最近確立的Kubernetes使用模式,咱們建議你遵循官方的Kubernetes文檔,並週期性的閱讀它;除此以外,也要關注在每一個Kubernetes發佈中引入的變動,這些變動體如今發佈說明(release notes)中。服務器
二、利用基礎鏡像節省時間網絡
建立用於Kubernetes集羣的應用容器涉及到構建一個Docker基礎鏡像;基於這個基礎鏡像來構建部分或者全部應用容器。使用基礎鏡像,使得複用鏡像配置成爲可能,由於不少應用會共享依賴項、庫和配置。架構
Docker Hub和Google Container Registry都有數以千計的、即拿即用的基礎鏡像供下載。經過在你的應用中使用這些預先配置的基礎鏡像能夠節省大量時間。app
如圖1所示,它展現了基礎鏡像和應用的關係。工具
圖1 Ubuntu基礎鏡像和應用的關係學習
三、不要信任隨意選擇的基礎鏡像;老是使用漏洞掃描
雖然使用預先構建的鏡像很是方便,可是要保證安全,也要確認,首先你對其執行了某些漏洞掃描。
一些開發者會從Docker Hub上獲取別人建立的基礎鏡像,由於初看起來,這個基礎鏡像有他們須要的包。而後,他們把這個隨意選擇的容器推送到了生產環境。
這樣作是錯誤的。你在使用的代碼版本可能會有可被利用的漏洞,可能有缺陷,更糟糕的,它可能被人有目的的綁上了惡意軟件。而只是你不知道而已。
爲了減輕風險,你可使用靜態分析工具(例如Snyk或者Twistlock)並將其集成進持續集成和持續交付流水線來掃描全部容器中的漏洞。
如下是一條通用規則:若是你確實在基礎鏡像中發現了漏洞,你應該從新構建它,而不是僅僅爲其打補丁。容器應該是不可變的。所以,最佳實踐是用已包含的補丁來從新構建鏡像,而後從新部署這個鏡像。
四、優化基礎鏡像
從最精簡、最小可行的基礎鏡像開始,而後在其之上構建你的包。經過這種方法,你會準確的知道,在你的容器裏面有什麼東西。
更小的基礎鏡像也有助於減小開銷。你的應用可能只有5MB,可是,若是你直接把現成的鏡像(例如Node.js)加在上面並且包含了整個庫,那麼你最終可能獲得了600MB你不須要的額外庫。
更小的鏡像帶來的其餘優點包括:
更快的構建更小的存儲空間使用更快的拉取鏡像可能更小的攻擊面
五、在一個容器中只運行一個進程
與保持小的基礎鏡像相關的是,在一個容器中只運行一個進程。容器與其託管的應用擁有相同的生命週期。這意味着,你的每一個容器都應該只有一個單一的父進程(如圖2中好的例子所示)。
圖2 容器進程模型示例
按照Google Cloud文檔(https://cloud.google.com/solutions/best-practices-for-building-containers#package_a_single_app_per_container),把容器當成虛擬機(能夠同時運行多個進程)是常見的錯誤。雖然可能以這種方式來使用容器,可是這沒有利用到Kubernetes的自愈特性(self-healing properties)。
請記住,容器和應用這兩者應該在同一時刻啓動;相應的,當應用中止運行的時候,容器也應該中止運行。若是在一個容器中有多個進程,那麼你可能會遇到這樣的狀況:應用的狀態是不同的,這會致使Kubernetes沒法判斷容器是不是健康的。
六、正確的處理Linux信號
Linux信號用於控制容器內進程的生命週期。爲了把應用和容器的生命週期連接在一塊兒,你須要確保應用正確的處理了Linux信號。
Linux信號,例如SIGTERM、SIGKILL和SIGINIT,用於在內核中終止進程。可是,容器中的Linux以不一樣的方式執行這些常見的信號。默認狀況下,它們不能按預期工做,這致使錯誤和中斷寫入。
解決這種問題的方法之一是,使用一種特殊化的init系統,例如適用於容器的Linux Tini。Linux Tini這個工具會正確的註冊信號處理器(例如PID),這樣一來,對於容器化的應用來講,Linux信號也能夠正常工做了,並且可以優雅的關閉孤立進程和殭屍進程以回收內存。
七、利用Docker構建緩存順序
容器鏡像是使用模板或者Dockerfile中的指令以一系列層的方式構建的。層以及層構建的順序一般被緩存在容器平臺上。例如,Docker就有一個構建緩存,它用於層的複用。這種緩存使你構建更快,可是隻有在這種狀況下你纔可以使用到它:之前構建中用到的全部前置層都是存在的。
例如,你有個構建文件,其中有步驟X、步驟Y和步驟Z。你對步驟Z作了變動。在這種狀況下,構建文件會複用緩存中的步驟X和步驟Y,由於在你修改的層(步驟Z)以前的那些層(步驟X和步驟Y)都是存在的。這就加速了構建,節省了一些時間。可是,若是你僅僅改變了步驟X,那麼緩存將不會包含其後的任何步驟和層。
雖然這很方便並且節省了時間,可是你必須確保全部的層都是最新的以及它們不是從更老的過期的緩存中拉取出來的。
八、使用相似Helm的包管理器
做爲Kubernetes非官方的包管理器,Helm是獲取和更新運行在集羣上的常見工做負載和容器的另外一個可選方案。Helm使用chart來聲明依賴項,並提供了滾動升級和回滾的工具。
對於你但願在Kubernetes集羣中提供的通用服務來講,你能夠利用已存在的基礎鏡像。這些通用服務的例子包括數據庫和Web服務器。對於你的內部應用來講,你能夠建立定製化的基礎鏡像。建立你本身的chart會簡化部署,減小開銷,減小開發團隊的重複工做。
能夠參考文章「Managing Helm Releases the GitOps Way」(https://www.weave.works/blog/managing-helm-releases-the-gitops-way)來學習Helm是如何工做的。
九、使用標籤(tag)和語義版本
請記住,你不該該使用:latest標籤。對大部分開發者來講,這是顯而易見的事情。可是,若是你沒有爲容器添加一個定製的標籤,那麼將永遠會嘗試從倉庫中拉取最新的一個。那個最新的容器可能會也可能不會包含有你認爲應該有的變動。
在建立定製化的鏡像時,使用鏡像標籤和語義版本化來追蹤對Docker容器的變動。當它們運行在Kubernetes裏面時,鏡像標籤用於表達出你但願運行在Kubernetes集羣中的鏡像版本是什麼。爲了最優化的使用Kubernetes,在選擇Docker鏡像版本化方案時,要同時考慮生產工做負載和開發流程。
十、聰明的管理祕鑰
在不少構建Docker鏡像的案例中,你須要受權運行在容器中的應用訪問敏感數據。那些敏感數據包括API令牌、私鑰和數據庫鏈接字符串。
把那些祕鑰嵌入到容器中不是一個安全的解決方案,即便在你保持鏡像處於私有狀態的狀況下。把未加密的祕鑰做爲Docker鏡像的一部分推送出去讓你暴露在各類額外的安全風險之下,例如網絡和鏡像倉庫的安全等。Docker架構自己並無爲容器中存放未加密敏感數據而作優化。
相反,最容易的安全的在容器外存儲祕鑰的方式是使用Kubernetes祕鑰對象(https://kubernetes.io/docs/concepts/configuration/secret/)。
Kubernetes提供了Secrets抽象來讓你在Docker鏡像外或者pod定義以外存儲祕鑰。你能夠以在容器內掛載卷的方式來使用Kubernetes祕鑰,或者以環境變量的方式來使用它。當你更新Kubernetes Secrets中的祕鑰值的時候,只要滾動服務的pods便可開始使用新的憑據。也有一些其餘的存儲祕鑰的選項存在,例如Hashicorp Vault和 Bitnami密封祕鑰(https://www.weave.works/blog/storing-secure-sealed-secrets-using-gitops)。
原文連接:https://dzone.com/articles/10-tips-for-building-and-managing-containers