在上一篇文章中,有幸和各位
分享了一點(diǎn)人生的經(jīng)驗(yàn)柱彻,正如我在文章末所說(shuō)豪娜,這些都只是滄海一粟,學(xué)會(huì) docker 的基本概念和操作還不足以讓你快速部署代碼哟楷,今天我們就來(lái)聊一聊 Dockerfile
在了解什么是 Dockerfile之前瘤载,我們先來(lái)做一個(gè)小實(shí)驗(yàn)
還記得我們?cè)谏弦还?jié)中 pull 下來(lái)的 python 鏡像嗎,首先通過(guò) docker run -it 進(jìn)入容器內(nèi)部卖擅,回憶一下鸣奔, -it 這個(gè)參數(shù)的作用是什么,沒(méi)錯(cuò)惩阶,使用這個(gè)參數(shù)挎狸,docker會(huì)為容器分配一個(gè)偽輸入終端,通過(guò)這個(gè)終端断楷,用戶就可以和容器進(jìn)行相應(yīng)的交互了锨匆。
進(jìn)入容器后,先列出當(dāng)前路徑下的所有文件
[root@FUCC ~]# docker run -it python:3.7 /bin/bash
root@692f87774bf7:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@692f87774bf7:/#
OK冬筒,接著恐锣,我們將創(chuàng)建一個(gè)hello.py 的文件,創(chuàng)建完成后再次列出所有文件
root@692f87774bf7:/# touch hello.py
root@692f87774bf7:/# ls
bin boot dev etc hello.py home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
可以看到舞痰,hello.py 已經(jīng)創(chuàng)建完成了土榴,這時(shí)我們退出容器,使用之前的 docker run -it python:3.7 /bin/bash 命令再次進(jìn)入容器的交互模式匀奏,并列出所有文件
root@692f87774bf7:/# exit
exit
[root@FUCC ~]# docker run -it python:3.7 /bin/bash
root@65c767655e8a:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@65c767655e8a:/#
不用我多說(shuō)鞭衩,相信你已經(jīng)發(fā)現(xiàn)了問(wèn)題的所在学搜,奇怪,為什么我們之前創(chuàng)建的文件憑空消失了呢论衍?
這是因?yàn)椋?strong>在容器內(nèi)部執(zhí)行的操作并不會(huì)修改鏡像瑞佩,容器其實(shí)只是在鏡像上面添加了一個(gè)可寫(xiě)層,就像字帖里的臨摹紙一樣坯台,無(wú)論你在臨摹紙上怎么寫(xiě)炬丸,對(duì)下面一層都不會(huì)有任何影響,這個(gè)特性其實(shí)和VM的快照有些類似蜒蕾。
但是問(wèn)題來(lái)了稠炬,既然在容器內(nèi)部的操作都不會(huì)修改鏡像,那如何做到快速部署咪啡,每次部署代碼前都去重復(fù)執(zhí)行一些操作首启,豈不是太low了?
假設(shè)你是一家社交網(wǎng)站的技術(shù)負(fù)責(zé)人撤摸,某一天毅桃,奧特蝦突然宣布戀情上了熱搜,哦不是准夷,八對(duì)明星突然同時(shí)出軌钥飞,你需要在短時(shí)間內(nèi)創(chuàng)建上百臺(tái)云服務(wù)器以支撐吃瓜群眾海量的請(qǐng)求,團(tuán)隊(duì)選用了 Docker 去部署應(yīng)用衫嵌,如果通過(guò)上面這種方法去部署读宙,吃瓜群眾想殺了你的心都有了,為什么楔绞?等你的服務(wù)恢復(fù)结闸,吃瓜群眾早就散了,動(dòng)不動(dòng)就崩酒朵,怎么愉快吃瓜膀估?
這時(shí),就輪到 Dockerfile 閃亮登場(chǎng)了耻讽,老規(guī)矩,先看一下 Docker 官方對(duì)于 Dockerfile 的介紹
Docker can build images automatically by reading the instructions from a Dockerfile. A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image. Using docker build users can create an automated build that executes several command-line instructions in succession
簡(jiǎn)單來(lái)說(shuō)帕棉,Dockerfile是一個(gè)文本文檔针肥,其中包含用戶可以在命令行上調(diào)用以構(gòu)建鏡像的所有命令,舉個(gè)例子香伴,你可以理解為構(gòu)建鏡像是一個(gè)搭積木的過(guò)程慰枕,Dockerfile 就像是說(shuō)明書(shū)一樣,Docker 會(huì)根據(jù)這份說(shuō)明書(shū)去構(gòu)建你想生成的鏡像即纲。
接下來(lái)我們會(huì)從一個(gè)實(shí)際的場(chǎng)景出發(fā)具帮,講一講如何構(gòu)建 Dockerfile
依舊是以一個(gè) python 鏡像為例,在我的本地(容器外部),有一個(gè) Optimal_Hotel_Matching.py 的代碼文件蜂厅,這是一個(gè)爬蟲(chóng)程序匪凡,先嘗試在容器中運(yùn)行它
果不其然,出現(xiàn)了報(bào)錯(cuò)掘猿,這是因?yàn)樵趐ython鏡像中病游,并沒(méi)有安裝requests這個(gè)第三方的http庫(kù),這其實(shí)就是一個(gè)典型的安裝依賴環(huán)境的過(guò)程稠通,我們?cè)囍?Dockerfile 去解決這個(gè)問(wèn)題
[root@FUCC dockerfileTest]# ls
Optimal_Hotel_Matching.py
[root@FUCC dockerfileTest]# docker run -v $PWD:/usr/src/code -w /usr/src/code python:3.7 python Optimal_Hotel_Matching.py
Traceback (most recent call last):
File "Optimal_Hotel_Matching.py", line 1, in <module>
import requests
ModuleNotFoundError: No module named 'requests'
[root@FUCC dockerfileTest]#
在編寫(xiě)第一個(gè) Dockerfile 之前衬衬,我們先來(lái)熟悉一下 Dockerfile 中幾個(gè)常用的指令
FROM
語(yǔ)法: FROM <image>
說(shuō)明:這是 Dockerfile 中的第一條指令,它用于指定一個(gè)構(gòu)建鏡像的基礎(chǔ)源鏡像改橘,如果本地沒(méi)有的話滋尉, Docker 會(huì)從倉(cāng)庫(kù)中自動(dòng)拉取
MAINTAINER
語(yǔ)法:MAINTAINER <name> <email>
說(shuō)明:用于描述鏡像創(chuàng)建者的名稱和郵箱
RUN
語(yǔ)法: RUN <command> <param1> <param2>
說(shuō)明:RUN 絕對(duì)是 Dockerfile 中最重要的命令之一了,當(dāng)RUN執(zhí)行完成后飞主,會(huì)在原先的基礎(chǔ)鏡像上創(chuàng)建一個(gè)新的鏡像層狮惜,每執(zhí)行一次RUN就會(huì)產(chǎn)生一個(gè)新的層。通常既棺,安裝軟件或者配置環(huán)境都是通過(guò)RUN來(lái)實(shí)現(xiàn)的
CMD
語(yǔ)法: CMD <command> <param1> <param2>
說(shuō)明:CMD相對(duì)而言比較簡(jiǎn)單讽挟,相信大家看到名字就能理解,這個(gè)指令用于指定容器啟動(dòng)時(shí)執(zhí)行的命令
Tips: 在我剛接觸Docker的時(shí)候丸冕,RUN 和 CMD 一度傻傻分不清楚耽梅,其實(shí)這兩者的作用完全不同,RUN 用于構(gòu)建鏡像胖烛,是對(duì)鏡像進(jìn)行操作眼姐,而 RUN 則是指定了容器啟動(dòng)時(shí)執(zhí)行的命令,是對(duì)容器進(jìn)行操作
COPY
語(yǔ)法:COPY <src> <dest>
說(shuō)明:COPY 用于復(fù)制本地文件佩番,并將其放置在指定的容器目錄众旗,但是需要注意的是 COPY 并不能將復(fù)制的壓縮文件自動(dòng)解壓,也不能復(fù)制網(wǎng)絡(luò)文件趟畏,如果有這兩點(diǎn)需求可以使用 ADD 命令贡歧,這兩個(gè)命令的用法是相同的, ADD 可以將復(fù)制的壓縮文件自動(dòng)解壓
WORKDIR
語(yǔ)法: WORKDIR <path>
說(shuō)明:為RUN赋秀、CMD利朵、ENTRYPOINT指令配置工作目錄,在一個(gè) Dockerfile 中可以使用多個(gè)WORKDIR指令
編寫(xiě)第一個(gè)Dockerfile
掌握了以上指令后猎莲,我們就已經(jīng)能寫(xiě)一個(gè)較為基礎(chǔ)的 Dockerfile 了绍弟,回到我們之前的需求,一句話總結(jié)下來(lái)就是著洼,安裝requests庫(kù)后運(yùn)行代碼文件
思考一下樟遣,應(yīng)該怎么做而叼?
如果你還是沒(méi)有眉目,不妨來(lái)看看我為你準(zhǔn)備的參考答案
FROM python:3.7 #指定基礎(chǔ)鏡像為python:3.7
MAINTAINER ultraxia "ultraxia@foxmail.com" #維護(hù)者名稱和郵箱
RUN pip install requests #安裝requests庫(kù)豹悬,并構(gòu)建一個(gè)新的鏡像層
WORKDIR /dockerfileTest #指定工作目錄為/dockerfileTest
COPY . . #將當(dāng)前目錄下的文件復(fù)制到容器中葵陵,這里為工作目錄
CMD [ "python", "Optimal_Hotel_Matching.py" ] #運(yùn)行代碼
將上面的內(nèi)容保存為名稱為Dockerfile的文件,并放置在項(xiàng)目所在的目錄
[root@FUCC dockerfileTest]# ls
Dockerfile Optimal_Hotel_Matching.py
開(kāi)始構(gòu)建
這時(shí)屿衅,我們就可以使用docker build去構(gòu)建了埃难,通常為了區(qū)分不同的鏡像,需要給鏡像打上tag(標(biāo)簽)
[root@FUCC dockerfileTest]# docker build --tag python:requests .
Sending build context to Docker daemon 5.12 kB
Step 1/6 : FROM python:3.7
---> 42d620af35be
Step 2/6 : MAINTAINER ultraxia "ultraxia@foxmail.com"
---> Running in b9ca2049ef19
---> c6fb2a731a82
Removing intermediate container b9ca2049ef19
Step 3/6 : RUN pip install requests
---> Running in 4edba5ca3ead
Collecting requests
Downloading https://files.pythonhosted.org/packages/51/bd/23c926cd341ea6b7dd0b2a00aba99ae0f828be89d72b2190f27c11d4b7fb/requests-2.22.0-py2.py3-none-any.whl (57kB)
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests)
Downloading https://files.pythonhosted.org/packages/e6/60/247f23a7121ae632d62811ba7f273d0e58972d75e58a94d329d51550a47d/urllib3-1.25.3-py2.py3-none-any.whl (150kB)
解釋一下這條命令
docker build 命令用于使用 Dockerfile 創(chuàng)建鏡像
--tag 參數(shù)用于指定鏡像tag涤久,這里我們命名為python:requests
. docker 會(huì)從當(dāng)前目錄尋找Dockerfile文件涡尘,并開(kāi)始構(gòu)建鏡像
構(gòu)建完成!使用 docker images命令驗(yàn)證一下吧
[root@FUCC dockerfileTest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
python requests 04f20acdc288 2 hours ago 926 MB
docker.io/python 3.7 42d620af35be 3 weeks ago 918 MB
docker.io/rabbitmq 3-management 7aae48fa6ef6 3 weeks ago 179 MB
docker.io/golang latest f50db16df5da 4 weeks ago 774 MB
docker.io/mariadb latest 3a2ef06682ac 4 weeks ago 356 MB
docker.io/centos latest 9f38484d220f 4 months ago 202 MB
docker.io/hello-world latest fce289e99eb9 7 months ago 1.84 kB
docker.io/django latest eb40dcf64078 2 years ago 436 MB
[root@FUCC dockerfileTest]#
可以看到响迂,此時(shí)本地的倉(cāng)庫(kù)中已經(jīng)生成了一個(gè)tag為requests的python鏡像考抄。試著運(yùn)行一下這個(gè)鏡像,看看是否還會(huì)出現(xiàn)No module named 'requests'的報(bào)錯(cuò)蔗彤,以及川梅,程序是否會(huì)如我們期待的一樣開(kāi)始運(yùn)行。
[root@FUCC dockerfileTest]# docker run python:requests
Computing distance between 116.368816,39.866464 and 116.438946,39.921624
Computing distance between 116.370910,39.869603 and 116.438946,39.921624
Computing distance between 116.409583,39.983356 and 116.438946,39.921624
Computing distance between 116.302621,39.966272 and 116.438946,39.921624
Computing distance between 116.322551,39.886995 and 116.438946,39.921624
可以看到然遏,運(yùn)行成功贫途,容器中的代碼運(yùn)行完成后,容器退出待侵。
完結(jié)了嗎丢早?
在這一篇里,我通過(guò)一個(gè)簡(jiǎn)單的案例和各位分享了 Dockerfile 的簡(jiǎn)單應(yīng)用秧倾,事實(shí)上在企業(yè)的實(shí)際生產(chǎn)中怨酝,Dockerfile 的內(nèi)容會(huì)比這個(gè)更復(fù)雜一些薄嫡。
最后固翰,正好趕上七夕仗阅,祝各位七夕快樂(lè)起趾,下期再見(jiàn)。
今天過(guò)節(jié)的人會(huì)有時(shí)間看你的文章嗎法瑟?不會(huì)