Docker中鏡像構(gòu)建文件Dockerfile與相關(guān)命令的詳細(xì)介紹
前言
使用docker build
命令或使用Docker Hub
的自動(dòng)構(gòu)建功能構(gòu)建Docker鏡像時(shí),都需要一個(gè)Dockerfile文件。Dockerfile文件是一個(gè)由一系列構(gòu)建指令組成的文本文件,docker build
命令會(huì)根據(jù)這些構(gòu)建指令完成Docker鏡像的構(gòu)建。本文將會(huì)介紹Dockerfile文件,及其中使用的構(gòu)建指令。
1. Dockerfile文件使用
docker build
命令會(huì)根據(jù)Dockerfile文件及上下文構(gòu)建新Docker鏡像。構(gòu)建上下文是指Dockerfile所在的本地路徑或一個(gè)URL(Git倉(cāng)庫地址)。構(gòu)建上下文環(huán)境會(huì)被遞歸處理,所以,構(gòu)建所指定的路徑還包括了子目錄,而URL還包括了其中指定的子模塊。
構(gòu)建鏡像
將當(dāng)前目錄做為構(gòu)建上下文時(shí),可以像下面這樣使用docker build
命令構(gòu)建鏡像:
$ docker build . Sending build context to Docker daemon 6.51 MB ...
說明:構(gòu)建會(huì)在Docker后臺(tái)守護(hù)進(jìn)程(daemon)中執(zhí)行,而不是CLI中。構(gòu)建前,構(gòu)建進(jìn)程會(huì)將全部?jī)?nèi)容(遞歸)發(fā)送到守護(hù)進(jìn)程。大多情況下,應(yīng)該將一個(gè)空目錄作為構(gòu)建上下文環(huán)境,并將Dockerfile文件放在該目錄下。
在構(gòu)建上下文中使用的Dockerfile文件,是一個(gè)構(gòu)建指令文件。為了提高構(gòu)建性能,可以通過.dockerignore文件排除上下文目錄下,不需要的文件和目錄。
Dockerfile一般位于構(gòu)建上下文的根目錄下,也可以通過-f指定該文件的位置:
$ docker build -f /path/to/a/Dockerfile .
構(gòu)建時(shí),還可以通過-t參數(shù)指定構(gòu)建成后,鏡像的倉(cāng)庫、標(biāo)簽等:
鏡像標(biāo)簽
$ docker build -t shykes/myapp .
如果存在多個(gè)倉(cāng)庫下,或使用多個(gè)鏡像標(biāo)簽,就可以使用多個(gè)-t參數(shù):
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
在Docker守護(hù)進(jìn)程執(zhí)行Dockerfile中的指令前,首先會(huì)對(duì)Dockerfile進(jìn)行語法檢查,有語法錯(cuò)誤時(shí)會(huì)返回:
$ docker build -t test/myapp . Sending build context to Docker daemon 2.048 kB Error response from daemon: Unknown instruction: RUNCMD
緩存
Docker 守護(hù)進(jìn)程會(huì)一條一條的執(zhí)行Dockerfile中的指令,而且會(huì)在每一步提交并生成一個(gè)新鏡像,最后會(huì)輸出最終鏡像的ID。生成完成后,Docker 守護(hù)進(jìn)程會(huì)自動(dòng)清理你發(fā)送的上下文。
Dockerfile文件中的每條指令會(huì)被獨(dú)立執(zhí)行,并會(huì)創(chuàng)建一個(gè)新鏡像,RUN cd /tmp
等命令不會(huì)對(duì)下條指令產(chǎn)生影響。
Docker 會(huì)重用已生成的中間鏡像,以加速docker build
的構(gòu)建速度。以下是一個(gè)使用了緩存鏡像的執(zhí)行過程:
$ docker build -t svendowideit/ambassador . Sending build context to Docker daemon 15.36 kB Step 1/4 : FROM alpine:3.2 ---> 31f630c65071 Step 2/4 : MAINTAINER SvenDowideit@home.org.au ---> Using cache ---> 2a1c91448f5f Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/ ---> Using cache ---> 21ed6e7fbb73 Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh ---> Using cache ---> 7ea8aef582cc Successfully built 7ea8aef582cc
構(gòu)建緩存僅會(huì)使用本地父生成鏈上的鏡像。如果不想使用本地緩存的鏡像,也可以通過--cache-from
指定緩存。指定后將再不使用本地生成的鏡像鏈,而是從鏡像倉(cāng)庫中下載。
2. Dockerfile文件格式
Dockerfile文件格式如下:
# Comment INSTRUCTION arguments
# 注釋 指令 參數(shù)
Dockerfile文件中指令不區(qū)分大小寫,但為了更易區(qū)分,約定使用大寫形式。
Docker 會(huì)依次執(zhí)行Dockerfile中的指令,文件中的第一條指令必須是FROM,F(xiàn)ROM指令用于指定一個(gè)基礎(chǔ)鏡像。
以#開頭的行,Docker會(huì)認(rèn)為是注釋。但#出現(xiàn)在指令參數(shù)中時(shí),則不是注釋。如:
# Comment RUN echo 'we are running some # of cool things'
3. Dockerfile中使用指令
3.1 FROM
FROM指令用于指定其后構(gòu)建新鏡像所使用的基礎(chǔ)鏡像。FROM指令必是Dockerfile文件中的首條命令,啟動(dòng)構(gòu)建流程后,Docker將會(huì)基于該鏡像構(gòu)建新鏡像,F(xiàn)ROM后的命令也會(huì)基于這個(gè)基礎(chǔ)鏡像。
FROM語法格式為:
FROM <image>
或
FROM <image>:<tag>
或
FROM <image>:<digest>
通過FROM指定的鏡像,可以是任何有效的基礎(chǔ)鏡像。FROM有以下限制:
- FROM必須是Dockerfile中第一條非注釋命令
- 在一個(gè)Dockerfile文件中創(chuàng)建多個(gè)鏡像時(shí),F(xiàn)ROM可以多次出現(xiàn)。只需在每個(gè)新命令FROM之前,記錄提交上次的鏡像ID。
- tag或digest是可選的,如果不使用這兩個(gè)值時(shí),會(huì)使用latest版本的基礎(chǔ)鏡像
3.2 RUN
RUN用于在鏡像容器中執(zhí)行命令,其有以下兩種命令執(zhí)行方式:
shell執(zhí)行
在這種方式會(huì)在shell中執(zhí)行命令,Linux下默認(rèn)使用/bin/sh -c
,Windows下使用cmd /S /C
。
注意:通過SHELL命令修改RUN所使用的默認(rèn)shell
RUN <command>
exec執(zhí)行
RUN ["executable", "param1", "param2"]
RUN可以執(zhí)行任何命令,然后在當(dāng)前鏡像上創(chuàng)建一個(gè)新層并提交。提交后的結(jié)果鏡像將會(huì)用在Dockerfile文件的下一步。
通過RUN執(zhí)行多條命令時(shí),可以通過\換行執(zhí)行:
RUN /bin/bash -c 'source $HOME/.bashrc; \ echo $HOME'
也可以在同一行中,通過分號(hào)分隔命令:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
RUN指令創(chuàng)建的中間鏡像會(huì)被緩存,并會(huì)在下次構(gòu)建中使用。如果不想使用這些緩存鏡像,可以在構(gòu)建時(shí)指定--no-cache
參數(shù),如:docker build --no-cache
。
3.3 CMD
CMD用于指定在容器啟動(dòng)時(shí)所要執(zhí)行的命令。CMD有以下三種格式:
CMD ["executable","param1","param2"] CMD ["param1","param2"] CMD command param1 param2
CMD不同于RUN,CMD用于指定在容器啟動(dòng)時(shí)所要執(zhí)行的命令,而RUN用于指定鏡像構(gòu)建時(shí)所要執(zhí)行的命令。
CMD與RUN在功能實(shí)現(xiàn)上也有相似之處。如:
docker run -t -i itbilu/static_web_server /bin/true
等價(jià)于:
cmd ["/bin/true"]
CMD在Dockerfile文件中僅可指定一次,指定多次時(shí),會(huì)覆蓋前的指令。
另外,docker run命令也會(huì)覆蓋Dockerfile中CMD命令。如果docker run
運(yùn)行容器時(shí),使用了Dockerfile中CMD相同的命令,就會(huì)覆蓋Dockerfile中的CMD命令。
如,我們?cè)跇?gòu)建鏡像的Dockerfile文件中使用了如下指令:
CMD ["/bin/bash"]
使用docker build
構(gòu)建一個(gè)新鏡像,鏡像名為itbilu/test。構(gòu)建完成后,使用這個(gè)鏡像運(yùn)行一個(gè)新容器,運(yùn)行效果如下:
$ sudo docker run -i -t itbilu/test root@e3597c81aef4:/#
在使用docker run運(yùn)
行容器時(shí),我們并沒有在命令結(jié)尾指定會(huì)在容器中執(zhí)行的命令,這時(shí)Docker就會(huì)執(zhí)行在Dockerfile的CMD中指定的命令。
如果不想使用CMD中指定的命令,就可以在docker run
命令的結(jié)尾指定所要運(yùn)行的命令:
$ sudo docker run -i -t itbilu/test /bin/ps PID TTY TIME CMD 1 ? 00:00:00 ps
這時(shí),docker run
結(jié)尾指定的/bin/ps
命令覆蓋了Dockerfile的CMD中指定的命令。
3.4 ENTRYPOINT
ENTRYPOINT用于給容器配置一個(gè)可執(zhí)行程序。也就是說,每次使用鏡像創(chuàng)建容器時(shí),通過ENTRYPOINT指定的程序都會(huì)被設(shè)置為默認(rèn)程序。ENTRYPOINT有以下兩種形式:
ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2
ENTRYPOINT與CMD非常類似,不同的是通過docker run
執(zhí)行的命令不會(huì)覆蓋ENTRYPOINT,而docker run
命令中指定的任何參數(shù),都會(huì)被當(dāng)做參數(shù)再次傳遞給ENTRYPOINT。Dockerfile中只允許有一個(gè)ENTRYPOINT命令,多指定時(shí)會(huì)覆蓋前面的設(shè)置,而只執(zhí)行最后的ENTRYPOINT指令。
docker run
運(yùn)行容器時(shí)指定的參數(shù)都會(huì)被傳遞給ENTRYPOINT,且會(huì)覆蓋CMD命令指定的參數(shù)。如,執(zhí)行docker run <image> -d
時(shí), -d
參數(shù)將被傳遞給入口點(diǎn)。
也可以通過docker run --entrypoint
重寫ENTRYPOINT入口點(diǎn)。
如:可以像下面這樣指定一個(gè)容器執(zhí)行程序:
ENTRYPOINT ["/usr/bin/nginx"]
完整構(gòu)建代碼:
# Version: 0.0.3 FROM ubuntu:16.04 MAINTAINER 何民三 "cn.liuht@gmail.com" RUN apt-get update RUN apt-get install -y nginx RUN echo 'Hello World, 我是個(gè)容器' \ > /var/www/html/index.html ENTRYPOINT ["/usr/sbin/nginx"] EXPOSE 80
使用docker build
構(gòu)建鏡像,并將鏡像指定為itbilu/test:
$ sudo docker build -t="itbilu/test" .
構(gòu)建完成后,使用itbilu/test
啟動(dòng)一個(gè)容器:
$ sudo docker run -i -t itbilu/test -g "daemon off;"
在運(yùn)行容器時(shí),我們使用了-g "daemon off;"
,這個(gè)參數(shù)將會(huì)被傳遞給ENTRYPOINT,最終在容器中執(zhí)行的命令為/usr/sbin/nginx -g "daemon off;"
。
3.5 LABEL
LABEL用于為鏡像添加無數(shù)據(jù),無數(shù)以鍵值對(duì)的形式指定:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
使用LABEL指定元數(shù)據(jù)時(shí),一條LABEL指定可以指定一或多條元數(shù)據(jù),指定多條元數(shù)據(jù)時(shí)不同元數(shù)據(jù)之間通過空格分隔。推薦將所有的元數(shù)據(jù)通過一條LABEL指令指定,以免生成過多的中間鏡像。
如,通過LABEL指定一些元數(shù)據(jù):
LABEL version="1.0" description="這是一個(gè)Web服務(wù)器" by="IT筆錄"
指定后可以通過docker inspect
查看:
$sudo docker inspect itbilu/test "Labels": { "version": "1.0", "description": "這是一個(gè)Web服務(wù)器", "by": "IT筆錄" },
注意;Dockerfile中還有個(gè)MAINTAINER命令,該命令用于指定鏡像作者。但MAINTAINER并不推薦使用,更推薦使用LABEL來指定鏡像作者。如:
LABEL maintainer="itbilu.com"
3.6 EXPOSE
EXPOSE用于指定容器在運(yùn)行時(shí)監(jiān)聽的端口:
EXPOSE <port> [<port>...]
EXPOSE并不會(huì)讓容器的端口訪問到主機(jī)。要使其可訪問,需要在docker run
運(yùn)行容器時(shí)通過-p來發(fā)布這些端口,或通過-P
參數(shù)來發(fā)布EXPOSE導(dǎo)出的所有端口。
3.7 ENV
ENV用于設(shè)置環(huán)境變量,其有以下兩種設(shè)置形式:
ENV <key> <value> ENV <key>=<value> ...
如,通過ENV設(shè)置一個(gè)環(huán)境變量:
ENV ITBILU_PATH /home/itbilu/
設(shè)置后,這個(gè)環(huán)境變量在ENV命令后都可以使用。如:
WORKERDIR $ITBILU_PATH
這些環(huán)境變量不僅可以構(gòu)建鏡像過程使用,使用該鏡像創(chuàng)建的容器中也可以使用。如:
$ docker run -i -t itbilu/test root@196ca123c0c3:/# cd $ITBILU_PATH root@196ca123c0c3:/home/itbilu#
3.8 ADD
ADD用于復(fù)制構(gòu)建環(huán)境中的文件或目錄到鏡像中。其有以下兩種使用方式:
ADD <src>... <dest> ADD ["<src>",... "<dest>"]
通過ADD復(fù)制文件時(shí),需要通過<src>指定源文件位置,并通過<dest>來指定目標(biāo)位置。<src>可以是一個(gè)構(gòu)建上下文中的文件或目錄,也可以是一個(gè)URL,但不能訪問構(gòu)建上下文之外的文件或目錄。
如,通過ADD復(fù)制一個(gè)網(wǎng)絡(luò)文件:
ADD http://wordpress.org/latest.zip $ITBILU_PATH
在上例中,$ITBILU_PATH
是我們使用ENV指定的一個(gè)環(huán)境變量。
另外,如果使用的是本地歸檔文件(gzip、bzip2、xz)時(shí),Docker會(huì)自動(dòng)進(jìn)行解包操作,類似使用tar -x。
3.9 COPY
COPY同樣用于復(fù)制構(gòu)建環(huán)境中的文件或目錄到鏡像中。其有以下兩種使用方式:
COPY <src>... <dest> COPY ["<src>",... "<dest>"]
COPY指令非常類似于ADD,不同點(diǎn)在于COPY只會(huì)復(fù)制構(gòu)建目錄下的文件,不能使用URL也不會(huì)進(jìn)行解壓操作。
3.10 VOLUME
VOLUME用于創(chuàng)建掛載點(diǎn),即向基于所構(gòu)建鏡像創(chuàng)始的容器添加卷:
VOLUME ["/data"]
一個(gè)卷可以存在于一個(gè)或多個(gè)容器的指定目錄,該目錄可以繞過聯(lián)合文件系統(tǒng),并具有以下功能:
- 卷可以容器間共享和重用
- 容器并不一定要和其它容器共享卷
- 修改卷后會(huì)立即生效
- 對(duì)卷的修改不會(huì)對(duì)鏡像產(chǎn)生影響
- 卷會(huì)一直存在,直到?jīng)]有任何容器在使用它
VOLUME讓我們可以將源代碼、數(shù)據(jù)或其它內(nèi)容添加到鏡像中,而又不并提交到鏡像中,并使我們可以多個(gè)容器間共享這些內(nèi)容。
如,通過VOLUME創(chuàng)建一個(gè)掛載點(diǎn):
ENV ITBILU_PATH /home/itbilu/ VOLUME [$ITBILU_PATH]
構(gòu)建的鏡像,并指定鏡像名為itbilu/test。構(gòu)建鏡像后,使用新構(gòu)建的運(yùn)行一個(gè)容器。運(yùn)行容器時(shí),需-v參將能本地目錄綁定到容器的卷(掛載點(diǎn))上,以使容器可以訪問宿主機(jī)的數(shù)據(jù)。
$ sudo docker run -i -t -v ~/code/itbilu:/home/itbilu/ itbilu/test root@31b0fac536c4:/# cd /home/itbilu/ root@31b0fac536c4:/home/itbilu# ls README.md app.js bin config.js controller db demo document lib minify.js node_modules package.json public routes test views
如上所示,我們已經(jīng)可以容器的/home/itbilu/
目錄下訪問到宿主機(jī)~/code/itbilu
目錄下的數(shù)據(jù)了。
3.11 USER
USER用于指定運(yùn)行鏡像所使用的用戶:
USER daemon
使用USER指定用戶時(shí),可以使用用戶名、UID或GID,或是兩者的組合。以下都是合法的指定試:
USER user USER user:group USER uid USER uid:gid USER user:gid USER uid:group
使用USER指定用戶后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT都將使用該用戶。鏡像構(gòu)建完成后,通過docker run
運(yùn)行容器時(shí),可以通過-u參數(shù)來覆蓋所指定的用戶。
3.12 WORKDIR
WORKDIR用于在容器內(nèi)設(shè)置一個(gè)工作目錄:
WORKDIR /path/to/workdir
通過WORKDIR設(shè)置工作目錄后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都會(huì)在該目錄下執(zhí)行。
如,使用WORKDIR設(shè)置工作目錄:
WORKDIR /a WORKDIR b WORKDIR c RUN pwd
在以上示例中,pwd最終將會(huì)在/a/b/c目錄中執(zhí)行。
在使用docker run
運(yùn)行容器時(shí),可以通過-w參數(shù)覆蓋構(gòu)建時(shí)所設(shè)置的工作目錄。
3.13 ARG
ARG用于指定傳遞給構(gòu)建運(yùn)行時(shí)的變量:
ARG <name>[=<default value>]
如,通過ARG指定兩個(gè)變量:
ARG site ARG build_user=IT筆錄
以上我們指定了site和build_user兩個(gè)變量,其中build_user指定了默認(rèn)值。在使用docker build
構(gòu)建鏡像時(shí),可以通過--build-arg <varname>=<value>
參數(shù)來指定或重設(shè)置這些變量的值。
$ sudo docker build --build-arg site=itiblu.com -t itbilu/test .
這樣我們構(gòu)建了itbilu/test鏡像,其中site會(huì)被設(shè)置為itbilu.com,由于沒有指定build_user,其值將是默認(rèn)值IT筆錄。
3.14 ONBUILD
ONBUILD用于設(shè)置鏡像觸發(fā)器:
ONBUILD [INSTRUCTION]
當(dāng)所構(gòu)建的鏡像被用做其它鏡像的基礎(chǔ)鏡像,該鏡像中的觸發(fā)器將會(huì)被鑰觸發(fā)。
如,當(dāng)鏡像被使用時(shí),可能需要做一些處理:
[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
3.15 STOPSIGNAL
STOPSIGNAL用于設(shè)置停止容器所要發(fā)送的系統(tǒng)調(diào)用信號(hào):
STOPSIGNAL signal
所使用的信號(hào)必須是內(nèi)核系統(tǒng)調(diào)用表中的合法的值,如:9、SIGKILL。
3.16 SHELL
SHELL用于設(shè)置執(zhí)行命令(shell式)所使用的的默認(rèn)shell類型:
SHELL ["executable", "parameters"]
SHELL在Windows環(huán)境下比較有用,Windows下通常會(huì)有cmd和powershell兩種shell,可能還會(huì)有sh。這時(shí)就可以通過SHELL來指定所使用的shell類型:
FROM microsoft/windowsservercore # Executed as cmd /S /C echo default RUN echo default # Executed as cmd /S /C powershell -command Write-Host default RUN powershell -command Write-Host default # Executed as powershell -command Write-Host hello SHELL ["powershell", "-command"] RUN Write-Host hello # Executed as cmd /S /C echo hello SHELL ["cmd", "/S"", "/C"] RUN echo hello
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來一定的幫助,如果有疑問大家可以留言交流。
相關(guān)文章
docker build鏡像時(shí),無法訪問網(wǎng)絡(luò)問題
這篇文章主要介紹了docker build鏡像時(shí),無法訪問網(wǎng)絡(luò)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-08-08如何利用Docker容器實(shí)現(xiàn)代理轉(zhuǎn)發(fā)與數(shù)據(jù)備份詳解
這篇文章主要給大家介紹了關(guān)于如何利用Docker容器實(shí)現(xiàn)代理轉(zhuǎn)發(fā)與數(shù)據(jù)備份的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-10-10docker?創(chuàng)建容器時(shí)指定容器ip的實(shí)現(xiàn)示例
在實(shí)際部署中,我們需要指定容器ip,本文主要介紹了docker?創(chuàng)建容器時(shí)指定容器ip,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12Docker之蘋果Mac安裝Docker的兩種方式小結(jié)
這篇文章主要介紹了Docker之蘋果Mac安裝Docker的兩種方式小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04docker部署訪問postgres數(shù)據(jù)庫的實(shí)現(xiàn)方法
本文主要介紹了docker部署訪問postgres數(shù)據(jù)庫的實(shí)現(xiàn)方法,文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03