Docker學習第三課 -- Dockerfile詳解

一、 什麼是dockerfile?

     Dockerfile是一個包含用於組合映像的命令的文本文檔。可以使用在命令行中調用任何命令。 Docker通過讀取Dockerfile中的指令自動生成映像。

docker build命令用於從Dockerfile構建映像。可以在docker build命令中使用-f標誌指向文件系統中任何位置的Dockerfile。

      在Docker中創建鏡像最常用的方式,就是使用Dockerfile。Dockerfile是一個Docker鏡像的描述文件,我們可以理解成火箭發射的A、B、C、D…的步驟。Dockerfile其內部包含了一條條的指令每一條指令構建一層,因此每一條指令的內容,就是描述該層應當如何構建

                 

Dockerfile結構大致分爲四個部分:

  (1)基礎鏡像信息

  (2)維護者信息

  (3)鏡像操作指令

  (4)容器啓動時執行指令。

二、環境介紹

  • 1.Dockerfile中所用的所有文件一定要和Dockerfile文件在同一級父目錄下,可以爲Dockerfile父目錄的子目錄
  • 2.Dockerfile中相對路徑默認都是Dockerfile所在的目錄
  • 3.Dockerfile中一定要惜字如金,能寫到一行的指令,一定要寫到一行,原因是分層構建,聯合掛載這個特性。
  • Dockerfile中每一條指令被視爲一層
  • 4.Dockerfile中指明大寫(約定俗成)

三、Dockerfile指令

    Dockerfile中包括FROM、MAINTAINER、RUN、CMD、EXPOSE、ENV、ADD、COPY、ENTRYPOINT、VOLUME、USER、WORKDIR、ONBUILD等13個指令。

指令 解釋
FROM 指定基礎鏡像,即當前鏡像是基於哪個鏡像的並且必須是第一條指令
MAINTAINER 指明該鏡像的作者和其電子郵件
RUN 指定構建過程中要執行的命令
ENV 設置環境變量
WORKDIR 指定默認的工作目錄,即進入容器後默認進入的目錄
COPY 拷貝文件或者目錄到鏡像中
ADD 拷貝文件到鏡像中,且會自動解壓縮,可以訪問網絡資源,類似wget
EXPOSE 指定對外暴露的端口
VOLUME 創建掛載點,也成容器數據卷,用於數據共享和持久化
CMD 副本創建容器後,容器啓動的時候要執行是命令
ENTRYPOINT 啓動容器時執行的Shell命令,同CMD類似,只是由ENTRYPOINT啓動的程序不會被docker run命令行指定的參數所覆蓋,而且,這些命令行參數會被當作參數傳遞給ENTRYPOINT指定指定的程序
USER 指定運行容器時的用戶名或 UID,後續的 RUN 也會使用指定用戶

    

四 指令介紹

  4.1 FROM:指定基礎鏡像,必須爲第一個命令

FROM <image>
FROM <image>:<tag>
FROM <image>:<digest> 
三種寫法,其中<tag>和<digest> 是可選項,如果沒有選擇,那麼默認值爲latest

示例:
  FROM centos

 4.2 MAINTAINER 維護者信息

格式:
    MAINTAINER <name>
示例:
    MAINTAINER dukun ai
    MAINTAINER [email protected]
    MAINTAINER dukun ai <[email protected]>

4.3 LABEL  爲鏡像指定標籤

LABEL <key>=<value> <key>=<value> <key>=<value> ...
 一個Dockerfile種可以有多個LABEL,如下:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
 但是並不建議這樣寫,最好就寫成一行,如太長需要換行的話則使用\符號

如下:

LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
 

說明:LABEL會繼承基礎鏡像種的LABEL,如遇到key相同,則值覆蓋

4.4 RUN 構建鏡像的時候執行命令

RUN用於在鏡像容器中執行命令,其有以下兩種命令執行方式:
shell執行
格式:
    RUN <command>
exec執行
格式:
    RUN ["executable", "param1", "param2"]
示例:
    RUN ["executable", "param1", "param2"]
    RUN apk update
    RUN ["/etc/execfile", "arg1", "arg1"]
注:
  RUN指令創建的中間鏡像會被緩存,並會在下次構建中使用。
如果不想使用這些緩存鏡像,可以在構建時指定--no-cache參數,如:docker build --no-cache

  注:多行命令不要寫多個RUN,原因是Dockerfile中每一個指令都會建立一層.多少個RUN就構建了多少層鏡像,會造成鏡像的臃腫、多層,不僅僅增加了構件部署的時間,還容易出錯,RUN書寫時的換行符是\

4.5 ADD:將本地文件添加到容器中

      拷貝文件、文件必須和Dockerfil在同一目錄  tar類型文件會自動解壓(網絡壓縮資源不會被解壓),可以訪問網絡資源,類似wget

格式:
    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"] 用於支持包含空格的路徑
