您好,登錄后才能下訂單哦!
在“Docker部署您的第一個應用程序”一篇中,我們已經使用了Dockerfile來構建鏡像,這一篇將補充Dockerfile經常使用指令。
Docker可以通過讀取Dockerfile中的指令來生成鏡像。Dockerfile是一個文本文件,用戶對鏡像操作的所有指令都可以寫在Dockerfile文件中,最后使用docker build來構建鏡像。
在“Docker部署您的第一個應用程序”中,我們使用了命令“docker image build -t bulletinboard:1.0 . ”,docker image build命令通過讀取Dockerfile和指定的上下文來構建鏡像,命令結尾有一個“." 點,這個點就是構建鏡像的上下文。
上下文是遞歸進行處理的。因此,即包括該上下文下的所有子目錄。
鏡像的構建是由Docker守護進程(Docker daemon)完成的,而不是由CLI。構建過程首先要做的是將整個上下文(遞歸地)發送給守護進程。在大多數情況下,最好從一個空目錄作為上下文開始,并將Dockerfile保存在該目錄中。只添加生成Dockerfile所需的文件。
注意:千萬不要使用"/"根作為上下文,例如如下命令,因為它將會將宿主機"/"根目錄下所有文件傳輸到Docker的守護進程,可以在開發環境嘗試執行如下命令進行驗證。
# docker image build /
若要在構建的上下文中將配置文件或包構建到鏡像中,可在Dockerfile中使用COPY指令。若要提高構建性能,可通過在上下文目錄中添加.dockerignore文件來排除文件和目錄。通常Dockerfile,位于上下文的根目錄中,在docker build中使用-f標志可以指定文件系統中任何地方的docker file,使用-t標志可以指定構建鏡像的倉庫以及tag標簽,例如:
#?cat?>/tmp/centos?<<EOF FROM?centos:latest MAINTAINER?firefly@demo.com EOF #?docker?image?build?-f?/tmp/centos?-t?centos:v0.1?. #?docker?images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos v0.1 7eab7b4cc6ea 38 seconds ago 220MB
您也可以指定構建鏡像的多個倉庫以及tag,例如:
#?docker?image?build?-f?/tmp/centos?-t?t01/centos:v0.1?-t?t02/centos:v0.2?. #?docker?images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos v0.1 7eab7b4cc6ea 3 minutes ago 220MB
t01/centos v0.1 7eab7b4cc6ea 3 minutes ago 220MB
t02/centos v0.2 7eab7b4cc6ea 3 minutes ago 220MB
注意:當前所指的倉庫和tag均位于當前宿主機,在其他宿主機上,您是無法獲取這些鏡像的(除非您推送到您的docker hub賬戶下或其他方式),后續將會講到docker的私有倉庫registry或Harobor來遠程分享我們做好的鏡像。
使用Dockerfile構建鏡像步驟總結如下:
1、為鏡像創建一個目錄,如bulletin-board-app
2、進入bulletin-board-app目錄,在該目錄下創建并完成Dockerfile文件編寫
3、鏡像所需要的文件或代碼都拷貝到bulletin-board-app目錄
4、如果bulletin-board-app目錄下有文件是構建時不需要的,則可以創建并編寫.dockerignore文件來忽略不需要的文件
5、在bulletin-board-app目錄下執行docker image build命令,并指定上下文位置為".",如命令”docker image build -t test/bulletinboard .“
Docker守護進程在執行Dockerfile中的指令之前,會先對Dockerfile執行初步驗證,如果語法不正確,則返回相關錯誤,如果是參數錯誤,例如目標目錄不存在則不會檢查,直到執行到該指令時拋出錯誤。
Docker守護進程逐個執行Dockerfile中的指令,必要時將每條指令的結果提交給新鏡像,最后輸出新鏡像的ID。Docker守護進程將自動清理您發送的上下文。
注意,每個指令都是獨立運行的,因此上一指命的執行不會對下一個指令產生任何影響。
只要有可能,Docker將會重用中間鏡像(緩存),以顯著加快Docker的構建過程。并且在控制臺會輸出Using cache消息。
演示示例:
#?cat?>Dockerfile?<<EOF FROM?alpine:3.2 MAINTAINER?firefly@demo.com RUN?apk?update?&&?apk?add?socat?&&?rm?-r?/var/cache/ 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 EOF
第一次構建
#?docker?build?-t?demo/demo:v0.1?.
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM alpine:3.2
3.2: Pulling from library/alpine
95f5ecd24e43: Pull complete
Digest: sha256:ddac200f3ebc9902fb8cfcd599f41feb2151f1118929da21bcef57dc276975f9
Status: Downloaded newer image for alpine:3.2
---> 98f5f2d17bd1
Step 2/4 : MAINTAINER firefly@demo.com
---> Running in fa3786732ad5
Removing intermediate container fa3786732ad5
---> 6f5007fa547d
Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/
---> Running in b157222691fb
fetch http://dl-cdn.alpinelinux.org/alpine/v3.2/main/x86_64/APKINDEX.tar.gz
v3.2.3-474-g10ee65f [http://dl-cdn.alpinelinux.org/alpine/v3.2/main]
OK: 5294 distinct packages available
(1/4) Installing ncurses-terminfo-base (5.9)
(2/4) Installing ncurses-libs (5.9)
(3/4) Installing readline (6.3.008)
(4/4) Installing socat (1.7.3.0)
Executing busybox-1.23.2.trigger
OK: 7 MiB in 19 packages
Removing intermediate container b157222691fb
---> 58c5258280f7
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
---> Running in ca843dd16f02
Removing intermediate container ca843dd16f02
---> 7bf06f4ab80b
Successfully built 7bf06f4ab80b
Successfully tagged demo/demo:v0.1
第二次構建
#?docker?build?-t?demo/demo:v0.2?.
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM alpine:3.2
---> 98f5f2d17bd1
Step 2/4 : MAINTAINER firefly@demo.com
---> Using cache
---> 6f5007fa547d
Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/
---> Using cache
---> 58c5258280f7
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
---> 7bf06f4ab80b
Successfully built 7bf06f4ab80b
Successfully tagged demo/demo:v0.2
生成緩存僅用于具有本地父鏈的鏡像。這也意味著這些緩存鏡像均是由之前的構建生成的,或者整個鏡像鏈是用docker load方式加載的。如果需要指定鏡像緩存,可以使用--cache from選項。使用--cache from指定的鏡像不需要有父鏈,可以從其他倉庫中拉取。
完成構建后,就可以考慮將存儲在本地倉庫的鏡像推送到遠端倉庫(例如:Harobor)
BuildKit
從18.09版開始,Docker支持一個新的構建工具buildkit,moby/buildkit項目(https://github.com/moby/buildkit)。與現有的實現工具相比,BuildKit提供了許多特性:
1、檢測并跳過執行未使用的構建階段
2、并行化獨立構建階段
3、構建過程中只增量地傳輸上下文中更改的文件
4、檢測并跳過在上下文中傳輸未使用的文件
5、許多新特性在外部Dockerfile實現
6、避免與API的其余部分(中間鏡像和容器)產生副作用
7、自動修剪并設置生成緩存的優先級
要使用BuildKit,需要在調用docker build命令之前在CLI上設置環境變量DOCKER_BUILDKIT=1。
要了解可用于基于BuildKit的構建的實驗Dockerfile語法,請參閱BuildKit文檔(https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md)。
Dockerfile指令與語法
Dockerfile中的指令不區分大小寫。但是,按慣例是要大寫,以便更容易地將它們與參數區分開來。
Docker按順序運行Dockerfile中的指令。Dockerfile必須以“FROM”指令開頭。當然,FROM指令之前可以有注釋和全局參數。FROM指令指定了父鏡像。FROM前面只能有一個或多個ARG指令,這些指令聲明Dockerfile的FROM行中使用的參數。
Docker將以#開頭的行視為注釋。
1、FROM 鏡像:標簽
指定新鏡像是基于哪個(基礎)鏡像創建,每一個鏡像的創建都需要一條FROM指令,例如:
FROM centos:latest
2、MAINTAINER 名字/郵箱
維護人信息,例如:
MAINTAINER firefly@demo.com
3、ADD 源文件 新鏡像目錄
將源文件復制到新創建鏡像中,源文件要與Dockerfile同屬一個目錄,ADD指令會自動解壓tar、tgz包,例如:
ADD example.tgz /data
4、COPY 源文件 目標目錄
將源文復制到新建像中,源文件要與Dockerfile所屬同一個目錄,同ADD類似,例如:
COPY sources.list /etc/apt
5、ENV 關鍵字 值
設置變量或環境變量,例如:
ENV foo /var/www/html
上述表示變量foo的值是/var/www/html
6、RUN 命令
基于現有鏡像執行命令,并提交到新鏡像上,通常在安裝軟件包時使用RUN,例如:
RUN yum -y install sysstat
7、WORKDIR 目錄
指定工作目錄,通過WORKDIR設置工作目錄后,Dockerfile中其后的命令RUN、CMD、ENTRYPOINT、ADD、COPY等命令都會在該目錄下執行,后續登錄基于該鏡像的容器缺省路徑就是WORKDIR。
8、EXPOSE 端口號
指定Docker容器從該鏡像運行時所開啟的端口,例如:
EXPOSE 80
9、VOLUME 掛載點
Docker容器從該鏡像運行時會設置一個掛載點,例如:
VOLUME /data
10、CMD["要運行的程序","參數1","參數2"]
容器啟動時要運行的命令或腳本,Dockerfile只能有一條CMD命令,如果有多條,則執行最后一條,另外執行docker run 命令時若使用了/bin/bash,則會覆蓋CMD。例如:
CMD ["/bin/bash","/root/start.sh"]
示例演示
1、創建Dockerfile
#?mdkir?demo #?cd?demo #?cat?>?Dockerfile?<<EOF #My?first?image FROM?ubuntu:latest MAINTAINER?firefly@demo.com ENV?foo?/var/www/html WORKDIR?${foo} ADD?code.tgz?$foo COPY?sources.list?/etc/apt COPY?start.sh?/root/ RUN?chmod?755?/root/start.sh RUN?mkdir?/data VOLUME?/data RUN?apt-get?-y?update?&&?apt-get?-y?install?sysstat?lsof?net-tools?procps?vim?bash RUN?apt-get?-y?install?apache2 RUN?ln?-fs?/usr/share/zoneinfo/Asia/Shanghai?/etc/localtime RUN?date COPY?ports.conf?/etc/apache2/ports.conf ADD?example.tgz?/data EXPOSE?80 CMD?["/bin/bash","/root/start.sh"] EOF
上述Dockerfile中用到的相關腳本配置如下:
#?cat?>sources.list?<<EOF deb?http://mirrors.aliyun.com/ubuntu/?bionic?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?bionic-security?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?bionic-updates?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?bionic-proposed?main?restricted?universe?multiverse deb?http://mirrors.aliyun.com/ubuntu/?bionic-backports?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?bionic?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-security?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-updates?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-proposed?main?restricted?universe?multiverse deb-src?http://mirrors.aliyun.com/ubuntu/?bionic-backports?main?restricted?universe?multiverse EOF #?cat?>ports.conf?<<EOF ServerName?localhost Listen?80 <IfModule?ssl_module> Listen?443 </IfModule> <IfModule?mod_gnutls.c> Listen?443 </IfModule> EOF #?cat?>start.sh?<<EOF #!/bin/bash apache2ctl?start bash EOF
2、通過Dockerfile構建鏡像
#?docker?image?build?-t?test/httpd:v0.1?. #?docker?images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/httpd v0.1 9a9a2b7dd312 2 minutes ago 165MB
httpd latest 2ae34abc2ed0 3 weeks ago 165MB
3、基于鏡像運行容器
#?docker?container?run?-idt?-p?80?--name?test_httpd01?test/httpd:v0.1
6e7a40ec63b618bf043b45d334c289df782f02e19617dc0686c3be41a582e047
注意:在創建容器時不要加/bin/bash,不然會覆蓋CMD導致apache服務不啟動。
4、查看容器狀態并確認端口處于監聽狀態
#?docker?ps?-a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a919ee33ae0e test/httpd:v0.1 "/bin/bash /root/sta…" 3 minutes ago Up 3 minutes 0.0.0.0:32787->80/tcp test_httpd01
#?docker?exec?-it?test_httpd01?netstat?-antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 18/apache2
5、測試
#?curl?http://127.0.0.1:32787
hello
6、刪除容器和鏡像,容器的生命周期結束
#?docker?stop?test_httpd01 #?docker?rm?test_httpd01 #?docker?rmi?$(docker?images?|grep?"test/httpd"?|awk?'{print?$3}')
總結
對于有一定Linux基礎的童鞋,編寫Dockerfile是比較簡單的,但仍然需要注意一些細節,比如ADD、COPY指令差異,RUN與CMD指令差異等。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。