上周對(duì)象突然心血來(lái)潮說(shuō)想養(yǎng)個(gè)小寵物,我問(wèn)想養(yǎng)啥她又說(shuō)隨便,你看著辦?。?!這我真的比較難辦??!但是咱們程序員能有個(gè)對(duì)象就不錯(cuò)了,還不趕緊寵著,我只能照辦咯!
我去到了一家寵物店,半天也沒(méi)有找到合適的目標(biāo)。正在我猶豫彷徨之時(shí),看到了老板門(mén)口魚(yú)缸里面的金魚(yú)游來(lái)游去還挺順眼!于是我問(wèn)老板
??我:老板,金魚(yú)多少錢(qián)?
??老板:加魚(yú)缸一起100塊錢(qián)不講價(jià)!
??我:這...便宜一點(diǎn)咯!
??老板:小伙子看你骨骼驚奇,定是個(gè)養(yǎng)魚(yú)的奇才,2塊錢(qián)賣給你吧!但是魚(yú)缸可不能給你!
??我:那,你幫我打包一條吧,幫我拿個(gè)袋子裝著就好了!
于是我興高采烈的拎著小金魚(yú)就回家了,找了個(gè)大罐子養(yǎng)著!對(duì)象看到我買的小金魚(yú)后露出了幸福的笑容~
??第二天早上對(duì)象把我從睡夢(mèng)中搖醒:“嚶嚶嚶,人家的小魚(yú)動(dòng)不了了,你賠~~~ ”。于是我很憤怒的跑去寵物店找老板索賠!
??我:你們家賣的魚(yú)有問(wèn)題,回去就不行了!
??老板:不可能,昨天在我們這都活蹦亂跳的!
??我:就是你們家的魚(yú)有問(wèn)題!
??老板:肯定是你自己買的魚(yú)缸有問(wèn)題!
??我:手持兩把錕斤拷,口中疾呼燙燙燙。
??老板:腳踏千朵屯屯屯,笑看萬(wàn)物锘锘锘?
這一幕,似曾相識(shí)!像極了我們?cè)陂_(kāi)發(fā)中
??測(cè)試:xx,你的代碼在生產(chǎn)環(huán)境上運(yùn)行有問(wèn)題。
??我:不可能,我本地都運(yùn)行得好好的。
??測(cè)試:你自己上生產(chǎn)環(huán)境上看。
??我:我不看,我的代碼在本地沒(méi)問(wèn)題,肯定是運(yùn)維的鍋,你去找運(yùn)維!
或許很多開(kāi)發(fā)人員都有過(guò)上面的經(jīng)歷,程序在本地運(yùn)行都很正常,一上到生產(chǎn)環(huán)境就崩了。這是因?yàn)槌绦蚋〗痿~(yú)一樣也會(huì)“水土不服”!而導(dǎo)致程序水土不服的原因一般就是環(huán)境和配置的差異!加上現(xiàn)在互聯(lián)網(wǎng)高并發(fā)、大流量的訪問(wèn),一個(gè)應(yīng)用往往需要部署到集群的多臺(tái)機(jī)器上,并且集群擴(kuò)容縮容的需求也比較頻繁。如果按照傳統(tǒng)的方式部署,那每一臺(tái)服務(wù)器上都需要裝各種軟件...然后進(jìn)行各種配置...我仿佛看到了“工作996,生病ICU”在向運(yùn)維工程師招手!
那有沒(méi)有一種方案不僅能屏蔽環(huán)境的差異,并且還能快速部署呢?既然“水土不服”那我把程序及整個(gè)“水土”都打包遷移,就看你服不服。而docker就是這樣的一種讓你服技術(shù)!
昂,上面的對(duì)象是我自己new的(* ̄︶ ̄)...
Hello Docker
Docker是什么呢?百度百科是這樣跟我說(shuō)的:Docker 是一個(gè)開(kāi)源的應(yīng)用容器引擎,讓開(kāi)發(fā)者可以打包他們的應(yīng)用以及依賴包到一個(gè)可移植的鏡像中,然后發(fā)布到任何流行的 Linux或Windows 機(jī)器上,也可以實(shí)現(xiàn)虛擬化。容器是完全使用沙箱機(jī)制,相互之間不會(huì)有任何接口。
這段話已經(jīng)很概括的描述了docker是什么,docker能干嘛,docker的基本特性!相信剛開(kāi)始接觸docker的你跟我也一樣,看了幾遍都很懵逼!沒(méi)關(guān)系,看完全文再回頭看這段話,或許就有不一樣的體會(huì)了!我們先看看docker官方給出的“定妝照”

