1. 程式人生 > >Docker 映象構建之 Dockerfile

Docker 映象構建之 Dockerfile

  在 Docker 中構建映象最常用的方式,就是使用 `Dockerfile`。Dockerfile 是一個用來構建映象的文字檔案,文字內容包含了一條條構建映象所需的指令和說明。官方文件:https://docs.docker.com/engine/reference/builder/    ## Dockerfile 常用指令    ### FROM      語法:`FROM :`   指明構建的新映象是來自於哪個基礎映象,如果沒有選擇 tag,那麼預設值為 latest。 ```shell FROM centos:7 ``` >   如果不以任何映象為基礎,那麼寫法為:FROM scratch。官方說明:scratch 映象是一個空映象,可以用於構建 busybox 等超小映象,可以說是真正的從零開始構建屬於自己的映象。    ### ~~MAINTAINER~~(deprecated)      語法:`MAINTAINER `   指明映象維護者及其聯絡方式(一般是郵箱地址)。官方說明已過時,推薦使用 LABEL。 ```shell MAINTAINER mrhelloworld ```    ### LABEL      語法:`LABEL = = = ...`   功能是為映象指定標籤。也可以使用 LABEL 來指定映象作者。 ```shell LABEL maintainer="mrhelloworld.com" ```    ### RUN      語法:`RUN `   構建映象時執行的 Shell 命令,比如構建的新映象中我們想在 /usr/local 目錄下建立一個 java 目錄。 ```shell RUN mkdir -p /usr/local/java ```    ### ADD      語法:`ADD ... `   拷貝檔案或目錄到映象中。src 可以是一個本地檔案或者是一個本地壓縮檔案,壓縮檔案會自動解壓。還可以是一個 url,如果把 src 寫成一個 url,那麼 ADD 就類似於 wget 命令,然後自動下載和解壓。 ```shell ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java ```    ### COPY      語法:`COPY ... `   拷貝檔案或目錄到映象中。用法同 ADD,只是不支援自動下載和解壓。 ```shell COPY jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java ```    ### EXPOSE      語法:`EXPOSE [/...]`   暴露容器執行時的監聽埠給外部,可以指定埠是監聽 TCP 還是 UDP,如果未指定協議,則預設為 TCP。 ```shell EXPOSE 80 443 8080/tcp ``` > 如果想使得容器與宿主機的埠有對映關係,必須在容器啟動的時候加上 -P 引數。    ### ENV      語法:`ENV ` 新增單個,`ENV = ...` 新增多個。   設定容器內環境變數。 ```shell 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 會生效。 ```shell 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 會生效。 ```shell ENTRYPOINT ehco $JAVA_HOME ``` > - 如果在 Dockerfile 中同時寫了 ENTRYPOINT 和 CMD,並且 CMD 指令不是一個完整的可執行命令,那麼 CMD 指定的內容將會作為 ENTRYPOINT 的引數; > - 如果在 Dockerfile 中同時寫了 ENTRYPOINT 和 CMD,並且 CMD 是一個完整的指令,那麼它們兩個會互相覆蓋,誰在最後誰生效    ### WORKDIR      語法:`WORKDIR /path/to/workdir`   為 RUN、CMD、ENTRYPOINT 以及 COPY 和 AND 設定工作目錄。 ```shell WORKDIR /usr/local ```    ### VOLUME      指定容器掛載點到宿主機自動生成的目錄或其他容器。一般的使用場景為需要持久化儲存資料時。 ```shell # 容器的 /var/lib/mysql 目錄會在執行時自動掛載為匿名卷,匿名卷在宿主機的 /var/lib/docker/volumes 目錄下 VOLUME ["/var/lib/mysql"] ``` > 一般不會在 Dockerfile 中用到,更常見的還是在 docker run 的時候通過 -v 指定資料卷。    ## 構建映象      Dockerfile 檔案編寫好以後,真正構建映象時需要通過 `docker build` 命令。   `docker build` 命令用於使用 `Dockerfile` 建立映象。 ```shell # 使用當前目錄的 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 目錄下,檔案內容如下: ```shell ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java ```   那麼構建映象時的命令就該這樣寫: ```shell docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 /root ```      再舉個栗子:我的宿主機 jdk 檔案和 Dockerfile 檔案都在 /usr/local/dockerfile 目錄下,檔案內容如下: ```shell ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java ```   那麼構建映象時的命令則這樣寫: ```shell docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 . ```    ## Dockerfile 實踐      接下來我們通過基礎映象 `centos:7`,在該映象中安裝 jdk 和 tomcat 以後將其製作為一個新的映象 `mycentos:7`。   建立目錄。 ```shell mkdir -p /usr/local/dockerfile ```   編寫 Dockerfile 檔案。 ```shell vi Dockerfile ```   Dockerfile 檔案內容如下: ```shell # 指明構建的新映象是來自於 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 並檢視 tomcat 日誌資訊 ENTRYPOINT /usr/local/tomcat/apache-tomcat-9.0.37/bin/startup.sh && tail -f /usr/local/tomcat/apache-tomcat-9.0.37/logs/catalina.out ```   構建映象。 ```shell docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 /root/ [root@localhost ~]# docker build -f /usr/local/dockerfile/Dockerfile -t mycentos:7 /root/ Sending build context to Docker daemon 191.4MB Error response from daemon: Dockerfile parse error line 1: unknown instruction: NTOS:7 [root@localhost ~]# vi /usr/local/dockerfile/Dockerfile [root@localhost ~]# vi /usr/local/dockerfile/Dockerfile [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 4c561fed28a5 Removing intermediate container 4c561fed28a5 ---> b536fc4e4290 Step 3/10 : WORKDIR /usr/local ---> Running in 50141816c10e Removing intermediate container 50141816c10e ---> 030f9db632da Step 4/10 : RUN mkdir -p /usr/local/java && mkdir -p /usr/local/tomcat ---> Running in d1f8f4e008c8 Removing intermediate container d1f8f4e008c8 ---> 68773de3525a Step 5/10 : ADD jdk-11.0.6_linux-x64_bin.tar.gz /usr/local/java ---> 92f410a9e1ba Step 6/10 : ADD apache-tomcat-9.0.37.tar.gz /usr/local/tomcat ---> 8e0576fccd4e Step 7/10 : EXPOSE 8080 ---> Running in bb6c4ef8f4e1 Removing intermediate container bb6c4ef8f4e1 ---> 01edd4710cc1 Step 8/10 : ENV JAVA_HOME /usr/local/java/jdk-11.0.6/ ---> Running in 722c2d369a2f Removing intermediate container 722c2d369a2f ---> ef5172fb1dd6 Step 9/10 : ENV PATH $PATH:$JAVA_HOME/bin ---> Running in eaa287937565 Removing intermediate container eaa287937565 ---> 0347db73b904 Step 10/10 : ENTRYPOINT /usr/local/tomcat/apache-tomcat-9.0.37/bin/startup.sh && tail -f /usr/local/tomcat/apache-tomcat-9.0.37/logs/catalina.out ---> Running in 8f93d36f4de2 Removing intermediate container 8f93d36f4de2 ---> 1674e0191270 Successfully built 1674e0191270 Successfully tagged mycentos:7 ```    ## 映象構建歷史    ```shell docker history 映象名稱:標籤|ID docker history mycentos:7 ``` ![](https://mrhelloworld.com/resources/articles/docker/image-20200817200725799.png " ")    ## 使用構建的映象建立容器    ```shell # 建立容器 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! ``` ![](https://mrhelloworld.com/resources/articles/docker/image-20200812190553942.png " ") > 太棒了,Dockerfile 構建映象的方式你也學會了,再接再厲學習一下 Docker 映象的備份恢復遷移,go ~ ![](https://user-gold-cdn.xitu.io/2020/5/1/171cf87f564bc82e?w=433&h=133&f=gif&s=333013) 本文采用 `知識共享「署名-非商業性使用-禁止演繹 4.0 國際」許可協議`。 大家可以通過 `分類` 檢視更多關於 `Docker` 的文章。