Docker小白到实战之Dockerfile解析及实战演示,果然顺手
前言
使用第三方鏡像肯定不是學習Docker的最終目的,最想要的還是自己構(gòu)建鏡像;將自己的程序、文件、環(huán)境等構(gòu)建成自己想要的應用鏡像,方便后續(xù)部署、啟動和維護;而Dockerfile就是專門做這個事的,通過類似簡單編碼的形式,最終就可以構(gòu)建出屬于自己的鏡像,所以必須學起來。
正文
1. Dockerfile簡介
在日常開發(fā)過程中,需要編寫對應的程序文件,最后通過編譯打包生成對應的可執(zhí)行文件或是類庫;這里的Dockerfile文件就好比平時我們編寫的程序文件,但內(nèi)部的語法和關(guān)鍵字并沒有程序那么復雜和繁多,相對來說還是很簡單的,最后通過docker build命令就可以將對應的程序、文件、環(huán)境等構(gòu)建成鏡像啦。
在第一篇文章最后就簡單使用了Dockerfile構(gòu)建了一個鏡像,這里重新認識下這個Dockerfile文件,如下圖:
Dockerfile就是一個文本文件,但不需要指定后綴類型;文件內(nèi)容中FROM、WORKDIR、COPY等就是關(guān)鍵字,按照規(guī)則寫好之后,就可以將指定的文件構(gòu)建為鏡像啦。
構(gòu)建操作統(tǒng)一由Docker daemon進行,它會先對文件內(nèi)容語法進行初步驗證(語法不對就會返回錯誤信息),然后逐一運行指令,每次生成一個新的鏡像層,直到執(zhí)行完所有指令,就構(gòu)建出最終的鏡像。 Dockerfile、鏡像、容器的關(guān)系如下:
總結(jié)一下Dockerfile的知識點;
構(gòu)建時,指令從上到下逐一執(zhí)行;
每條指令都會創(chuàng)建一個新的鏡像層,每一層都是前一層變化的增量;
使用#號進行注釋;
關(guān)鍵字約定都是大寫,后面至少跟一個參數(shù);
2. Dockerfile關(guān)鍵字
2.1 FROM 關(guān)鍵字
指定基礎鏡像, 就是新鏡像是基于哪個鏡像構(gòu)建的。
比如建房子,可以在一塊空地開始,也可以在別人打好的基石基礎上開始, 甚至可以在別人弄好的毛坯房基礎上裝修即可。
如果要建房的話,可以FROM 空地,或者FROM 打好的基石,或者 FROM 毛坯房, 反正最后建好房就行;
這里需要注意的是,不管咋樣,空地是少不了的;構(gòu)建鏡像也一樣,最底層肯定有一個最基礎的鏡像。
建議使用官方的鏡像作為基礎鏡像,推薦使用Alpine這種類型,因為它是嚴格控制的,而且體積很小。
用法如下:
?#?FROM?[--platform=<platform>]?<image>[:<tag>]?[AS?<name>]ARG??CODE_VERSION=latest?#?定義變量FROM?base:${CODE_VERSION}?#?指定基礎鏡像2.2 MAINTAINER/LABEL 關(guān)鍵字
MAINTAINER 指定維護者的相關(guān)信息,也就是構(gòu)建的鏡像是由誰構(gòu)建的,他的郵箱是什么;
LABLE 就是用于給鏡像打標簽,以鍵值對的方式進行指定,相對MAINTAINER 來說比較靈活,可以使用LABLE替代MAINTAINER。
用法如下:
?#?LABEL?<key>=<value>?<key>=<value>?<key>=<value>?...LABEL?com.example.version="0.0.1-beta"?LABEL?vendor1="ACME?Incorporated"2.3 RUN 關(guān)鍵字
構(gòu)建過程中需要運行的命令, 比如在構(gòu)建過程中需要執(zhí)行一條命令下載對應的包,這里就需要用到RUN關(guān)鍵字;
用法如下:
?#?兩種命令方式都可以#?RUN?<command>#?RUN?["executable",?"param1",?"param2"]#?執(zhí)行命令,Linux支持的相關(guān)命令RUN?/bin/bash?-c?'source?$HOME/.bashrc;?echo?$HOME'RUN?["/bin/bash",?"-c",?"echo?hello"]2.4 WORKDIR 關(guān)鍵字
根據(jù)鏡像啟動容器時,通常需要進入到容器內(nèi)部;則可以通過WORKDIR指定進入容器時的目錄;
用法如下:
?WORKDIR?/path?#?指定路徑2.5 ENV 關(guān)鍵字
可以在構(gòu)建過程中設置環(huán)境變量;就好比平時我們安裝完程序,需要配置環(huán)境變量,方便訪問;ENV關(guān)鍵字就是根據(jù)需求可以設置對應的環(huán)境變量;
用法如下:
?#?ENV?<key>=<value>?...#?指定環(huán)境變量ENV?PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH2.6 ADD 關(guān)鍵字
將宿主機的資源拷貝進鏡像中,會自動解壓縮,而且還能從遠程宿主機中讀取資源并拷貝到鏡像中;
用法如下:
?#?兩種命令方式都可以#?ADD?[--chown=<user>:<group>]?<src>...?<dest>#?ADD?[--chown=<user>:<group>]?["<src>",...?"<dest>"]ADD?https://example.com/big.tar.xz?/usr/src/things/2.7 COPY 關(guān)鍵字
將宿主機的資源拷貝到鏡像中,只支持讀取構(gòu)建所在宿主機的資源。相對于ADD關(guān)鍵字來說更加透明,操作什么就是什么。
用法如下:
?#?拷貝資源到容器,兩種命令格式都行#?COPY?[--chown=<user>:<group>]?<源地址>...?<目標地址>#?COPY?[--chown=<user>:<group>]?["<源地址>",...?"<目標地址>"]COPY?requirements.txt?/tmp/2.8 VOLUME 關(guān)鍵字
掛載數(shù)據(jù)卷,之前在常用命令那說到通過命令的方式進行數(shù)據(jù)卷掛載,在Dockerfile中使用VOLUME指定掛載路徑即可,根據(jù)構(gòu)建出來的鏡像運行容器時,默認就有構(gòu)建時掛載的信息。
用法如下:
?#?掛載數(shù)據(jù)卷VOLUME?["/data"]VOLUME?/myvol2.9 EXPOSE 關(guān)鍵字
指定運行容器時對外暴露的端口;即根據(jù)鏡像啟動容器時,容器向外暴露端口。
用法如下:
?#?EXPOSE?<port>?[<port>/<protocol>...]EXPOSE?80/tcp?#?暴露端口EXPOSE?80/udp2.10 CMD 關(guān)鍵字
指定啟動容器時要執(zhí)行的命令,只有最后一個會生效;即根據(jù)鏡像啟動容器時,容器需要執(zhí)行啥命令。
用法如下:
?#?兩種格式都行#?CMD?["param1","param2"]#?CMD?command?param1?param2#?執(zhí)行命令統(tǒng)計?行數(shù)、字數(shù)、字節(jié)數(shù)CMD?echo?"This?is?a?test."?|?wc?-#?執(zhí)行wc?--help命令?CMD?["/usr/bin/wc","--help"]2.11 ENTRYPOINT 關(guān)鍵字
指定根據(jù)鏡像啟動容器時要執(zhí)行的命令,可以追加命令;執(zhí)行時機同CMD。
用法如下:
?#?ENTRYPOINT?["executable",?"param1",?"param2"]#?ENTRYPOINT?command?param1?param2ENTRYPOINT?["top",?"-b"]2.12 ARG 關(guān)鍵字
通過ARG指令定義了一個變量;和寫代碼時定義的變量一樣,根據(jù)需要,定義就行啦。
用法如下:
?#?ARG?<name>[=<default?value>]ARG?user1=someuserARG?buildno=12.13 ONBUILD 關(guān)鍵字
基于父鏡像構(gòu)建新的鏡像時,父鏡像的OBUILD會被觸發(fā)。
3. 實戰(zhàn)演示
這里還是以.NetCore項目構(gòu)建鏡像為例,其他編程語言的項目同理;這次咱們一步一步的來,搞清楚每個命令的使用。
以下關(guān)于項目創(chuàng)建和發(fā)布的具體細節(jié)在第一篇最后就分享了,小伙伴可以參考,這里主要演示Dockerfile關(guān)鍵字。
3.1 準備項目和Dockerfile文件
新建一個項目,啥都不需要改,就用默認的接口演示,如下:
Dockerfile內(nèi)容如下:
?#?指定基礎鏡像,在此基礎上構(gòu)建自己的項目鏡像FROM?mcr.microsoft.com/dotnet/core/aspnet:3.1#?指定自己的工作目錄,進入容器時目錄WORKDIR?/myApp#?將構(gòu)建上下文目錄下的文件拷貝到容器的當前工作目錄中,即/myAppCOPY?.?.#?容器向外暴露端口,項目以什么端口啟動就暴露對應的端口EXPOSE?80#?執(zhí)行命令,這里默認是以80端口啟動的#就類似于在Linux系統(tǒng)的項目目錄下執(zhí)行?dotnet?DockerfileDemo.dll?是一樣的ENTRYPOINT?["dotnet",?"DockerfileDemo.dll"]記得右鍵Dockerfile,選擇屬性,然后設置Dockerfile為始終復制,這樣后續(xù)更新變動,發(fā)布時就會自動拷貝到對應的發(fā)布目錄。
3.2 以文件的形式發(fā)布項目,并連同Dockerfile拷貝到安裝好Docker的機器上進行構(gòu)建(這里還是用我的云服務器);
docker build -t myimage:v1.0 .解析:
-t:指定鏡像的名字及標簽,通常 name:tag 或者 name 格式,myimage就是鏡像名字,v1.0就是tag;
-f :指定要使用的Dockerfile路徑,這里由于Dockerfile在當前路徑,所以不用指定;
最后面的點:官方稱為構(gòu)建上下文,點表示指定為當前目錄。會把指定的這個目錄下的文件發(fā)送給docker daemon進行構(gòu)建,所以千萬不要指定/(斜杠代表根目錄,有很多文件的)。
其他選項參數(shù)小伙伴可以根據(jù)需要使用,以上是比較重要的。
3.3 根據(jù)構(gòu)建出來的鏡像啟動容器,看Dockerfile中的命令效果;
啟動容器如下:
ENTRYPOINT ["dotnet", "DockerfileDemo.dll"]這行代碼就等同于的項目目錄下直接執(zhí)行 dotnet DockerfileDemo.dll是一樣的,目的就是啟動我們的項目。
通過docker logs可以查看容器內(nèi)部的日志,如下:
3.4 豐富化Dockefile文件內(nèi)容并查看構(gòu)建之后的細節(jié)
文件內(nèi)容如下:
?#?指定基礎鏡像,在此基礎上構(gòu)建自己的項目鏡像FROM?mcr.microsoft.com/dotnet/core/aspnet:3.1#?指定維護人MAINTAINER?CodeZYQ<1137533407@qq.com>#?打標簽LABEL?createname="CodeZYQ"#?指定自己的工作目錄,進入容器時目錄?appWORKDIR?/myapp#?將構(gòu)建上下文目錄下的文件拷貝到容器中的工作目錄中COPY?.?.#?定義變量ARG?myPort=8080#?使用環(huán)境變量方式改變啟動端口,拼接用到了定義的變量ENV?ASPNETCORE_URLS=http://+:$myPort#?通過RUN?執(zhí)行相關(guān)命令,根據(jù)需要執(zhí)行相關(guān)命令RUN?mkdir?testDir#?掛載數(shù)據(jù)卷,這里模擬掛載日志目錄VOLUME?/Logs#?容器向外暴露端口,項目以什么端口啟動就暴露對應的端口EXPOSE?$myPort#?執(zhí)行命令,這里默認是以80端口啟動的#?就類似于在Linux系統(tǒng)的項目目錄下執(zhí)行?dotnet?DockerfileDemo.dll?是一樣的ENTRYPOINT?["dotnet",?"DockerfileDemo.dll"]執(zhí)行如下命令,構(gòu)建新的鏡像:
?#?這里沒有顯示指定tag?默認就latestdocker?build?-t?newimage?.通過docker logs看看容器日志,如下:
看看數(shù)據(jù)卷掛載是否成功,進入容器,看根目錄下就會多了Logs目錄,也可以通過docker inspect 容器 看容器詳細信息,如下:
標簽也打成功了:
也可以通過docker inspect 鏡像查看鏡像內(nèi)部的詳細信息,執(zhí)行命令docker inspect newimage如下:
關(guān)于步驟和效果,在Dockerfile注釋和圖表中已經(jīng)詳細描述。
3.5 CMD和ENTRYPOINT的區(qū)別
兩個命令都是啟動容器時指定執(zhí)行命令和對應的參數(shù),但兩者稍有不同,如下:
CMD:只能最后一個命令會生效,命令會被docker run之后的參數(shù)替換掉;
ENTRYPOINT:可以追加命令,比如增加參數(shù);
上面構(gòu)建出來的newimage鏡像用到的是ENTRYPOINT,所以我們先來測試一下ENTRYPOINT,如下:
docker run啟動容器時指定了參數(shù) --urls="http://+:9999",容器正常啟動,并且參數(shù)還能生效,等同于在當前目錄直接執(zhí)行如下命令:
?dotnet?DockerfileDemo.dll?--urls="http://+:9999"現(xiàn)在把ENTRYPOINT換成CMD試試,如下:
?#?在以上的Dockerfile中#?將ENTRYPOINT?["dotnet",?"DockerfileDemo.dll"]換成CMD,如下:CMD?["dotnet",?"DockerfileDemo.dll"]然后重新構(gòu)建一個鏡像試試,測試如下:
如上圖,對于CMD而言,如果在運行容器時,后面指定參數(shù),這個參數(shù)就會把CMD命令替換掉,不能拼接,導致命令不對,所以報錯;但這樣就可以執(zhí)行,如下:
如果在當前構(gòu)建的上下文目錄中不想要一些文件參與構(gòu)建,可以通過在.dockerignore文件中進行配置,這個和git中的.gitignore一個道理,編寫也比較簡單,這里就不演示了。
對了,.NetCore的鏡像列表可以參照這個地址:https://hub.docker.com/_/microsoft-dotnet-aspnet/,每個鏡像都有對應的Dockerfile,感興趣的小伙伴可以點進去看看,參考參考。
總結(jié)
關(guān)于Dockerfile的演示就先說那么多,小伙伴們一定要舉一反三,上面演示只是一個小例子而已,在正式項目中可以根據(jù)需要,編輯出屬于符合需求的Dockefile文件,最終構(gòu)建出方便、好用的鏡像,這樣開發(fā)和運維就和諧了(嘿嘿嘿)。
Docker之前文章目錄:
Docker小白到實戰(zhàn)之開篇概述
Docker小白到實戰(zhàn)之常用命令演示,通俗易懂
Docker小白到實戰(zhàn)之容器數(shù)據(jù)卷,整理的明明白白
好了,下次聊聊Docker中的網(wǎng)絡應用,關(guān)注“Code綜藝圈”,和我一起學習吧;
圖片總結(jié)
以上是生活随笔為你收集整理的Docker小白到实战之Dockerfile解析及实战演示,果然顺手的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RabbitMQ有5种工作模式
- 下一篇: 一年几百亿的电费 中国移动再提5G功耗问