如果非要我用一句話描述這張圖片,還在上幼兒園的我會(huì)說(shuō):“一條可愛(ài)的鯨魚(yú)背著多個(gè)集裝箱,暢游在大海里 ”!而現(xiàn)在我會(huì)說(shuō):“docker是一個(gè)運(yùn)行在操作系統(tǒng)上的軟件,這個(gè)軟件上面可以運(yùn)行多個(gè)相互隔離的容器”!不同的表述,同一個(gè)意思!這條可愛(ài)的鯨魚(yú)就是咱們的docker,而大海就是我們的操作系統(tǒng),多個(gè)集裝箱就是在docker上運(yùn)行的容器!什么是容器咱們后面會(huì)說(shuō)~
假如你想漂洋過(guò)海來(lái)看我,你可以選擇自己造一條船,這樣你就得自己備足很多干糧,還得準(zhǔn)備很多一些其他的必需品才能出發(fā)!但是現(xiàn)在有一條鯨魚(yú)游過(guò)來(lái)對(duì)你說(shuō),我這里有很多集裝箱,里面有你所需要的一切,你選一個(gè)適合你的進(jìn)來(lái)就可以了,我會(huì)帶你乘風(fēng)破浪的!
看到這里,你是否對(duì)docker有個(gè)初步的印象了呢?至少知道了:1、docker是什么?2、為什么需要docker?
與傳統(tǒng)虛擬機(jī)對(duì)比
前面我們說(shuō)過(guò)docker可以實(shí)現(xiàn)虛擬化,那docker與我們平時(shí)用的虛擬機(jī)有什么區(qū)別和聯(lián)系呢?在那些年我們還買不起云服務(wù)器的時(shí)候,如果我們想學(xué)linux那就得先安裝一個(gè)創(chuàng)建虛擬機(jī)的軟件,然后在軟件上面創(chuàng)建虛擬機(jī),然后分配內(nèi)存、分配磁盤(pán)、安裝linux操作系統(tǒng)等等一系列的操作,然后等個(gè)分把鐘讓虛擬機(jī)運(yùn)行起來(lái)~
??為什么傳統(tǒng)虛擬機(jī)啟動(dòng)會(huì)那么慢呢?因?yàn)閭鹘y(tǒng)虛擬機(jī)技術(shù)是虛擬出一套硬件后,在其上面運(yùn)行一個(gè)完整的操作系統(tǒng),然后在該系統(tǒng)上面再運(yùn)行所需要的應(yīng)用程序,并且虛擬機(jī)的資源需要提前分配,一旦分配這些資源將全部被占用。但是docker容器內(nèi)的應(yīng)用程序是直接運(yùn)行于宿主的內(nèi)核,容器沒(méi)有自己的內(nèi)核,更加不會(huì)對(duì)硬件進(jìn)行虛擬。因此docker容器比傳統(tǒng)的虛擬機(jī)更為輕便!但是docker容器技術(shù)也是參考虛擬機(jī)一步一步的迭代優(yōu)化過(guò)來(lái)的!我們來(lái)看看官方給出的docker容器和傳統(tǒng)虛擬機(jī)的對(duì)比圖:

圖中也能看出來(lái),docker就是一個(gè)運(yùn)行在操作系統(tǒng)上的軟件!以后如果想在windows上面學(xué)習(xí)Linux,只需要在本地安裝一個(gè)windows版本的docker,然后看完本文的剩下的部分,就能輕輕松松的玩轉(zhuǎn)linux啦!不過(guò)在windows上安裝docker也需要先安裝一個(gè)虛擬機(jī)~
基本組成要素
前面對(duì)docker的基本概念有了個(gè)大致印象,但是到目前為止,可能你對(duì)docker的認(rèn)識(shí)還比較空泛,那下面部分我們就從docker的基本組成要素來(lái)更深入的走進(jìn)docker!docker是一個(gè)client-server的結(jié)構(gòu)!先看看官網(wǎng)給出的架構(gòu)圖:

