Docker小白到實戰之Dockerfile解析及實戰演示,果然順手

Code綜藝圈發表於2021-09-09

前言

使用第三方映象肯定不是學習Docker的最終目的,最想要的還是自己構建映象;將自己的程式、檔案、環境等構建成自己想要的應用映象,方便後續部署、啟動和維護;而Dockerfile就是專門做這個事的,通過類似簡單編碼的形式,最終就可以構建出屬於自己的映象,所以必須學起來。

正文

1. Dockerfile簡介

在日常開發過程中,需要編寫對應的程式檔案,最後通過編譯打包生成對應的可執行檔案或是類庫;這裡的Dockerfile檔案就好比平時我們編寫的程式檔案,但內部的語法和關鍵字並沒有程式那麼複雜和繁多,相對來說還是很簡單的,最後通過docker build命令就可以將對應的程式、檔案、環境等構建成映象啦。

在第一篇文章最後就簡單使用了Dockerfile構建了一個映象,這裡重新認識下這個Dockerfile檔案,如下圖:

Dockerfile就是一個文字檔案,但不需要指定字尾型別; 檔案內容中FROM、WORKDIR、COPY等就是關鍵字,按照規則寫好之後,就可以將指定的檔案構建為映象啦。

構建操作統一由Docker daemon進行,它會先對檔案內容語法進行初步驗證(語法不對就會返回錯誤資訊),然後逐一執行指令,每次生成一個新的映象層,直到執行完所有指令,就構建出最終的映象。 Dockerfile、映象、容器的關係如下:

總結一下Dockerfile的知識點;

  • 構建時,指令從上到下逐一執行;
  • 每條指令都會建立一個新的映象層,每一層都是前一層變化的增量;
  • 使用#號進行註釋;
  • 關鍵字約定都是大寫,後面至少跟一個引數;

2. Dockerfile關鍵字

2.1 FROM 關鍵字

指定基礎映象, 就是新映象是基於哪個映象構建的。

比如建房子,可以在一塊空地開始,也可以在別人打好的基石基礎上開始, 甚至可以在別人弄好的毛坯房基礎上裝修即可。

如果要建房的話,可以FROM 空地,或者FROM 打好的基石,或者 FROM 毛坯房, 反正最後建好房就行;

這裡需要注意的是,不管咋樣,空地是少不了的;構建映象也一樣,最底層肯定有一個最基礎的映象

建議使用官方的映象作為基礎映象,推薦使用Alpine這種型別,因為它是嚴格控制的,而且體積很小。

用法如下:

 # FROM [--platform=<platform>] <image>[:<tag>] [AS <name>]
 ARG  CODE_VERSION=latest # 定義變數
 FROM base:${CODE_VERSION} # 指定基礎映象
2.2 MAINTAINER/LABEL 關鍵字

MAINTAINER 指定維護者的相關資訊,也就是構建的映象是由誰構建的,他的郵箱是什麼

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 關鍵字

構建過程中需要執行的命令, 比如在構建過程中需要執行一條命令下載對應的包,這裡就需要用到RUN關鍵字;

用法如下:

 # 兩種命令方式都可以
 # RUN <command>
 # RUN ["executable", "param1", "param2"]
 # 執行命令,Linux支援的相關命令
 RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
 RUN ["/bin/bash", "-c", "echo hello"]
2.4 WORKDIR 關鍵字

根據映象啟動容器時,通常需要進入到容器內部;則可以通過WORKDIR指定進入容器時的目錄

用法如下:

 WORKDIR /path # 指定路徑
2.5 ENV 關鍵字

可以在構建過程中設定環境變數; 就好比平時我們安裝完程式,需要配置環境變數,方便訪問; ENV關鍵字就是根據需求可以設定對應的環境變數;

用法如下:

 # ENV <key>=<value> ...
 # 指定環境變數
 ENV PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH
2.6 ADD 關鍵字

將宿主機的資源拷貝進映象中,會自動解壓縮,而且還能從遠端宿主機中讀取資源並拷貝到映象中

用法如下:

 # 兩種命令方式都可以
 # 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 關鍵字

將宿主機的資源拷貝到映象中,只支援讀取構建所在宿主機的資源。相對於ADD關鍵字來說更加透明,操作什麼就是什麼。

