使用Docker實(shí)現(xiàn)持續(xù)集成
大?。?/span>0.8 MB 人氣: 2017-10-10 需要積分:1
推薦 + 挑錯(cuò) + 收藏(0) + 用戶評(píng)論(0)
標(biāo)簽:Docker(11471)
本文轉(zhuǎn)載自《程序員》,謝絕轉(zhuǎn)載,更多精彩,請(qǐng)訂閱2016年《程序員》持續(xù)集成(Continuous Integration,簡(jiǎn)稱CI)作為先進(jìn)的項(xiàng)目實(shí)踐之一,近年來(lái)逐漸受到國(guó)內(nèi)軟件公司的重視;但對(duì)于許多朋友來(lái)說(shuō),可能從未聽說(shuō)過(guò)持續(xù)集成這個(gè)詞,抑或只是了解概念但并沒(méi)有實(shí)踐過(guò)。
什么是持續(xù)集成?它對(duì)軟件開發(fā)有哪些好處呢?
持續(xù)集成的概念
隨著軟件開發(fā)復(fù)雜度的不斷提高,團(tuán)隊(duì)開發(fā)成員間如何更好地協(xié)同工作以確保軟件開發(fā)的質(zhì)量已經(jīng)慢慢成為開發(fā)過(guò)程中不可回避的問(wèn)題。尤其是近些年來(lái),敏捷(Agile)在軟件工程領(lǐng)域越來(lái)越紅火,如何能在不斷變化的需求中快速適應(yīng)和保證軟件質(zhì)量也顯得尤其重要。
持續(xù)集成正是針對(duì)這類問(wèn)題的一種軟件開發(fā)實(shí)踐:它倡導(dǎo)團(tuán)隊(duì)開發(fā)成員必須經(jīng)常集成他們的工作,甚至每天都可能發(fā)生多次。而每次集成都是通過(guò)自動(dòng)化的構(gòu)建來(lái)驗(yàn)證,包括自動(dòng)編譯、發(fā)布和測(cè)試,從而盡快地發(fā)現(xiàn)集成錯(cuò)誤,讓團(tuán)隊(duì)能夠更快的開發(fā)產(chǎn)品。
讓我們以A項(xiàng)目為例描述一普通團(tuán)隊(duì)是如何使用CI的:
首先,解釋下集成:所有的項(xiàng)目代碼都托管在SVN或者Git服務(wù)器上(以下簡(jiǎn)稱代碼服務(wù)器)。每個(gè)項(xiàng)目都有若干單元測(cè)試和集成測(cè)試。集成測(cè)試是單元測(cè)試的邏輯擴(kuò)展:在單元測(cè)試的基礎(chǔ)上,將所有模塊按照設(shè)計(jì)要求組裝成為子系統(tǒng)或系統(tǒng)進(jìn)行集成測(cè)試。實(shí)踐表明,一些模塊雖然能夠單獨(dú)地工作,但并不能保證連接起來(lái)也能正常工作。一些局部反映不出來(lái)的問(wèn)題,在全局上很可能暴露出來(lái)(關(guān)于單元測(cè)試及集成測(cè)試的詳述,讀者可以查閱相關(guān)文檔)。
簡(jiǎn)單來(lái)說(shuō),集成測(cè)試就是把所有的單元測(cè)試跑一遍,以及其他能自動(dòng)完成的測(cè)試。只有通過(guò)了集成測(cè)試的代碼才能上傳到代碼服務(wù)器,確保上傳的代碼沒(méi)有問(wèn)題。集成一般指集成測(cè)試。持續(xù),顯而易見就是長(zhǎng)期對(duì)代碼進(jìn)行的集成測(cè)試。既然是長(zhǎng)期進(jìn)行,那么最好是自動(dòng)執(zhí)行,否則人工執(zhí)行既沒(méi)保證,而且耗人力。
基于此種目的,我們需要有一臺(tái)服務(wù)器,它將定期從代碼服務(wù)器中拉取,并進(jìn)行編譯,然后自動(dòng)運(yùn)行集成測(cè)試;并且每次集成測(cè)試的結(jié)果都會(huì)記錄在案。
在A項(xiàng)目中,設(shè)定執(zhí)行這個(gè)工作的周期是1天。也就是說(shuō)服務(wù)器每天都會(huì)準(zhǔn)時(shí)地對(duì)代碼服務(wù)器上的最新代碼自動(dòng)進(jìn)行一次集成測(cè)試。
持續(xù)集成的特點(diǎn)
它是一個(gè)自動(dòng)化的周期性的集成測(cè)試過(guò)程,從拉取代碼、編譯構(gòu)建、運(yùn)行測(cè)試、結(jié)果記錄、測(cè)試統(tǒng)計(jì)等都是自動(dòng)完成的,無(wú)需人工干預(yù);
需要有專門的集成服務(wù)器來(lái)執(zhí)行集成構(gòu)建;
需要有代碼托管工具支持。
持續(xù)集成的作用
保證團(tuán)隊(duì)開發(fā)人員提交代碼的質(zhì)量,減輕了軟件發(fā)布時(shí)的壓力;
任何一個(gè)環(huán)節(jié)都是自動(dòng)完成的,無(wú)需太多的人工干預(yù),有利于減少重復(fù)過(guò)程以節(jié)省時(shí)間、費(fèi)用和工作量;
筆者在實(shí)踐的過(guò)程中總結(jié)出了以下心得:
代碼越早push出去,用戶能越早用到,快就是商業(yè)價(jià)值;
用戶越早用到就越早反饋,團(tuán)隊(duì)越早得到反饋,好壞都是有價(jià)值的輸入;
用戶不反饋,說(shuō)明我們做了用戶不想要的東西(通過(guò)用例跟蹤)或者市場(chǎng)沒(méi)做好,能幫助產(chǎn)品市場(chǎng)人員調(diào)整策略;
代碼庫(kù)存越是積壓,就越得不到生產(chǎn)檢驗(yàn),積壓越多,代碼間交叉感染的概率越大,下個(gè)release的復(fù)雜度和風(fēng)險(xiǎn)越高;
代碼庫(kù)存越多,workflow的包袱越重,管理成本越大。
了解了持續(xù)集成的優(yōu)點(diǎn),讀者是不是有立馬部署一套的沖動(dòng)呢?然而,部署持續(xù)集成環(huán)境,并不簡(jiǎn)單。
從一個(gè)Java項(xiàng)目持續(xù)集成的典型場(chǎng)景為例。我們只要建立一個(gè)基于Jenkins + Maven + Git(SVN) 的持續(xù)集成環(huán)境,再加上持續(xù)集成所要求的測(cè)試和流程就可以大致運(yùn)行。
但在搭建好一整套持續(xù)集成的流水線之后,卻發(fā)現(xiàn)它并不像想象中絲般順滑,甚至比在本地開發(fā)測(cè)試的效率還低。為什么會(huì)出現(xiàn)這樣的情況?
目前常見的在持續(xù)集成過(guò)程中遇到的問(wèn)題有如下幾種:
編譯時(shí)依賴和運(yùn)行時(shí)依賴
從字面上不難理解這兩種依賴。雖然編譯時(shí)依賴通常也是運(yùn)行時(shí)依賴,但并不能由此判定編譯時(shí)依賴一定是運(yùn)行時(shí)依賴。例如,在開發(fā)過(guò)程中需要某些提供API的Jar包,但在運(yùn)行時(shí)可能需要的是具體API實(shí)現(xiàn)的Jar包。其次,被依賴的包會(huì)有它自身的依賴,這樣的情況下,項(xiàng)目會(huì)對(duì)這些包產(chǎn)生間接依賴(運(yùn)行時(shí)依賴),依此類推,最終形成一個(gè)依賴樹。當(dāng)項(xiàng)目運(yùn)行時(shí),這些依賴樹上的包必須全部就位,否則項(xiàng)目無(wú)法運(yùn)行。
Maven在POM中通過(guò)scope來(lái)判定依賴的類型,從而幫助開發(fā)和運(yùn)維人員擺脫手動(dòng)處理依賴樹的工作,然而運(yùn)行時(shí)所有依賴包最終是要安裝到生產(chǎn)環(huán)境的,這部分工作Maven并不能自動(dòng)完成。因此,一個(gè)常用方式是將運(yùn)行時(shí)所依賴的包拷貝到項(xiàng)目文件中,比如Java Web應(yīng)用的WEB-INF/lib,然后將項(xiàng)目全部打成一個(gè)包。在安裝項(xiàng)目包后,修改環(huán)境變量,將這些依賴包所在的路徑加入相應(yīng)的環(huán)境變量中,如ClassPath。
再舉個(gè)典型的例子,目前的操作系統(tǒng)和其他系統(tǒng)框架都考慮到了運(yùn)行時(shí)依賴樹的處理問(wèn)題,比如Ubuntu的apt-get,CentOS的yum,Ruby的RubyGem,Node的npm等等,在安裝某個(gè)軟件包時(shí),系統(tǒng)會(huì)自動(dòng)將所需的依賴包按順序下載并安裝。
依賴時(shí)的復(fù)雜度
項(xiàng)目除了對(duì)程序包的依賴,對(duì)于運(yùn)行環(huán)境也有些具體的要求。比如,Web應(yīng)用需要安裝和配置Web服務(wù)器、應(yīng)用服務(wù)器、數(shù)據(jù)服務(wù)器等,企業(yè)應(yīng)用中可能需要消息隊(duì)列、緩存、定時(shí)作業(yè),或是對(duì)其他系統(tǒng)以Web Service或API的方式暴露服務(wù)等。這些可以看成項(xiàng)目在系統(tǒng)層面對(duì)外部的依賴。這些依賴有些可以由項(xiàng)目自行處理,而有些則是項(xiàng)目無(wú)法處理的,比如運(yùn)行容器,操作系統(tǒng)等,這些是項(xiàng)目的運(yùn)行環(huán)境。
總之,依賴的復(fù)雜度主要有兩個(gè):
依賴包間的版本兼容性問(wèn)題。兼容性問(wèn)題是軟件開發(fā)者的噩夢(mèng)。
間接依賴,或多重依賴問(wèn)題。例如:A依賴于Python 2.7,A還依賴于B,但B卻依賴于Python 3,苦逼的是Python 2.7和Python 3不兼容。依賴中最痛苦的事莫過(guò)于此。
不一致的環(huán)境
簡(jiǎn)單項(xiàng)目中,開發(fā)和運(yùn)行環(huán)境都由開發(fā)人員搭建,當(dāng)公司變大時(shí),系統(tǒng)的運(yùn)行環(huán)境將由運(yùn)維人員搭建,而開發(fā)測(cè)試環(huán)境如果由運(yùn)維人員搭建則工作量太大,由開發(fā)人員自己搭建則操作復(fù)雜又容易產(chǎn)生不一致的情況。假設(shè)公司為項(xiàng)目A和項(xiàng)目B開發(fā)了新版本。但環(huán)境和軟件升級(jí)不是同步進(jìn)行,出錯(cuò)的可能性非常大(想一想間接依賴和多重依賴的情況)。大家對(duì)這樣的場(chǎng)景有沒(méi)有印象:當(dāng)新版本部署時(shí),發(fā)現(xiàn)問(wèn)題,測(cè)試或部署人員說(shuō):“版本有問(wèn)題,無(wú)法運(yùn)行!”開發(fā)人員卻說(shuō):“我這里沒(méi)問(wèn)題啊,運(yùn)行正常!”
泛濫的部署
如果項(xiàng)目簡(jiǎn)單,沒(méi)有任何歷史項(xiàng)目和代碼的拖累,且各項(xiàng)目之間也沒(méi)有任何的關(guān)聯(lián),只需進(jìn)行資源方面的管理:分配機(jī)器,初始化系統(tǒng),分配IP地址等。各個(gè)項(xiàng)目的運(yùn)行環(huán)境、數(shù)據(jù)庫(kù)、開發(fā)環(huán)境等都由具體項(xiàng)目的開發(fā)人員手動(dòng)完成,這樣的環(huán)境出問(wèn)題怎么辦?很簡(jiǎn)單,涼拌——重裝系統(tǒng)。
理想很豐滿,現(xiàn)實(shí)很骨感,歷史遺留問(wèn)題往往對(duì)現(xiàn)在的項(xiàng)目有很大影響:多語(yǔ)言(Java,PHP、C ),多系統(tǒng)(各種Windows、Linux),多構(gòu)建工具版本(Java7、8),各種配置文件和各種黑科技補(bǔ)丁腳本散落在系統(tǒng)的各個(gè)角落,沒(méi)人能找得到,也沒(méi)人搞得懂。配置被誰(shuí)改掉了,服務(wù)宕掉了,根本無(wú)從管理。
問(wèn)題分析完了,我們又該如何克服這些問(wèn)題,使用什么工具和方法,從而達(dá)到絲般順滑的持續(xù)集成呢?下面就是要介紹的主角:Docker、AppoSoar及AppHouse。
Docker如今在國(guó)內(nèi)已經(jīng)如火如荼,Docker可以做到一次構(gòu)建,處處運(yùn)行;各種實(shí)踐和生產(chǎn)部署也紛紛上馬,Docker的基本知識(shí)和好處筆者也就不在這里科普了。
AppSoar,以Docker為基礎(chǔ),以企業(yè)應(yīng)用為導(dǎo)向,以安全穩(wěn)定為目標(biāo),打造專業(yè)、簡(jiǎn)單易用的企業(yè)級(jí)容器云解決方案。它提供了企業(yè)應(yīng)用商店、友好圖形化界面管理、多環(huán)境管理、混合云支持、容器持久存儲(chǔ)、容器網(wǎng)絡(luò)模式、容器可擴(kuò)展性、容器負(fù)載均衡與調(diào)度、API接口支持、系統(tǒng)高可用等一系列強(qiáng)大功能。
AppHouse為容器運(yùn)行平臺(tái)提供了一種集鏡像管理、鏡像安全、鏡像高可用及鏡像高速訪問(wèn)為一體的企業(yè)級(jí)鏡像倉(cāng)庫(kù)管理方案。AppHouse支持HTTPS訪問(wèn);基于角色的權(quán)限控制;系統(tǒng)高可用;部署靈活;一鍵安裝,一鍵升級(jí);友好的圖形化界面,LDAP/AD用戶集成;支持swift/Glusterfs/公有云存儲(chǔ)接入;提供豐富的API接口;支持連接Git源碼倉(cāng)庫(kù),代碼自動(dòng)構(gòu)建;提供webhook接口,支持持續(xù)部署。解決了docker build、push、pull的一攬子問(wèn)題。
言歸正傳,既然為了達(dá)到順滑的持續(xù)集成要求,那么為什么選擇用Docker、AppSoar、AppHouse來(lái)部署?
上面我們提到了傳統(tǒng)方式搭建持續(xù)集成平臺(tái)經(jīng)常遇到4個(gè)問(wèn)題:編譯和運(yùn)行時(shí)依賴、依賴時(shí)的復(fù)雜度、不一致的環(huán)境和泛濫的部署,接下來(lái)我們來(lái)分析下Docker+AppSoar+AppHouse組合如何解決這些問(wèn)題。
首先,Docker可以讓你非常容易和方便地以“容器化”的方式去部署應(yīng)用。 它就像集裝箱一樣,打包了所有依賴,再在其他服務(wù)器上部署很容易,不至于換服務(wù)器后發(fā)現(xiàn)各種配置文件散落一地,這樣就解決了編譯時(shí)依賴和運(yùn)行時(shí)依賴的問(wèn)題。
其次,Docker的隔離性使得應(yīng)用在運(yùn)行時(shí)就像處于沙箱中,每個(gè)應(yīng)用都認(rèn)為自己是在系統(tǒng)中唯一運(yùn)行的程序,就像剛才例子中,A依賴于python 2.7,同時(shí)A還依賴于B,但B卻依賴于Python 3,這樣我們可以在系統(tǒng)中部署一個(gè)基于Python 2.7的容器和一個(gè)基于Python 3的容器,這樣就可以很方便地在系統(tǒng)中部署多種不同環(huán)境來(lái)解決依賴復(fù)雜度的問(wèn)題。這里有些朋友可能會(huì)說(shuō),虛擬機(jī)也可以解決這樣的問(wèn)題。誠(chéng)然,虛擬化確實(shí)可以做到這一點(diǎn),但是這需要硬件支持虛擬化及開啟BIOS中虛擬化相關(guān)的功能,同時(shí)還需要在系統(tǒng)中安裝兩套操作系統(tǒng),虛擬機(jī)的出現(xiàn)是解決了操作系統(tǒng)和物理機(jī)的強(qiáng)耦合問(wèn)題。但Docker就輕量化很多,只需內(nèi)核支持,無(wú)需硬件和BIOS的強(qiáng)制要求,可以輕松迅速地在系統(tǒng)上部署多套不同容器環(huán)境,容器的出現(xiàn)解決了應(yīng)用和操作系統(tǒng)的強(qiáng)耦合問(wèn)題。正因?yàn)镈ocker是以應(yīng)用為中心,鏡像中打包了應(yīng)用及應(yīng)用所需的環(huán)境,一次構(gòu)建,處處運(yùn)行。這種特性完美解決了傳統(tǒng)模式下應(yīng)用遷移后面臨的環(huán)境不一致問(wèn)題。
同時(shí),Docker壓根不管內(nèi)部應(yīng)用怎么啟動(dòng),你自己愛咋來(lái)咋來(lái),我們用docker start或run作為統(tǒng)一標(biāo)準(zhǔn)。這樣應(yīng)用啟動(dòng)就標(biāo)準(zhǔn)化了,不需要再根據(jù)不同應(yīng)用而記憶一大串不同啟動(dòng)命令。
基于Docker的特征,現(xiàn)在常見的利用Docker進(jìn)行持續(xù)集成的流程如下:
開發(fā)者提交代碼;
觸發(fā)鏡像構(gòu)建;
構(gòu)建鏡像上傳至私有倉(cāng)庫(kù);
鏡像下載至執(zhí)行機(jī)器;
鏡像運(yùn)行。
其基本拓?fù)浣Y(jié)構(gòu)如圖1所示。
圖1 利用 Docker 進(jìn)行持續(xù)集成基本拓?fù)浣Y(jié)構(gòu)
熟悉Docker的朋友都知道,Docker啟動(dòng)非??欤梢哉f(shuō)是秒啟。在上述的五步中,1和5的耗時(shí)較短,整個(gè)持續(xù)集成主要耗時(shí)集中在中間的3個(gè)步驟,也就是docker build、docker push、docekr pull這樣還是無(wú)法達(dá)到順滑的極致要求,下來(lái)我們來(lái)分析下build、push、pull的耗時(shí)和解決方法:
docker build
網(wǎng)絡(luò)優(yōu)化
dockerhub的官方鏡像在國(guó)外,由于眾所周知的原因,在國(guó)內(nèi)進(jìn)行構(gòu)建時(shí)網(wǎng)絡(luò)會(huì)是很大的瓶頸,甚至某些公司的環(huán)境是無(wú)Internet連接的。 在這種情況下,建議使用國(guó)內(nèi)的鏡像源,或者自己搭建私有倉(cāng)庫(kù),保存項(xiàng)目需要的基礎(chǔ)鏡像,把構(gòu)建過(guò)程中的網(wǎng)絡(luò)傳輸都控制在國(guó)內(nèi)或者內(nèi)網(wǎng),這樣就不用再考慮網(wǎng)絡(luò)方面的問(wèn)題。
使用 .dockerignore文件
dockerignore文件的設(shè)計(jì)是為了在docker build的過(guò)程中排除不需要用到的文件以及目錄,目的是為了docker build這個(gè)過(guò)程可以盡可能地快速高效以及構(gòu)建出來(lái)的image沒(méi)有多余的“垃圾”。
最小化鏡像層數(shù)(layers)
把鏡像層數(shù)減到最少,能加快容器的啟動(dòng)速度,但是這里也要權(quán)衡另一個(gè)問(wèn)題:dockerfile的可讀性。你可以把一個(gè)dockerfile寫得很復(fù)雜以達(dá)到構(gòu)建出最小層數(shù)的鏡像,但同時(shí)你的dockerfile可讀性也降低了。所以我們要在鏡像層數(shù)和dockerfile可讀性之間做出妥協(xié)。
docker push
docker registry升級(jí)到v2后加入了很多安全相關(guān)檢查,在v2中的鏡像的存儲(chǔ)格式變成了gzip ,鏡像在壓縮過(guò)程中占用的時(shí)間也比較多。我們簡(jiǎn)單分解一下docker push的流程。
buffer to disk,將該層文件系統(tǒng)壓縮成本地的一個(gè)臨時(shí)文件;
上傳文件至registry;
本地計(jì)算壓縮包digest,刪除臨時(shí)文件,digest傳給registry;
registry計(jì)算上傳壓縮包digest并進(jìn)行校驗(yàn);
registry將壓縮包傳輸至后端存儲(chǔ)文件系統(tǒng);
重復(fù)1-5直至所有層傳輸完畢;
計(jì)算鏡像的manifest并上傳至registry重復(fù) 3-5。
這樣設(shè)計(jì)導(dǎo)致push會(huì)很慢,如果采用官方dockerhub,需要考慮docker build一節(jié)中提及的網(wǎng)絡(luò)方面影響,dockerhub公有鏡像庫(kù)還需考慮安全方面因素。
同時(shí)docker和registry設(shè)置了過(guò)多的安全防范措施(如雙向證書認(rèn)證等),主要是為了防止在公有云的環(huán)境下鏡像的偽造和越權(quán)獲取。但是在一個(gè)可信的環(huán)境內(nèi),如果build和push過(guò)程都是自己掌控,很多措施都是多余的。
docker pull
docker pull 鏡像的速度對(duì)服務(wù)啟動(dòng)速度至關(guān)重要,好在registry v2后可以并行pull了,速度有了很大改善。但是依然有一些小的問(wèn)題影響了啟動(dòng)的速度:
下載鏡像和解壓鏡像是串行的;
串行解壓,由于v2都是gzip要解壓,盡管并行下載了還是串行解壓,內(nèi)網(wǎng)的話解壓時(shí)間比網(wǎng)絡(luò)傳輸都要長(zhǎng);
和registry通信, registry在pull的過(guò)程中并不提供下載內(nèi)容只是提供下載url和鑒權(quán),這一部分加長(zhǎng)了網(wǎng)絡(luò)傳輸,而且一些metadata還是要去后端存儲(chǔ)獲取,延時(shí)還是有一些的。
通過(guò)剛才的分析,大家可以看到,其實(shí)docker build、push、pull其實(shí)主要耗時(shí)是在網(wǎng)絡(luò)傳輸(主要)及安全防范措施(輕微)上,整個(gè)傳輸過(guò)程甚至大大超過(guò)了其他所有步驟的時(shí)間;這樣可以借助我們的AppHouse方便的搭建本地企業(yè)級(jí)鏡像倉(cāng)庫(kù),將網(wǎng)絡(luò)傳輸轉(zhuǎn)移至內(nèi)網(wǎng),同時(shí)完全掌控了 build、push和pull的過(guò)程,這樣提高效率的同時(shí)也解決了安全問(wèn)題,可謂一舉兩得。
經(jīng)過(guò)Docker、AppHouse的幫助,我們距極致追求的如絲般順滑的持續(xù)集成目標(biāo)只有一步之遙,Docker解決了依賴和環(huán)境問(wèn)題,AppHouse解決了鏡像安全快速傳輸?shù)膯?wèn)題,接下來(lái)就是容器的部署和管理問(wèn)題。
Docker實(shí)現(xiàn)了底層技術(shù)的創(chuàng)新,它的出現(xiàn)將開發(fā)者從與系統(tǒng)的糾纏中釋放了出來(lái),但是阻礙企業(yè)使用Docker的問(wèn)題是容器的大規(guī)模部署、管理問(wèn)題和缺少企業(yè)級(jí)容器工具及系統(tǒng)。
鏡像創(chuàng)建完成后,需要把它發(fā)布到測(cè)試和生產(chǎn)環(huán)境。因?yàn)镈ocker占用資源小,在單個(gè)服務(wù)器上部署成百上千個(gè)容器也不足為奇。這個(gè)階段中如何更合理地使用Docker也是一個(gè)難點(diǎn),開發(fā)團(tuán)隊(duì)需要考慮如何打造一個(gè)可伸縮擴(kuò)展的分發(fā)環(huán)境。
AppSoar提供人性化的Web管理界面,豐富的Compose文件格式和功能完備的API接口,通過(guò)Compose實(shí)現(xiàn)以十分簡(jiǎn)單的文件描述復(fù)雜的應(yīng)用結(jié)構(gòu),讓部署變得更簡(jiǎn)單。并且,AppSoar還提供豐富的企業(yè)應(yīng)用商店,讓在一鍵創(chuàng)建服務(wù)成為可能。這樣可以快速搭建應(yīng)用場(chǎng)景,開發(fā)者只需要關(guān)注開發(fā)本身即可。
非常好我支持^.^
(0) 0%
不好我反對(duì)
(0) 0%
下載地址
使用Docker實(shí)現(xiàn)持續(xù)集成下載
相關(guān)電子資料下載
- 如何在Windows系統(tǒng)上設(shè)置Docker鏡像源 55
- 機(jī)器學(xué)習(xí)需要掌握的九種工具盤點(diǎn) 16
- Docker鏡像國(guó)內(nèi)加速的幾種方法 55
- VectorCAST|Docker場(chǎng)景下的代碼白盒測(cè)試實(shí)施 401
- 如何用Springboot整合Redis 118
- 如何在macOS系統(tǒng)中用Docker運(yùn)行macOS鏡像呢? 364
- 什么是Docker容器?為什么需要Docker容器? 71
- 為什么需要Docker容器?Docker容器和VM有什么區(qū)別? 323
- 如何使用 Docker容器化技術(shù) 1187
- Dockerfile定義Docker鏡像的構(gòu)建過(guò)程 1088