dockerfile是構造Docker images的一行行命令的集合,是一個純文本文件。html
#
註釋信息node
INSTRUCTION
指令,指令不區分大小寫,但約定使用大寫linux
非註釋行的第一行必須是FROM
指令nginx
使用Dockerfile製做鏡像時須要一個乾淨的工做目錄,該目錄結構以下:git
Dockerfile文件 可選的 .dockerignore,用於存放要打包進鏡像的文件目錄中須要排除的文件 文件1,文件2,... 目錄1,目錄2,...
要打包進鏡像的文件或目錄都存放在與Dockerfile
文件同級。github
更多的dockerfile指令相關信息請參考:https://docs.docker.com/engine/reference/builderweb
FROM
docker
Dockerfile文件開篇的第一個非註釋行,用於爲鏡像文件構建過程指定基準鏡像,後續的指令運行於此基準鏡像所提供的運行環境。shell
語法 FROM <repository>[:<tag>]或 FROM <repository>@<digest> <repository>: 基礎鏡像名稱 <tag>: 基礎鏡像的標籤,省略時默認爲latest <digest>: 能夠不指定鏡像的名稱而使用鏡像的惟一識別hash碼
LABLE
json
爲Dockerfile提供key,value對的源數據信息,是MAINTAINER
的替代指令
LABEL <key>=<value> <key>=<value> <key>=<value> ...
COPY
從Docker主機複製文件至建立的新鏡像文件中
有兩種方式 COPY [--chown=<user>:<group>] <src>... <dest> COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] --chow只適用於類linux系統的鏡像 <src>: 要複製的源文件或目錄,支持通配符 <dest>: 目標路徑,即正在建立的image的文件系統路徑,使用絕對路徑,不然是以WORKDIR爲其起始路徑 文件複製準則: <src> 必須是Dockerfile文件所在目錄中的文件,不能是其父目錄中的文件 若是<src>是目錄,則其內部的文件或子目錄會被遞歸複製,但<src>目錄自身不會被複制 若是指定了多個<src>,或使用了通配符,則<dest>必須是一個目錄,且以「/」結尾 若是<dest>事先不存在,會被遞歸建立
ADD
相似COPY指令,ADD支持使用tar文件和url路徑
兩種語法格式 ADD [--chown=<user>:<group>] <src>... <dest> ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] --chow只適用於類linux系統的鏡像 操做準則 1. 同COPY指令 2. 若是<src>爲URL且<dest>不以/結尾,則<src>指定的文件將被下載而且直接被建立爲<dest>;若是<des>以/結尾,則文件名URL指定的文件將被直接下載並保存爲<des>/<filename> 3. 若是<src>是一個本地系統上的壓縮格式的tar文件,它將被展開爲一個目錄,其行爲相似於「tar -x」命令;然而,經過URL獲取到的tar文件將不會自動展開; 4. 若是<src>有多個,或其間接或直接使用了通配符,則<dest>必須爲一個以/結尾的目錄路徑;若是<dest>不以/結尾,其被視爲一個普通文件,<src>的內容將被直接寫入到<des>;
WORKDIR
用於爲Dockerfile中全部的RUN、CMD、ENTRYPOINT、COPY和ADD指定設定的工做目錄。
語法 WORKDIR /path/to/workdir 在Dockerfile文件中,WORKDIR指令能夠出現屢次,其路徑也能夠爲相對路徑,不過,其是相對此前一個WORKDIR指令指定的路徑。另外,WORKDIR也可調用由ENV指令指定的變量。 如: ENV DIRPATH /path WORKDIR $DIRPATH/
VOLUME
用於在image中建立一個掛載點目錄,以掛載Docker host上的卷或其它容器上的卷,該卷屬於Docker managed volume
類型的卷,即宿主機上要掛載的目錄由dockerd管理。
語法 VOLUME ["/data"] 若是掛載點目錄路徑下此前有文件存在,docker run命令會在卷掛載完成後將此前的全部文件複製到新掛載的卷中。
EXPOSE
用於爲容器打開指定要監聽的端口以實現與外部通訊
語法 EXPOSE <port> [<port>/<protocol>...] <protocol> 用於指定傳輸層協議,可爲tcp或udp兩者之一,默認爲tcp協議 可一次指定多個端口,如: EXPOSE 80/tcp 8080/udp EXPOSE指令並不會真正把相應的端口暴露到宿主機上,而是說明以該鏡像運行的容器具備該種能力,須要在`docker run`命令時使用`-P`(大寫的字母p)選項就可把EXPOSE指定的端口進行暴露,宿主機使用的隨機端口,也可使用`-p <hostPort>:<containerPort>`來指定宿主機上使用的端口。
ENV
用於爲鏡像定義所須要的環境變量,並可被Dockerfile文件中位於其後的其它指令(如ENV、ADD、COPY等)所調用。
語法 ENV <key> <value> ENV <key>=<value> ... 第一種格式中,<key>以後的全部內容均會被視做其<value>的組成部分,所以,一次只能設置一個變量; 第二種格式中可一次設置多個變量,每個變量爲一個「<key>=<value>」鍵值對,若是<value>有空格,使用反斜線(\)進行轉義,可經過對<value>加引號進行標識;另外反斜線也可用於續行; 如: ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy 引用時使用「$myName」或「${myName}」 定義多個變量時,建議使用第二種方式。
RUN
用於指定docker build過程當中運行的程序,其能夠是任何命令
語法 RUN <command> RUN ["executable", "param1", "param2", ...] 第一種格式中,<command>一般是一個shell命令,且以「/bin/sh -c」來運行它,這意味着此進程在容器中的PID不爲1,不能接收Unix信號,所以,當使用「docker stop <container>」命令中止容器時,此進程接收不到SIGTERM信息; 第二種格式中的參數是一個JSON格式的數組,其中<executable>爲要運行的命令,後面的<paramN>爲傳遞給命令的選項或參數;然而,此種格式指定的命令不會以「/bin/sh -c」來發起,所以常見的shell操做如變量替換以及通配符(?,*等)替換將不會進行;不過,若是要運行的命令依賴此shell特性話,能夠將其替換爲相似下面的格式。 RUN ["/bin/bash", "-c", "<executable>", "param1"] JSON數組中必定要使用雙引號
CMD
相似RUN指令,CMD指令也可用於運行任何命令或程序,不過兩者的運行時間點不一樣。
RUN指令運行於鏡像文件構建過程當中,而CMD指令運行於基於Dockerfile構建出的新鏡像文件啓動一個容器時;
CMD指令的首要目的在於爲啓動的容器指定默認要運行的程序,且其運行結束後,容器也將終止;不過,CMD指定的命令能夠被「docker run」的命令行選項所覆蓋;
在Dockerfile中能夠存在多個CMD指令,但僅最後一個會生效。
語法 CMD ["executable","param1","param2"] (exec的形式, 首選使用這種) CMD ["param1","param2"] (爲ENTRYPOINT指代默認參數) CMD command param1 param2 (同RUN同樣)
ENTRYPOINT
相似CMD指令的功能,用於爲容器指定默認運行程序,從而使得容器像是一個單獨的可執行程序。與CMD不一樣的是,由ENTRYPOINT啓動的程序不會被docker run命令行指定的參數所覆蓋,並且,這些命令行參數會被看成參數傳遞給ENTRYPOINT指定的程序。不過,docker run命令的--entrypoint選項的參數能夠覆蓋ENTRYPOINT指令指定的程序。
語法 ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2 docker run命令傳入的命令參數會覆蓋CMD指令的內容,而且附加到ENTRYPOINT命令最後作爲其參數使用,若是docker run命令行未傳入命令參數,那ENTRYPOINT會以CMD指令中的內容做爲其默認參數 Dockerfile文件中也能夠存在多個ENTRYPOINT指令,但僅有最後一個會生效
USER
用於指定運行image時的或運行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序時的用戶名或UID
默認狀況下,container的運行身份爲root用戶
語法 USER <user>[:<group>] USER <UID>[:<GID>] UDI,GID必須爲鏡像系統中有效用戶的UID,GID,不然,docker run命令將運行失敗。
HEALTHCHECK
用於Docker如何測試容器是否仍在正常工做。
語法 HEALTHCHECK [OPTIONS] CMD command (經過在容器內部運行命令來檢查容器的運行情況) HEALTHCHECK NONE (禁用從基本映像繼承的任何運行情況檢查) [OPTIONS]: --interval=DURATION(默認值:30s) 表示檢查間隔時間 --timeout=DURATION(默認值:30s) 表示檢查超時時間 --start-period=DURATION(默認值:0s) 表示container運行後等待主進程起動程序,開始健康檢查前的等待時長 --retries=N(默認值:3) 當檢查失敗時,須要連續檢查多少次才斷定該服務處於不健康狀態 檢查命令的退出狀態,可能的值爲: 0:成功-容器健康且可使用 1:不健康-容器沒法正常工做 2:保留-請勿使用此退出代碼 事例 HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1
SHELL
用於覆蓋RUN,CMD,ENTRYPOINT等指令運行的默認shell。
語法 SHELL ["executable", "parameters"] linux默認使用["/bin/sh", "-c"],windows默認使用["cmd", "/S", "/C"]
STOPSIGNAL
向容器發送退出的信號
語法 STOPSIGNAL signal signal爲系統合法的無符號的信號數字,如9
ARG
用於給docker build
時傳遞變量
語法 ARG <name>[=<default value>] 在「docker build」時使用「--build-arg <varname>=<value>」傳遞參數 如: FROM busybox ARG user USER ${user:-some_user} USER $user 在build時使用 $ docker build --build-arg user=what_user ./
ONBUILD
用於在Dockerfile中定義一個觸發器
Dockerfile用於build映像文件,此映像文件亦可做爲base image被另外一個Dockerfile用做FROM指令的參數,並以之構建新的映像文件,在後面的這個Dockerfile中的FROM指令在build過程當中被執行時,將會「觸發」建立其base image的Dockerfile文件中的ONBUILD指令定義的觸發器。
語法 ONBUILD <INSTRUCTION> 儘管任何指令均可註冊爲觸發器指令,但ONBUILD不能自我嵌套,且不會觸發FROM和MAINTAINER指令。 使用包含ONBUILD指令的Dockerfile構建的鏡像應該使用特殊的標籤,如 ruby:2.0-onbuild,來告訴用戶會觸發ONBUILD 在ONBUILD指令中使用ADD或COPY指令應該格外當心,由於新構建過程的上下文在缺乏指定的源文件時會失敗
root@node01:~/img01# pwd /root/img01 root@node01:~/img01# ls -al total 20 drwxr-xr-x 2 root root 4096 Jul 20 09:58 . drwx------ 5 root root 4096 Jul 20 09:58 .. -rw-r--r-- 1 root root 513 Jul 20 09:32 Dockerfile -rwxr-xr-x 1 root root 195 Jul 20 09:58 entrypoint.sh -rw-r--r-- 1 root root 35 Jul 20 09:22 index.html root@node01:~/img01# cat Dockerfile FROM nginx:1.14-alpine # ARG定義的變量能夠在build時經過--build-arg 傳遞參數替換 ARG author="Jack <jack@qq.com>" LABEL maintainer="${author}" ENV NGX_DOC_ROOT="/data/web/html/" ADD index.html ${NGX_DOC_ROOT} ADD entrypoint.sh /bin/ EXPOSE 80/TCP 8080/TCP # 健康檢查 HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/ # 觸發器 ONBUILD RUN echo "Hello Word!" > /tmp/readme.txt CMD ["/usr/sbin/nginx","-g","daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"] root@node01:~/img01# cat entrypoint.sh #!/bin/sh cat > /etc/nginx/conf.d/www.conf << EOF server { server_name ${HOSTNAME}; listen ${IP:-0.0.0.0}:${PORT:-10080}; root ${NGX_DOC_ROOT:-/usr/share/nginx/html}; } EOF exec "$@" root@node01:~/img01# cat index.html <h1>This is a nginx test page</h1>
entrypoint.sh
文件中末尾的exec "$@"
尤其重要,因爲Dockerfile中同時定義了ENTRYPOINT和CMD指令,因此容器運行時執行的程序爲/bin/entrypoint.sh "/usr/sbin/nginx" "-g" "daemon off;"
然後邊的參數都會entrypoint.sh腳本末尾的「$@」收集,即成了exec "/usr/sbin/nginx" "-g" "daemon off;"
,因使用了exec
來執行,因此啓動nginx的進程ID會替代運行/bin/entrypoint.sh
腳本時的sh
進程的ID。
build生成鏡像
root@node01:~/img01# docker build --build-arg 'author="Tom <tom@163.com>"' -t mynginx:v0.1-1 ./ Sending build context to Docker daemon 4.608kB Step 1/11 : FROM nginx:1.14-alpine ---> 8a2fb25a19f5 Step 2/11 : ARG author="Jack <jack@qq.com>" ---> Running in ffe97dc263b2 Removing intermediate container ffe97dc263b2 ---> 48cccb2b3ac2 Step 3/11 : LABEL maintainer="${author}" ---> Running in e31958e5d9eb Removing intermediate container e31958e5d9eb ---> b2c494b442d5 Step 4/11 : ENV NGX_DOC_ROOT="/data/web/html/" ---> Running in 1aabf04d1295 Removing intermediate container 1aabf04d1295 ---> 4fdb24fa67f2 Step 5/11 : ADD index.html ${NGX_DOC_ROOT} ---> e334aa452daa Step 6/11 : ADD entrypoint.sh /bin/ ---> ad5488c7c47c Step 7/11 : EXPOSE 80/TCP 8080/TCP ---> Running in 773ae947ecd7 Removing intermediate container 773ae947ecd7 ---> 23c16ae625fe Step 8/11 : HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/ ---> Running in 7be92e4c77a7 Removing intermediate container 7be92e4c77a7 ---> 544097889172 Step 9/11 : ONBUILD RUN echo "Hello Word!" > /tmp/readme.txt ---> Running in 3f121c8e23d0 Removing intermediate container 3f121c8e23d0 ---> 6d80a88f95ee Step 10/11 : CMD ["/usr/sbin/nginx","-g","daemon off;"] ---> Running in b5dbfb4a6c46 Removing intermediate container b5dbfb4a6c46 ---> 7eaa7434d331 Step 11/11 : ENTRYPOINT ["/bin/entrypoint.sh"] ---> Running in f3d78245e25a Removing intermediate container f3d78245e25a ---> 3a250eefa3a7 Successfully built 3a250eefa3a7 Successfully tagged mynginx:v0.1-1
查看鏡像詳細信息
root@node01:~/img01# docker image inspect mynginx:v0.1-1 ... "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.14.2", "NGX_DOC_ROOT=/data/web/html/" ], "Cmd": [ "/usr/sbin/nginx", "-g", "daemon off;" ], "Healthcheck": { "Test": [ "CMD-SHELL", "wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/" ], "StartPeriod": 3000000000 }, "Image": "sha256:7eaa7434d331cfc56db82b03ee9472eca1dd4ee3411252fb0155d86debb5fa78", "Volumes": null, "WorkingDir": "", "Entrypoint": [ "/bin/entrypoint.sh" ], "OnBuild": [ "RUN echo \"Hello Word!\" > /tmp/readme.txt" ], "Labels": { "maintainer": "\"Tom <tom@163.com>\"" }, ...
其中Labels中的maintainer是docker build
使用--build-arg
傳遞的值Tom <tom@163.com>
,再也不是Docerfile中定義的值Jack <jack@qq.com>
。
基於鏡像mynginx:v0.1-1
運行一個容器
root@node01:~# docker container run --rm --name nginx01 -e "PORT=8080" mynginx:v0.1-1 127.0.0.1 - - [20/Jul/2020:14:43:44 +0000] "GET / HTTP/1.1" 200 35 "-" "Wget" "-" 127.0.0.1 - - [20/Jul/2020:14:44:14 +0000] "GET / HTTP/1.1" 200 35 "-" "Wget" "-" ......
因配置了HEALTHCHECK,在容器運行後,運行進程運行3秒後每隔30秒都會檢查nginx的主頁。
另起終端鏈接到容器中
root@node01:~# docker container exec -i -t nginx01 /bin/sh / # cat /etc/nginx/conf.d/www.conf server { server_name eaf2cfb1eece; listen 0.0.0.0:8080; root /data/web/html/; } / # netstat -tanl Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8080 127.0.0.1:33032 TIME_WAIT tcp 0 0 127.0.0.1:8080 127.0.0.1:33030 TIME_WAIT / # ps PID USER TIME COMMAND 1 root 0:00 nginx: master process /usr/sbin/nginx -g daemon off; 8 nginx 0:00 nginx: worker process 44 root 0:00 /bin/sh 66 root 0:00 ps / # ls /tmp/ / #
生成了配置文件,監聽8080
端口是docker run
命令行傳遞的PORT
變量的值。
再來測試一下ONBUILD指令,以生成的新鏡像mynginx:v0.1-1
爲基礎鏡像再來製做一個鏡像
root@node01:~/img02# pwd /root/img02 root@node01:~/img02# ls Dockerfile root@node01:~/img02# cat Dockerfile FROM mynginx:v0.1-1 RUN /bin/touch /tmp/1.txt root@node01:~/img02# docker build -t test:v0.1-1 ./ Sending build context to Docker daemon 2.048kB Step 1/2 : FROM mynginx:v0.1-1 # Executing 1 build trigger ---> Using cache ---> 8fd69355802f Step 2/2 : RUN /bin/touch /tmp/1.txt ---> Running in 2e123d9c7683 Removing intermediate container 2e123d9c7683 ---> cce488581509 Successfully built cce488581509 Successfully tagged test:v0.1-1
以此鏡像運行一個容器
root@node01:~# docker container run -i -t --rm --name test01 test:v0.1-1 /bin/sh / # ls /tmp/ 1.txt readme.txt / # cat /tmp/readme.txt Hello Word! / #
/tmp/readme.txt
生成了,說明基礎鏡像裏定義的ONBUILD指令被觸發了。
docker官方在github在還有許多Dockerfile事例,能夠參考:https://github.com/docker-library
Registry用於保存docker鏡像,包括鏡像的層次結構和元數據。用戶能夠自建Registry,也可使用官方的Docker Hub。
分類:
官方提供了docker-distribution
軟件包來搭建一個Private Registry
,也提供了一個名爲registry
的鏡像,只須要pull該鏡像,啓動容器就能夠搭建起來,若是要提供http
的請求,那客戶端須要修改/etc/docker/daemon.json
文件,配置insecure-registries
這樣一個key
"insecure-registries": ["192.168.101.41/myreposition"]
此key表示訪問192.168.101.41/myreposition
這個Private Registry
可使用http協議。
官方提供的registry過於簡陋,vmware對該軟件進行了二次開發,名爲Harbor
爲其增長了許多特性,還提供了一個web界面,詳細信息請參考:https://github.com/goharbor/harbor