這張圖里面概括了docker的所有的元素!我們就逐一分析docker客戶端、docker服務(wù)、倉(cāng)庫(kù)、鏡像、容器等概念!
docker客戶端
最左邊是docker的客戶端,類似我們操作mysql的工具navcat,只不過(guò)我們這里的是沒(méi)有圖形化界面的命令終端。docker客戶端是用戶與docker服務(wù)交互的窗口!我們能看到圖中就是各種操作的命令!
docker服務(wù)
中間的是docker后臺(tái)運(yùn)行的服務(wù),一個(gè)稱為docker daemon的守護(hù)進(jìn)程。可以理解為我們mysql的服務(wù),我們的操作命令都是在這部分進(jìn)行處理!docker deamon監(jiān)聽(tīng)著客戶端的請(qǐng)求,并且管理著docker的鏡像、容器、網(wǎng)絡(luò)、磁盤(pán)(圖中只列出了鏡像與容器)等對(duì)象。同樣,docker的客戶端與服務(wù)可以運(yùn)行在同一機(jī)器上,也可以用某臺(tái)機(jī)器上的客戶端遠(yuǎn)程連接另一臺(tái)機(jī)器上的docker服務(wù),這跟我們的mysql一樣的呢。
倉(cāng)庫(kù)
右邊部分是注冊(cè)倉(cāng)庫(kù),在遠(yuǎn)古時(shí)代做開(kāi)發(fā)的都知道,我們以前需要一個(gè)第三方包的時(shí)候需要去網(wǎng)上下載對(duì)應(yīng)的jar包,很麻煩不說(shuō),還容易下的包是不穩(wěn)定的版本。有了maven之后,我們只要在maven配置文件中引入對(duì)應(yīng)的依賴,就可以直接從遠(yuǎn)程倉(cāng)庫(kù)中下載對(duì)應(yīng)版本的jar包了。docker中的倉(cāng)庫(kù)與maven的倉(cāng)庫(kù)是一個(gè)概念,可以遠(yuǎn)程下載常用的鏡像,也可以push包到遠(yuǎn)程倉(cāng)庫(kù)(如圖中的redis、nginx等鏡像),同一個(gè)鏡像又可以有多個(gè)版本,在docker中稱為tag!
鏡像&容器
前面我們有多次提到鏡像和容器,這是docker里面很核心的兩個(gè)概念。那鏡像和容器分別是什么呢?鏡像和容器的關(guān)系是什么呢?
??鏡像
??官方給出的定義是:docker鏡像是一個(gè)只讀模板,可以用來(lái)創(chuàng)建docker容器。鏡像是一種輕量級(jí)的、可執(zhí)行的獨(dú)立軟件包,用來(lái)打包軟件運(yùn)行環(huán)境和基于運(yùn)行環(huán)境開(kāi)發(fā)的軟件。它包含運(yùn)行某個(gè)軟件所需要的所有的內(nèi)容,包括代碼、運(yùn)行時(shí)、庫(kù)、環(huán)境變量、配置文件等。我們開(kāi)發(fā)的web應(yīng)用需要jdk環(huán)境、需要tomcat容器、需要linux操作系統(tǒng),那我們可以把我們所需要的一切都進(jìn)行打包成一個(gè)整體(包括自己開(kāi)發(fā)的web應(yīng)用+jdk+tomcat+centos/ubuntu+各種配置文件)。打包后的鏡像在某臺(tái)機(jī)器上能運(yùn)行,那它就能夠在任何裝有docker的機(jī)器上運(yùn)行。
任何鏡像的創(chuàng)建會(huì)基于其他的父鏡像,也就是說(shuō)鏡像是一層套一層,比如一個(gè)tomcat鏡像,需要運(yùn)行在centos/ubuntu上,那我們的tomcat鏡像就會(huì)基于centos/ubuntu鏡像創(chuàng)建(在后面的操作部分我們可以通過(guò)命令查看),這樣的結(jié)構(gòu)就類似于我們吃的洋蔥,如果你愿意一層一層一層地剝開(kāi)我的心~