用法如下:

 # 拷貝資源到容器,兩種命令格式都行
 # COPY [--chown=<user>:<group>] <源地址>... <目標地址>
 # COPY [--chown=<user>:<group>] ["<源地址>",... "<目標地址>"]
 COPY requirements.txt /tmp/
2.8 VOLUME 關鍵字

掛載資料卷,之前在常用命令那說到通過命令的方式進行資料卷掛載,在Dockerfile中使用VOLUME指定掛載路徑即可,根據構建出來的映象執行容器時,預設就有構建時掛載的資訊。

用法如下:

 # 掛載資料卷
 VOLUME ["/data"]
 VOLUME /myvol
2.9 EXPOSE 關鍵字

指定執行容器時對外暴露的埠;即根據映象啟動容器時,容器向外暴露埠。

用法如下:

 # EXPOSE <port> [<port>/<protocol>...]
 EXPOSE 80/tcp # 暴露埠
 EXPOSE 80/udp
2.10 CMD 關鍵字

指定啟動容器時要執行的命令,只有最後一個會生效;即根據映象啟動容器時,容器需要執行啥命令。

用法如下:

 # 兩種格式都行
 # CMD ["param1","param2"]
 # CMD command param1 param2
 # 執行命令統計 行數、字數、位元組數
 CMD echo "This is a test." | wc -
 # 執行wc --help命令 
 CMD ["/usr/bin/wc","--help"]
2.11 ENTRYPOINT 關鍵字

指定根據映象啟動容器時要執行的命令,可以追加命令;執行時機同CMD。

用法如下:

 # ENTRYPOINT ["executable", "param1", "param2"]
 # ENTRYPOINT command param1 param2
 ENTRYPOINT ["top", "-b"]
2.12 ARG 關鍵字

通過ARG指令定義了一個變數;和寫程式碼時定義的變數一樣,根據需要,定義就行啦。

用法如下:

 # ARG <name>[=<default value>]
 ARG user1=someuser
 ARG buildno=1
2.13 ONBUILD 關鍵字

基於父映象構建新的映象時,父映象的OBUILD會被觸發。

3. 實戰演示

這裡還是以.NetCore專案構建映象為例,其他程式語言的專案同理;這次我們們一步一步的來,搞清楚每個命令的使用。

以下關於專案建立和釋出的具體細節在第一篇最後就分享了,小夥伴可以參考,這裡主要演示Dockerfile關鍵字。

3.1 準備專案和Dockerfile檔案

新建一個專案,啥都不需要改,就用預設的介面演示,如下:

Dockerfile內容如下:

 # 指定基礎映象,在此基礎上構建自己的專案映象
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
 # 指定自己的工作目錄,進入容器時目錄
 WORKDIR /myApp
 # 將構建上下文目錄下的檔案拷貝到容器的當前工作目錄中,即/myApp
 COPY . .
 # 容器向外暴露埠,專案以什麼埠啟動就暴露對應的埠
 EXPOSE 80
 # 執行命令,這裡預設是以80埠啟動的
 #就類似於在Linux系統的專案目錄下執行 dotnet DockerfileDemo.dll 是一樣的
 ENTRYPOINT ["dotnet", "DockerfileDemo.dll"]

記得右鍵Dockerfile,選擇屬性,然後設定Dockerfile為始終複製,這樣後續更新變動,釋出時就會自動拷貝到對應的釋出目錄。

3.2 以檔案的形式釋出專案,並連同Dockerfile拷貝到安裝好Docker的機器上進行構建(這裡還是用我的雲伺服器);

docker build -t myimage:v1.0 .解析

  • -t:指定映象的名字及標籤,通常 name:tag 或者 name 格式,myimage就是映象名字,v1.0就是tag;
  • -f :指定要使用的Dockerfile路徑,這裡由於Dockerfile在當前路徑,所以不用指定;
  • 最後面的點官方稱為構建上下文,點表示指定為當前目錄。 會把指定的這個目錄下的檔案傳送給docker daemon進行構建,所以千萬不要指定/(斜槓代表根目錄,有很多檔案的)。
  • 其他選項引數小夥伴可以根據需要使用,以上是比較重要的。
3.3 根據構建出來的映象啟動容器,看Dockerfile中的命令效果;

啟動容器如下:

ENTRYPOINT ["dotnet", "DockerfileDemo.dll"]這行程式碼就等同於的專案目錄下直接執行 dotnet DockerfileDemo.dll是一樣的,目的就是啟動我們的專案