示例:
    ADD hom* /mydir/          # 添加所有以"hom"開頭的文件
    ADD hom?.txt /mydir/      # ? 替代一個單字符,例如:"home.txt"
    ADD test relativeDir/     # 添加 "test" 到 `WORKDIR`/relativeDir/
    ADD test /absoluteDir/    # 添加 "test" 到 /absoluteDir/

4.6 COPY 

    功能類似ADD,但是是不會自動解壓文件,也不能訪問網絡資源

4.7 ENV 配置環境變量

在其他指令中可以直接引用ENV設置的環境變量。

格式:
    ENV <key> <value>  #<key>之後的所有內容均會被視爲其<value>的組成部分,因此,一次只能設置一個變量
    ENV <key>=<value> ...  #可以設置多個變量,每個變量爲一個"<key>=<value>"的鍵值對,
如果<key>中包含空格,可以使用\來進行轉義,也可以通過""來進行標示;另外,反斜線也可以用於續行
示例:
ENV JAVA_HOME /usr/local/jdk1.8.0_171
ENV CLASSPATH .:$JAVA_HOME/lib
ENV CATALINA_HOME /usr/local/apache-tomcat-8.5.30
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin

4.8 EXPOSE 聲明容器運行的服務端口

      EXPOSE命名適用於設置容器對外映射的容器端口號,如tomcat容器內使用的端口8080,則用EXPOSE命令可以告訴外界該容器的8080端口對外

格式:
    EXPOSE <port> [<port>...]
示例:
    EXPOSE 80 443
    EXPOSE 8080
    EXPOSE 11211/tcp 11211/udp
注:
  EXPOSE並不會讓容器的端口訪問到主機。要使其可訪問,
    需要在docker run運行容器時通過-p來發布這些端口,或通過-P參數來發布EXPOSE導出的所有端口

4.9 WORKDIR:工作目錄,類似於cd命令

      通過WORKDIR設置工作目錄後,Dockerfile中其後的命令RUN、CMD、ENTRYPOINT、ADD、COPY
等命令都會在該目錄下執行。在使用docker run運行容器時,可以通過-w參數覆蓋構建時所設置的工作目錄。

格式:
    WORKDIR /path/to/workdir
示例:
    WORKDIR /a  (這時工作目錄爲/a)
    WORKDIR b  (這時工作目錄爲/a/b)
    WORKDIR c  (這時工作目錄爲/a/b/c)

  

4.10 CMD  容器啓動的時候執行

      CMD命令用於容器啓動時需要執行的命令,CMD在Dockerfile中只能出現一次,如果出現多個,那麼只有最後一個會有效。
其作用是在啓動容器的時候提供一個默認的命令項。

      如果用戶執行docker run的時候提供了命令項,就會覆蓋掉這個命令,沒提供就會使用構建時的命令。

格式:
    CMD ["executable","param1","param2"] (執行可執行文件,優先)
    CMD ["param1","param2"] (設置了ENTRYPOINT,則直接調用ENTRYPOINT添加參數)
    CMD command param1 param2 (執行shell內部命令)
示例:
   如容器啓動時進入bash:
   CMD /bin/bash
   CMD ["/bin/bash"]
注:
   CMD不同於RUN,CMD用於指定在容器啓動時所要執行的命令,而RUN用於指定鏡像構建時所要執行的命令。

4.11 ENTRYPOINT  容器啓動執行命令

  ENTRYPOINT的作用和用法和CMD一模一樣,但是ENTRYPOINT有和CMD有2處不一樣:

  1. CMD的命令會被docker run的命令覆蓋而ENTRYPOINT不會
  2. CMD和ENTRYPOINT都存在時,CMD的指令變成了ENTRYPOINT的參數,並且此CMD提供的參數會被 docker run 後面的命令覆蓋
用例一:使用CMD要在運行時重新寫命令才能追加運行參數,ENTRYPOINT則可以運行時接受新參數。
示例:
FROM ubuntu:16.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl", "-s", "http://ip.cn" ]

追加-i參數
$ docker run myip -i
......

4.12 VOLUME 容器目錄掛載點

    VOLUME用來創建一個可以從本地主機或其他容器掛載的掛載點。例如我們知道tomcat的webapps目錄是放web應用程序代碼的地方,此時我們要把webapps目錄掛載爲匿名卷,這樣任何寫入webapps中的心都不會被記錄到容器的存儲層,讓容器存儲層無狀態化。
格式:
    VOLUME ["/path/to/dir"]
示例:
    VOLUME ["/data"]
    VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"

4.13 USER

設置啓動容器的用戶,可以是用戶名或UID,所以,只有下面的兩種寫法是正確的

格式:
  USER user
  USER user:group
  USER uid
  USER uid:gid
  USER user:gid
  USER uid:group
 示例:
      USER www
 注:
  使用USER指定用戶後,Dockerfile中其後的命令RUN、CMD、ENTRYPOINT都將使用該用戶。
鏡像構建完成後,通過docker run運行容器時,可以通過-u參數來覆蓋所指定的用戶。