??容器
??官方給出的定義是:docker的容器是用鏡像創(chuàng)建的運(yùn)行實(shí)例,docker可以利用容器獨(dú)立運(yùn)行一個(gè)或一組應(yīng)用。我們可以使用客戶端或者API控制容器的啟動(dòng)、開(kāi)始、停止、刪除。每個(gè)容器之間是相互隔離的。上一步我們構(gòu)建的鏡像只是一個(gè)靜態(tài)的文件,這個(gè)文件需要運(yùn)行就需要變?yōu)槿萜?,我們可以把容器看做是一個(gè)簡(jiǎn)易版的linux系統(tǒng)和運(yùn)行在其中的應(yīng)用程序!就是前面看到的鯨魚(yú)背上的一個(gè)一個(gè)的集裝箱,每個(gè)集裝箱都是獨(dú)立的!
??鏡像與容器關(guān)系
??上面的概念很抽象,可以理解為容器就是鏡像的一個(gè)實(shí)例,相信大家都寫(xiě)過(guò)類似下面的代碼:
public void Dog extends Animal{
......
}
......
Dog dog = new Dog()
我們?cè)诖a中定義了一個(gè)Dog類,這個(gè)類就相當(dāng)于一個(gè)鏡像,可以根據(jù)這個(gè)類new出很多的實(shí)例,new出來(lái)的實(shí)例就相當(dāng)于一個(gè)個(gè)的容器。鏡像是靜態(tài)的文件,而容器就是有生命的個(gè)體!Dog類可以繼承父類Animal,如果不顯式的指定繼承關(guān)系,Dog類就默認(rèn)繼承Object類。同樣上面也說(shuō)到過(guò)docker中的鏡像也有繼承關(guān)系,一個(gè)鏡像可以繼承其他的鏡像創(chuàng)建,添加新的功能!
看到這里的你是不是對(duì)docker有了更多的了解了呢?我們?cè)倩仡^看看百度百科對(duì)docker的描述,可能你又會(huì)有更深的印象:
??Docker 是一個(gè)開(kāi)源的應(yīng)用容器引擎,讓開(kāi)發(fā)者可以打包他們的應(yīng)用以及依賴包到一個(gè)可移植的鏡像中,然后發(fā)布到任何流行的 Linux或Windows 機(jī)器上,也可以實(shí)現(xiàn)虛擬化。容器是完全使用沙箱機(jī)制,相互之間不會(huì)有任何接口。
容器數(shù)據(jù)卷
上面說(shuō)到容器是一個(gè)簡(jiǎn)易版的linux系統(tǒng)和運(yùn)行在其中的應(yīng)用程序,那我們的應(yīng)用程序產(chǎn)生的數(shù)據(jù)(比如操作日志、異常日志、數(shù)據(jù))也是在容器內(nèi)的系統(tǒng)中存放的,默認(rèn)不會(huì)做持久化,我們可以進(jìn)入到容器中查看。但是萬(wàn)一有一天,docker這條鯨魚(yú)不滿人類的壓迫,反抗了...老子打爛你的集裝箱!

隨著容器的關(guān)閉,容器內(nèi)的數(shù)據(jù)也會(huì)丟失,重新開(kāi)啟的容器不會(huì)加載原來(lái)的數(shù)據(jù)(簡(jiǎn)單說(shuō)就是容器重新啟動(dòng)又是另外一個(gè)實(shí)例了)。那對(duì)容器內(nèi)的數(shù)據(jù)需要持久化到宿主機(jī)上就很有必要了,這就需要了解我們的容器數(shù)據(jù)卷~
容器數(shù)據(jù)卷的設(shè)計(jì)目的就是做數(shù)據(jù)的持久化和容器間的數(shù)據(jù)共享,數(shù)據(jù)卷完全獨(dú)立于容器的生命周期,也就是說(shuō)就算容器關(guān)閉或者刪除,數(shù)據(jù)也不會(huì)丟失。簡(jiǎn)單點(diǎn)說(shuō)就將宿主機(jī)的目錄掛在到容器,應(yīng)用在容器內(nèi)的數(shù)據(jù)可以同步到宿主機(jī)磁盤(pán)上,這樣容器內(nèi)產(chǎn)生的數(shù)據(jù)就可以持久化了。關(guān)于容器卷的命令我們后面會(huì)有操作實(shí)例!
命令操作
上面說(shuō)了那么多,下面就到了咱們的實(shí)操環(huán)節(jié)啦!這一節(jié)的內(nèi)容會(huì)通過(guò)一些常用的命令讓大家更進(jìn)一步的了解docker,注意??!這里只是一些常用的命令來(lái)加深理解,而不是命令大全!如果沒(méi)有安裝docker的小伙伴可以自己按照官網(wǎng)的文檔進(jìn)行安裝,本文不會(huì)講到這部分的內(nèi)容!所以我假設(shè)你在自己的服務(wù)器上已經(jīng)裝好了docker!
幫助命令
1、docker version 查看docker客戶端和服務(wù)的版本。
2、docker info 查看docker的基本信息,如有多少容器、多少鏡像、docker根目錄等等。
3、docker --help 查看docker的幫助信息,這個(gè)命令可以查看所有docker支持的命令~
這幾個(gè)命令非常簡(jiǎn)單,有過(guò)一點(diǎn)linux基礎(chǔ)的小伙伴應(yīng)該很容易理解!
鏡像命令
1、docker images 查看本地主機(jī)上所有的鏡像。注意是本地主機(jī)的!這里能看到鏡像的名稱、版本、id、大小等基本信息,注意這里的image ID是鏡像的唯一標(biāo)識(shí)!還可以通過(guò)docker images tomcat指定某個(gè)具體的鏡像查看對(duì)應(yīng)信息。這里還要注意的是centos的鏡像才200MB的大小,比我們物理機(jī)器上裝的centos要小得多的多,這是因?yàn)閏entos的鏡像只保留了linux核心部分,這也是為什么docker虛擬化技術(shù)比虛擬機(jī)運(yùn)行效率更高的原因!那為什么tomcat的鏡像這么大呢?那是因?yàn)槲覀冎罢f(shuō)過(guò)我們的鏡像就像一個(gè)洋蔥一樣,是一層套一層的!tomcat的運(yùn)行需要基于centos、jdk等等鏡像,tomcat在上層所以體積比較大啦!
??

