目錄
??dockerfile是什么
??鏡像的緩存特性
??dockerfile命令
??FROM
??RUN
??CMD
??LABEL
??EXPOSE
??ENV
??ADD
??COPY
??ENTRYPOINT
??VOLUME
??USER
??WORKDIR
??ARG
??ONBUILD
??STOPSIGNAL
??????博客主頁(yè):大蝦好吃嗎的博客
? ? ??專欄地址:云原生專欄
dockerfile是什么
docker中并不建議用戶通過commit方式來構(gòu)建鏡像,主要原因如下:
-
這是一種手工創(chuàng)建鏡像的方式,容易出錯(cuò),效率低且可重復(fù)性弱。比如要在 debian base 鏡像中也加入vi,還得重復(fù)前面的所有步驟。
-
更重要的:使用者并不知道鏡像是如何創(chuàng)建出來的,里面是否有惡意程序。也就是說無法對(duì)鏡像進(jìn)行審計(jì),存在安全隱患。
????????用 Dockerfile(推薦方法)構(gòu)建鏡像,底層也 docker commit 一層一層構(gòu)建新鏡像的。docker commit 能夠幫助我們更加深入地理解構(gòu)建過程和鏡像的分層結(jié)構(gòu)。
強(qiáng)烈推薦看官方文檔:MySQL官方dockerfile文檔
????????用 Dockerfile(推薦方法)構(gòu)建鏡像,底層也 docker commit 一層一層構(gòu)建新鏡像的。docker commit 能夠幫助我們更加深入地理解構(gòu)建過程和鏡像的分層結(jié)構(gòu)。
????????下面來個(gè)小案例,使用centos:7來構(gòu)建系統(tǒng)鏡像,里面安裝vim(默認(rèn)里面僅支持vi)。下面使用buid構(gòu)建鏡像,os1鏡像名,“ . ”是dockerfile的路徑
[root@localhost ~]# mkdir doc_file
[root@localhost ~]# cd doc_file/
[root@localhost doc_file]# docker images
REPOSITORY ? TAG ? ? ? IMAGE ID ? ? ? CREATED ? ? ? ? SIZE
nginx ? ? ? latest ? 605c77e624dd ? 16 months ago ? 141MB
httpd ? ? ? latest ? dabbfbe0c57b ? 16 months ago ? 144MB
centos ? ? ? 7 ? ? ? ? eeb6ee3f44bd ? 19 months ago ? 204MB
[root@localhost doc_file]# vim dockerfile
FROM centos:7
RUN yum -y install vim
[root@localhost doc_file]# docker build -t os1 .
[+] Building 110.7s (6/6) FINISHED ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
=> [internal] load build definition from dockerfile ? ? ? ? 0.0s
=> => transferring dockerfile: 74B ? ? ? ? ? ? ? ? ? ? ? ? 0.0s
=> [internal] load .dockerignore ? ? ? ? ? ? ? ? ? ? ? ? ? 0.0s
=> => transferring context: 2B ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> CACHED [1/2] FROM docker.io/library/centos:7 ? ? ? ? ? ? 0.0s
=> [2/2] RUN yum -y install vim ? ? ? ? ? ? ? ? ? ? ? ? ? 108.6s
=> exporting to image ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.0s
=> => exporting layers ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 2.0s
=> => writing image sha256:8326a9eb4706b6687c5b1329426b81e 0.0s
=> => naming to docker.io/library/os1
[root@localhost doc_file]# docker images
REPOSITORY ? TAG ? ? ? IMAGE ID ? ? ? CREATED ? ? ? ? SIZE
os1 ? ? ? ? latest ? 8326a9eb4706 ? 14 minutes ago ? 468MB
nginx ? ? ? latest ? 605c77e624dd ? 16 months ago ? 141MB
httpd ? ? ? latest ? dabbfbe0c57b ? 16 months ago ? 144MB
centos ? ? ? 7 ? ? ? ? eeb6ee3f44bd ? 19 months ago ? 204MB
[root@localhost doc_file]# docker run -it os1 /bin/bash
[root@66fd2b023bbb /]# vim a.txt #使用vim對(duì)a.txt插入內(nèi)容并查看測(cè)試
[root@66fd2b023bbb /]# cat a.txt
hello
1. 運(yùn)行 docker build 命令,-t 將新鏡像命名為 os1,命令末尾的 . 指明 build context 為當(dāng)前目錄。Docker 默認(rèn)會(huì)從 build context 中查找 Dockerfile 文件,我們也可以通過 -f 參數(shù)指定 Dockerfile 的位置。
2. 從這步開始就是鏡像真正的構(gòu)建過程。 首先 Docker 將 build context 中的所有文件發(fā)送給 Dockerdaemon。build context 為鏡像構(gòu)建提供所需要的文件或目錄。 Dockerfile 中的 ADD、COPY 等命令可以將 build context 中的文件添加到鏡像。此例中,build context 為當(dāng)前目錄 /root,該目錄下的所有文件和子目錄都會(huì)被發(fā)送給 Docker daemon。所以,使用 build context 就得小心了,不要將多余文件放到 build context,特別不要把 /、/usr 作為 buildcontext,否則構(gòu)建過程會(huì)相當(dāng)緩慢甚至失敗。
3. Step 1:執(zhí)行 FROM,將 centos 作為 base 鏡像。
4. Step 2:執(zhí)行 RUN,安裝 vim。
5. 啟動(dòng) ID 臨時(shí)容器,在容器中通過 yum 安裝 vim。
6. 安裝成功后,將容器保存為鏡像。 這一步底層使用的是類似 docker commit的命令。
7. 刪除臨時(shí)容器。
8. 鏡像構(gòu)建成功。 通過 docker images 查看鏡像信息。
鏡像的緩存特性
????????Docker 會(huì)緩存已有鏡像的鏡像層,構(gòu)建新鏡像時(shí),如果某鏡像層已經(jīng)存在,就直接使用緩存,不在重新創(chuàng)建。 例如下面,在docker中添加一些新內(nèi)容,因?yàn)樯厦娴囊呀?jīng)安裝,它會(huì)直接跳過鏡像選擇和vim的包,直接安裝net-tools,最終系統(tǒng)和這兩個(gè)服務(wù)都可以正常運(yùn)行。
[root@localhost doc_file]# vim dockerfile
FROM centos:7
RUN yum -y install vim
RUN yum -y install net-tools
[root@localhost doc_file]# docker build -t os2 .
[+] Building 5.3s (7/7) FINISHED ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
=> [internal] load build definition from dockerfile ? ? ? ? 0.0s
=> => transferring dockerfile: 104B ? ? ? ? ? ? ? ? ? ? ? ? 0.0s
=> [internal] load .dockerignore ? ? ? ? ? ? ? ? ? ? ? ? ? 0.0s
=> => transferring context: 2B ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [1/3] FROM docker.io/library/centos:7 ? ? ? ? ? ? ? ? ? 0.0s
=> CACHED [2/3] RUN yum -y install vim ? ? ? ? ? ? ? ? ? ? 0.0s
=> [3/3] RUN yum -y install net-tools ? ? ? ? ? ? ? ? ? ? ? 4.1s
=> exporting to image ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1.1s
=> => exporting layers ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 1.1s
=> => writing image sha256:8242c9c2514d73021f09a962cf1394a 0.0s
=> => naming to docker.io/library/os2
????????如果我們希望在構(gòu)建鏡像時(shí)不使用緩存,可以在 docker build 命令中加上 --no-cache 參數(shù)。 Dockerfile 中每一個(gè)指令都會(huì)創(chuàng)建一個(gè)鏡像層,上層是依賴于下層的。無論什么時(shí)候,只要某一層發(fā)生變化,其上面所有層的緩存都會(huì)失效。 也就是說,如果我們改變 Dockerfile 指令的執(zhí)行順序,或者修改或添加指令,都會(huì)使緩存失效。舉例說明,比如交換順序:
????????除了構(gòu)建時(shí)使用緩存,Docker 在下載鏡像時(shí)也會(huì)使用。例如我們下載 httpd 鏡像。 docker pull 命令輸出顯示第一層(base 鏡像)已經(jīng)存在,不需要下載。由 Dockerfile 可知 httpd 的 base 鏡像為 debian,正好之前已經(jīng)下載過 debian 鏡像,所以有緩存可用。通過docker history 可以進(jìn)一步驗(yàn)證。
dockerfile命令
????????在dockerfile中雖然大小寫都可以使用,推薦使用大寫容易區(qū)分命令。
dockerfile構(gòu)建過程
1、 編寫一個(gè)dockerfile文件
2、 docker build 構(gòu)建稱為一個(gè)鏡像
3、 docker run運(yùn)行鏡像
4、 docker push發(fā)布鏡像(DockerHub 、阿里云倉(cāng)庫(kù))
FROM
????????功能為指定基礎(chǔ)鏡像,并且必須是第一條指令。 如果不以任何鏡像為基礎(chǔ),那么寫法為:FROM scratch。 同時(shí)意味著接下來所寫的指令將作為鏡像的第一層開始 語(yǔ)法:
FROM <image>
FROM <image>:<tag>
FROM <image>:<digest>
三種寫法,其中<tag>和<digest> 是可選項(xiàng),如果沒有選擇,那么默認(rèn)值為latest。
RUN
功能為運(yùn)行指定的命令 RUN命令有兩種格式
RUN
RUN ["executable", "param1", "param2"]
????????第一種后邊直接跟shell命令。在linux操作系統(tǒng)上默認(rèn) /bin/sh -c。 在windows操作系統(tǒng)上默認(rèn) cmd /S /C 第二種是類似于函數(shù)調(diào)用。 可將executable理解成為可執(zhí)行文件,后面就是兩個(gè)參數(shù)。
兩種寫法比對(duì):
RUN /bin/bash -c 'source $HOME/.bashrc && echo $HOME'
RUN ["/bin/bash", "-c", "echo hello"]
????????注意:多行命令不要寫多個(gè)RUN,原因是Dockerfile中每一個(gè)指令都會(huì)建立一層. 多少個(gè)RUN就構(gòu)建了多少層鏡像,會(huì)造成鏡像的臃腫、多層,不僅僅增加了構(gòu)件部署的時(shí)間,還容易出錯(cuò)。 RUN書寫時(shí)的換行符是\
CMD
功能為容器啟動(dòng)時(shí)要運(yùn)行的命令 語(yǔ)法有三種寫法
CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2
????????第三種比較好理解了,就時(shí)shell這種執(zhí)行方式和寫法 第一種和第二種其實(shí)都是可執(zhí)行文件加上參數(shù)的形式 舉例說明兩種寫法:
CMD [ "sh", "-c", "echo $HOME"
CMD [ "echo", "$HOME" ]
????????補(bǔ)充細(xì)節(jié):這里邊包括參數(shù)的一定要用雙引號(hào),就是",不能是單引號(hào)。千萬不能寫成單引號(hào)。原因是參數(shù)傳遞后,docker解析的是一個(gè)JSON array
RUN & CMD
????????不要把RUN和CMD搞混了。 RUN是構(gòu)件容器時(shí)就運(yùn)行的命令以及提交運(yùn)行結(jié)果;CMD是容器啟動(dòng)時(shí)執(zhí)行的命令,在構(gòu)件時(shí)并不運(yùn)行,構(gòu)件時(shí)緊緊指定了這個(gè)命令到底是個(gè)什么樣子。
實(shí)例
[root@localhost doc_file]# vim dockerfile
FROM centos:7
CMD echo hello
[root@localhost doc_file]# docker build -t os1 .
#省略部分內(nèi)容
[root@localhost doc_file]# docker run os1
hello
LABEL
為鏡像指定標(biāo)簽,可以標(biāo)識(shí)作者等信息。
一個(gè)Dockerfile中可以有多個(gè)LABEL,語(yǔ)法如下:
LABEL <key>=<value> <key>=<value> <key>=<value> ...
EXPOSE
????????功能為暴露容器運(yùn)行時(shí)的監(jiān)聽端口給外部,但是EXPOSE并不會(huì)vim,使容器訪問主機(jī)的端口,如果想使得容器與主機(jī)的端口有映射關(guān)系,必須在容器啟動(dòng)的時(shí)候加上 -P參數(shù)
EXPOSE <port> [<port>/<protocol>...]
實(shí)例
[root@localhost doc_file]# vim dockerfile
FROM centos:7
EXPOSE 80/tcp 88/udp
[root@localhost doc_file]# docker build -t os2 .
#省略部分內(nèi)容
[root@localhost doc_file]# docker run -id os2 /bin/bash
947de4db7eae383bd4a2103637c65f3552dd361d909f317582a7ac5495bcbddc
[root@localhost doc_file]# docker ps -a | grep os2
947de4db7eae os2 "/bin/bash" 15 seconds ago Up 14 seconds 80/tcp, 88/udp sweet_davinci
ENV
功能為設(shè)置環(huán)境變量 語(yǔ)法有兩種:
ENV
ENV = <key>=<value> ...
兩者的區(qū)別就是第一種是一次設(shè)置一個(gè),第二種是一次設(shè)置多個(gè)
實(shí)例
[root@localhost doc_file]# vim dockerfile
FROM centos:7
ENV a="hello world"
CMD echo $a
[root@localhost doc_file]# docker build -t os3 .
#省略部分內(nèi)容
[root@localhost doc_file]# docker run os3
hello world
ADD
????????一個(gè)復(fù)制命令,把文件復(fù)制到鏡象中。 如果把虛擬機(jī)與容器想象成兩臺(tái)linux服務(wù)器的話,那么這個(gè)命令就類似于scp,只是scp需要加用戶名和密碼的權(quán)限驗(yàn)證,而ADD不用。 語(yǔ)法如下:
ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>
ADD [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
????????路徑的填寫可以是容器內(nèi)的絕對(duì)路徑,也可以是相對(duì)于工作目錄的相對(duì)路徑 可以是一個(gè)本地文件或者是一個(gè)本地壓縮文件,還可以是一個(gè)url 如果把寫成一個(gè)url,那么ADD就類似于wget命令 如以下寫法都是可以的:
ADD 本地文件 目標(biāo)位置
ADD URL地址 目標(biāo)位置
????????盡量不要把寫成一個(gè)文件夾,如果是一個(gè)文件夾,則復(fù)制整個(gè)目錄的內(nèi)容,包括文件系統(tǒng)元數(shù)據(jù)。當(dāng)復(fù)制tar包進(jìn)入容器,會(huì)自行解壓為目錄。
實(shí)例
[root@localhost doc_file]# tar zcf back.tar.gz /boot
tar: 從成員名中刪除開頭的“/”
[root@localhost doc_file]# ls
back.tar.gz dockerfile
[root@localhost doc_file]# vim dockerfile
FROM centos:7
ADD back.tar.gz /tmp
[root@localhost doc_file]# docker build -t os4 .
#省略部分內(nèi)容
[root@26df4b67e3fc /]# cd /tmp/
[root@26df4b67e3fc tmp]# ls
boot ks-script-DrRL8A yum.log
COPY
看這個(gè)名字就知道,又是一個(gè)復(fù)制命令 語(yǔ)法如下:
COPY [--chown=<user>:<group>] [--chmod=<perms>] <src>... <dest>
COPY [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]
與ADD的區(qū)別 COPY的只能是本地文件,其他用法一致。
ENTRYPOINT
功能是啟動(dòng)時(shí)的默認(rèn)命令 語(yǔ)法如下:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
第二種就是寫shell 第一種就是可執(zhí)行文件加參數(shù) 與CMD比較說明(這倆命令太像了,而且還可以配合使用):
-
相同點(diǎn): 只能寫一條,如果寫了多條,那么只有最后一條生效 容器啟動(dòng)時(shí)才運(yùn)行,運(yùn)行時(shí)機(jī)相同
-
不同點(diǎn): ENTRYPOINT不會(huì)被運(yùn)行的command覆蓋,而CMD則會(huì)被覆蓋 如果我們?cè)贒ockerfile種同時(shí)寫了ENTRYPOINT和CMD,并且CMD指令不是一個(gè)完整的可執(zhí)行命令,那么CMD指定的內(nèi)容將會(huì)作為ENTRYPOINT的參數(shù) 如下:
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]
????????如果我們?cè)贒ockerfile種同時(shí)寫了ENTRYPOINT和CMD,并且CMD是一個(gè)完整的指令,那么它們兩個(gè)會(huì)互相覆蓋,誰在最后誰生效 如下:
FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ls -al
那么將執(zhí)行l(wèi)s -al ,top -b不會(huì)執(zhí)行。
VOLUME
實(shí)現(xiàn)掛載功能,將本地文件/目錄或其他容器文件/目錄改在這個(gè)容器里。
語(yǔ)法如下:
VOLUME ["/var/log/"]
VOLUME /var/log
VOLUME /var/log /var/db
實(shí)例如下:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
USER
設(shè)置啟動(dòng)容器的用戶,有兩種語(yǔ)法,使用用戶名或UID。謹(jǐn)慎使用,如果使用z3用戶時(shí),RUN、CMD等都將以z3用戶執(zhí)行。
USER <user>[:<group>]
USER <UID>[:<GID>]
WORKDIR
設(shè)置工作目錄,對(duì)RUN、CMD等生效。如果該目錄不存在則會(huì)自動(dòng)創(chuàng)建,可以設(shè)置多次。下面使用pwd執(zhí)行的結(jié)果是/a/b/c。
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
也可以解析環(huán)境變量,pwd執(zhí)行的結(jié)果是/path/$DIRNAME
ENV DIRPATH=/path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
ARG
????????使用ARG定義一個(gè)變量,在構(gòu)建鏡像時(shí),使用--build-arg = 指定參數(shù),如果在構(gòu)建鏡像時(shí)指定的參數(shù)沒有在dockerfile中,將會(huì)楚江Waring提醒。
直接定義參數(shù)
FROM busybox
ARG user1
ARG buildno
# ...
給參數(shù)一個(gè)默認(rèn)值,如果給了一個(gè)默認(rèn)值時(shí),構(gòu)建鏡像時(shí)沒有指定參數(shù),將會(huì)自動(dòng)使用默認(rèn)值。
FROM busybox
ARG user1=someuser
ARG buildno=1
# ...
ONBUILD
????????指定當(dāng)前鏡像的子鏡像執(zhí)行,就是說,我在構(gòu)建dockerfile時(shí),執(zhí)行下面ls操作時(shí),不執(zhí)行。如果有人基于我的鏡像修改時(shí),將會(huì)執(zhí)行l(wèi)s操作。文章來源:http://www.zghlxwxcb.cn/news/detail-474098.html
ONBUILD RUN ls
STOPSIGNAL
當(dāng)退出容器時(shí),執(zhí)行定義的命令。文章來源地址http://www.zghlxwxcb.cn/news/detail-474098.html
STOPSIGNAL signal
到了這里,關(guān)于【云原生 · Docker】輕松學(xué)會(huì)dockerfile構(gòu)建鏡像的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!