為增加本文的代入感,本譯文將以原作者第一稱視角闡述Jesse Newland的經(jīng)歷,請讀者知悉。
去年,GitHub已經(jīng)改進(jìn)了Ruby on Rails應(yīng)用的基礎(chǔ)設(shè)施,該應(yīng)用負(fù)責(zé)運行g(shù)ithub.com和api.github.com。最近我們實現(xiàn)了一個重要里程碑,即:所有Web和API請求都由Kubernetes集群中運行的容器來處理,這些集群都部署在了我們的metal云上。將一個重要的應(yīng)用遷移到Kubernetes是一個非常有趣的挑戰(zhàn),所以我們非常激動可以向你分享我們學(xué)到的東西。
為什么要改變?
在做出這次遷移之前,我們主要的Ruby on Rails應(yīng)用(我們稱之為github/github)的配置和它8年前沒什么兩樣:即由一個名叫God的Ruby進(jìn)程管理器管理著Unicorn(獨角獸)進(jìn)程,而該Ruby進(jìn)程管理器則運行在受Puppet管理的許多服務(wù)器上。類似地,chatops部署的工作方式和它剛被引入時差不多:即Capistrano與每個前端服務(wù)器建立SSH連接,然后更新代碼并重啟應(yīng)用進(jìn)程。當(dāng)峰值請求負(fù)載超過可用的前端CPU能力時,GitHub網(wǎng)站可靠性工程師會分配額外的能力并添加到有效的前端服務(wù)器池中。
雖然我們基本的生產(chǎn)方式這些年并未改變多少,但GitHub本身卻發(fā)生了巨大的變化,包括:新特性、更大的軟件社區(qū)、更多的GitHub用戶以及更高的每秒請求數(shù)。隨著我們不斷地發(fā)展,這一方式開始出現(xiàn)問題。許多團(tuán)隊希望將其負(fù)責(zé)的功能從這個龐大的應(yīng)用中提取到一個更小的服務(wù)中,以便該服務(wù)可以單獨運行或部署。隨著運行的服務(wù)量增大,網(wǎng)站可靠性工程師團(tuán)隊開始讓幾十個其它的應(yīng)用支持與前面提到的配置相類似的配置。這增加了我們在服務(wù)器維護(hù)、分配和其它工作上花費的時間,而這些工作與改善GitHub整體的體驗并無直接關(guān)系。新服務(wù)往往需要幾天、幾周甚至幾個月的時間來部署,這取決于其復(fù)雜程度和網(wǎng)站可靠性工程師團(tuán)隊是不是有空。隨著時間的推移,我們發(fā)現(xiàn),這一方式不能給工程師帶來足夠的靈活性,以使他們繼續(xù)打造世界級的服務(wù)。工程師們需要一個可以讓他們實驗、部署和擴(kuò)展新服務(wù)的自助服務(wù)平臺。同時我們也需要這樣的平臺來滿足核心Ruby on Rails應(yīng)用的需求,從而使工程師或機(jī)器人能在幾秒鐘之內(nèi)(而不是幾小時、幾周甚至更長時間)分配額外的計算資源,從而應(yīng)對需求上的變化。
為了應(yīng)對這些需求,網(wǎng)站可靠性工程師、平臺和開發(fā)者體驗團(tuán)隊啟動了一個共同的項目,在這個項目中,我們最開始只是對容器編排平臺進(jìn)行評估,而到今天,我們已取得這樣的成就,即:每天能將支撐github.com和api.github.com運行的代碼往Kubernetes集群部署幾十次。本文旨在概述一下這個過程中涉及的工作。
為什么是Kubernetes?
作為對“平臺即服務(wù)”工具當(dāng)前局勢評估的一部分,我們對Kubernetes做了近距離考查。Kubernetes是一個谷歌的項目,它自稱是一個開源的系統(tǒng),用來自動部署、擴(kuò)展和管理容器化的應(yīng)用。Kubernetes一些優(yōu)點使它從眾多平臺中脫穎而出,例如:支撐該項目的活躍的開源社區(qū)、首次運行的體驗(這使我們能夠在最初實驗的最初幾個小時內(nèi)部署小型的集群和應(yīng)用)、以及大量與刺激其設(shè)計的體驗有關(guān)的信息。
這些實驗的范圍迅速擴(kuò)大:我們組建了一個小項目,來構(gòu)建Kubernetes集群和部署工具,以便在接下來的黑客(hack)周獲得一些有關(guān)該平臺實際的體驗。我們在這個項目的體驗以及使用過它的工程師的反饋都極其正面。是時候?qū)嶒灁U(kuò)大了,所以我們開始計劃一個更大的上線活動。
為什么要從github/github開始?
在本項目的初期,我們做了一個慎重的決定,那就是將遷移的目標(biāo)設(shè)定為某個關(guān)鍵的負(fù)載:即github/github。許多因素促使我們做出這個決定,但其中尤為突出的是:
我們知道,貫穿GitHub深入了解這個應(yīng)用會對整個遷移過程有幫助。 我們需要自助服務(wù)容量擴(kuò)展工具來應(yīng)對持續(xù)性的增長。我們需要確保我們養(yǎng)成的習(xí)慣和模式不僅適合大型應(yīng)用,還同樣適合小規(guī)模服務(wù)。我們希望更好地讓應(yīng)用不受開發(fā)、過渡、生產(chǎn)、企業(yè)和其它環(huán)境的差異所影響。我們知道,成功遷移一個關(guān)鍵且高度引人注目的負(fù)載可以鼓勵在GitHub更大范圍地采用Kubernetes。考慮到選擇遷移的負(fù)載的關(guān)鍵性,我們需要在引入任何生產(chǎn)流量之前,樹立高度的運營信心。
通過審查實驗室快速迭代和樹立信心
作為此次遷移的一部分,我們使用了如Pods、Deployments和Services之類的Kubernetes基本單元設(shè)計了目前前端服務(wù)器所提供的服務(wù)的替代品,制作了其原型并進(jìn)行了驗證。這個新設(shè)計的某些驗證可以通過在容器內(nèi)運行g(shù)ithub/github現(xiàn)有的測試套件完成,而不是在同前端服務(wù)器配置相似的服務(wù)器上完成。然而,我們?nèi)匀恍枰^察這個容器作為大量Kubernetes資源的一部分有怎樣的表現(xiàn)。很快我們就清楚發(fā)現(xiàn),我們必須得有一個環(huán)境,能夠支持對Kubernetes和我們要運行的服務(wù)進(jìn)行探索性測試。
大約在同一時間,我們發(fā)現(xiàn),現(xiàn)有的github/github pull request的探索性測試模式已經(jīng)開始出現(xiàn)痛點增長的跡象。隨著部署速度以及項目工作的工程師的數(shù)量的增加,使用幾個額外的部署環(huán)境來驗證向github/github發(fā)出pull request的頻率也在增加。通常,在峰值工作時間內(nèi),少量功能完備的部署環(huán)境已經(jīng)被預(yù)定了,這就減緩了部署pull request的過程。工程師經(jīng)常要求能夠在“分支實驗室”上測試更多的生產(chǎn)子系統(tǒng)。雖然分支實驗室允許許多工程師進(jìn)行并發(fā)部署,但它只給每個部署單獨啟動了一個Unicorn進(jìn)程,這意味著“分支實驗室”僅在測試API和UI變化時才有用。這些需求重疊的很多,所以我們將這些項目結(jié)合起來,并采用了一個由Kubernetes專為github/github開發(fā)的新部署環(huán)境,名為“審查實驗室”。
在構(gòu)建審查實驗室的過程中,我們交付了不少子項目,每個子項目都可以在各自單獨的博客文章中進(jìn)行介紹。前前后后,我們共交付了:
一個在AWS VPC中運行的Kubernetes集群,該VPC由Terraform和kops共同管理。一系列短暫運行Kubernetes集群的Bash集成測試。在項目初期我們大量使用這些測試,以樹立對Kubernetes的信心。github/github的Dockerfile文件。增強(qiáng)內(nèi)部CI平臺,以支持將容器構(gòu)建和發(fā)布到容器注冊表。50個Kubernetes資源的YAML陳述,它們檢查后被加入到github/github。增強(qiáng)內(nèi)部部署應(yīng)用,以支持將Kubernetes資源從存儲庫部署到Kubernetes命名空間,以及從內(nèi)部secret存儲庫創(chuàng)建Kubernetes secrets。一個將haproxy和consul-template組合在一起的服務(wù),以便將Unicorn pod的流量路由到現(xiàn)有服務(wù),并在那里發(fā)布服務(wù)信息。一個讀取Kubernetes事件并將異常事件發(fā)送到內(nèi)部錯誤跟蹤系統(tǒng)的服務(wù)。一個名為kube-me的兼容chatops-rpc的服務(wù),它會通過聊天向用戶公開一組有限的kubectl命令。最終成果是一個基于聊天的界面,它可以為任何pull request創(chuàng)建GitHub的單獨部署。一旦pull request通過了所有必需的CI作業(yè),用戶就可以將該pull request部署到審查實驗室,如下所示:
jnewland
.deploy https://github.com/github/github/pull/4815162342 to review-lab
用戶說:部署https://github.com/github/github/pull/4815162342 到審查實驗室
Hubot
@jnewland's review-lab deployment of github/add-pre-stop-hook (00cafefe) is done! (12 ConfigMaps, 17 Deployments, 1 Ingress, 1 Namespace, 6 Secrets, and 23 Services)(77.62s) your lab is available at https://jnewland.review-lab.github.com
答復(fù)用戶:@ jnewland的審查實驗室部署github/add-pre-stop-hook(00cafefe)已經(jīng)完成! (共12個ConfigMap、17個Deployment、1個Ingress、1個Namespace、6個Secrets和23個Service)(用時77.62秒),點擊https://jnewland.review-lab.github.com 即可使用。
像分支實驗室一樣,實驗室在上次部署之后的一天內(nèi)即被清理干凈。由于每個實驗室都是在自己的Kubernetes命名空間中創(chuàng)建的,因此清理命名空間與刪除命名空間一樣簡單,部署系統(tǒng)在必要時會自動執(zhí)行這些動作。
審查實驗室是一個成功的項目,產(chǎn)生了一些積極的結(jié)果。在將該環(huán)境普遍開放給工程師之前,它充當(dāng)Kubernetes集群設(shè)計的基本試驗場和原型環(huán)境,以及Kubernetes資源設(shè)計和配置的基本試驗場和原型環(huán)境,現(xiàn)在github/github Unicorn工作負(fù)載由Kubernetes資源來描述。發(fā)布后,大量工程師被迫適應(yīng)新的部署風(fēng)格,一些感興趣的工程師提供了反饋,而一些沒有注意到任何變化的工程師仍在正常使用,這使我們逐步建立了信心。就在最近,我們觀察了高可用性團(tuán)隊中一些工程師使用審查實驗室的情況,他們使用審查實驗室來實驗與Unicorn的互動,并通過將某個新實驗子系統(tǒng)部署到共享實驗室來實驗該子系統(tǒng)的表現(xiàn)。這種環(huán)境能使工程師以自助服務(wù)的方式實驗和解決問題,我們對此感到非常高興。
每周向分支實驗室和審查實驗室的部署量
Metal上的Kubernetes
隨著審查實驗室的交付,我們的注意力轉(zhuǎn)移到了github.com。為了滿足旗艦服務(wù)的性能和可靠性要求(旗艦服務(wù)依賴于低延遲來訪問其它數(shù)據(jù)服務(wù)),我們需要構(gòu)建Kubernetes基礎(chǔ)設(shè)施來支持在物理數(shù)據(jù)中心和POP中運行的metal云。這次的工作又有近十幾個子項目:
這篇關(guān)于容器聯(lián)網(wǎng)的及時而全面的帖子幫助我們選擇了Calico網(wǎng)絡(luò)提供商,它提供了我們在ipip模式下快速交付集群所需的開箱即用功能,同時讓我們之后能夠靈活地與網(wǎng)絡(luò)基礎(chǔ)設(shè)施進(jìn)行對等互連。經(jīng)過對@kelseyhightower的“艱難但必不可少的Kubernetes”的不少于十幾次的拜讀,我們將一些手動分配的服務(wù)器組裝到了某臨時的Kubernetes集群中,該集群通過了與我們用來鍛煉AWS集群相同的一套集成測試。我們構(gòu)建了一個小工具,來為每個集群生成CA和配置,它們的格式可被內(nèi)部Puppet和secret系統(tǒng)使用。我們Puppet化了兩個實例角色(Kubernetes節(jié)點和Kubernetes apiservers)的配置,并允許用戶提供已配置的集群的名稱于分配時加入。我們構(gòu)建了一個小型Go服務(wù)來使用容器日志,并將元數(shù)據(jù)按鍵/值的格式附加(append)到每一行,并將它們發(fā)送到主機(jī)的本地syslog端點。我們加強(qiáng)了GLB,即內(nèi)部負(fù)載均衡服務(wù),以支持Kubernetes NodePort服務(wù)。所有這些努力產(chǎn)生了一個集群,并通過了我們的內(nèi)部驗收測試。鑒于此,我們相信,同一套輸入(即由審查實驗室使用的Kubernetes資源)、同一組數(shù)據(jù)(即通過VPN與審查實驗室連接的網(wǎng)絡(luò)服務(wù))以及同樣的工具會產(chǎn)生類似的結(jié)果。在不到一周的時間內(nèi),即便其中大部分時間用于內(nèi)部溝通和對那些對遷移有重大影響的事件進(jìn)行排序,我們?nèi)阅軐⒄麄€工作負(fù)載從運行在AWS上的Kubernetes集群遷移到數(shù)據(jù)中心內(nèi)的Kubernetes集群。
提高信心
憑借在metal云上搭建Kubernetes集群的成功和可重復(fù)的模式,現(xiàn)在我們可以對用Unicorn部署替代當(dāng)前前端服務(wù)器池的能力充滿信心了。在GitHub,工程師及其團(tuán)隊通常會通過創(chuàng)建Flipper特性來驗證新功能,然后在其可行后立即選擇該功能。在加強(qiáng)部署系統(tǒng)后,我們將一套新的Kubernetes資源部署到與現(xiàn)有的生產(chǎn)服務(wù)器并行的github-production命名空間,并加強(qiáng)GLB,以支持通過受Flipper影響的cookie將員工請求路由到不同的后端。因此員工可以通過在任務(wù)控制欄中選擇某按鈕進(jìn)入Kubernetes實驗后端:
內(nèi)部用戶的負(fù)載幫助我們找到問題、修復(fù)錯誤,并在生產(chǎn)中開始習(xí)慣Kubernetes了。在此期間,我們通過模擬將來要執(zhí)行的程序、編寫運行手冊和執(zhí)行故障測試來努力提高信心。我們還將少量生產(chǎn)流量路由到此集群,以確認(rèn)我們對負(fù)載下的性能和可靠性的假設(shè)。我們從每秒100個請求開始,并將其擴(kuò)大到github.com和api.github.com10%的請求。經(jīng)過這些模擬后,我們暫停了一下,重新評估了全面遷移的風(fēng)險。
集群組
幾個故障測試產(chǎn)生了始料未及的結(jié)果。尤其是,一個模擬單個apiserver節(jié)點的故障的測試對運行的工作負(fù)載的可用性產(chǎn)生了負(fù)面影響,從而中斷了集群。對這些測試結(jié)果的調(diào)查并沒有產(chǎn)生確鑿的結(jié)果,但是幫助我們確定中斷可能與連接到Kubernetes apiserver的各種客戶端之間的交互有關(guān)(如calico-agent,kubelet,kube-proxy和kube-controller-manager)和確定內(nèi)部負(fù)載均衡器在apiserver節(jié)點故障期間的行為。鑒于觀察到Kubernetes集群降級可能會中斷服務(wù),我們開始考慮在每個站點的多個集群上運行旗艦應(yīng)用,并自動將請求從不正常的集群轉(zhuǎn)移到其他正常集群。
我們的路線圖已包含類似的工作,以支持將此應(yīng)用部署到多個獨立運行的站點。同時,這種方法其它積極的折衷 - 包括為低中斷集群升級提供可行的故事、將集群與現(xiàn)有故障域(如共享網(wǎng)絡(luò)和電源設(shè)備)相關(guān)聯(lián) - 支持我們繼續(xù)走這條路線。我們最終決定使用某個設(shè)計,它利用了部署系統(tǒng)支持部署到多個“分區(qū)”的功能,并且通過自定義的Kubernetes資源注釋來增強(qiáng)該設(shè)計,以支持集群特定的配置。所以我們放棄了現(xiàn)有的聯(lián)合解決方案,轉(zhuǎn)而使用另一個方法,因為該方法能夠利用已經(jīng)存在于部署系統(tǒng)中的業(yè)務(wù)邏輯。
從10%到100%
隨著集群組的實施,我們逐漸將前端服務(wù)器轉(zhuǎn)換為Kubernetes節(jié)點,并增加路由到Kubernetes的流量百分比。除了一些其他負(fù)責(zé)的設(shè)計 團(tuán)隊,我們在短短一個多月內(nèi)完成了前端轉(zhuǎn)型,同時將性能和錯誤率保持在目標(biāo)范圍內(nèi)。
Web請求百分比:Kubernetes/github-fe (%)
在這次遷移期間,有個問題一直延續(xù)到今天:在高負(fù)載和/或高比率容器抖動的時候,一些Kubernetes節(jié)點會引起內(nèi)核崩潰和重啟。雖然我們對此不滿意,并且正在繼續(xù)高度重視和調(diào)查該問題,但讓我們高興的是,Kubernetes能夠自動繞過這些故障,并繼續(xù)在目標(biāo)錯誤率范圍內(nèi)提供流量。我們已經(jīng)通過echo c> / proc / sysrq-trigger執(zhí)行了一些模擬內(nèi)核崩潰的故障測試,而且發(fā)現(xiàn)這可以作為我們故障測試模式的有用補(bǔ)充。
接下來該做什么?
將此應(yīng)用遷移到Kubernetes,我們深受鼓舞,并期待后續(xù)做更多的遷移。雖然我們故意將首次遷移的范圍限定于于無狀態(tài)的工作負(fù)載,但能夠在Kubernetes上嘗試運行有狀態(tài)的服務(wù)仍令人激動不已。
在本項目的最后階段,我們還交付了一個工作流程,用于將新的應(yīng)用和服務(wù)部署到類似的Kubernetes集群組中。在過去幾個月中,工程師已經(jīng)將數(shù)十個應(yīng)用部署到了這個集群。以前,這些應(yīng)用中每一個都需要網(wǎng)站可靠性工程師進(jìn)行配置管理和分配支持。通過自助服務(wù)應(yīng)用分配工作流程,網(wǎng)站可靠性工程師可以將更多的時間投入到為組織其它部門提供基礎(chǔ)設(shè)施產(chǎn)品,以支持我們的最佳實踐,以及為每個人提供更快、更有彈性的GitHub體驗。
鳴謝
我們衷心感謝整個Kubernetes團(tuán)隊提供的軟件、文字和指導(dǎo)。我也要感謝以下GitHub用戶在本項目上所做出杰出貢獻(xiàn):
和我們一起工作!
想幫助GitHub網(wǎng)站可靠性工程師團(tuán)隊解決像這樣有趣的問題嗎? 歡迎你加入我們。請通過這里申請!