Docker 鏡像構建之 Dockerfile


在 Docker 中構建鏡像最常用的方式,就是使用 Dockerfile。Dockerfile 是一個用來構建鏡像的文本文件,文本內容包含了一條條構建鏡像所需的指令和說明。官方文檔:https://docs.docker.com/engine/reference/builder/

  

Dockerfile 常用指令

  

FROM

  

  語法:FROM <image>:<tag>

  指明構建的新鏡像是來自於哪個基礎鏡像,如果沒有選擇 tag,那么默認值為 latest。

FROM centos:7

  如果不以任何鏡像為基礎,那么寫法為:FROM scratch。官方說明:scratch 鏡像是一個空鏡像,可以用於構建 busybox 等超小鏡像,可以說是真正的從零開始構建屬於自己的鏡像。

  

MAINTAINER(deprecated)

  

  語法:MAINTAINER <name>

  指明鏡像維護者及其聯系方式(一般是郵箱地址)。官方說明已過時,推薦使用 LABEL。

MAINTAINER mrhelloworld <mrhelloworld@126.com>

  

LABEL

  

  語法:LABEL <key>=<value> <key>=<value> <key>=<value> ...

  功能是為鏡像指定標簽。也可以使用 LABEL 來指定鏡像作者。

LABEL maintainer="mrhelloworld.com"

  

RUN

  

  語法:RUN <command>

  構建鏡像時運行的 Shell 命令,比如構建的新鏡像中我們想在 /usr/local 目錄下創建一個 java 目錄。

RUN mkdir -p /usr/local/java

  

ADD

  

  語法:ADD <src>... <dest>

  拷貝文件或目錄到鏡像中。src 可以是一個本地文件或者是一個本地壓縮文件,壓縮文件會自動解壓。還可以是一個 url,如果把 src 寫成一個 url,那么 ADD 就類似於 wget 命令,然后自動下載和解壓。

ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java

  

COPY

  

  語法:COPY <src>... <dest>

  拷貝文件或目錄到鏡像中。用法同 ADD,只是不支持自動下載和解壓。

COPY jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java

  

EXPOSE

  

  語法:EXPOSE <port> [<port>/<protocol>...]

  暴露容器運行時的監聽端口給外部,可以指定端口是監聽 TCP 還是 UDP,如果未指定協議,則默認為 TCP。

EXPOSE 80 443 8080/tcp

如果想使得容器與宿主機的端口有映射關系,必須在容器啟動的時候加上 -P 參數。

  

ENV

  

  語法:ENV <key> <value> 添加單個,ENV <key>=<value> ... 添加多個。

  設置容器內環境變量。

ENV JAVA_HOME /usr/local/java/jdk-11.0.6/

  

CMD

  

  語法:

  • CMD ["executable","param1","param2"],比如:CMD ["/usr/local/tomcat/bin/catalina.sh", "start"]
  • CMD ["param1","param2"] ,比如:CMD [ "echo", "$JAVA_HOME" ]
  • CMD command param1 param2,比如:CMD echo $JAVA_HOME

  啟動容器時執行的 Shell 命令。在 Dockerfile 中只能有一條 CMD 指令。如果設置了多條 CMD,只有最后一條 CMD 會生效。

CMD ehco $JAVA_HOME

  如果創建容器的時候指定了命令,則 CMD 命令會被替代。假如鏡像叫 centos:7,創建容器時命令是:docker run -it --name centos7 centos:7 echo "helloworld" 或者 docker run -it --name centos7 centos:7 /bin/bash,就不會輸出 $JAVA_HOME 的環境變量信息了,因為 CMD 命令被 echo "helloworld"/bin/bash 覆蓋了。

  