通過docker logs可以檢視容器內部的日誌,如下:

3.4 豐富化Dockefile檔案內容並檢視構建之後的細節

檔案內容如下:

 # 指定基礎映象,在此基礎上構建自己的專案映象
 FROM mcr.microsoft.com/dotnet/core/aspnet:3.1
 # 指定維護人
 MAINTAINER CodeZYQ<1137533407@qq.com>
 # 打標籤
 LABEL createname="CodeZYQ"
 # 指定自己的工作目錄,進入容器時目錄 app
 WORKDIR /myapp
 # 將構建上下文目錄下的檔案拷貝到容器中的工作目錄中
 COPY . .
 # 定義變數
 ARG myPort=8080
 # 使用環境變數方式改變啟動埠,拼接用到了定義的變數
 ENV ASPNETCORE_URLS=http://+:$myPort
 # 通過RUN 執行相關命令,根據需要執行相關命令
 RUN mkdir testDir
 # 掛載資料卷,這裡模擬掛載日誌目錄
 VOLUME /Logs
 # 容器向外暴露埠,專案以什麼埠啟動就暴露對應的埠
 EXPOSE $myPort
 # 執行命令,這裡預設是以80埠啟動的
 # 就類似於在Linux系統的專案目錄下執行 dotnet DockerfileDemo.dll 是一樣的
 ENTRYPOINT ["dotnet", "DockerfileDemo.dll"]

執行如下命令,構建新的映象:

 # 這裡沒有顯示指定tag 預設就latest
 docker build -t newimage .

通過docker logs看看容器日誌,如下:

看看資料卷掛載是否成功,進入容器,看根目錄下就會多了Logs目錄,也可以通過docker inspect 容器 看容器詳細資訊,如下:

標籤也打成功了:

也可以通過docker inspect 映象檢視映象內部的詳細資訊,執行命令docker inspect newimage如下:

關於步驟和效果,在Dockerfile註釋和圖表中已經詳細描述。

3.5 CMD和ENTRYPOINT的區別

兩個命令都是啟動容器時指定執行命令和對應的引數,但兩者稍有不同,如下:

  • CMD:只能最後一個命令會生效,命令會被docker run之後的引數替換掉;
  • ENTRYPOINT:可以追加命令,比如增加引數;

上面構建出來的newimage映象用到的是ENTRYPOINT,所以我們先來測試一下ENTRYPOINT,如下:

docker run啟動容器時指定了引數 --urls="http://+:9999",容器正常啟動,並且引數還能生效,等同於在當前目錄直接執行如下命令:

 dotnet DockerfileDemo.dll --urls="http://+:9999"

現在把ENTRYPOINT換成CMD試試,如下:

 # 在以上的Dockerfile中
 # 將ENTRYPOINT ["dotnet", "DockerfileDemo.dll"]換成CMD,如下:
 CMD ["dotnet", "DockerfileDemo.dll"]

然後重新構建一個映象試試,測試如下:

如上圖,對於CMD而言,如果在執行容器時,後面指定引數,這個引數就會把CMD命令替換掉,不能拼接,導致命令不對,所以報錯;但這樣就可以執行,如下:

如果在當前構建的上下文目錄中不想要一些檔案參與構建,可以通過在.dockerignore檔案中進行配置,這個和git中的.gitignore一個道理,編寫也比較簡單,這裡就不演示了。

對了,.NetCore的映象列表可以參照這個地址:https://hub.docker.com/_/microsoft-dotnet-aspnet/,每個映象都有對應的Dockerfile,感興趣的小夥伴可以點進去看看,參考參考。

總結

關於Dockerfile的演示就先說那麼多,小夥伴們一定要舉一反三,上面演示只是一個小例子而已,在正式專案中可以根據需要,編輯出屬於符合需求的Dockefile檔案,最終構建出方便、好用的映象,這樣開發和運維就和諧了(嘿嘿嘿)。

Docker之前文章目錄:

  1. Docker小白到實戰之開篇概述
  2. Docker小白到實戰之常用命令演示,通俗易懂
  3. Docker小白到實戰之容器資料卷,整理的明明白白

好了,下次聊聊Docker中的網路應用,關注“Code綜藝圈”,和我一起學習吧;

圖片

相關文章