使用這個命令一定要確認容器中擁有這個用戶,並且擁有足夠權限
 

4.14 ONBUILD:用於設置鏡像觸發器

   ONBUILD用於配置當前所創建的鏡像作爲其它新創建鏡像的基礎鏡像時,所執行的操作指令。
意思就是:這個鏡像創建後,如果其它鏡像以這個鏡像爲基礎,會先執行這個鏡像的ONBUILD命令

格式:
  ONBUILD [INSTRUCTION]
示例:
  ONBUILD ADD . /app/src
  ONBUILD RUN /usr/local/bin/python-build --dir /app/src
注:
  當所構建的鏡像被用做其它鏡像的基礎鏡像,該鏡像中的觸發器將會被鑰觸發

4.15 ARG

    在構建鏡像時,指定一些參數,例如:

FROM centos:6
ARG user # ARG user=root
USER $user

這時,我們在docker build時可以帶上自定義參數user了,如下所示:

docker build --build-arg user=edisonzhou Dockerfile .

4.16 HEALTHCHECK  健康檢查

告訴Docker如何測試容器以檢查它是否仍在工作,即健康檢查,例如:

HEALTHCHECK --interval=5m --timeout=3s --retries=3 \
    CMD curl -f http:/localhost/ || exit 1
  其中,一些選項的說明:

 --interval=DURATION (default: 30s):每隔多長時間探測一次,默認30秒
 -- timeout= DURATION (default: 30s):服務響應超時時長,默認30秒
 --start-period= DURATION (default: 0s):服務啓動多久後開始探測,默認0秒
 --retries=N (default: 3):認爲檢測失敗幾次爲宕機,默認3次
  一些返回值的說明:

 0:容器成功是健康的,隨時可以使用
 1:不健康的容器無法正常工作
 2:保留不使用此退出代碼

4.17. docker build

     創建好Dockerfile之後,通過docker build命令來創建鏡像,該命令首先會上傳Dockerfile文件給Docker服務器端,服務器端將逐行執行Dockerfile中定義的指令。
    通常建議放置Dockerfile的目錄爲空目錄。另外可以在目錄下創建.dockerignore文件,讓Docker忽略路徑下的文件和目錄,這一點與Git中的配置很相似。

通過 -t 指定鏡像的標籤信息,例如:docker build -t regenzm/first_image . ##"."指定的是Dockerfile所在的路徑

五 示例

 5.1、自定義tomcat 鏡像

#1.指定基礎鏡像,並且必須是第一條指令
FROM centos
#2.指明改鏡像作者
MAINTAINER dukun

#3拷貝文件,文件必須與DockerFile在同一目錄下
COPY dukun /usr/local
ADD jdk-8u181-linux-x64.tar.gz /usr/local
ADD apache-tomcat-9.0.31.tar.gz /usr/local

#4 配置環境變量
ENV JAVA_HOME /usr/local/jdk1.8.0_181

ENV CLASSPATH .:$JAVA_HOME/lib
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.31
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin

# 5 配置工作路徑
WORKDIR $CATALINA_HOME
#安裝vim
RUN yum -y install vim
#7 設置端口
EXPOSE 8080

CMD ["catalina.sh", "run"]

5.2 部署springboot項目

# Docker image for springboot file run
# VERSION 0.0.1
# Author: eangulee
# 基礎鏡像使用java
FROM java:8
# 作者
MAINTAINER eangulee <[email protected]>
# VOLUME 指定了臨時文件目錄爲/tmp。
# 其效果是在主機 /var/lib/docker 目錄下創建了一個臨時文件,並鏈接到容器的/tmp
VOLUME /tmp 
# 將jar包添加到容器中並更名爲app.jar
ADD demo-0.0.1-SNAPSHOT.jar app.jar 
# 運行jar包
RUN bash -c 'touch /app.jar'
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar", \
"--spring.profiles.active=dev", "--server.port=8099", "> /log/app.log"]

解釋下這個配置文件:

java:8是指Docker Hub上官方提供的java鏡像,版本號是8也就是jdk1.8,有了這個基礎鏡像後,Dockerfile可以通過FROM指令直接獲取它的狀態——也就是在容器中java是已經安裝的,接下來通過自定義的命令來運行Spring Boot應用:

VOLUME指向了一個/tmp的目錄,由於Spring Boot使用內置的Tomcat容器,Tomcat默認使用/tmp作爲工作目錄。效果就是在主機的/var/lib/docker目錄下創建了一個臨時文件,並連接到容器的/tmp。

將項目的jar文件作爲app.jar添加到容器

RUN表示在新創建的鏡像中執行一些命令,然後把執行的結果提交到當前鏡像。這裏使用touch命令來改變文件的修改時間,Docker創建的所有容器文件默認狀態都是“未修改”。這對於簡單應用來說不需要,不過對於一些靜態內容(比如:index.html)的文件就需要一個“修改時間”。

EXPOSE 容器暴露端口

ENTRYPOINT 應用啓動命令 參數設定
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章