Dockerfile詳解

2023-02-02 12:01:30

本文基於應用容器引擎-Docker繼續講解DockerFile的有關知識。在學習完Dockerfile的知識後,你可以自己獨立部署一個前後端分離的專案,具體部署操作可以瀏覽我之前的部落格:部署實戰-Docker+nginx部署前後端分離專案
@Author:Akai-yuan
@更新時間:2023/2/2

1.Dockerfile是什麼

Dockerfile 是一個用來構建映象的文字檔案
我們直接從倉庫獲取的映象可能很多時候是不滿足我們的需求,比如你有這個需求場景:部署你的SpringBoot專案:

1.基於JDK1.8的映象
2.需要將自己的jar等檔案放到映象目錄
3.執行映象後需要啟動SpringBoot專案

這時候如果直接從倉庫獲取映象,然後執行成容器,並進入容器部署自己的專案,這一列操作就非常麻煩。
而如果有的Dockerfile,則可以一次性生成滿足你需求的自有映象。

2.Dockerfile構建映象範例

以下範例將展示:如何構建一個基於JDK1.8的SpringBoot專案

1、新增一個目錄

例如:/usr/local/dockerfile

2、新增Dockerfile檔案

在上面的目錄下建立一個Dockerfile檔案,檔名最好使用Dockerfile,這樣生成映象的命令就不用指定檔案了,檔案內容如下:

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY *.jar demo.jar
ENTRYPOINT ["java","-jar","/demo.jar"]

3、將Jar包放到目錄下

可以使用Idea連線遠端伺服器,也可以通過Xftp上傳,或者在Xshell中執行rz指令
關於linux中的rz命令:

rz [選項]

選項說明:
-+, --append:將檔案內容追加到已存在的同名檔案
-a,--ascii:以文字方式傳輸
-b, --binary:以二進位制方式傳輸,推薦使用
--delay-startup N:等待N秒
-e, --escape:對所有控制字元跳脫,建議使用
-E, --rename:已存在同名檔案則重新命名新上傳的檔案,以點和數位作為字尾
-p, --protect:對ZMODEM協定有效,如果目標檔案已存在則跳過 -
-q, --quiet:安靜執行,不輸出提示資訊
-v, --verbose:輸出傳輸過程中的提示資訊
-y, --overwrite:存在同名檔案則替換
-X, --xmodem:使用XMODEM協定
--ymodem:使用YMODEM協定
-Z, --zmodem:使用ZMODEM協定
--version:顯示版本資訊
--h, --help:顯示幫助資訊

但是其實博主在使用rz命令從使用者端上傳檔案到伺服器端時,經常會遇到上傳異常中斷,然後生成亂碼檔案,此時還需要rm -rf 檔名清除掉指定檔案。所以其實能用Xftp的話還是儘量避免使用rz。

4、生成映象

docker build -t 映象名稱:標籤名 .

docker build -t demo:v1 .

生成完成之後,檢視本地映象:

docker ps

以上就是一個簡單的Dockerfile構建映象的範例

3.Dockerfile構建命令詳解

1.FROM

FROM命令是Dockerfile檔案的開始,標識建立的映象是基於哪個映象
格式:FROM 映象名[:標籤名]

FROM 映象名[:標籤名]

# 範例1:基於Nginx
FROM nginx

# 範例2:基於openjdk:8-jdk-alpine
FROM openjdk:8-jdk-alpine

2.COPY

複製指令,從上下文目錄中複製檔案或者目錄到容器裡指定路徑
格式:

COPY [--chown=:] <源路徑1>...  <目標路徑>
COPY [--chown=:] ["<源路徑1>",...  "<目標路徑>"]

  
# 將以hom開頭的檔案和目錄拷貝到容器目錄下
COPY hom* /mydir/
# 將一些檔案拷貝到容器目錄下
COPY hom?.txt /mydir/
# 將一個檔案拷貝到容器,並重新命名
COPY xxxx.jar abc.jar

