【Docker】(10)---詳細說說 Dockerfile檔案

雨點的名字發表於2021-10-19

一、基礎概念

1、基本概念

Dockerfile 是一個文字檔案,其內包含了一條條的指令,每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建。有了 Dockerfile,當我們需要定製額外的

需求時,只需在 Dockerfile上新增或者修改指令,重新生成image即可,省去了敲命令的麻煩。

2、檔案格式

Dockerfile由一行行命令語句組成,並且支援用“#”開頭作為註釋,一般的Dockerfile分為四部分:基礎映象資訊維護者資訊映象操作指令容器啟動時執行的指令


二、基礎命令

1、FROM

指定base映象。

# 製作基準映象
FROM 映象
# 比如我們要釋出一個應用到tomcat裡,那麼的第一步就是FROM tomcat
FROM tomcat<:tags>

第一條指令必須為FROM指令,並且,如果在同一個Dockerfile中建立多個映象時,可以使用多個FROM指令(每個映象一次)

2、LABEL&MAINTAINER

指定維護者的資訊。

# MAINTAINER,一般寫個人id或組織id
# LABEL 就是註釋,方便閱讀的,純註釋說明。不會對Dockerfile造成任何影響
# 比如:
MAINTAINER zhangsan
LABEL version = "1.0.0"
LABEL description = "我們是大百度!"
# ...等等描述性資訊,純註釋。

3、WORKDIR

類似於Linux中的cd命令,但是他比cd高階的地方在於,我先cd,發現沒有這個目錄,我就自動建立出來,然後在cd進去,為後續的RUN 、 CMD 、 ENTRYPOINT

指令配置工作目錄。

WORKDIR /usr/local/testdir

4、COPY

將檔案從 本地 複製到映象。

# 示例
# 將1.txt拷貝到根目錄下。它不僅僅能拷貝單個檔案,還支援Go語言風格的萬用字元,比如如下:
COPY 1.txt /
# 拷貝所有 abc 開頭的檔案到testdir目錄下
COPY abc* /testdir/
# ? 是單個字元的佔位符,比如匹配檔案 abc1.log
COPY abc?.log /testdir/

5、ADD

將檔案從 本地 複製到映象。可以是Dockerfile所在的目錄的一個相對路徑;可以是URL,也可以是tar.gz(自動解壓)

# 示例
# 將1.txt拷貝到根目錄的abc目錄下。若/abc不存在,則會自動建立
ADD 1.txt /abc
# 將test.tar.gz解壓縮然後將解壓縮的內容拷貝到/home/work/test
ADD test.tar.gz /home/work/test

docker官方建議當要從遠端複製檔案時,儘量用curl/wget命令來代替ADD。因為用ADD的時候會建立更多的映象層。映象層的size也大。

6、COPY與ADD比較

1)COPY能幹的事ADD都能幹,甚至還有附加功能。

2) ADD可以支援拷貝的時候順帶解壓縮檔案,以及新增遠端檔案(不在本宿主機上的檔案)類似wget。

3) 只是檔案拷貝的話可以用COPY,有額外操作只能用ADD代替。

7、ENV

設定環境變數,環境變數可被後面的指令使用。例如:

# 設定環境常量,方便下文引用,比如:
ENV JAVA_HOME /usr/local/jdk1.8
# 引用上面的常量,下面的RUN指令可以先不管啥意思,目的是想說明下文可以通過${xxx}的方式引用
RUN ${JAVA_HOME}/bin/java -jar xxx.jar

8、VOLUME

建立一個可以從本地主機或其他容器掛載的掛載點,一般用來存放資料庫和需要保持的資料等。後面單獨文章講解。

 VOLUME ["/data"]

三、執行指令

一共有三個:RUN、CMD、ENTRYPOINT

1、RUN

構建映象時執行的命令。

1.1 執行時機

RUN指令是在構建映象時執行,在構建時能修改映象內部的檔案。每條指令將在當前映象基礎上執行,並提交為新的映象。

1.2 命令格式

: 命令格式不光是RUN獨有,而是下面的CMD和ENTRYPOINT都通用。

SHELL命令格式

RUN yum -y install vim

EXEC命令格式

RUN ["yum","-y","install","vim"]

二者對比

SHELL:當前shell是父程式,生成一個子shell程式去執行指令碼,指令碼執行完後退出子shell程式,回到當前父shell程式。

EXEC:用EXEC程式替換當前程式,並且保持PID不變,執行完畢後直接退出,不會退回原來的程式。

總結:也就是說shell會建立子程式執行,EXEC不會建立子程式。

1.3 舉例

舉個最簡單的例子,構建映象時輸出一句話,那麼在Dockerfile裡寫如下即可:

RUN ["echo", "image is building!!!"]

再比如我們要下載vim,那麼在Dockerfile裡寫如下即可:

RUN ["yum","-y","install","vim"]

下面會有實戰來完完整整的演示。

2、CMD

2.1 執行時機

容器啟動時執行,而不是映象構建時執行。

2.2 解釋說明

容器啟動時執行指定的命令。

Dockerfile 中可以有多個 CMD 指令,但只有最後一個生效。重點在於如果容器啟動的時候有其他額外的附加指令,則CMD指令不生效

2.3 舉例

CMD ["echo", "container starting..."]

3、ENTRYPOINT

3.1 執行時機

容器建立時執行,而不是映象構建時執行。

3.2 解釋說明

在容器啟動的時候執行此命令,且Dockerfile中只有最後一個ENTRYPOINT會被執行,推薦用EXEC格式。

3.3 舉例

ENTRYPOINT ["ps","-ef"]

4、RUN vs CMD vs ENTRYPOINT

