一、Dockerfile的格式
Dockerfile的格式如下:
# Comment
以“#”開頭的行為注釋行。跨行注釋也必須加“#”,Dockerfile不支援連續字元“”。指令解析指令也是以“#”開頭,指令解析器是一個可選項,位于Dockerfile的首行,隻允許出現一次,第二次出現則被認為是注釋,在解析器中換行符同樣是不被支援的,但是其中的非斷行空格是允許的。
#directive=value
# directive =value
# directive= value
# directive = value
# escap
Escape在dockerfile中被用作轉義字元和換行符,如果不特别指定,系統預設的轉義字元為: (反斜杠)。轉義不能在RUN指令中執行,除非位于行末進行格式換行。作為換行符時,escape允許Dockerfile指令跨行執行。反引号在Windows下非常有用(舉例可以參閱
官方文檔)
# escape=\ (反斜杠)
或
# escape=` (反引号)
INSTRUCTION arguments
INSTRUCTION一般被稱為指令或者指令,對大小寫不敏感,為了與其他參數差別開,習慣大寫。
.dockerfileignore file
使用Dockerfile建構鏡像時最好是将Dockerfile放置在一個建立的空目錄下。然後将建構鏡像所需要的檔案添加到該目錄中。為了提高建構鏡像的效率,你可以在目錄下建立一個.dockerignore檔案來指定要忽略的檔案和目錄。.dockerignore檔案的排除模式文法和 Git的.gitignore檔案相似。
二、相關指令詳解
FROM
每個Dockerfile必須以FROM指令開頭,FROM指明了目前鏡像建立的基鏡像,也就是說每個鏡像必須基于一個已存在的鏡像進行建立。FROM指令後直接跟基鏡像的名稱或者鏡像名稱加标簽。鏡像的名稱和标簽可以去Docker Hub或者使用指令docker search keyword 進行搜尋。用法如下:
FROM <image>
或
FROM <image>[:<tag>]
ARG
ARG指令定義了使用者可以在建立鏡像時或者運作時傳遞的變量,申明于調用類似于shell中的變量申明與定義。
ARG CODE_VERSION=latest
FROM base:${CODE_VERSION}
ENV
ENV指令用來定義鏡像的環境變量,并且可以引用已經存在的環境變量,例如:HOME、HOSTNAME、PATH。ENV的值跟ARG指令申明的變量一樣可以傳遞、被引用,定義方法也基本一緻。
FROM busybox
ENV foo /bar
# WORKDIR /bar
WORKDIR ${foo}
Dockerfile中的ENV支援以下變量的通路:ADD、COPY、ENV、EXPOSE、FROM、LABEL、STOPSIGNAL、USER、VOLUME、WORKDIR。
RUN
RUN指令在目前鏡像的頂層中執行指令并送出結果,新産生的鏡像用于下一步的Dockerfile。分層執行指令和生成送出符号Docker的核心概念,送出很友善,容器可以從鏡像曆史中的任意點建立,類似于源碼控制。在shell形式中,可以使用(反斜杠)将單個RUN指令繼續到下一行。RUN指令有兩種使用格式:
RUN <command>(shell形式,該指令在shell中運作,預設情況下/bin/sh -c在Linux中運作,cmd /S /CWindows中運作)
RUN ["executable", "param1", "param2"](exec執行形式)
[root@ChatDevOps ~]# cat Dockerfile
FROM centos
RUN mkdir /chatdevops
RUN ["touch","/chatdevops/chatdevops.log"]
RUN /bin/bash
[root@ChatDevOps ~]# docker run -it --name chatdevops chatdevops /bin/bash
[root@99484f802e71 /]# ll /chatdevops/chatdevops.log
-rw-r--r--. 1 root root 0 May 29 03:00 /chatdevops/chatdevops.log
CMD
CMD的主要是為一個正運作的容器提供預設執行指令。如果存在多個CMD指令,那麼隻有最後一個會被執行。如果在容器運作時指定了指令,則CMD指定的預設内容會被替代。CMD一共有三種格式:
CMD ["executable","param1","param2"] #(執行形式,這是比較常見的一種形式)
CMD ["param1","param2"] #(以json數組的形式将兩個參數存儲下來,在指定了ENTRYPOINT 指令後,用CMD指定具體的參數,此處必須用雙引号将涉及到的變量引起來)
CMD command param1 param2 #(shell形式)
[root@ChatDevOps ~]# cat Dockerfile
FROM centos
CMD echo "chatdevops"
CMD ["echo","Hello world"]
[root@ChatDevOps ~]# docker run -it --rm --name chatdevops chatdevops
Hello world
ENTRYPOINT
ENTRYPOINT的格式和RUN指令格式一樣,分為exec格式和shell格式。ENTRYPOINT的目的和CMD一樣,都是在指定容器啟動程式及參數。ENTRYPOINT在運作時 也可以替代,不過比CMD要略顯繁瑣,需要通過docker run的參數--entrypoint來指定。
當指定了ENTRYPOINT後,CMD的含義就發生了改變,不再是直接的運作其指令,而是将CMD的内容作為參數傳給ENTRYPOINT指令。
[root@ChatDevOps ~]# cat Dockerfile
FROM ubuntu:18.04
RUN apt-get update \
&& apt-get install -y curl \
&& rm -rf /var/lib/apt/lists/*
ENTRYPOINT [ "curl","-s","http://ip.cn" ]
[root@ChatDevOps ~]# docker run e317e4042076
目前 IP:71.184.25.21 來自:北京市
[root@ChatDevOps ~]# docker run e317e4042076 -i
HTTP/1.1 200 OK
Date: Tue, 29 May 2018 09:00:10 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d4439884e43e37c36aac129e9f4d0507f1527584410; expires=Wed, 29-May-19 09:00:10 GMT; path=/; domain=.ip.cn; HttpOnly
Server: cloudflare
CF-RAY: 4227c4e460886d9c-SJC
LABEL
LABEL指令用于添加一個中繼資料到鏡像,鍵和值配對存在。例如可以給容器添加輔助說明資訊。值中支援換行字元斜杠()。如果Docker中出現重複的鍵,則新的值會覆寫原來的值。為了減少Docker的層數,可以在單一LABEL指令中指定多個标簽:
LABEL multi.label1="value1" \
multi.label2="value2" \
other="value3"
MAINTAINER
MAINTAINER在新版本中已經廢棄,可以使用LABEL來替代MAINTAINER進行聲明。
EXPOSE
EXPOSE指定容器在運作中監聽的端口。預設情況下,EXPOSE指定的是TCP端口,若要指定監聽udp端口:
EXPOSE 80/udp
COPY
COPY能夠從建構上下文中複制檔案到新的一層中鏡像中,COPY指令有兩種形式:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
chown屬性隻支援Linux容器的建構。COPY指令支援通配符,可以把多個源檔案複制到目标檔案下。
ADD
ADD的格式和用法基本與COPY一緻,并在COPY的基礎上新增了一些功能。ADD的源檔案可以是一個URL。如果本地源路徑的檔案為一個tar壓縮檔案的話,壓縮格式為gzip,bzip2以及xz的情況 下,ADD指令将會自動解壓縮這個壓縮檔案到目标路徑,來自于URL的遠端檔案則不會被解壓。
VOLUME
VOLUME旨在建立一個具有名稱的挂載點。容器在運作時盡量保持存儲層不發生資料寫入操作。一個卷可以存在于一個或多個容器的特定目錄,這個目錄可以繞過聯合檔案系統,并提供資料共享或資料持久化功能。卷可以在容器間共享或重用,對卷的修改是及時生效的。對卷的修改不會對新的鏡像産生影響,卷會一直存在直到沒有容器使用它。可以使用數組的形式指定多個卷。使用方式如下:
VOLUME /data
VOLUME ["/data"]
VOLUME ["data","test","chatdevops"]
VOLUME也可以在建立容器時進行聲明:
[root@ChatDevOps docker]# docker run -it -v /myvolume --name myvolume chatdevops
以上指令建立一個名為myvolume的容器,同時挂載/myvolume。/myvolume在之前并不存在,在建立myvolume時同時建立了該目錄。
USER
USER指令為Dockerfile中全部RUN,CMD,ENTRYPOINT設定運作Image時使用的使用者名或UID。這個使用者或組必須事先在系統中存在。若不存在則下一層鏡像以root使用者進行執行。
USER <user>[:<group>]
USER <UID>[:<GID>]
WORKDIR
WORKDIR用來為Dockerfile下文中的RUN, CMD, ENTRYPOINT, COPY和ADD等指令指定目前工作目錄。如果存在多個WORKDIR則以指令錢最近的一條為參考。如果該目錄不存在,則系統會自動建立該目錄。如果要改變目前的工作目錄,不能使用cd指令來切換,需要使用WORKDIR來進行切換。
ONBUILD
這是一個特殊的指令,它後面跟的是其它指令,比如 RUN , COPY等,而這些指令,
在目前鏡像建構時并不會被執行。隻有當以目前鏡像為基礎鏡像,去建構下一級鏡像的時候才會被執行。
STOPSIGNAL
STOPSIGNAL指令設定喚醒信号并将其發送到容器後退出。後跟信号值(無符号整數)或者SIGNAME格式的信号名稱,例如SIGKILL。
STOPSIGNAL signal
HEALTHCHECK
Docker提供了HEALTHCHECK指令,通過該指令指定一行指令,用這行指令來判斷容器主程序的服務狀态是否還正常,進而比較真實的反應容器實際狀态。當在一個鏡像指定了HEALTHCHECK指令後,用其啟動容器,初始狀态會為 starting ,在HEALTHCHECK指令檢查成功後變為healthy,如果連續一定次數失敗,則會變為
unhealthy。格式如下:
HEALTHCHECK [OPTIONS] CMD command (check container health by running a command inside the container)
HEALTHCHECK NONE (disable any healthcheck inherited from the base image)
HEALTHCHECK 支援下列選項:
- --interval=<間隔> :兩次健康檢查的間隔,預設為 30 秒;
- --timeout=<時長> :健康檢查指令運作逾時時間,如果超過這個時間,本次健康檢查就被視為失敗,預設 30 秒;
- --retries=<次數> :當連續失敗指定次數後,則将容器狀态視為 unhealthy ,預設3次。
HEALTHCHECK在Dockerfile中隻能出現一次,如果出現多次則最後一個生效。
SHELL
SHEELL指令允許預設的shell形式被指令形式覆寫。在Linux系統中預設shell形式為 [“/bin/sh”, “-c”], 在 Windows上是[“cmd”, “/S”, “/C”]。SHELL指令必須用Dockerfile中的JSON格式寫入。SHELL指令在Windows上特别有用,其中有兩個常用的和完全不同的本機shell:cmd和powershell,以及包括sh的備用shell。 SHELL指令可以出現多次。每個SHELL指令都會覆寫所有以前的SHELL指令,并影響所有後續指令。