2、docker rmi 刪除本地的鏡像,如下圖所示,可以加上-f參數(shù)進(jìn)行強(qiáng)制刪除。這里的rmi命令跟linux中的刪除命令就很像啦,只是這里加了一個(gè)i代表image!
??

3、docker search 根據(jù)鏡像名稱搜索遠(yuǎn)程倉(cāng)庫(kù)中的鏡像!
??

4、docker pull 搜索到某個(gè)鏡像之后就可以從遠(yuǎn)程拉取鏡像啦,有點(diǎn)類似咱們git中的pull命令,當(dāng)然對(duì)應(yīng)的還有個(gè)docker push的命令。如圖,如果我們沒(méi)有指定tag,默認(rèn)就會(huì)拉取latest版本,也可以通過(guò)docker pull tomcat:1.7的方式拉取指定版本!注意這里在拉取鏡像的時(shí)候打印出來(lái)的信息有很多,這也是前面說(shuō)到的鏡像是一層套一層,拉取一個(gè)鏡像也是一層一層的拉?。?br>
??

容器命令
通過(guò)鏡像命令我們就能獲取鏡像、刪除鏡像等操作啦!鏡像有了下面自然就需要通過(guò)鏡像創(chuàng)建對(duì)應(yīng)的實(shí)例啦,也就是我們的容器。下面我們以tomcat為例:
1、docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 可以基于某個(gè)鏡像運(yùn)行一個(gè)容器,如果本地有指定的鏡像則使用本地鏡像,如果沒(méi)有則從遠(yuǎn)程拉取對(duì)應(yīng)的鏡像然后啟動(dòng)!由于這個(gè)命令非常重要,所以下面列出幾個(gè)比較重要的參數(shù):
-d:啟動(dòng)容器,并且后臺(tái)運(yùn)行(docker容器后臺(tái)運(yùn)行,就必須要有一個(gè)前臺(tái)進(jìn)程,容器運(yùn)行的命令如果不是一直掛起的命令,容器啟動(dòng)后就會(huì)自動(dòng)退出);
-i:以交互模式運(yùn)行容器,通常與-t同時(shí)使用;
-t:為容器重新分配一個(gè)偽輸入終端,通常與-i同時(shí)使用(容器啟動(dòng)后進(jìn)入到容器內(nèi)部的命令窗口);
-P:隨機(jī)端口映射,容器內(nèi)部端口隨機(jī)映射到主機(jī)的高端口;
-p:指定端口映射,格式為:主機(jī)(宿主)端口:容器端口;
-v:建立宿主機(jī)與容器目錄的同步;
--name="myTomcat": 為容器指定一個(gè)名稱(如果不指定,則有個(gè)隨機(jī)的名字);

上面我通過(guò)命令啟動(dòng)了一個(gè)tomcat的容器,由于使用了 -t 的參數(shù),所以容器啟動(dòng)后就進(jìn)入到了容器的內(nèi)部的命令窗口,打印了很多tomcat啟動(dòng)的日志。并且使用 -p 參數(shù)指定了端口映射,也就是容器內(nèi)tomcat運(yùn)行的端口是8080,并且映射到了宿主機(jī)上的8888端口,這樣我們?cè)谕獠烤涂梢酝^(guò)服務(wù)器的ip+8888端口 訪問(wèn)到我們?nèi)萜鲀?nèi)部tomcat部署的服務(wù)了。
前面我們提到過(guò)容器內(nèi)的數(shù)據(jù)會(huì)隨著容器的關(guān)閉而丟失。那我們就需要有容器數(shù)據(jù)卷的技術(shù)能將容器內(nèi)的數(shù)據(jù)持久化到宿主機(jī)。這里需要用到 -v 參數(shù)!我們看下面的截圖
??

