一、 什麼是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處不一樣:
- CMD的命令會被docker run的命令覆蓋而ENTRYPOINT不會
- 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 應用啓動命令 參數設定