簡單的說:

1、RUN 執行命令並建立新的映象層,RUN 經常用於安裝軟體包。
2、CMD 設定容器啟動後預設執行的命令及其引數,但 CMD 能夠被 docker run 後面跟的命令列引數替換。
3、ENTRYPOINT 配置容器啟動時執行的命令。

RUN

RUN是在構建層面的,就是每執行一個RUN,就代表多一層。所以我們經常會用於安裝軟體包,好比 RUN yum -y install vim。執行這個命令就是讓當前映象可以支援vim指令。

CMD

CMD 指令允許使用者指定容器的預設執行的命令。此命令會在容器啟動且 docker run 沒有指定其他命令時執行。如果 docker run 指定了其他命令,CMD 命令將被忽略。

如果 Dockerfile 中有多個 CMD 指令,只有最後一個 CMD 有效。

ENTRYPOINT

ENTRYPOINT 指令可讓容器以應用程式或者服務的形式執行。ENTRYPOINT 看上去與 CMD 很像,它們都可以指定要執行的命令及其引數。不同的地方在於 ENTRYPOINT

不會被忽略,一定會被執行,即使執行 docker run 時指定了其他命令。

5、RUN VS CMD案例

上面雖然用文字闡述了它們之間的區別,但是估計還是會有點不太明白,所以這裡通過一個小小案例來理解。

建立Dockerfile,並新增如下內容

FROM centos
RUN ["echo", "image building!!!"]
CMD ["echo", "container starting..."]

構建映象

docker build -t runvscmd-test .
【Docker】(10)---詳細說說 Dockerfile檔案

可以看出構建映象的過程中發現RUN的image building!!! 輸出了,所以RUN命令是在映象構建時執行。而並沒有container starting…的輸出。

啟動容器

docker run runvscmd-test
【Docker】(10)---詳細說說 Dockerfile檔案

啟動容器的時候 container starting...,足以發現CMD命令是在容器啟動的時候執行。

總結: 這就是上面所說的 run是 構建映象 時候的指令,CMD和ENTRYPOINT是啟動容器時的指令。

接下來在舉個例子來理解區分CMD和ENTRYPOINT。

6、CMD VS ENTRYPOINT案例

ENTRYPOINT和CMD可以共用,若共用則他會一起合併執行。如下Demo:

FROM centos
RUN ["echo", "image building!!!"]
ENTRYPOINT ["ps"]
CMD ["-ef"]

構建啟動容器

# 構建映象
docker build -t docker-test .
# 啟動容器
docker run docker-test

輸出結果

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 13:02 ?        00:00:00 ps -ef

他給我們合併執行了:ps -ef,這麼做的好處在於如果容器啟動的時候新增額外指令,CMD會失效,可以理解成我們可以動態的改變CMD內容而不需要重新構建映象等操作。比如

docker run docker-test -aux

輸出結果:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.0  0.0  46340  1692 ?        Rs   13:02   0:00 ps -aux

結果直接變成了 ps -aux,CMD命令不執行了。

總結:從這個示例中就可以看出區別,ENTRYPOINT無論容器啟動是否帶引數,都會執行。而CMD就不一樣。上面沒帶引數那麼它就會被執行。而下面帶了 -aux,

CMD指令就不會執行了。


四、專案實戰

這裡就是以當前自己的vue專案來演示,正常不用docker,那麼就是先打包專案,npm run bulid,再啟動專案 npm run start。

但是因為vue專案依賴Node,就好像我們java專案依賴JDk一樣。所以不同環境版本一直很重要,所以這裡通過映象來啟動專案。

1、DockerFile檔案

在vue專案當前目錄建立DockerFile檔案,並寫入以下指令碼。

#獲取基礎映象
FROM node:12.17
#指定作者
MAINTAINER xiaoxiao
#指定工作目錄
WORKDIR /app
#將當前根目錄的vue專案所有檔案,都移動到/app目錄下
#COPY package*.json ./
COPY . .
##安裝專案相關依賴
RUN npm install
#將當前根目錄的vue專案所有檔案,都移動到/app目錄下
#打包專案
RUN npm run build
#暴露埠
EXPOSE 8000
#啟動專案
ENTRYPOINT ["npm","run","start"]

2、構建映象

命令

# docker build代表構建映象 -t後面指定生成映象名稱 .代表在當前目錄構建
docker build -t xiaoxiao-web .
【Docker】(10)---詳細說說 Dockerfile檔案

構建映象命令執行完後,我們可以看下該映象有沒有建立成功

【Docker】(10)---詳細說說 Dockerfile檔案

可以看出映象已經構建成功,不過映象有點大。

3、啟動容器

# docker run表示啟動容器 -d 在後臺執行 --name 容器的名稱 -p埠對映 xiaoxiao-web就是指定哪個映象
docker run -d --name=xiaoxiao-run-web -p 7000:8000 xiaoxiao-web
【Docker】(10)---詳細說說 Dockerfile檔案

說明容器已經啟動成功。

4、進入容器

#09ff5738660e 為容器ID
docker  exec -it 09ff5738660e /bin/bash
【Docker】(10)---詳細說說 Dockerfile檔案

從這裡可以看出2點 1:我一進來就是根目錄就是/app 這就是上面我們自己設定的工作目錄。2:前端專案檔案已經都拷貝到當前根目錄下。

5、訪問專案

【Docker】(10)---詳細說說 Dockerfile檔案

成功


參考

1、《每天5分鐘玩轉 Docker 容器技術》書籍

2、面試官:你說你精通 Docker,那你來詳細說說 Dockerfile 吧

3、DockerFile 詳解


相關文章