這里第一個(gè)要注意的是我們用的 -d 參數(shù),啟動(dòng)后沒(méi)有進(jìn)入到容器內(nèi)部,還是在宿主機(jī)。(可以對(duì)比一下與上面 -it 參數(shù)的區(qū)別)。第二個(gè)要注意的是 -v /宿主機(jī):/容器內(nèi)目錄 實(shí)現(xiàn)了宿主機(jī)與容器內(nèi)指定目錄的數(shù)據(jù)同步!容器啟動(dòng)后就可以使用 linux 的 ll 命令查看宿主機(jī)上已經(jīng)同步到了容器內(nèi)的文件。第三個(gè)要注意的是這里的同步是雙向的,也就是說(shuō)在宿主機(jī)上對(duì)文件的修改也會(huì)同步到容器內(nèi)部!多個(gè)不同的容器映射到宿主機(jī)的同一個(gè)目錄,就可以實(shí)現(xiàn)不同容器間的數(shù)據(jù)共享啦!
??

2、進(jìn)入到容器后可以通過(guò)exit命令退出容器,也可以通過(guò)ctrl+P+Q快捷鍵退出容器,這兩種方式的不同之處是exit會(huì)退出并且關(guān)閉容器,而ctrl+P+Q快捷鍵只是單純的退出,容器還在運(yùn)行,并且還能再次進(jìn)入!
3、docker ps我們可以通過(guò)該命令查看正在運(yùn)行的容器的信息,這里能看到容器的唯一id,啟動(dòng)時(shí)間等等...這里跟linux的ps命令類似,所以也可以把容器理解為一個(gè)運(yùn)行在docker上的進(jìn)程!docker ps -a可以查看運(yùn)行中與停止的所有容器。
??

4、docker attach [OPTIONS] CONTAINER上面說(shuō)過(guò)通過(guò)ctrl+P+Q快捷鍵退出容器后容器還在后臺(tái)運(yùn)行,那如果想再次進(jìn)入容器怎么辦呢?我們就可以通過(guò)attach命令+容器的id再次進(jìn)入容器!
5、docker exec [OPTIONS] CONTAINER這個(gè)命令與attach一樣都可以再次進(jìn)入后臺(tái)運(yùn)行的容器,但是該命令可以不進(jìn)入容器而在運(yùn)行的容器中執(zhí)行命令!比attach更加強(qiáng)大!
6、docker stop docker kill docker restart這三個(gè)命令分別用來(lái)停止容器、強(qiáng)制停止容器和重啟容器,就跟我們?cè)趌inux上停止、強(qiáng)制停止和重啟某個(gè)進(jìn)程一樣的啦,這里就不做演示了!
7、docker rm 使用這個(gè)命令就可以刪除某個(gè)容器,這里跟刪除鏡像的區(qū)別是這里少了一個(gè) i 啦!需要注意的是通過(guò)stop和kill停止的容器還存在于docker中,而使用 rm 命令操作后的容器將不再存在!
??