ENTRYPOINT

  

  語法:

  • ENTRYPOINT ["executable", "param1", "param2"],比如:ENTRYPOINT ["/usr/local/tomcat/bin/catalina.sh", "start"]
  • ENTRYPOINT command param1 param2,比如:ENTRYPOINT ehco $JAVA_HOME

  啟動容器時執行的 Shell 命令,同 CMD 類似,不會被 docker run 命令行指定的參數所覆蓋。在 Dockerfile 中只能有一條 ENTRYPOINT 指令。如果設置了多條 ENTRYPOINT,只有最后一條 ENTRYPOINT 會生效。

ENTRYPOINT ehco $JAVA_HOME
  • 如果在 Dockerfile 中同時寫了 ENTRYPOINT 和 CMD,並且 CMD 指令不是一個完整的可執行命令,那么 CMD 指定的內容將會作為 ENTRYPOINT 的參數;
  • 如果在 Dockerfile 中同時寫了 ENTRYPOINT 和 CMD,並且 CMD 是一個完整的指令,那么它們兩個會互相覆蓋,誰在最后誰生效

  

WORKDIR

  

  語法:WORKDIR /path/to/workdir

  為 RUN、CMD、ENTRYPOINT 以及 COPY 和 AND 設置工作目錄。

WORKDIR /usr/local

  

VOLUME

  

  指定容器掛載點到宿主機自動生成的目錄或其他容器。一般的使用場景為需要持久化存儲數據時。

# 容器的 /var/lib/mysql 目錄會在運行時自動掛載為匿名卷,匿名卷在宿主機的 /var/lib/docker/volumes 目錄下
VOLUME ["/var/lib/mysql"]

一般不會在 Dockerfile 中用到,更常見的還是在 docker run 的時候通過 -v 指定數據卷。

  

構建鏡像

  

  Dockerfile 文件編寫好以后,真正構建鏡像時需要通過 docker build 命令。

  docker build 命令用於使用 Dockerfile 創建鏡像。

# 使用當前目錄的 Dockerfile 創建鏡像
docker build -t mycentos:7 .
# 通過 -f Dockerfile 文件的位置創建鏡像
docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 .
  • -f:指定要使用的 Dockerfile 路徑;
  • --tag, -t:鏡像的名字及標簽,可以在一次構建中為一個鏡像設置多個標簽。

  

關於 . 理解

  

  我們在使用 docker build 命令去構建鏡像時,往往會看到命令最后會有一個 . 號。它究竟是什么意思呢?

  很多人以為是用來指定 Dockerfile 文件所在的位置的,但其實 -f 參數才是用來指定 Dockerfile 的路徑的,那么 . 號究竟是用來做什么的呢?

  Docker 在運行時分為 Docker 引擎(服務端守護進程)客戶端工具,我們日常使用各種 docker 命令,其實就是在使用 客戶端工具Docker 引擎 進行交互。

  當我們使用 docker build 命令來構建鏡像時,這個構建過程其實是在 Docker 引擎 中完成的,而不是在本機環境。如果在 Dockerfile 中使用了一些 ADD 等指令來操作文件,如何讓 Docker 引擎 獲取到這些文件呢?

  這里就有了一個 鏡像構建上下文 的概念,當構建的時候,由用戶指定構建鏡像時的上下文路徑,而 docker build 會將這個路徑下所有的文件都打包上傳給 Docker 引擎,引擎內將這些內容展開后,就能獲取到上下文中的文件了。

  

  舉個栗子:我的宿主機 jdk 文件在 /root 目錄下,Dockerfile 文件在 /usr/local/dockerfile 目錄下,文件內容如下:

ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java

  那么構建鏡像時的命令就該這樣寫:

docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 /root

  

  再舉個栗子:我的宿主機 jdk 文件和 Dockerfile 文件都在 /usr/local/dockerfile 目錄下,文件內容如下:

ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java

  那么構建鏡像時的命令則這樣寫:

docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 .

  

Dockerfile 實踐

  

  接下來我們通過基礎鏡像 centos:7,在該鏡像中安裝 jdk 和 tomcat 以后將其制作為一個新的鏡像 mycentos:7

  創建目錄。

mkdir -p /usr/local/dockerfile

  編寫 Dockerfile 文件。