3.ADD

ADD 指令和 COPY 的使用格類似(同樣需求下,官方推薦使用 COPY)。功能也類似,不同之處如下:
ADD 的優點:
在執行 <原始檔> 為 tar 壓縮檔案的話,壓縮格式為 gzip, bzip2 以及 xz 的情況下,會自動複製並解壓到 <目標路徑>。
ADD 的缺點:
在不解壓的前提下,無法複製 tar 壓縮檔案。會令映象構建快取失效,從而可能會令映象構建變得比較緩慢。具體是否使用,可以根據是否需要自動解壓來決定。

4.RUN

用於執行後面跟著的命令列命令。
注意:RUN是在docker build時執行,而非docker run時執行
Shell格式:

RUN <shell 命令>

# 範例一
FROM centos
RUN yum -y install wget
RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
RUN tar -xvf redis.tar.gz

# 範例二,合併簡化
FROM centos
RUN yum -y install wget \
&& wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
&& tar -xvf redis.tar.gz

exec格式:

RUN ["可執行檔案", "引數1", "引數2"]

# 等價於 RUN ./test.php dev offline
RUN ["./test.php", "dev", "offline"] 

5.CMD

類似於 RUN 指令,用於執行程式。與RUN不同的是,CMD命令是在docker run時執行
格式:

CMD <shell 命令> 
CMD ["<可執行檔案或命令>","<param1>","<param2>",...] 
CMD ["<param1>","<param2>",...]  # 該寫法是為 ENTRYPOINT 指令指定的程式提供預設引數

推薦使用第二種格式,執行過程比較明確。第一種格式實際上在執行的過程中也會自動轉換成第二種格式執行,並且預設可執行檔案是 sh。

範例:

# CMD <shell 命令> 
CMD java -jar demo.jar

# CMD ["<可執行檔案或命令>","<param1>","<param2>",...] 
CMD ["java","-jar","demo.jar"]

# CMD ["<param1>","<param2>",...] 為 ENTRYPOINT 指令指定的程式提供預設引數
CMD ["/etc/nginx/nginx.conf"]

6.ENTRYPOINT
類似於 CMD 指令,但其不會被 docker run 的命令列引數指定的指令所覆蓋,而且這些命令列引數會被當作引數送給 ENTRYPOINT 指令指定的程式。
但是, 如果執行 docker run 時使用了 --entrypoint 選項,將覆蓋 ENTRYPOINT 指令指定的程式。
優點:在執行 docker run 的時候可以指定 ENTRYPOINT 執行所需的引數。
注意:如果 Dockerfile 中如果存在多個 ENTRYPOINT 指令,僅最後一個生效。
格式:

ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是變參才會使用 CMD ,這裡的 CMD 等於是在給 ENTRYPOINT 傳參,見以下範例。

範例:
假設已通過 Dockerfile 構建了 nginx:test 映象:

FROM nginx
ENTRYPOINT ["nginx", "-c"] # 可以在docker run -c 指定引數
CMD ["/etc/nginx/nginx.conf"] # 給ENTRYPOINT約定預設引數

不傳參執行:

docker run  nginx:test
# 相當於nginx -c /etc/nginx/nginx.conf

傳參執行:

docker run  nginx:test -c /etc/nginx/new.conf
# 忽略CMD中的引數,使用自定義引數

7.ENV
設定環境變數,定義了環境變數,那麼在後續的指令中,就可以使用這個環境變數
格式:

ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下範例設定 NODE_VERSION = 7.2.0 , 在後續的指令中可以通過 $NODE_VERSION 參照:

ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
  && curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

8.ARG
構建引數,與 ENV 作用一致。不過作用域不一樣。ARG 設定的環境變數僅對 Dockerfile 內有效,也就是說只有 docker build 的過程中有效,構建好的映象內不存在此環境變數。
構建命令 docker build 中可以用 --build-arg <引數名>=<值> 來覆蓋。
格式:

ARG <引數名>[=<預設值>]

9.VOLUME
定義匿名資料卷。在啟動容器時忘記掛載資料卷,會自動掛載到匿名卷。
作用:
避免重要的資料,因容器重啟而丟失,這是非常致命的。
避免容器不斷變大。
格式:

VOLUME ["<路徑1>", "<路徑2>"...]
VOLUME <路徑>

在啟動容器 docker run 的時候,我們可以通過 -v 引數修改掛載點。

10.EXPOSE

僅僅只是宣告埠。
作用:
幫助映象使用者理解這個映象服務的守護埠,以方便設定對映。
在執行時使用隨機埠對映時,也就是 docker run -P 時,會自動隨機對映 EXPOSE 的埠。
格式:

EXPOSE <埠1> [<埠2>...]

11.WORKDIR
指定工作目錄。用 WORKDIR 指定的工作目錄,會在構建映象的每一層中都存在。(WORKDIR 指定的工作目錄,必須是提前建立好的)。
docker build 構建映象過程中的,每一個 RUN 命令都是新建的一層。只有通過 WORKDIR 建立的目錄才會一直存在。
格式:

WORKDIR <工作目錄路徑>

12.USER
用於指定執行後續命令的使用者和使用者組,這邊只是切換後續命令執行的使用者(使用者和使用者組必須提前已經存在)。
格式:

USER <使用者名稱>[:<使用者組>]

13.HEALTHCHECK

用於指定某個程式或者指令來監控 docker 容器服務的執行狀態。
格式:

HEALTHCHECK [選項] CMD <命令>:設定檢查容器健康狀況的命令
HEALTHCHECK NONE:如果基礎映象有健康檢查指令,使用這行可以遮蔽掉其健康檢查指令

14.ONBUILD
用於延遲構建命令的執行。簡單的說,就是 Dockerfile 裡用 ONBUILD 指定的命令,在本次構建映象的過程中不會執行(假設映象為 test-build)。當有新的 Dockerfile 使用了之前構建的映象 FROM test-build ,這時執行新映象的 Dockerfile 構建時候,會執行 test-build 的 Dockerfile 裡的 ONBUILD 指定的命令。
格式:

ONBUILD <其它指令>

15.LABEL

LABEL 指令用來給映象新增一些後設資料(metadata),以鍵值對的形式,語法格式如下:

LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如我們可以新增映象的作者:

LABEL org.opencontainers.image.authors="runoob"

4.構建映象命令

# 格式
docker build [OPTIONS] PATH | URL | -

# 範例
docker build -t 映象名:標籤名 .

引數說明:

–build-arg=[] :設定映象建立時的變數;
–cpu-shares :設定 cpu 使用權重;
–cpu-period :限制 CPU CFS週期;
–cpu-quota :限制 CPU CFS配額;
–cpuset-cpus :指定使用的CPU id;
–cpuset-mems :指定使用的記憶體 id;
–disable-content-trust :忽略校驗,預設開啟;
-f :指定要使用的Dockerfile路徑;
–force-rm :設定映象過程中刪除中間容器;
–isolation :使用容器隔離技術;
–label=[] :設定映象使用的後設資料;
-m :設定記憶體最大值;
–memory-swap :設定Swap的最大值為記憶體+swap,"-1"表示不限swap;
–no-cache :建立映象的過程不使用快取;
–pull :嘗試去更新映象的新版本;
–quiet, -q :安靜模式,成功後只輸出映象 ID;
–rm :設定映象成功後刪除中間容器;
–shm-size :設定/dev/shm的大小,預設值是64M;
–ulimit :Ulimit設定。
–squash :將 Dockerfile 中所有的操作壓縮為一層。
-t: 映象的名字及標籤,通常 name:tag 或者 name 格式;可以在一次構建中為一個映象設定多個標籤。
–network: 預設 default。在構建期間設定RUN指令的網路模式