您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么通過Docker容器進行持續部署”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么通過Docker容器進行持續部署”吧!
持續部署管道是在每次代碼提交時會執行的一系列步驟。管道的目的是執行一系列任務,將一個經過完整測試的功能性服務或應用部署至生產環境。唯一一個手工操作就是向代碼倉庫執行一次簽入操作,之后的所有步驟都是自動完成的。這種流程可(在一定程度上)消除人為錯誤的因素,從而增加可靠性。并且可讓機器完成他們最擅長的工作(運行重復性的過程,而不是創新性思考),從而增加系統吞吐量。之所以每次提交都需要通過這個管道,原因就在于“持續”這個詞。如果你選擇延遲這一過程的執行,例如在某個sprint結束前再運行,那么整個測試與部署過程都不再是持續的了。
如果你選擇延遲測試與生產環境的部署,那么你同樣也延誤了發現系統潛在問題的時機,導致的結果是修復這些問題需要投入更多的精力。如果在問題發生一個月后再去嘗試修復,比起在問題發生一周內進行修復的成本就要高得多。與之類似,如果在代碼提交的幾分鐘內立即發出bug的通知,那么定位該bug所需的時間就是微不足道的了。不過,持續部署的意義不僅在于節省維護與bug修復的投入,它還能夠讓你更快地將新特性發布至生產環境中。特性的開發與最終為用戶使用之間的時間越短,你就能夠越快地從中受益。
我們先不必列出管道中應當包含的全部構建步驟,而是先從一個最小的子集開始,探討一種可能的方案。這個最小子集能夠讓你對服務進行測試、構建以及部署。這些任務都是必不可少的。缺少了測試,我們就無法保證該服務能夠正常運行。缺少了構建,就沒有什么東西可部署。而缺少了部署,用戶就無法從新的發布中受益。
傳統的軟件測試方式是對源代碼進行單元測試,這種方式雖然能夠帶來較高的代碼覆蓋率,但不見得一定能夠保證特性按照預期的方式工作,也無法保證單獨的代碼單元(方法、函數、類等等)的行為符合設計。為了對特性進行驗證,你需要進行功能性測試,這種方式偏向于墨盒測試,與代碼沒有直接的關聯。功能性測試的一個問題在于系統的依賴。Java應用可能需要一個特定的JDK,而Web應用可能需要在大量的瀏覽器上進行測試。很有可能需要在不同的系統條件組合中對相同的測試集進行重復的測試。
一個令人遺憾的事實是,許多組織的測試并不充分,這無法確保一次新的發布能夠在沒有人工干預的情況下部署至生產環境中。即使這些測試本身是可靠的,但往往沒有將這些測試在所有可能在生產環境中出現的相同條件下運行。出現這一問題的原因與我們對基礎設施的管理方式有關。以人工方式對基礎設施進行設置的代價是非常高的。為了配置用戶可能會使用的所有瀏覽器,你需要設置多少臺服務器?10臺還是100臺?如果某個項目的運行時依賴與其他項目不同,你又該怎樣處理?
大多數企業都需要用到多種不同的環境。比方說某個環境需要運行Ubuntu而另一個需要運行Red Hat,或者是某個環境需要JDK8而另一個環境需要JDK7。這是一種非常費時費力的途徑,尤其當這些環境作為靜態環境(與之相對的是通過云計算托管的“創建與銷毀”途徑)時更為明顯。即使你為了滿足各種組合而設置了足夠的服務器,你仍然會遇到速度與靈活性的問題。舉例來說,如果某個團隊決定開發一個新服務,或是使用不同的技術對某個現有的服務進行重構,從請求搭建新環境直至該環境具備完整的可操作性為止也會浪費大量時間。在這段過程中,持續部署過程將陷入停頓。如果你在這種環境中添加微服務,則浪費的時間將產生指數級的增長。在過去,開發者通常只需關注有限的幾個應用程序,而如今則需要關注幾十個、幾百個、乃至上千個服務。畢竟,微服務的益處包括為某個用例選擇最佳技術的靈活性,以及高速的發布。你不希望等到整個系統開發完成,而是希望完成某個屬于單一微服務的功能后立即進行發布。這樣的瓶頸只要存在一個,就可能會大大地降低整體速度。而在許多情況下,基礎設施就是瓶頸所在。
你可以通過使用Docker容器輕松地處理各種測試問題。對服務或應用進行測試所需的各種元素需要、也應當能夠設置在某個容器中。請參考一下這個Dockerfile.tests文件,這是一個用于測試微服務的容器,它在后端使用Scala開發,前端使用了Polymer,而數據庫則采用了MongoDB。它所測試的是一個具備完全自治性的服務切面,與系統中的其他服務相互分離。我并不打算深入討論Dockerfile定義的細節,只是簡單列舉其中所包含的內容。該定義包含Git、NodeJS、Gulp以及用于前端的Bower、Scala、SBT以及用于后端的MongoDB。某些測試需要用到Chrome和Firefox。此外還包括了該服務的源代碼與所有依賴。我并不是說你的服務也應當選擇相同的技術棧,而是想指出,在許多情況下,測試需要用到大量的運行時與系統依賴。
如果你需要搭建一臺這樣的服務器,就意味著大量的等待時間,直到所有元素都設置完成。而當其他服務也提出了類似的請求之后,你就很可能會遇到各種沖突與問題,畢竟服務器本身就不是為了托管無數存在潛在沖突的依賴而存在的。你也可以選擇為測試某個服務創建VM,但這意味著對資源的極大浪費與緩慢的初始化過程。通過使用Docker容器,這一工作就不再屬于基礎設施團隊,而轉交開發者負責。開發者們會在測試過程中選擇應用所需的組件,在Dockerfile中進行定義,通過團隊所用的持續部署工具構建并運行容器,讓這一容器執行所需的各種測試。當代碼通過全部測試之后,你就可以邁入下一階段,對服務本身進行構建。測試所用的容器應當在Docker注冊表(可選擇私有或公有)中進行注冊,以便之后重用。除了我們已經提到的各種益處之外,在測試執行結束之后,你就可以銷毀該容器,使host服務器回到原來的狀態。如此一來,你就可以使用同一臺服務器(或服務集群)對你所開發的全部服務進行測試了。
下圖中的流程已經開始顯得有些復雜了。
當你執行完所有測試后,就可以開始創建容器,并最終將其部署至生產環境中了。由于你很可能會將其部署至一個與你構建所用不同的服務器中,因此你同樣應當將其注冊在Docker注冊表中。
當你完成測試并構建好新的發布后,就可以準備將其部署至生產服務器中了。你所要做的就是獲取對應的鏡像并運行容器。
當容器已上傳至注冊表之后,你就可以在每次簽入之后部署你的微服務,并以前所未有的速度將新的特性交付給用戶。業務負責人會非常高興并對你進行獎勵,而你也會感覺到你的工作是偉大而有意義的。
但目前所定義的流程還遠遠談不上一個完整的持續部署管道。它還遺漏了許多步驟、需要考慮的內容以及必需的路徑。讓我們依次找出這些問題并逐個解決。
整個管道中最危險的步驟可能就是部署了。如果我們獲取了某個新的發布并開始運行,Docker Compose就會以新的發布取代舊的發布。也就是說,在過程中會出現一定程度的停機時間。Docker需要停止舊的發布并啟動新的發布,同時你的服務也需要進行初始化。雖然這一過程可能只需幾分鐘、幾秒鐘甚至是幾微秒,但還是造成了停機時間。如果你實施了微服務與持續部署實踐,那么發布的次數會比之前更頻繁。最終,你可能會在一天之內進行多次部署。無論你決定采用怎樣的發布頻率,對用戶的干擾都是你應當避免的。
應對這一問題的解決方案是藍-綠部署。如果你初次接觸這一主題,歡迎閱讀我的文章“藍-綠部署”。簡單地說,這個過程將部署一個新發布,使其與舊發布并行運行。可將某個版本稱為“藍”,另一個版本稱為“綠”。由于兩者是并行運行的,因此不會產生停機時間(至少不會由于部署流程引起停機時間)。并行運行兩個版本的方式為我們帶來了一些新的可能性,但同時也造成了一些新的挑戰。
在實踐藍-綠部署時要考慮的第一件事就是如何將用戶的請求從舊的發布重定向至新的發布。在此之前的部署方式中,你只是簡單地將舊的發布替換為新的發布,因此他們將在相同的服務器與端口上運行。而藍-綠部署將并行運行兩個版本,每個版本將使用自己的端口。有可能你已經使用了某些代理服務(NGINX、HAProxy等等),那么你可能會面對一個新的挑戰,即這些代理不能是靜態的了。在每次新發布中,代理的配置需要進行持續變更。如果你在集群中進行部署,那么該過程將變得更為復雜。不僅端口需要變更,IP地址也需要變更。為了有效地使用集群,你需要將服務部署至在當時最適合的服務器上。決定最適合服務器的條件包括可用的內存、磁盤和CPU的類型等等。通過這種方式,你就能夠以最佳的方式分布服務,并極大地優化可用資源的利用率。而這又造成了新的問題,最緊迫的問題是如何找到你所部署的服務的IP地址與端口號。對這個問題的答案是使用服務發現。
服務發現包括三個部分。你首先需要通過一個服務注冊表以保存服務的信息。其次,你需要某個進程對新的服務進行注冊,并撤消已中止的服務。最后,你需要通過某種方式獲取服務的信息。舉例來說,當你部署一個新的發布時,注冊進程需要在服務注冊表中保存IP地址與端口信息。隨后,代理可發現這些信息,并通過信息對本身進行重新配置。常見的服務注冊表包括etcd、Consul和ZooKeeper。你可以使用Registrator用于注冊和撤消服務以及confd,并用Consul Template實現服務發現與模板創建。
現在,你已經找到了一種保存及獲取服務信息的機制,可利用該機制對代理進行重新配置,(目前)唯一一個還未解答的問題就是要部署哪個版本(顏色)。當你進行手工部署時,你自然知道之前部署的是哪個顏色。如果你之前部署了綠色,那么現在當然要部署藍色。如果一切都是自動化執行的,你就需要將這一信息保存起來,讓部署流程能夠訪問它。由于你在流程中已經建立了服務發現功能,你就可以將部署顏色與服務IP地址和端口信息一同保存起來,以便在必要時獲取該信息。
在完成了以上工作后,管道將變為下圖中所顯示的狀態。由于步驟的數量提高了,因此我將這些步驟劃分為預部署、部署以及部署后三個組。
你或許已經注意到,部署管道中的第一個步驟是運行測試。雖然測試的運行至關重要,并且為你提供了代碼(很可能)能夠按預期運行的信心,但它無法驗證要部署至生產環境中的服務是否真的能夠按預期運行。許多環節都有可能產生錯誤,可能是沒有正確地安裝數據庫、或是防火墻阻礙了對服務的訪問。服務在生產環境上無法正常工作的原因是多種多樣的。即使代碼按預期工作,也不代表你已驗證了部署的服務已得到正確的配置。即便你搭建了一個預發布服務器以部署你的服務,并且進行了又一輪測試,也無法使你完全確信在生產環境中總是能夠得到相同的結果。為了區分不同類型的測試,我將其稱為“預部署”測試。我有意避免使用更準確的名稱,因為你在早期階段所運行的測試類型對于每個項目來說都是不同的。他們有可能表示單元測試、功能測試或是其他類型的測試。無論是哪種類型的測試,他們的共同點在于,你會在構建與部署服務之前運行這些測試。
藍-綠流程為你展現了一種新的機會。由于舊發布與新發布是并行運行的,你就可以對新發布進行測試,隨后再對代理進行重新配置,以指向新的發布。通過這種方式,你就可以放心地將新發布部署至生產環境并進行測試,而代理仍會將你的用戶重定向至舊的發布。我傾向于將這一階段的測試稱為“預集成”測試。這個名字或許不是最好的,因為許多開發者更熟悉它的另一個名字“集成測試”。但在這個特殊的場景中,它意味著你在將新發布與代理服務集成之前(在代理進行重新配置之前)所需運行的測試。這些測試可以讓你忽略預發布環境(這種環境與生產環境永遠做不到完全一致),使用對代理重新配置之后用戶將使用的完全相同配置對新發布進行測試。當然,“完全”這個詞并不太準確,區別在于你會在不使用代理的情況下對服務進行測試,而用戶將無法訪問這些服務。與預部署測試一樣,預集成測試的結果將指示你是繼續走完工作流,還是中止這一流程。
最后,當我們重新配置代理之后,還需要再進行一輪測試。這一輪測試稱為“集成后”測試,這一過程應當能夠快速完成,因為唯一需要驗證的就是代理是否確實正確地配置了。通常來說,只需對80(HTTP)與443(HTTPS)端口進行幾次請求作為測試就足夠了。
在你實施了Docker之后,就應當以容器方式運行所有這些測試,與我建議你進行預部署測試的方式相同,也能夠帶來相同的益處。并且在很多情況下,同樣的測試容器可用于所有的測試類型。我傾向于通過一個環境變量表示所運行的測試的類型。
在我們回顧這套測試步驟的成敗之前,讓我們首先定義生產環境的理想狀態。我們的邏輯很簡單,如果整個流程有任何一部分出錯,整個環境就應當保持與該流程尚未初始化之前相同的狀態。我們要實現的并不復雜,只是為發生的問題觸發某種形式的通知,并且在團隊中建立一種文化:修復破壞流程的問題是第一優先任務。問題在于,回滾并不像聽上去那么簡單。幸運的是,Docker容器使這一操作比使用其他任何途徑都要簡單,因為它對環境本身會產生的副作用非常小。
根據預部署測試的結果決定下一步非常簡單,因為此時你還沒有進行任何實際的部署,因此可隨意決定繼續流程還是中止流程。但另一方面,在你獲得預集成測試的結果前所執行的步驟會使生產環境處于一個非理想狀態。你已經部署了新的發布(藍或綠),如果該發布有錯誤,你必須撤消這一發布。在撤消發布之后,你還需要刪除這些發布所生成的任何服務數據。由于代理仍然指向舊發布,因此用戶實際上仍然在使用舊發布的特性,而不會注意到你在嘗試部署新的特性。而最后的測試過程(即集成后測試)會帶來一些額外的困難,因為代理已經重新定向至新的發布,你需要將其恢復成原先的設置。而部署顏色(版本)的注冊也同樣需要成原先的設置。
雖然我之前僅談到了由測試所引起的故障,但并不意味著流程中的其他步驟不會失敗。這些步驟同樣會出錯,應當使用類似的邏輯以解決這些問題。無論是哪個步驟失敗了,系統環境都需要恢復成之前的狀態。
即使整個過程如計劃般一樣順利執行,也仍然有一些清理工作需要處理。你需要停止舊的發布,并刪除其注冊信息。
目前為止,我還沒有提到數據庫,而數據庫往往會給回滾階段造成最大的挑戰。這一主題已經超出了本文的范圍,所以我只打算描述一下我認為最主要的規則:始終確保新發布中產生的模式變更是向后兼容的,并通過大量的測試來確認這一點。你必須在預部署測試階段運行這些測試。經常有人向我抱怨,保證向后兼容性是不可行的。在某些場景中,這種說法沒錯。但在多數情況下,這種觀點總是來自于瀑布開發過程,團隊每個月、甚至每年才會發布一次產品。而如果團隊能夠保持管道周期的簡短,并且在每次簽入時都能夠執行(假設我們每天至少部署一次),那么影響到數據庫的變更通常來說是比較小的,在這種情況下可以比較簡單地實現向后兼容性。
決定每個步驟的執行環境是至關重要的。按照一般的規則來說,盡量不要在生產服務器中執行。這表示除了部署相關的任務都應當在一個專屬于持續部署的獨立的集群中執行。在下圖中,我將這些任務標記為黃色,并將需要在生產環境中執行的任務標記為藍色。請注意,即使是藍色的任務也不應當直接在生產環境中執行,而是通過工具的API執行。舉例來說,如果你使用Docker Swarm進行容器的部署,那么無需直接訪問主節點所在的服務,而是創建DOCKER_HOST變量,將最終的目標地址通知本地Docker客戶端。
現在我們已經能夠可靠地將每次簽入部署至生產環境中了,但我們的工作只完成了一半。另一半工作是對部署進行監控,并根據實時數據與歷史數據進行相應的操作。由于我們的最終目標是將代碼簽入后的一切操作實現自動化,因此人為的交互將會降至最低。創建一個具備自恢復能力的系統是一個很大的挑戰,它需要你進行持續地調整。你不僅希望系統能夠從故障中恢復(響應式恢復),同時也希望能夠第一時間防止這些故障出現的可能(預防性恢復)。
如果某個服務進程出于某種原因中止了運行,系統應當再次將其初始化。如果產生故障的原因是某個節點變得不可靠,那么初始化過程應當在另一個(健康的)服務器中運行。響應式恢復的要點在于通過工具進行數據收集、持續地監控服務、并在發生故障時采取行動。預防性恢復則要復雜許多,它需要將歷史數據記錄在數據庫中,對各種模式進行評估,以預測未來是否會發生某些異常情況。預防性恢復可能會發現訪問量處于不斷上升的情況,需要在幾個小時之內對系統進行擴展。也可能是每個周一早上是訪問量的峰值,系統在這段時間需要擴展,隨后在訪問量恢復正常之后收縮成原來的規模。
到此,相信大家對“怎么通過Docker容器進行持續部署”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。