vi Dockerfile

  Dockerfile 文件內容如下:

# 指明構建的新鏡像是來自於 centos:7 基礎鏡像
FROM centos:7
# 通過鏡像標簽聲明了作者信息
LABEL maintainer="mrhelloworld.com"
# 設置工作目錄
WORKDIR /usr/local
# 新鏡像構建成功以后創建指定目錄
RUN mkdir -p /usr/local/java && mkdir -p /usr/local/tomcat
# 拷貝文件到鏡像中並解壓
ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java
ADD apache-tomcat-9.0.37.tar.gz /usr/local/tomcat
# 暴露容器運行時的 8080 監聽端口給外部
EXPOSE 8080
# 設置容器內 JAVA_HOME 環境變量
ENV JAVA_HOME /usr/local/java/jdk-11.0.6/
ENV PATH $PATH:$JAVA_HOME/bin
# 啟動容器時啟動 tomcat
CMD ["/usr/local/tomcat/apache-tomcat-9.0.37/bin/catalina.sh", "run"]

  構建鏡像。

[root@localhost ~]# docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 /root/
Sending build context to Docker daemon  191.4MB
Step 1/10 : FROM centos:7
 ---> 7e6257c9f8d8
Step 2/10 : LABEL maintainer="mrhelloworld.com"
 ---> Running in 3f18aa4f3fb2
Removing intermediate container 3f18aa4f3fb2
 ---> 7364f68ca4ab
Step 3/10 : WORKDIR /usr/local
 ---> Running in d9889152cfc4
Removing intermediate container d9889152cfc4
 ---> d05bd2e09fa4
Step 4/10 : RUN mkdir -p /usr/local/java && mkdir -p /usr/local/tomcat
 ---> Running in 3bcd6ef78350
Removing intermediate container 3bcd6ef78350
 ---> 4832abf9d769
Step 5/10 : ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java
 ---> e61474bf7a76
Step 6/10 : ADD apache-tomcat-9.0.37.tar.gz /usr/local/tomcat
 ---> 7110cdff7438
Step 7/10 : EXPOSE 8080
 ---> Running in a4731c1cf77d
Removing intermediate container a4731c1cf77d
 ---> f893cefee00c
Step 8/10 : ENV JAVA_HOME /usr/local/java/jdk-11.0.6/
 ---> Running in f0cb08f390db
Removing intermediate container f0cb08f390db
 ---> ff9f6acf6844
Step 9/10 : ENV PATH $PATH:$JAVA_HOME/bin
 ---> Running in eae88cf841d0
Removing intermediate container eae88cf841d0
 ---> 4b9226a23b10
Step 10/10 : CMD ["/usr/local/tomcat/apache-tomcat-9.0.37/bin/catalina.sh", "run"]
 ---> Running in ccf481045906
Removing intermediate container ccf481045906
 ---> 9ef76a16441b
Successfully built 9ef76a16441b
Successfully tagged mycentos:7

  

鏡像構建歷史

  

docker history 鏡像名稱:標簽|ID
docker history mycentos:7

  

使用構建的鏡像創建容器

  

# 創建容器
docker run -di --name mycentos7 -p 8080:8080 mycentos:7
# 進入容器
docker exec -it mycentos7 /bin/bash
# 測試 java 環境變量
[root@dcae87df010b /]# java -version
java version "11.0.6" 2020-01-14 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.6+8-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.6+8-LTS, mixed mode)
# 訪問 http://192.168.10.10:8080/ 看到頁面說明環境 OK!

太棒了,Dockerfile 構建鏡像的方式你也學會了,再接再厲學習一下 Docker 鏡像的備份恢復遷移,go ~

本文采用 知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議

大家可以通過 分類 查看更多關於 Docker 的文章。

  

🤗 您的點贊轉發是對我最大的支持。

📢 掃碼關注 哈嘍沃德先生「文檔 + 視頻」每篇文章都配有專門視頻講解,學習更輕松噢 ~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM