Docker 在英雄聯(lián)盟游戲中的實踐探索
【原文編者的話】Riot將Docker和Jenkins相結(jié)合,以此來構(gòu)建流水線(Pipeline)。這篇博客是Riot實踐Docker的系列博客的***篇,主要介紹了他們的目標(biāo)和理念;后續(xù)博客則以教程的形式一步一步地記錄Riot的Docker實踐。
容器技術(shù)已經(jīng)風(fēng)靡全球,我們歡迎容器化領(lǐng)域的新霸主們。
然而,他們也給Riot的流水線工程團(tuán)隊(Pipeline Engineering team)的同事們帶來了新挑戰(zhàn)。我叫Maxfield Stewart,是Riot的工程師,我們組主要負(fù)責(zé)構(gòu)建流水線(Pipeline)——從代碼簽入(check in)到部署的一切工作,甚至更多。如果說持續(xù)交付是一首主題曲的話,那么我們就是用清唱的方式演唱它。我們運(yùn)轉(zhuǎn)的是一個類似云的環(huán)境,管理著Riot***的一個服務(wù)器和虛擬機(jī)集群。其中的一個龐然大物是構(gòu)建集群(Build Farm),由大量的物理機(jī)和虛擬機(jī)組成。它是從數(shù)年前的一個小集群發(fā)展而來的,當(dāng)時只負(fù)責(zé)構(gòu)建英雄聯(lián)盟的游戲客戶端。
最近,我們已經(jīng)融入了Docker容器技術(shù)。我們是如何將容器與傳統(tǒng)的構(gòu)建集群集成,并使其越來越像一個自服務(wù)的基于云的工作引擎呢?我們能否使用Dockerfiles定義構(gòu)建環(huán)境,并與我們常用的開源架構(gòu)相結(jié)合呢?我們又能不能拋棄傳統(tǒng)的基于虛擬機(jī)的云,轉(zhuǎn)身擁抱容器云呢?
上述問題已經(jīng)持續(xù)了相當(dāng)長的一段時間,就像寒冰射手(Ashe)的箭一樣。接下來,我將通過一個系列博客介紹我們的團(tuán)隊是如何嘗試回答上述問題的。本文是其中***篇博客,主要是介紹我們的團(tuán)隊背景,以及我們?yōu)槭裁匆先萜骷夹g(shù)。在后續(xù)博客中,我將具體地分享如何整合Jenkins和Docker。***篇教程是一個基礎(chǔ)介紹(http://engineering.riotgames.com/news/putting-jenkins-docker-container)。如果你對于使用容器創(chuàng)建構(gòu)建集群、持續(xù)交付、幫助工程師快速交付,那么這個系列就是你要的。請準(zhǔn)備好:我將從基本介紹,逐步深入,最終介紹如何使用Docker承載真正的業(yè)務(wù)。
一年之前,我們將持續(xù)集成引入到了英雄聯(lián)盟。在那之前,我們拼命地嘗試以一個常規(guī)節(jié)奏來發(fā)布英雄聯(lián)盟,但是我們步履維艱。因此我們打算盡可能自動化這一切,從構(gòu)建流水線到創(chuàng)建測試環(huán)境,獲得了大量的成果,包括提高交付一致性、減少構(gòu)建時間、改善總體完成度。英雄聯(lián)盟從一天幾次的構(gòu)建,增長到了每天30次構(gòu)建。
構(gòu)建英雄聯(lián)盟可不是開玩笑的,其中包括了超過150個任務(wù),我們構(gòu)建每個重要的版本。每次構(gòu)建有各種形式,從傳統(tǒng)的debug構(gòu)建到新版本,以及專門為了包括騰訊和Garena在內(nèi)的全球合作伙伴準(zhǔn)備的變種版本。我們可以追蹤到每次構(gòu)建、什么測試環(huán)境、什么測試內(nèi)容、PBE以及快速部署成產(chǎn)品。我們可以一鍵創(chuàng)建測試環(huán)境,并且可以在幾個星期內(nèi)從20個測試環(huán)境增加到70多個,包括450多個虛擬機(jī)。構(gòu)建英雄聯(lián)盟只是構(gòu)建集群的一部分工作,構(gòu)建集群本身支持了Riot各個工程團(tuán)隊的3300多個構(gòu)建任務(wù)。然而,這一構(gòu)建流程并不是***的,這些陳舊的工具有時需要連接起來才能工作。在持續(xù)集成中,我們秉持4項原則:
- 我們認(rèn)為工程師團(tuán)隊必須能完全掌控他們的技術(shù)棧,包括對于構(gòu)建環(huán)境的管理員權(quán)限。
- 我們認(rèn)為配置即代碼。團(tuán)隊?wèi)?yīng)當(dāng)盡可能使用源碼控制來維護(hù)他們自己的構(gòu)建流水線和環(huán)境。
- 我們認(rèn)為每當(dāng)工程師執(zhí)行一次構(gòu)建,都需要針對所有可部署的配置構(gòu)建一個可交付的版本。一個“構(gòu)建”并不只是編譯代碼而已,而是所有可部署的組件的集合。
- 我們認(rèn)為一次交付就是一個產(chǎn)品決策(shipping is a product decision)。只需按一下按鈕,產(chǎn)品團(tuán)隊就能夠部署并查看***版本。
我們需要世界***的技術(shù)棧才能達(dá)到這些目標(biāo)。通常有三種選擇:完全重頭編寫、購買別人的工具或者定制化開源項目。
我們選擇了第三種。在這篇博客中,我不想比較各種CI工具。不過,通過修改開源工具來符合我們的需求是一個***的折中方案:不需要重頭編寫;可以與開源世界合作;如果有必要的話,可以輕易脫離它。
#p#
因此,我們的技術(shù)棧非常簡單:
- 開源版本的Jenkins
- Jenkins的任務(wù)DSL插件(Job DSL Plugin)
- Jenkins的構(gòu)建流插件(Build Flow plugin)
- 將各個組件連接在一起的工程***性
我們選擇和繼續(xù)使用Jenkins,是因為它是靈活的、開源的、易于處理我們的基本構(gòu)建操作。總體來說,Jenkins是易于創(chuàng)建一個構(gòu)建流水線的,符合我們持續(xù)交付的核心需求(如上所述)。作為一款廣泛應(yīng)用的開源工具,我們有一個***活力的社區(qū)在與我們合作。與重頭編寫自定義工具相比,工程師團(tuán)隊可以利用開源標(biāo)準(zhǔn)的實現(xiàn),這是很有幫助的,也是具有風(fēng)險的。開源標(biāo)準(zhǔn)經(jīng)常變化,昨天的一個好主意明天就可能變成一個壞主意。然而,利用合適的插件和技術(shù)訣竅,我們只用了少量的代碼、配置和開銷,就完成了一個全自動的持續(xù)集成鏈。
那么,Docker發(fā)揮了什么作用呢?讓我們回想一下我提到的持續(xù)交付的核心原則。最近,我們團(tuán)隊遇到的一個挑戰(zhàn)是構(gòu)建環(huán)境的所有權(quán)。之前,工程師們通過Packer.io定義自己的虛擬機(jī)鏡像,然后給產(chǎn)品團(tuán)隊集群的root權(quán)限。本質(zhì)上,我們需要通過Jenkins這一個工作流引擎定義一個內(nèi)部的云環(huán)境。我們探索了幾個通用的配置管理工具,如Puppet和Chef,來實現(xiàn)虛擬云環(huán)境,并使工程師們能控制這些機(jī)器。
然后,Docker出現(xiàn)了。
這件事情就變得簡單了:Dockerfile比其他工具更易于維護(hù)。在Docker的幫助下,我們意識到容器更容易管理了。如果我們把Docker中Dockerfile的概念和構(gòu)建環(huán)境的所有權(quán)結(jié)合起來,我們就進(jìn)入了工程天堂。
Docker很善于解決部署中的挑戰(zhàn)。我主要關(guān)注Docker是如何幫助工作流引擎、構(gòu)建系統(tǒng)和流水線,同時也熟悉了如何將其作為一個部署工具和方法論。Riot管理著大量的微服務(wù),而容器和微服務(wù)的組合就像花生醬和巧克力的組合。因為Docker成為了一個“Thing(tm)”,我們也會使用它來解決其他的一些問題。
流水線工程團(tuán)隊的夢想變得更真實了:我們想要一個流水線構(gòu)建工具,它能動態(tài)地加速持續(xù)交付流水線,使用框架代碼來按需地一鍵構(gòu)建環(huán)境。為了創(chuàng)建一個完整的構(gòu)建流水線,我們之前是通過自動化配置虛擬機(jī)來實現(xiàn)的,現(xiàn)在我們認(rèn)為使用Docker容器來完成。
需要說明的是,Docker并不是一個***的整體解決方案。它不能解決Windows和OSX的構(gòu)建環(huán)境中的問題,也不能和我們使用的每個工具結(jié)合。但是,Docker確實解決了Linux平臺中我們遇到的很多困難。在Riot,我們在平臺和后端上進(jìn)行了大量的工程工作。包括核心的后臺服務(wù)在內(nèi),幾乎所有的特性都是通過跑在Linux上的微服務(wù)來提供的。因此,如何優(yōu)化解決方案空間是值得我們投入時間和精力的。
我們已經(jīng)開始將Docker與現(xiàn)有的構(gòu)建棧結(jié)合,并獲得了一些早期的成就。我們創(chuàng)建了Jenkins的一鍵部署環(huán)境,在容器中部署,加速了測試和調(diào)試過程。我們從一個小型集群(大概500個任務(wù))開始,使用容器作為構(gòu)建環(huán)境,在所有權(quán)和迭代速度上團(tuán)隊也提供了積極的反饋,包括:
- 基于Linux構(gòu)建微服務(wù)和網(wǎng)站的工程師們能夠以編程的方式定義他們的構(gòu)建環(huán)境了
- 本地的構(gòu)建環(huán)境和構(gòu)建集群中的構(gòu)建環(huán)境是完全一致的(在后續(xù)博客中,我將介紹如何做到這一點)
- 動態(tài)資源分配意味著降低整體計算成本
- 一臺虛擬機(jī)可以處理4個不同的組合300多個構(gòu)建任務(wù),這原本是通過8臺虛擬機(jī)完成的
這篇博客僅僅是一個系列話題的介紹,這個系列將覆蓋多個領(lǐng)域,以教程的形式發(fā)布,提供實例和源碼。首先,系列博客將介紹如何使用Docker來部署Jenkins,包括各種***實踐,并通過一個真實應(yīng)用引入Docker的基礎(chǔ)知識;然后,系列博客將探索容器化構(gòu)建環(huán)境的各種方案,并介紹Riot是如何將Docker融入Jenkins的生態(tài)環(huán)境;***,將介紹流水線工程團(tuán)隊是如何完成最終目標(biāo)的。
我們希望通過系列博客來能分享我們的發(fā)現(xiàn)以及遭遇的挫折。這些或許不是什么大秘密,但可能是不容易發(fā)現(xiàn)的。我希望我們的系列博客能回報社區(qū),并通過交流和對話學(xué)習(xí)到更多。