docker之dockerfile自動(dòng)構(gòu)建鏡像

Dockerfile 構(gòu)建鏡像常用指令

Dockerfile 是一個(gè)文本文件,其內(nèi)包含了一條條的指令(Instruction),每一條指令構(gòu)建一層,因此每一條指定的內(nèi)容,就是描述該層應(yīng)當(dāng)如何構(gòu)建。

通過使用build 命令,根據(jù)Dockerfile的描述來構(gòu)建鏡像

通過源代碼的方式

通過標(biāo)準(zhǔn)輸入流的方式

通過源代碼的路徑:

Dockerfile需要放置在項(xiàng)目的跟目錄位置

在構(gòu)建的時(shí)候,Dockerfile client會(huì)把整個(gè)context打包發(fā)送到Docker Server端,然后由server端負(fù)責(zé)build鏡像,在構(gòu)建成功后,會(huì)刪除context目錄

  docker build -t {鏡像名字} {項(xiàng)目的路徑可以是相對(duì)路徑}

通過標(biāo)準(zhǔn)輸入流:

通過標(biāo)準(zhǔn)輸入流的方式獲取Dockerfile的內(nèi)容

client不會(huì)打包上傳context目錄,因此對(duì)于一些ADD、COPY等涉及host本地文件復(fù)制的操作不能夠支持

  docker build -t {鏡像名字} - < Dockerfile路徑

使用dockerfile構(gòu)建鏡像步驟

1.手動(dòng)制作一次鏡像

2.根據(jù)歷史命令來編寫dockerfile文件

3.使用dockerfile構(gòu)鍵鏡像

docker build --network=host -t 鏡像名:標(biāo)簽

4.測(cè)試鏡像

示例nginx