8、docker inspect 查看容器的詳情(也能查看鏡像詳情)。
Dockerfile
前面我們對(duì)docker以及相關(guān)概念、常用命令有了基本的了解,我們也知道了可以從遠(yuǎn)程pull一個(gè)鏡像,那遠(yuǎn)程的鏡像是怎么來(lái)的呢?如果我們想自己創(chuàng)建一個(gè)鏡像又該怎么做呢?
對(duì),Dockerfile!Dockerfile是一個(gè)包含用戶能夠構(gòu)建鏡像的所有命令的文本文檔,它有自己的語(yǔ)法以及命令,docker能夠從dockerfile中讀取指令自動(dòng)的構(gòu)建鏡像!
??我們要想編寫(xiě)自己的Dockerfiler并構(gòu)建鏡像,那對(duì)Dockerfile的語(yǔ)法和命令的了解就是必須的,了解規(guī)則才好辦事嘛!
相關(guān)指令
FROM
??FROM <image> [AS <name>]
??FROM <image>[:<tag>] [AS <name>]
??FROM <image>[@<digest>] [AS <name>]
??指定基礎(chǔ)鏡像,當(dāng)前鏡像是基于哪個(gè)鏡像創(chuàng)建的,有點(diǎn)類似java中的類繼承。FROM指令必是Dockerfile文件中的首條命令。
MAINTAINER
??MAINTAINER <name>
??鏡像維護(hù)者的信息,該命令已經(jīng)被標(biāo)記為不推薦使用了。
LABEL
??LABEL <key>=<value> <key>=<value> <key>=<value> ...
??給鏡像添加元數(shù)據(jù),可以用LABEL命令替換MAINTAINER命令。指定一些作者、郵箱等信息。
ENV
??ENV <key> <value>
??ENV <key>=<value> ...
??設(shè)置環(huán)境變量,設(shè)置的變量可供后面指令使用。跟java中定義變量差不多的意思!
WORKDIR
??WORKDIR /path/to/workdir
??設(shè)置工作目錄,在該指令后的RUN、CMD、ENTRYPOINT, COPY、ADD指令都會(huì)在該目錄執(zhí)行。如果該目錄不存在,則會(huì)創(chuàng)建!
RUN
??RUN <command>
??RUN ["executable", "param1", "param2"]
??RUN會(huì)在當(dāng)前鏡像的最上面創(chuàng)建一個(gè)新層,并且能執(zhí)行任何的命令,然后對(duì)執(zhí)行的結(jié)果進(jìn)行提交。提交后的結(jié)果鏡像在dockerfile的后續(xù)步驟中可以使用。
ADD
??ADD [--chown=<user>:<group>] <src>... <dest>
??ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
??從宿主機(jī)拷貝文件或者文件夾到鏡像,也可以復(fù)制一個(gè)網(wǎng)絡(luò)文件!如果拷貝的文件是一個(gè)壓縮包,會(huì)自動(dòng)解壓縮!
COPY
??COPY [--chown=<user>:<group>] <src>... <dest>
??COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
??從宿主機(jī)拷貝文件或者文件夾到鏡像,不能復(fù)制網(wǎng)絡(luò)文件也不會(huì)自動(dòng)解壓縮!
VOLUME
??VOLUME ["/data"]
??VOLUME用于創(chuàng)建掛載點(diǎn),一般配合run命令的-v參數(shù)使用。
EXPOSE
??EXPOSE <port> [<port>/<protocol>...]
??指定容器運(yùn)行時(shí)對(duì)外暴露的端口,但是該指定實(shí)際上不會(huì)發(fā)布該端口,它的功能是鏡像構(gòu)建者和容器運(yùn)行者之間的記錄文件。
??回到容器命令中的run命令部分,run命令有-p和-P兩個(gè)參數(shù),如果是-P就是隨機(jī)端口映射,容器內(nèi)會(huì)隨機(jī)映射到EXPOSE指定的端口,如果是-p就是指定端口映射,告訴運(yùn)維人員容器內(nèi)需要映射的端口號(hào)。
CMD
??CMD ["executable","param1","param2"]
??CMD ["param1","param2"]
??CMD command param1 param2
??指定容器啟動(dòng)時(shí)默認(rèn)運(yùn)行的命令,在一個(gè)Dockerfile文件中,如果有多個(gè)CMD命令,只有一個(gè)最后一個(gè)會(huì)生效!同樣是可以執(zhí)行命令,可能你會(huì)覺(jué)得跟上面的RUN指令很相似,RUN指令是在構(gòu)建鏡像時(shí)候執(zhí)行的,而CMD指令是在每次容器運(yùn)行的時(shí)候執(zhí)行的!docker run命令會(huì)覆蓋CMD的命令!
ENTRYPOINT
??ENTRYPOINT ["executable", "param1", "param2"]
??ENTRYPOINT command param1 param2
??這個(gè)指令與CMD指令類似,都是指定啟動(dòng)容器時(shí)要運(yùn)行的命令,如果指定了ENTRYPOINT,則CMD指定的命令不會(huì)執(zhí)行!在一個(gè)Dockerfile文件中,如果有多個(gè)ENTRYPOINT命令,也只有一個(gè)最后一個(gè)會(huì)生效!不同的是通過(guò)docker run command命令會(huì)覆蓋CMD的命令!執(zhí)行的命令不會(huì)覆蓋ENTRYPOINT,docker run命令中指定的任何參數(shù)都會(huì)被當(dāng)做參數(shù)傳遞給ENTRYPOINT!
RUN、CMD、ENTRYPOINT區(qū)別
1、RUN指令是在鏡像構(gòu)建時(shí)運(yùn)行,而后兩個(gè)是在容器啟動(dòng)時(shí)執(zhí)行!
2、CMD指令設(shè)置的命令是容器啟動(dòng)時(shí)默認(rèn)運(yùn)行的命令,如果docker run沒(méi)有指定任何的命令,并且Dockerfile中沒(méi)有指定ENTRYPOINT,那容器啟動(dòng)的時(shí)候就會(huì)執(zhí)行CMD指定的命令!有點(diǎn)類似代碼中的缺省參數(shù)!
3、如果設(shè)置了ENTRYPOINT指令,則優(yōu)先使用!并且可以通過(guò)docker run給該指令設(shè)置的命令傳參!
4、CMD有點(diǎn)類似代碼中的缺省參數(shù)
USER
??USER <user>[:<group>]
??USER <UID>[:<GID>]
??用于指定運(yùn)行鏡像所使用的用戶。
ARG
??ARG <name>[=<default value>]
??指定在鏡像構(gòu)建時(shí)可傳遞的變量,定義的變量可以通過(guò)docker build --build-arg <varname style="box-sizing: border-box;">=<value style="box-sizing: border-box;">的方式在構(gòu)建時(shí)設(shè)置。</value></varname>
ONBUILD
??ONBUILD [INSTRUCTION]
??當(dāng)所構(gòu)建的鏡像被當(dāng)做其他鏡像的基礎(chǔ)鏡像時(shí),ONBUILD指定的命令會(huì)被觸發(fā)!
STOPSIGNAL
??STOPSIGNAL signal
??設(shè)置當(dāng)容器停止時(shí)所要發(fā)送的系統(tǒng)調(diào)用信號(hào)!
HEALTHCHECK
??HEALTHCHECK [OPTIONS] CMD command (在容器內(nèi)運(yùn)行運(yùn)行命令檢測(cè)容器的運(yùn)行情況)
??HEALTHCHECK NONE (禁止從父鏡像繼承檢查)
??該指令可以告訴Docker怎么去檢測(cè)一個(gè)容器的運(yùn)行狀況!
SHELL
??SHELL ["executable", "parameters"]
??用于設(shè)置執(zhí)行命令所使用的默認(rèn)的shell類型!該指令在windows操作系統(tǒng)下比較有用,因?yàn)閣indows下通常會(huì)有cmd和powershell兩種shell,甚至還有sh。
構(gòu)建
Dockerfile執(zhí)行順序是從上到下,順序執(zhí)行!每條指令都會(huì)創(chuàng)建一個(gè)新的鏡像層,并對(duì)鏡像進(jìn)行提交。編寫(xiě)好Dockerfile文件后,就需要使用docker build命令對(duì)鏡像進(jìn)行構(gòu)建了。
??docker build的格式:docker build [OPTIONS] PATH | URL | -
-f:指定要使用的Dockerfile路徑,如果不指定,則在當(dāng)前工作目錄尋找Dockerfile文件!
-t: 鏡像的名字及標(biāo)簽,通常name:tag或者name格式;可以在一次構(gòu)建中為一個(gè)鏡像設(shè)置多個(gè)標(biāo)簽。
例如我們可以docker build -t myApp:1.0.1 .這樣來(lái)構(gòu)建自己的鏡像,注意后面的 . ,用于指定鏡像構(gòu)建過(guò)程中的上下文環(huán)境的目錄。如果大家想了解那些官方鏡像的Dockerfile文件都是怎么樣寫(xiě)的,可以上https://hub.docker.com/ 進(jìn)行搜索,以tomcat鏡像為例
[圖片上傳中...(image-879cbc-1597474088475-2)]
能看到tomcat鏡像的父鏡像是openjdk鏡像,我們?cè)偎阉鱫penjdk的Dockerfile文件

openjdk鏡像的父鏡像又是oraclelinux鏡像,我們?cè)偎阉鱫raclelinux的Dockerfile文件
[圖片上傳中...(image-53778f-1597474088475-0)]
openjdk鏡像的父鏡像是scratch,這是根鏡像,所有的鏡像都會(huì)依賴該鏡像,就像我們代碼中所有的對(duì)象的父類都是Object!所以能看到tomcat鏡像就是這樣一層一層的構(gòu)建出來(lái)的,這也是為什么前面通過(guò)docker images查看到的tomcat鏡像為什么會(huì)有四百多兆的原因啦!
看到這里的你,是否對(duì)docker是什么?為什么需要docker?docker鏡像、docker容器的概念是什么?docker中常用的命令有哪些?Dockerfile有哪些指令?怎么去構(gòu)建自己的鏡像?這些問(wèn)題都能明白了呢?