[root@docker01 ~]# mkdir /data/dockerfile/nginx
?
[root@docker01 ~]# cd /data/dockerfile/nginx
?
[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
ADD nginx.repo /etc/yum.repos.d
RUN yum -y install nginx
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# ll
total 100
-rw-r--r-- 1 root root   319 Jan  9 10:11 dockerfile
-rw-r--r-- 1 root root   398 Jan  9 08:47 nginx.repo
?
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos_nginx:v1 .
[root@docker01 /data/dockerfile/nginx]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos_nginx        v1                  ddc845aaedd9        28 minutes ago      347MB
centos              7                   5e35e350aded        8 weeks ago         203MB
?

FROM 指定基礎(chǔ)鏡像

所謂的定制鏡像,必須是以一個(gè)鏡像為基礎(chǔ),在其上進(jìn)行定制。一個(gè) Dockerfile 中的 FROM 是必備的指定,并且必須是第一條指令。

FROM {bash鏡像}

RUN 執(zhí)行命令

RUN 指令是用來執(zhí)行命令行命令的,一個(gè)Dockerfile可以包含多個(gè) RUN,按照定義順序執(zhí)行。(每運(yùn)行一個(gè)run實(shí)際是開啟一個(gè)容器,只是執(zhí)行完成后刪除容器,只保留鏡像,所有最終的鏡像也是分層疊放在一起的。)

RUN 支持兩種運(yùn)行格式:

  • shell 格式:

RUN <cmd>,這個(gè)會(huì)當(dāng)做/bin/sh -c “cmd” 運(yùn)行,就像直接在命令行中輸入的命令一樣。比如上面的:

RUN echo '<h1>Hello, Nginx!</h1>' > /usr/share/nginx/html/index.html
  • exec 格式:

RUN ["可執(zhí)行文件", "參數(shù)1", "參數(shù)2", ...],Docker 把它當(dāng)做json的順序來解析,必須使用雙引號(hào),且可執(zhí)行文件必須是完整路徑。

示例nginx

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/*
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install nginx
CMD ["nginx", "-g"," daemon off;"]
#生成鏡像
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v2 .
#啟動(dòng)進(jìn)項(xiàng)測(cè)試
[root@docker01 /data/dockerfile/nginx]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos7_nginx       v2                  be89fe1379e3        22 minutes ago      418MB
centos_nginx        v1                  ddc845aaedd9        2 hours ago         347MB
centos              7                   5e35e350aded        8 weeks ago         203MB
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v2
c8e5f2c35d75a349840eae203b59d21d3c9ab202b3b3cf77c49d2237bc028ff8

測(cè)試訪問

file1.png

因?yàn)镈ockerfile 中的每一個(gè)指令都會(huì)建立一層,RUN 也不例外,每一個(gè)RUN 的行為,就和我們手工創(chuàng)建鏡象的過程一樣,新建一層,上面的這種寫法創(chuàng)建了4層,這樣會(huì)產(chǎn)生非常臃腫、非常多層的鏡像,不僅僅增加了構(gòu)建部署的時(shí)間,也容易出錯(cuò)。上面的Dockerfile正確寫法應(yīng)該如下:

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
CMD ["nginx", "-g"," daemon off;"]

這里只是更新yum源安裝nginx,實(shí)際只是為了安裝nginx,這里將四層合成一層更加的一層。

如果需要安裝nginx官方的可以參考第一個(gè)實(shí)例制作即可。只需創(chuàng)建官方源文件copy到對(duì)應(yīng)的保存目錄即可。

WORKDIR 指定工作目錄

格式:

  • WORKDIR <工作目錄路徑>

使用 WORKDIR 指令可以來制定工作目錄(或者稱為當(dāng)前目錄),以后各層的當(dāng)前目錄就被改為指定的目錄,如該目錄不存在,則會(huì)自動(dòng)創(chuàng)建。相當(dāng)于cd。

COPY 復(fù)制文件

格式:

  • COPY <源路徑> ... <目標(biāo)路徑>

  • COPY ["<源路徑1>", ... "<目標(biāo)路徑>"]

和 RUN 指令一樣,也有兩種格式,一種類似于命令行,一種類似于函數(shù)調(diào)用。

說明:這里測(cè)試一個(gè)小游戲小鳥飛飛

示例

[root@docker01 /data/dockerfile/nginx]# ll
total 100
-rw-r--r-- 1 root root   292 Jan  9 11:32 dockerfile
-rw-r--r-- 1 root root   398 Jan  9 10:32 nginx.repo
drwxr-xr-x 3 root root    98 Jan  3 19:41 xiaoniao
-rw-r--r-- 1 root root 91985 Jan  8 11:37 xiaoniao.tar.gz
?
[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
COPY xiaoniao .
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v4 .
?
[root@docker01 /data/dockerfile/nginx]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
centos7_nginx       v4                  b79afda2fe6f        39 seconds ago      418MB
centos7_nginx       v3                  4a93800b7239        20 minutes ago      418MB
centos7_nginx       v2                  be89fe1379e3        53 minutes ago      418MB
centos_nginx        v1                  ddc845aaedd9        2 hours ago         347MB
centos              7                   5e35e350aded        8 weeks ago         203MB
0 minutes       0.0.0.0:80->80/tcp   nice_franklin
?
[root@docker01 /data/dockerfile/nginx]# docker stop $(docker ps -q)
c8e5f2c35d75
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v4
987610dfb4a6c076a094695bbf382c28c81795e684e4486258d617d6626c6f57
?
[root@docker01 /data/dockerfile/nginx]# docker exec -it 564a5fb1fd91 /bin/bash
[root@564a5fb1fd91 html]# ls
2000.png  404.html  en-US     icons  index.html      poweredby.png
21.js     50x.html  icon.png  img    nginx-logo.png  sound1.mp3

測(cè)試訪問

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
COPY xiaoniao ./xiaoniao
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v5 .
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 81:80 centos7_nginx:v5
?
[root@docker01 /data/dockerfile/nginx]# docker exec -it cdea08555c04 /bin/bash
[root@cdea08555c04 html]# ls
404.html  50x.html  en-US  icons  img  index.html  nginx-logo.png  poweredby.png  xiaoniao

測(cè)試訪問

file3.png

file4.png

從上面示例可以看出, <目標(biāo)路徑> 可以是容器內(nèi)的相對(duì)路徑,如果該路徑不存在,會(huì)自動(dòng)在復(fù)制文件前創(chuàng)建缺失目錄,且<目標(biāo)路徑>也可以是相對(duì)路徑(工作目錄可以用WORKDIR 指令來指定)

如果是拷貝目錄, 那么在 <目標(biāo)地址 >也必須寫上 拷貝的目錄的名稱 。否則是將該目錄下的所文件拷貝到目標(biāo)路徑

還需注意一點(diǎn),使用COPY指令,源文件的各種元數(shù)據(jù)都會(huì)保留,比如讀、寫、執(zhí)行權(quán)限、文件變更時(shí)間等。這個(gè)特性對(duì)于鏡像定制很有用。特別是構(gòu)建相關(guān)的文件都在使用Git進(jìn)行管理的時(shí)候。

ADD 更高級(jí)的復(fù)制文件

ADD 指令和COPY 的格式和性質(zhì)基本一致。但是在 COPY 基礎(chǔ)上增加了一些功能。

比如 <源路徑> 可能是一個(gè) URL,這種情況下,會(huì)自動(dòng)去下載這個(gè)鏈接的文件到 <目標(biāo)路徑>里,下載完成的文件權(quán)限自動(dòng)設(shè)置為 600,如果不是想要的權(quán)限,那么可以通過 RUN 進(jìn)行權(quán)限調(diào)整。

如果 <源路徑> 為一個(gè) tar 壓縮文件的話,或者壓縮格式為 gzip,bzip以及xz 的情況下,ADD 指令會(huì)自動(dòng)解壓縮這個(gè)壓縮文件到 <目標(biāo)路徑>去。

示例

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v6 .
?
[root@docker01 /data/dockerfile/nginx]# docker rm -f $(docker ps -qa )
564a5fb1fd91
cdea08555c04
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v6

訪問測(cè)試

file5.png
[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao.tar.gz .
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos7_nginx:v7 .
?
[root@docker01 /data/dockerfile/nginx]# docker rm -f $(docker ps -qa )
09273df6a44b
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos7_nginx:v7
327c84ad622ff1809c586c83c4a28d3562b4638c0d7ebf31c62d88b1cbf3234e

測(cè)試訪問

VOLUME 定義匿名卷

格式:

  • VOLUME ["<路徑1>","<路徑2>"...]

  • VOLUME <路徑>

容器運(yùn)行時(shí)應(yīng)該盡量保持容器存儲(chǔ)層不會(huì)發(fā)生寫操作,對(duì)于數(shù)據(jù)庫類需要保存動(dòng)態(tài)數(shù)據(jù)的應(yīng)用,其數(shù)據(jù)文件應(yīng)該保存在數(shù)據(jù)卷中,為了防止運(yùn)行時(shí)忘記將動(dòng)態(tài)文件所保存目錄掛載為卷,在Dockerfile中,可以事先指定某些目錄掛載為匿名卷,這樣在運(yùn)行時(shí)如果用戶不指定掛載,其應(yīng)用也可以正常運(yùn)行,不會(huì)向容器存儲(chǔ)層寫入大量數(shù)據(jù)。

持久化

數(shù)據(jù)卷(文件或目錄)

-v卷名:/data/(第一次卷是空,會(huì)將容器中的數(shù)據(jù)復(fù)制到卷中,如果卷里有數(shù)據(jù),把卷數(shù)據(jù)掛載發(fā)到容器中)

-v src(宿主機(jī)目錄):dest(容器的目錄)

數(shù)據(jù)卷容器

--volumes-from (跟某一個(gè)已經(jīng)存在的容器掛載相同的卷)

[root@docker01 /data/dockerfile/nginx]# vim dockerfile 
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
VOLUME /usr/share/nginx/html
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 ~]# docker run -d -p 80:80 centos_nginx:v8
85a83e7686bbbe832b56a1287cb25ee93c81d2bf1f382cff46bd8f0971adc2f9
[root@docker01 ~]# docker inspect 85a83e7686bbbe|grep volume
 "Type": "volume",
 "Source": "/var/lib/docker/volumes/d3a703e7685bba38585127494e04e2c77cc6c9923d14a8ea719862b506348448/_data",
[root@docker01 ~]# cd /var/lib/docker
docker/        docker-engine/ 
[root@docker01 ~]# cd /var/lib/docker/volumes/d3a703e7685bba38585127494e04e2c77cc6c9923d14a8ea719862b506348448/_data/
[root@docker01 /var/lib/docker/volumes/d3a703e7685bba38585127494e04e2c77cc6c9923d14a8ea719862b506348448/_data]# ls
2000.png  21.js  icon.png  img  index.html  sound1.mp3

測(cè)試訪問

file7.png

重新開啟一個(gè)新的容器,然后修改默認(rèn)首頁

[root@docker01 ~]# docker run -d --name xiaoniao -p 81:80 centos_nginx:v8

測(cè)試訪問

數(shù)據(jù)卷容器

--volumes-from (跟某一個(gè)已經(jīng)存在的容器掛載相同的卷)

從新啟動(dòng)一個(gè)容器與之前的容器掛載相同的卷

[root@docker01 ~]# docker run -d -p 82:80 --volumes-from xiaoniao centos_nginx:v8
13197ed39494ac33460bb2d71f9276c031a747dcd2ec53fdf11cae9ba722d232
?
[root@docker01 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
13197ed39494        centos_nginx:v8     "nginx -g ' daemon o…"   2 minutes ago       Up 2 minutes        0.0.0.0:82->80/tcp   gifted_lamarr
20aa69a9e60d        centos_nginx:v8     "nginx -g ' daemon o…"   12 minutes ago      Up 12 minutes       0.0.0.0:81->80/tcp   xiaoniao
85a83e7686bb        centos_nginx:v8     "nginx -g ' daemon o…"   17 minutes ago      Up 17 minutes       0.0.0.0:80->80/tcp   elated_keller

測(cè)試訪問

EXPOSE 聲明端口

格式:

  • EXPOSE <端口1> [<端口2>...]

EXPOSE 指令是聲明運(yùn)行容器時(shí)提供的服務(wù)端口,這只是一個(gè)聲明,在運(yùn)行時(shí)并不會(huì)因?yàn)檫@個(gè)聲明就會(huì)開啟這個(gè)端口的服務(wù)。在Dockerfile中寫入這樣的聲明有兩個(gè)好處,一個(gè)是幫助使用鏡像者理解這個(gè)鏡像服務(wù)的守護(hù)端口,以方便配置映射;另一個(gè)用處則是在運(yùn)行時(shí)使用隨機(jī)端口映射時(shí),也就是 docker run -P 時(shí),會(huì)自動(dòng)隨機(jī)映射EXPOSE的端口。

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
EXPOSE 80 22
CMD ["nginx", "-g"," daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build -t centos_nginx:v9 .
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -P centos_nginx:v9
b0f5378bf1ff847ea896dcadcae341e0db225ee623229e4c30b73d8c296f8f67
?
[root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                          NAMES
b0f5378bf1ff        centos_nginx:v9     "nginx -g ' daemon o…"   11 seconds ago      Up 10 seconds       0.0.0.0:32769->22/tcp, 0.0.0.0:32768->80/tcp   busy_joliot

CMD 容器啟動(dòng)命令

容器不是虛擬機(jī),容器就是進(jìn)程,既然是進(jìn)程,那么在啟動(dòng)容器的時(shí)候,需要指定所運(yùn)行的程序及參數(shù)。CMD 指令就是用于指定容器默認(rèn)的主進(jìn)程啟動(dòng)命令的。(容易被改變)

CMD 指令有三種格式:

  • shell 格式: CMD <命令>

  • exec 格式:CMD ["可執(zhí)行文件","參數(shù)1","參數(shù)2", ...]

  • 參數(shù)列表格式:CMD ["參數(shù)1","參數(shù)2",...] , 這個(gè)時(shí)候CMD作為 ENTRYPOINT的參數(shù)。

在指令格式上,一般推薦使用exec 格式,這類格式在解析時(shí)會(huì)被解析為JSON數(shù)組,因此一定要使用雙引號(hào) “” ,而不要使用單引號(hào)。

如果使用shell 格式的話,實(shí)際的命令會(huì)被包裝為 sh -c 的參數(shù)的形式進(jìn)行執(zhí)行。比如:

CMD echo $HOME</pre>

在實(shí)際執(zhí)行中,會(huì)將其變更為:

CMD ["sh", "-c", "echo $HOME"]

在運(yùn)行時(shí)可以指定新的命令來替代鏡像設(shè)置中的這個(gè)默認(rèn)命令,比如,centos鏡像默認(rèn)的 CMD 是 /bin/bash, 如果我們直接 docker run -it centos 的時(shí)候,會(huì)直接進(jìn)入 bash。我們也可以在運(yùn)行時(shí)指定別的命令,如 docker run -it centos cat /etc/passwd 。這就是用 cat /etc/passwd命令替換了默認(rèn)的 /bin/bash 命令了。

前臺(tái)執(zhí)行和后臺(tái)執(zhí)行的問題:
 Docker 不是虛擬機(jī),容器中的應(yīng)用都應(yīng)該以前臺(tái)執(zhí)行,而不是像虛擬機(jī)、物理機(jī)里面那樣,用 start / systemctl 去啟動(dòng)后臺(tái)服務(wù),容器內(nèi)沒有后臺(tái)服務(wù)的概念。
比如:如果我們將CMD 寫成這樣:
CMD service nginx start
然后會(huì)發(fā)現(xiàn)容器執(zhí)行后就立刻退出了,甚至在容器內(nèi)使用systemctl 命令結(jié)果卻發(fā)現(xiàn)根本執(zhí)行不了。這就是因?yàn)闆]有搞明白前臺(tái)、后臺(tái)的概念,沒有區(qū)分容器和虛擬機(jī)的差異,依舊在以傳統(tǒng)虛擬機(jī)的角度去理解容器
對(duì)于容器而言,其啟動(dòng)程序就是容器應(yīng)用進(jìn)程,容器就是為了主進(jìn)程而存在的,主進(jìn)程退出,容器就失去了存在的意義,從而退出,其它輔助進(jìn)程不是它需要關(guān)心的東西。
而使用 service nginx start 命令,則是希望 start來已后臺(tái)守護(hù)進(jìn)程形式啟動(dòng)nginx服務(wù)。而 CMD service nginx start 會(huì)被理解為 CMD ["sh", "-c", "service nginx start"],因此主進(jìn)程實(shí)際上是sh, 那么當(dāng)service nginx start 命令結(jié)束后,sh 也就結(jié)束了, sh 作為主進(jìn)程退出了,自然就會(huì)令容器退出。
正確的做法是直接執(zhí)行 nginx 可執(zhí)行文件,并且要求以前臺(tái)形式。如:
CMD ["nginx", "-g"," daemon off;"]

ENTRYPOINT 入口點(diǎn)

ENTRYPOINT 的格式和 RUN 指令格式一樣,分為 exec 格式 和shell格式。

ENTRYPOINT 的目的和 CMD 一樣,都是在指定容器啟動(dòng)程序及參數(shù)。ENTRYPOINT 在運(yùn)行時(shí)也可以替代,不過比CMD要繁瑣,需要通過 docker run 的參數(shù) --entrypoint 來指定。

當(dāng)指定了 ENTRYPOINT 后,CMD 的含義就發(fā)生了改變,不再是直接運(yùn)行其命令,而是將 CMD 的內(nèi)容作為參數(shù)傳給 ENTRYPOINT 指令,換句話說實(shí)際執(zhí)行時(shí),將變?yōu)椋?/p>

ENTRYPOINT "<CMD>"

那么問題來了? 有了CMD ,為什么還要有ENTRYPOINT呢? 這種 ENTRYPOINT "<CMD>" 有什么好處呢?

場(chǎng)景一:讓鏡像變成命令一樣使用

假設(shè)我們需要一個(gè)得知自己當(dāng)前公網(wǎng)IP的鏡像,那么可以使用CMD來實(shí)現(xiàn):

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
CMD ["curl","-s","https://ip.cn"]                                                                        
[root@docker01 /data/dockerfile/nginx]# docker build -t centos:vi .
Sending build context to Docker daemon  267.8kB
Step 1/2 : FROM centos:7
 ---> 5e35e350aded
Step 2/2 : CMD ["curl","-s","https://ip.cn"]
 ---> Running in 1cd0d54ea938
Removing intermediate container 1cd0d54ea938
 ---> 5dfbd8f7e484
Successfully built 5dfbd8f7e484
Successfully tagged centos:vi
?
[root@docker01 /data/dockerfile/nginx]# docker run centos:vi
?
{"ip": "101.81.163.198", "country": "上海市", "city": "電信"}

這樣看起來是可以當(dāng)做命令來使用,不過命令一般有參數(shù),CMD 中實(shí)質(zhì)的命令是 curl, 如果希望顯示HTTP頭信息,就需要加上 -i 參數(shù)。

[root@docker01 /data/dockerfile/nginx]# docker run centos:vi -i
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"-i\": executable file not found in $PATH": unknown.

這里可以看到可執(zhí)行文件找不到的報(bào)錯(cuò), executable file not found。上面說過,跟在鏡像名后面的是 command, 運(yùn)行時(shí)會(huì)替換 CMD 的默認(rèn)值,因此這里的 -i 替換了原來的 CMD,而不是添加在原來的 curl -s https://ip.cn 后面,而 -i 根本不是命令,所以找不到。

那么如果我們希望加入 -i 參數(shù),我們就必須重新完整的輸入這個(gè)命令:

[root@docker01 /data/dockerfile/nginx]# docker run centos:vi curl -i https://ip.cn #替換了默認(rèn)的CMD
 % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
 Dload  Upload   Total   Spent    Left  Speed
100    67    0    67    0     0     16      0 --:--:--  0:00:03 --:--:--    16
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2020 12:26:29 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d0419e04a3638ee1d3087c5cf80f494101578572789; expires=Sat, 08-Feb-20 12:26:29 GMT; path=/; domain=.ip.cn; HttpOnly; SameSite=Lax
CF-Cache-Status: DYNAMIC
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 5526665d7be1e4cc-LAX
?
{"ip": "101.81.163.198", "country": "上海市", "city": "電信"}

顯然這不是好的解決辦法,而是用 ENTRYPOINT 就可以解決這個(gè)問題:

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
ENTRYPOINT ["curl","-s","https://ip.cn"]
?
[root@docker01 /data/dockerfile/nginx]# docker build -t centos:v1 .
Sending build context to Docker daemon  267.8kB
Step 1/2 : FROM centos:7
 ---> 5e35e350aded
Step 2/2 : ENTRYPOINT ["curl","-s","https://ip.cn"]
 ---> Running in f992ba880014
Removing intermediate container f992ba880014
 ---> 8b36c3256b89
Successfully built 8b36c3256b89
Successfully tagged centos:v1
[root@docker01 /data/dockerfile/nginx]# docker run centos:v1
{"ip": "101.81.163.198", "country": "上海市", "city": "電信"}
[root@docker01 /data/dockerfile/nginx]# docker run centos:v1 -i
HTTP/1.1 200 OK
Date: Thu, 09 Jan 2020 12:32:11 GMT
Content-Type: application/json; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: __cfduid=d3c35693353a4686d5d6eebe258bb5d5c1578573131; expires=Sat, 08-Feb-20 12:32:11 GMT; path=/; domain=.ip.cn; HttpOnly; SameSite=Lax
CF-Cache-Status: DYNAMIC
Expect-CT: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
Server: cloudflare
CF-RAY: 55266eb75f10e4d0-LAX
?
{"ip": "101.81.163.198", "country": "上海市", "city": "電信"}

從上面可以看出,不加-i 參數(shù)可以運(yùn)行成功, 加上-i參數(shù)也可以運(yùn)行成功,且達(dá)到了curl -i 的效果。這是因?yàn)楫?dāng)存在 ENTRYPOINT 后,CMD 的內(nèi)容將會(huì)作為參數(shù)傳遞給 ENTRYPOINT ,而這里 -i 就是新的CMD,因此會(huì)作為參數(shù)傳遞給curl,從而達(dá)到了我們預(yù)期的效果。

場(chǎng)景二:應(yīng)用運(yùn)行前的準(zhǔn)備工作

啟動(dòng)容器就是啟動(dòng)主進(jìn)程,但有些時(shí)候,啟動(dòng)主進(jìn)程前,需要一些準(zhǔn)備工作。比如 mysql 類的數(shù)據(jù)庫,可能需要一些數(shù)據(jù)庫配置、初始化的工作,這些工作要在最終的mysql 服務(wù)器運(yùn)行之前解決。此外,可能希望避免使用root 用戶去啟動(dòng)服務(wù)器, 從而提高安全性,而在啟動(dòng)還需要以 root 身份執(zhí)行一些必要的準(zhǔn)備工作,最后切換到服務(wù)用戶啟動(dòng)服務(wù)等?;蛘叱朔?wù)外,其它命令依舊可以使用 root 身份執(zhí)行,方便調(diào)試等。

這些準(zhǔn)備工作是和容器 CMD 無關(guān)的,無論CMD 是什么,都需要事先進(jìn)行一個(gè)預(yù)處理的工作。這種情況下,可以寫一個(gè)腳本,然后放入 ENTRYPOINT 中去執(zhí)行,而這個(gè)腳本會(huì)接到的參數(shù) (也就是CMD)作為指令,在腳本最后執(zhí)行。比如官方的redis 中就是這樣做的:

FROM alpine:3.4 
...
RUN addgroup -S redis && adduser -S -G redis redis 
...
ENTRYPOINT ["docker-entrypoint.sh"]
EXPOSE 6379 
CMD ["redis-server"]

可以看到其中為了 redis 服務(wù)創(chuàng)建了redis 用戶,并在最后指定了 ENTRYPOINT 為 docker-entrypoint.sh 腳本。

#!/bin/bash
...
# allow the container to be started with `--user` 
if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then
 chown -R redis .
 exec su-exec redis "$0" "$@"
fi
?
exec "$@"

該腳本的內(nèi)容就是根據(jù) CMD 的內(nèi)容來判斷,如果是 redis-server 的話,則切換到 redis用戶身份啟動(dòng)服務(wù),否則依舊使用 root 身份執(zhí)行。比如:

# docker run -it redis id
uid=0(root) gid=0(root) groups=0(root)

示例1

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build -t centos_nginx:v10 .
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos_nginx:v10
ff772730832e18068e01da1d1ce654314f222dc33e4628b8db8cc5b6f3703176
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 81:80 centos_nginx:v10 sdhdhj
6f7772a652a5759aff7ab635453b300a775b7a1d91a30a08a5c55999c2987799
?
[root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
ff772730832e        centos_nginx:v10    "nginx -g 'daemon of…"   32 seconds ago      Up 31 seconds       0.0.0.0:80->80/tcp   strange_pare
?
[root@docker01 /data/dockerfile/nginx]# docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED              STATUS                          PORTS                NAMES
6f7772a652a5        centos_nginx:v10            "nginx sdhdhj"           20 seconds ago       Exited (1) 20 seconds ago                            tender_rubin
ff772730832e        centos_nginx:v10            "nginx -g 'daemon of…"   37 seconds ago       Up 37 seconds                   0.0.0.0:80->80/tcp   strange_pare

示例2

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
RUN rm -rf /etc/yum.repos.d/* \
 && curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo \
 && curl -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo \
 && yum -y install nginx
WORKDIR /usr/share/nginx/html
RUN rm -rf ./*
ADD xiaoniao .
ADD init.sh /init.sh
ENTRYPOINT ["/bin/bash","/init.sh"]
?
[root@docker01 /data/dockerfile/nginx]# docker build -t centos_nginx:v11 .
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 80:80 centos_nginx:v11
eeac9eef5c6941bbd9581d4304d8f7f48ad89a39aecfd2e6479c50f9d424a144
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -p 81:80 centos_nginx:v11 1111 #參數(shù)被當(dāng)成參數(shù),該腳本沒有參數(shù),所以可以正常啟動(dòng)
fb656151c391b84411cb8bfb6e2b8e5b6b321dc9ca1246f2b00026e13c01ed89
?
[root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
fb656151c391        centos_nginx:v11    "/bin/bash /init.sh …"   10 seconds ago      Up 10 seconds       0.0.0.0:81->80/tcp   lucid_wilson
eeac9eef5c69        centos_nginx:v11    "/bin/bash /init.sh"     29 seconds ago      Up 28 seconds       0.0.0.0:80->80/tcp   affectionate_pike
?
[root@docker01 /data/dockerfile/nginx]# docker ps -a
CONTAINER ID        IMAGE                       COMMAND                  CREATED             STATUS                      PORTS                NAMES
fb656151c391        centos_nginx:v11            "/bin/bash /init.sh …"   30 seconds ago      Up 29 seconds               0.0.0.0:81->80/tcp   lucid_wilson
eeac9eef5c69        centos_nginx:v11            "/bin/bash /init.sh"     49 seconds ago      Up 48 seconds               0.0.0.0:80->80/tcp   affectionate_pike

ENV 設(shè)置環(huán)境變量

格式:

  • ENV <key><value>

  • ENV<key1>=<value1> <key2>=<value2>

這個(gè)指令很簡單,就是設(shè)置環(huán)境變量,無論是后面的其它指令,如RUN,還是運(yùn)行時(shí)的應(yīng)用,都可以直接使用這里定義的環(huán)境變量。

[root@docker01 /data/dockerfile/nginx]#  Dockerfile   #查看編輯好的Dockerfile文件內(nèi)容
FROM centos
ENV name1 xiaobai
ENV name2=zhazha name3=cainiao
[root@docker01 /data/dockerfile/nginx]#  build -t mycentos:v5 .  #構(gòu)建鏡像
[root@docker01 /data/dockerfile/nginx]#  run --rm -it --name test mycentos:v5  #啟動(dòng)一個(gè)容器,并以交互式啟動(dòng) 
[root@b55929b2c63f /]# echo $name1  #進(jìn)入容器后調(diào)用環(huán)境變量name1
xiaobai
[root@b55929b2c63f /]# echo $name2 $name3  #調(diào)用環(huán)境變量name2,name3
zhazha cainiao

定義了環(huán)境變量,可以在后續(xù)的指令中直接使用環(huán)境變量

FROM centos
ENV URL="https://nginx.org/download/" 
ADD $URLnginx.1.17.7.tar.gz /usr/local/

示例

[root@docker01 /data/dockerfile/nginx]# vim dockerfile
FROM centos:7
ADD http://nginx.org/download/nginx-1.17.7.tar.gz /opt/
RUN tar -xvzf /opt/nginx-1.17.7.tar.gz -C /usr/local/src/ \
 && useradd -M -s /sbin/nologin nginx
WORKDIR /usr/local/src/nginx-1.17.7
RUN ./configure --user=nginx --group=nginx --prefix=/usr/local/nginx --with-file-aio --with-http_ssl_module --wi
th-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with
-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module -
-with-http_gunzip_module --with-http_gzip_static_module --with-http_auth_request_module --with-http_random_index
_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module && make &&
make install
VOLUME ["/usr/local/nginx/html"]
RUN rm -rf /opt/nginx-1.17.7.tar.gz
ENV PATH=/usr/local/nginx/sbin:$PATH
EXPOSE 80
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
?
[root@docker01 /data/dockerfile/nginx]# docker build --network=host -t centos_nginxsrc:v4 .
?
[root@docker01 /data/dockerfile/nginx]# docker run -d -P centos_nginxsrc:v4
?
root@docker01 /data/dockerfile/nginx]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                   NAMES
8544d8311d16        centos_nginxsrc:v4   "nginx -g 'daemon of…"   4 minutes ago       Up 4 minutes        0.0.0.0:32771->80/tcp   gallant_neumann

訪問測(cè)試

file10.png

ARG 構(gòu)建參數(shù)

格式:

  • ARG <參數(shù)名>[=<默認(rèn)值>]

構(gòu)建參數(shù)和 ENV的效果一樣,都是設(shè)置環(huán)境變量。所不同的是,ARG 所設(shè)置的構(gòu)建環(huán)境和環(huán)境變量,在將來容器運(yùn)行時(shí)是不會(huì)存在這些環(huán)境變量的。但是不要因此就使用 ARG 保存密碼之類的信息,因?yàn)?docker history 還是可以看到所有值的。

Dockerfile 中的ARG指令是定義參數(shù)名稱,以及定義其默認(rèn)值。該默認(rèn)值可以在構(gòu)建命令 docker build 中用 --build-arg <參數(shù)名>=<值> 來覆蓋。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過簡信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容