【转一个朋友的dockerfile笔记

基于Dockerfile构建镜像

1. Dockerfile:source code for building Docker file

Docker可以通过从Dockerfile文件中读取指令自动构建镜像

Dockerfile是一个文本文档,它包含用户可以在命令行上调用的所有命令来组装映像

使用Docker build命令,用户可以通过逐条执行几条命令自动创建镜像

2. Dockerfile语法格式:

首行必须是以#开头的行

不区分大小写,但约定俗成的惯例都是使用全部大写。

Docker按顺序在Dockerfile中运行指令

第一个指令必须是“FROM”,以便指定要从其中构建的基本映像

3. 环境变量(使用ENV语句声明)也可以在某些指令中使用,作为由Dockerfile解释的变量。

在Dockerfile中,环境变量可以是$variable_name或${variable_name}

${variable_name}语法还支持一些标准bash修饰符

${variable:-word}表示,如果设置了变量,那么结果将是该值。如果变量未设置,则结果为word。

${variable:+word}表示如果设置了变量,那么结果将是word,否则结果将是空字符串。

4. .dockerignore文件

在工作目录中若有子目录,而子目录中有些文件不想引用,就可以用.dockerignore来隐藏文件。

.dockerignore文件内指明不引用的文件。

5. FROM

用来指定基础镜像,若指定的镜像不存在,会先到Docker Hub中下载

语法:

FROM [AS ] #[AS ]:别名

FROM [:] [AS ] #tag:标签

FROM [@] [AS ] #digest:哈希码

6. docker build命令

Build an image from a Dockerfile

Options

-t, --tag list Name and optionally a tag in the 'name:tag' format

-m, --memory bytes Memory limit

-c, --cpu-shares int CPU shares (relative weight)

7. LABEL

添加镜像文件的元数据,可出现多次,强烈建议只使用一条,因为一条指令会添加一个层,层数越多,运行效率越低。

语法格式:

LABEL = = =... #可指定多个LABEL

LABEL #只可指定一个LABEL,第一个空格后的内容都会被当作value

示例

只修改一个镜像的FROM、LABEL

创建工作目录image

[root@docker ~]# mkdir image[root@docker ~]# cd image

编辑Dockerfile文件,添加以下内容:

[root@docker image]# vim Dockerfile#Test Image BuildFROM alpineLABEL maintainer="lixinkuan "

制作镜像:

[root@docker image]# docker build .Sending build context to Docker daemon  2.048kBStep 1/2 : FROM alpine ---> 3fd9065eaf02Step 2/2 : LABEL maintainer="lixinkuan " --->Runningine1ce9acfc453Removing intermediate container e1ce9acfc453 ---> 1deb17a1af32Successfully built 1deb17a1af32

查看:REPOSITORY和TAG都为空的即为新创建的镜像文件

[root@docker image]#dockerimagelsREPOSITORYTAGIMAGEIDCREATEDSIZE                            1deb17a1af325minutesago4.15MBnginxlatestcd5239a0906a3weeksago109MBbusyboxlatest8c811b4aec355weeksago1.15MBhttpd2.4fb2f3851a9718weeksago178MBalpinelatest3fd9065eaf025monthsago4.15MB

创建docker镜像时,可使用-t后跟 'name:tag' 指定TAG

也可用如下命令添加标签:

[root@docker image]# docker image tag 1deb17a1af32 alpine:lxk[root@docker image]# docker imagesREPOSITORY                  TAG                IMAGE ID            CREATED            SIZEalpine                      lxk1deb17a1af325minutes ago4.41MB

8. COPY

用于从Docker宿主机复制文件至创建的新映像文件

语法:

COPY ...

COPY ["",... ""]

:要复制的源文件或目录,支持使用通配符

:目标路径,即正在创建的image的文件系统路径;建议为使用绝对路径,否则,COPY指定则以WORKDIR为其起始路径

注意:在路径中有空白字符时,通常使用第二种格式

文件复制准则:

必须是build上下文中的路径,不能是其父目录中的文件

如果是目录,则其内部文件或子目录会被递归复制,但目录自身不会被复制

如果指定了多个,或在中使用了通配符,则必须是一个目录,且必须以/结尾

如果事先不存在,它将会被自动创建,这包括其父目录路径

示例:复制单个文件

在image目录下为index.html添加内容:

[root@docker image]#  echo '

hello,docker!

' > index.html

编辑Dockerfile文件,添加语句:

[root@docker image]# vim Dockerfile #Test Image BuildFROM alpineLABEL maintainer="lixinkuan "COPY index.html/var/www/html/

用alpine启动一个容器,查看是否有/var/www/html目录

[root@docker image]# docker run -it --name a1 alpine/# ps aux PID  USER    TIME  COMMAND1root0:00/bin/sh7root0:00ps aux/# ls /var/www/htmlls: /var/www/html: No such fileordirectory

制作镜像

[root@docker image]# docker build -t cpindex:latest .Sending build context to Docker daemon  3.072kBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " --->Runningin9d96e0655a82Removing intermediate container 9d96e0655a82 ---> 56049399eb78Step 3/3 : COPY index.html /var/www/html/ ---> bace8e55c97bSuccessfully built bace8e55c97bSuccessfully tagged cpindex:latest

查看制作的镜像:

[root@docker image]# docker image lsREPOSITORY          TAG                IMAGE ID            CREATED            SIZEcpindex            latest              bace8e55c97b52seconds ago4.15MB

以制作的镜像启动一个容器,并查看文件是否存在

[root@docker image]# docker run --name copyfile -it --rm cpindex:latest/# ls /var/www/htmlindex.html/# cat /var/www/html/index.html

hello,docker!

示例:复制目录下的多个文件至目录

复制一个目录至/root/image下

[root@docker image]# cp -r /etc/default/ ./ [root@docker image]# lsdefaultDockerfile  index.html[root@docker image]# ls default/grub  kibana  nss  useradd

修改Dockerfile文件为以下内容:

#Test Image BuildFROM alpineLABEL maintainer="lixinkuan "COPYdefault/tmp/

制作镜像:

[root@docker image]# docker build -t cpdir:latest ./Sending build context to Docker daemon  9.216kBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/3 : COPY default /tmp/ ---> 18cacf50aef9Successfully built 18cacf50aef9Successfully tagged cpdir:latest

查看并验证:

[root@docker image]# docker image lsREPOSITORY          TAG                IMAGE ID            CREATED            SIZEcpdir              latest18cacf50aef924seconds ago4.15MB[root@docker image]# docker run --name cpdir -it --rm cpdir:latestWARNING: IPv4 forwardingisdisabled. Networking willnotwork./# ls /tmpgrub    kibana  nss      useradd

示例:使用数组格式创建配置文件

修改配置文件如下:

#Test Image BuildFROMalpineLABEL maintainer="lixinkuan "COPY ["default","/tmp/default"]

创建镜像并验证

[root@docker image]# docker build -t cp:latest ./Sending build context to Docker daemon9.216kBStep1/3: FROM alpine --->3fd9065eaf02Step2/3: LABEL maintainer="lixinkuan "---> Using cache --->56049399eb78Step3/3: COPY ["default","/tmp/default"] ---> bf0799319943Successfully built bf0799319943Successfully tagged cp:latest[root@docker image]# docker run --name cp -it --rm cp:latest/# cd /tmp/tmp# lsdefault/tmp # cd default//tmp/default# lsgrub    kibana  nss      useradd/tmp/default# exit

9. ADD

ADD类似于COPY指令,ADD支持tar文件和URL路径

Syntax

ADD ...

ADD [""...""]

操作准则:

同COPY指令

如果为URL且不以/结尾,则指定的文件将被下载并直接被创建为;如果以/结尾,则文件名URL指定的文件将被直接下载并保存为/

如果是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为类似于“tar -x”命令;然而,通过URL获取到的tar文件将不会自动展开;

如果有多个,或其间接或直接使用了通配符,则必须是一个以/结尾的目录路径;如果不以/结尾,则其被视作一个普通文件,的内容将被直接写入到

示例:下载一个文件至镜像文件

在工作目录下编写Dockerfile文件(使用URL时,用ftp协议失败)

#Test Image BuildFROM alpineLABEL maintainer="lixinkuan "COPY ["default","/tmp/default"]ADDhttps://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/zsh-5.0.2-28.el7.x86_64.rpm /tmp/

创建镜像文件

[root@docker image]# docker build -t zsh:latest ./Sending build context to Docker daemon  9.216kBStep 1/4 : FROM alpine ---> 3fd9065eaf02Step 2/4 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/4 : COPY ["default","/tmp/default"] ---> Using cache ---> bf0799319943Step 4/4 : ADD https://mirrors.aliyun.com/centos/7.5.1804/os/x86_64/Packages/zsh-5.0.2-28.el7.x86_64.rpm /tmp/Downloading [==================================================>]  2.494MB/2.494MB ---> 538ab9c6983eSuccessfully built 538ab9c6983eSuccessfully tagged zsh:latest

创建容器并查看

[root@docker image]# docker run -it --name zsh --rm zsh:latest/# cd /tmp/tmp# lsdefaultzsh-5.0.2-28.el7.x86_64.rpm

示例:ADD一个压缩包至镜像文件

复制压缩包至工作目录,并在工作目录编辑Dockerfile文件

[root@docker image]# cp /root/wordpress-4.8.1-zh_CN.tar.gz ./[root@docker image]# vim Dockerfile #Test Image BuildFROM alpineLABEL maintainer="lixinkuan "ADD wordpress-4.8.1-zh_CN.tar.gz/tmp/

制作镜像文件

[root@docker image]# docker build -t wordpress:latest ./Sending build context to Docker daemon  8.652MBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/3 : ADD wordpress-4.8.1-zh_CN.tar.gz /tmp/ ---> 58c32caba31eSuccessfully built 58c32caba31eSuccessfully tagged wordpress:latest

创建容器并查看

[root@docker image]# docker run --name a1 -it --rm wordpress:latest/# ls /tmp/wordpress/index.php            wp-admin              wp-content            wp-load.php          wp-signup.phplicense.txt          wp-blog-header.php    wp-cron.php          wp-login.php          wp-trackback.phpreadme.html          wp-comments-post.php  wp-includes          wp-mail.php          xmlrpc.phpwp-activate.php      wp-config-sample.php  wp-links-opml.php    wp-settings.php/# exit

10. WORKDIR

用于为Dockerfile中所有的RUN、CMD、ENTRYPOINT、COPY和ADD指定设定工作目录

Syntax

WORKDIR

在Dockerfile文件中,WORKDIR指令可出现多次,其路径也可以为相对路径,不过,其是相对此前一个WORKDIR指令指定的路径

另外,WORKDIR也可调用由ENV指定定义的变量

例如:

WORKDIR /var/log

WORKDIR $STATEPATH

示例

在工作目录下编辑Dockerfile文件:

#Test Image BuildFROMalpineLABEL maintainer="lixinkuan "WORKDIR /tmpADD wordpress-4.8.1-zh_CN.tar.gz src

创建镜像:

[root@docker image]# docker build -t wordpress:v0.1 ./Sending build context to Docker daemon  8.652MBStep 1/4 : FROM alpine ---> 3fd9065eaf02Step 2/4 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/4 : WORKDIR /tmpRemoving intermediate container 08bef4630472 ---> 54f97eda6b49Step 4/4 : ADD wordpress-4.8.1-zh_CN.tar.gz src ---> 0811aff4fa7dSuccessfully built 0811aff4fa7dSuccessfully tagged wordpress:v0.1

创建容器后,默认工作路径就是WORKDIR所指的目录/tmp

[root@docker image]# docker run --name a1 -it --rm wordpress:v0.1/tmp# lssrc/tmp # ls src/wordpress/tmp # ls src/wordpress/index.php            wp-admin              wp-content            wp-load.php          wp-signup.phplicense.txt          wp-blog-header.php    wp-cron.php          wp-login.php          wp-trackback.phpreadme.html          wp-comments-post.php  wp-includes          wp-mail.php          xmlrpc.phpwp-activate.php      wp-config-sample.php  wp-links-opml.php    wp-settings.php/tmp# exit

11. VOLUME

用于在image中创建一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷

Syntax

VOLUME

VOLUME [""]

如果挂载点目录路径下此前有文件存在,docker run命令会把原文件隐藏.

如果此前挂载点不存在,docker 会自动创建该目录.

挂载点下文件变化都可以在宿主机查看

查看方法:

docker volume ls #查看宿主机所有挂载的目录

docker inspect -f {{.Mounts}} a1 #通过查看指定容器信息查看挂载点路径

示例

在需要挂载的目录下提供文件

[root@docker image]# echo "hello,test dockerfile" > /var/www/html/index.html

在工作目录下编辑Dockerfile文件

#Test Image BuildFROM alpineLABEL maintainer="lixinkuan "#WORKDIR /tmp#ADD wordpress-4.8.1-zh_CN.tar.gz src/VOLUME /var/www/html

创建镜像文件

[root@docker image]# docker build -t file:v0.1 ./Sending build context to Docker daemon  8.651MBStep 1/3 : FROM alpine ---> 3fd9065eaf02Step 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56049399eb78Step 3/3 : VOLUME /var/www/html ---> [Warning] IPv4 forwarding is disabled. Networking will not work. --->Runninginda84d9f4ca1eRemoving intermediate container da84d9f4ca1e ---> b26c2d7ea64cSuccessfully built b26c2d7ea64cSuccessfully tagged file:v0.1

创建容器:

[root@docker image]# docker run --name a1 -it --rm file/# cd /var/www/html//var/www/html# echo abc > index.html/var/www/html# cat index.htmlabc

查看宿主机上的文件:

[root@docker ~]# docker volume ls      #查看本机所有容器挂载的目录DRIVER              VOLUME NAMElocal6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735[root@docker ~]# docker inspect -f {{.Mounts}} a1      #查看a1容器的挂载文件路径[{volume6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735 /var/lib/docker/volumes/6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735/_data /var/www/htmllocaltrue }][root@docker ~]# cd /var/lib/docker/volumes/6368d0a0b462f5329a4b3bdcb7030e0d6f724bf9f801386f87fdac7660cd1735/_data/[root@docker _data]# lsindex.html[root@docker _data]# cat index.html abc#该内容与容器中index.html内容一样

12. EXPOSE

用于为容器打开指定要监听的端口以实现与外部通信

实质是通过iptables添加DNAT规则,把外网主机访问宿主机的请求转发至指定容器.

需要宿主机开启核心转发功能.

可通过iptables -t nat -nvL查看添加的规则.

通过Dockerfile制作镜像时若不用EXPOSE指定要暴露的端口,可用以下两种方法暴露端口:

容器运行后,自行添加DNAT规则实现端口暴露.

docker run时使用-p选项指定暴露的端口.

docker run时使用-P选项暴露所有容器内监听的端口.

docker run时,使用-p选项指定的优先级要高于Dockerfile制作镜像时指定要暴露的端口.

Syntax

EXPOSE [/] [[/] ...]

用于指定传输层协议,可为tcp或udp二者之一,默认为TCP协议

EXPOSE指令可一次指定多个端口,例如

EXPOSE 11211/udp 11211/tcp

不用EXPOSE时,宿主机内容器若要被外网主机访问的情况

下载redis:4-alpine

[root@docker ~]# docker pull redis:4-alpine4-alpine: Pulling from library/redisff3a5c916c92: Pull complete 5fbab8756652: Pull complete ff7d4663b06c: Pull complete 0b5cf71258c2: Pull complete 54bbb9bad8ba: Pull complete 8fe9a341d124: Pull complete Digest: sha256:686ab026fae07b3b99a8e74210c361714a80311ecc55f23b349ae930ed2f5a95Status: Downloaded newer image for redis:4-alpine[root@docker ~]# docker imagesREPOSITORY          TAG                IMAGE ID            CREATED            SIZEredis              4-alpine            caaeda72bf8f        12 days ago        27.8MB

运行redis镜像

[root@docker ~]# docker run --name db1 -d --rm -p 6379 redis:4-alpine881d5648c7388449a39c67024206c5710b1538f4c941039fa3905bb601b09699[root@docker ~]# docker exec -it db1 ifconfigeth0Linkencap:Ethernet  HWaddr02:42:AC:11:00:02inetaddr:172.17.0.2Bcast:172.17.255.255Mask:255.255.0.0UP BROADCAST RUNNING MULTICASTMTU:1500Metric:1RXpackets:8errors:0dropped:0overruns:0frame:0TXpackets:0errors:0dropped:0overruns:0carrier:0collisions:0txqueuelen:0RXbytes:648(648.0B)  TXbytes:0(0.0B)lo        Linkencap:Local Loopback            inetaddr:127.0.0.1Mask:255.0.0.0UP LOOPBACK RUNNINGMTU:65536Metric:1RXpackets:0errors:0dropped:0overruns:0frame:0TXpackets:0errors:0dropped:0overruns:0carrier:0collisions:0txqueuelen:1RXbytes:0(0.0B)  TXbytes:0(0.0B)[root@docker ~]# docker exec -it db1 /bin/sh/data# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address          Foreign Address        State      tcp000.0.0.0:63790.0.0.0:*LISTEN      tcp00:::6379:::*LISTEN      /data#

查看映射的端口

[root@docker ~]# docker container port db16379/tcp ->0.0.0.0:32768

外网主机访问本地宿主机容器

[root@node1 tmp]#redis-cli-h192.168.1.106-p32768192.168.1.106:32768>select1OK192.168.1.106:32768[1]>setmykeyhiOK192.168.1.106:32768[1]>keys*1) "mykey"192.168.1.106:32768[1]>exit

查看本地容器内是否有数据

[root@docker ~]# docker exec -it db1 /bin/sh/data# redis-cli 127.0.0.1:6379>select1OK127.0.0.1:6379[1]>keys *1)"mykey"127.0.0.1:6379[1]>exit/data# exit

开启自动端口暴露

在工作目录下编写Dockerfile文件

#Test Image BuildFROMredis:4-alpineLABEL maintainer="lixinkuan "EXPOSE6379/tcp26379/tcp

制作镜像文件

[root@docker images]# docker build -t expose_db:latest ./Sending build context to Docker daemon  8.645MBStep 1/3 : FROM redis:4-alpine ---> caaeda72bf8fStep 2/3 : LABEL maintainer="lixinkuan " --->Runninginf43f9e43b27aRemoving intermediate container f43f9e43b27a ---> e98bb940a8a2Step 3/3 : EXPOSE 6379/tcp 26379/tcp --->Runninginf53a9be4f661Removing intermediate container f53a9be4f661 ---> ea40417716a0Successfully built ea40417716a0Successfully tagged expose_db:latest

运行并查看效果

[root@docker images]# docker run --name a1 -d --rm -P redis_expose:latestad1225390f8f246cc5bde693ea99b120ee3a2f474416603b0797cda94787cc03[root@docker images]# docker container port a16379/tcp ->0.0.0.0:32772

换一台主机连接数据库查看

[root@node1 ~]#redis-cli-h192.168.200.45-p32772192.168.200.45:32772>select1OK192.168.200.45:32772[1]>keys*(emptylistorset)192.168.200.45:32772[1]>settestdockerfileOK192.168.200.45:32772[1]>keys*1) "test"192.168.200.45:32772[1]>gettest"dockerfile"

在a1容器上查看:

[root@docker images]# docker exec -it a1 /bin/sh/data# redis-cli 127.0.0.1:6379>select1OK127.0.0.1:6379[1]>get test"dockerfile"

示例:验证Dockerfile与docker run时使用-p的优先级

编辑Dockerfile

[root@docker images]# cat Dockerfile #Test Image BuildFROM redis:4-alpineLABEL maintainer="lixinkuan "EXPOSE6379/tcp80/tcp

制作镜像:

[root@docker images]# docker build -t expose_port .Sending build context to Docker daemon  8.645MBStep 1/3 : FROM redis:4-alpine ---> caaeda72bf8fStep 2/3 : LABEL maintainer="lixinkuan " ---> Using cache ---> 188775dd2e3eStep 3/3 : EXPOSE 6379/tcp 80/tcp --->Runninginb0f5bfbaafaeRemoving intermediate container b0f5bfbaafae ---> 165e707c2b23Successfully built 165e707c2b23Successfully tagged expose_port:latest

运行容器时指定要暴露的端口:

[root@docker images]# docker run --name db1 -d --rm -p 25 expose_porte00f3e304103954c00651d44b00ae9961608900e0d5688eee4c08f140340f480[root@docker images]# docker container port db125/tcp ->0.0.0.0:32779

查看防火墙规则,只有暴露25端口的DNAT规则

[root@docker images]# iptables -t nat -nvLChain DOCKER (2 references) pkts bytes target    prot optinoutsourcedestination            0    0 RETURN    all  --  docker0 *      0.0.0.0/0            0.0.0.0/0              0    0 DNAT      tcp  --  !docker0 *      0.0.0.0/0            0.0.0.0/0            tcp dpt:32779 to:172.17.0.2:25

13. ENV

用于为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用

调用格式为$variable_name或${variable_name}

Syntax

ENV

ENV = ...

第一种格式中,之后的所有内容均会被视作其的组成部分,因此,一次只能设置一个变量

第二种格式可用一次设置多个变量,每个变量为一个"="的键值对,如果中包含空格,可以以反斜线()进行转义,也可通过对加引号进行标识;另外,反斜线也可用于续行

定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能

示例

编辑Dockerfile文件

FROMbusyboxLABEL maintainer="lixinkuan "ENV DOCROOT="/data/web/html/"COPY index.html${DOCROOT}VOLUME${DOCROOT}

提供index及所需挂载目录:

[root@docker bbox]# mkdir -pv /data/web/htmlmkdir: created directory ‘/data’mkdir: created directory ‘/data/web’mkdir: created directory ‘/data/web/html’[root@docker bbox]# echo hello Docker > index.html[root@docker bbox]# cat index.htmlhello Docker

制作镜像:

[root@docker bbox]# docker build -t bbox_file:latest ./Sending build context to Docker daemon  3.072kBStep 1/5 : FROM busyboxlatest: Pulling from library/busybox07a152489297: Pull complete Digest: sha256:141c253bc4c3fd0a201d32dc1f493bcf3fff003b6df416dea4f41046e0f37d47Status: Downloaded newer image for busybox:latest ---> 8c811b4aec35Step 2/5 : LABEL maintainer="lixinkuan " --->Runningin87a1f2c22ad6Removing intermediate container 87a1f2c22ad6 ---> 56f723d6220cStep 3/5 : ENV DOCROOT="/data/web/html/" --->Runningin21fd1fcb0474Removing intermediate container 21fd1fcb0474 ---> c095f8dd8418Step 4/5 : COPY index.html ${DOCROOT} --->ee77cd16629aStep 5/5 : VOLUME ${DOCROOT} --->Runningin00474fde8b85Removing intermediate container 00474fde8b85 ---> d51ea735fdd3Successfully built d51ea735fdd3Successfully tagged bbox_file:latest

运行容器并查看

[root@docker bbox]# docker run --name a1 -it --rm bbox_file:latest/# ls /data/web/htmlindex.html/# cat /data/web/html/index.htmlhello Docker

另启终端查看挂载的卷:

[root@docker ~]# docker volume lsDRIVER              VOLUME NAMElocal1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbflocalb2df5fcd0e1aa58c403d2e8f0ec880feb7dcb1a80a688697e76122adec55e789[root@docker ~]# docker inspect -f {{.Mounts}} a1[{volume1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf /var/lib/docker/volumes/1dcd37d2c4f2e6a71e0b96a385714ff01cad5d578e396c9b012922e9993aecbf/_data /data/web/htmllocaltrue }]

14. CMD与RUN

CMD

用于定义镜像启动为容器时默认运行的应用程序。

类似于RUN指令,CMD指令也可用于运行任何命令或应用程序,不过,二者的运行时间点不同

RUN指令运行于映像文件构建过程中,而CMD指令运行于基于Dockerfile构建出的新映像文件启动一个容器时

CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令其可以被docker run的命令行选项所覆盖

在Dockerfile中可以存在多个CMD指令,但仅最后一个会生效

Syntax

CMD

CMD [“”, “”, “”]

CMD ["",""]

前两种语法格式的意义同RUN

第三种则用于为ENTRYPOINT指令提供默认参数

RUN

指定docker build过程中运行的程序。必须是镜像中存在的命令。

Syntax

RUN

RUN ["", "", ""]

第一种格式中,通常是一个shell命令,且以“/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop 命令停止容器时,此进程接收不到SIGTERM信号;

第二种语法格式中的参数是一个JSON格式的数组,其中为要运行的命令,后面的为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,因此常见的shell操作如变量替换以及通配符(?,*等)替换将不会进行;不过,如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。

示例:RUN ["/bin/bash", "-c", "", ""]

示例1:基于centos基础镜像创建一个运行nginx的镜像

编辑Dockerfile文件:

FROM centosLABEL maintainer="lixinkuan "COPYbase.repo epel.repo /etc/yum.repos.d/RUN yum -y install nginx \        && yum clean all \        && rm -rf /var/cache/yum

提供base.repo epel.repo文件:

[root@docker nginx]# wget lixinkuan.top/base.repo--2018-06-3011:29:08--http://lixinkuan.top/base.repoResolving lixinkuan.top (lixinkuan.top)...47.94.102.99Connecting to lixinkuan.top (lixinkuan.top)|47.94.102.99|:80... connected.HTTP request sent, awaiting response...200OKLength:630Savingto:‘base.repo’100%[=================================================================================>]630--.-K/sin0s2018-06-3011:29:08 (87.9MB/s) - ‘base.repo’ saved [630/630][root@docker nginx]# wget lixinkuan.top/epel.repo--2018-06-3011:29:16--http://lixinkuan.top/epel.repoResolving lixinkuan.top (lixinkuan.top)...47.94.102.99Connecting to lixinkuan.top (lixinkuan.top)|47.94.102.99|:80... connected.HTTP request sent, awaiting response...200OKLength:214Savingto:‘epel.repo’100%[=================================================================================>]214--.-K/sin0s2018-06-3011:29:16(44.2MB/s) - ‘epel.repo’ saved [214/214][root@docker nginx]# lsbase.repo  Dockerfile  epel.repo

创建镜像:

[root@docker nginx]# docker build -t nginx:v0.1 ./Sending build context to Docker daemon  4.608kBStep 1/4 : FROM centoslatest: Pulling from library/centos7dc0dca2b151: Pull complete Digest: sha256:b67d21dfe609ddacf404589e04631d90a342921e81c40aeaf3391f6717fa5322Status: Downloaded newer image for centos:latest ---> 49f7960eb7e4Step 2/4 : LABEL maintainer="lixinkuan " --->Runningin6b16128ed7caRemoving intermediate container 6b16128ed7ca ---> b6ef19a3311fStep 3/4 : COPY base.repo epel.repo /etc/yum.repos.d/ ---> e571c2837442Step 4/4 : RUN yum -y install nginx    && yum clean all    && rm -rf /var/cache/yum --->Runningin445372de8e8dLoaded plugins: fastestmirror, ovl.....执行安装过程省略...Cleaning repos: base epel extras updatesCleaning up everythingMaybe you want: rm -rf /var/cache/yum, to also free up space taken by orphaned data from disabled or removed reposCleaning up list of fastest mirrorsRemoving intermediate container 445372de8e8d ---> 5cf6e8e3517eSuccessfully built 5cf6e8e3517eSuccessfully tagged nginx:v0.1

创建容器并查看:

[root@docker nginx]#dockerrun--nameweb-itnginx:v0.1[root@5e7adf4282c1 /]#rpm-qnginxnginx-1.12.2-2.el7.x86_64#nginx已安装[root@5e7adf4282c1 /]#

示例2:以busybox制作一个挂载本地/data/web/html目录并自动运行httpd的镜像

在工作目录编辑Dockerfile文件

FROM busyboxLABEL maintainer="lixinkuan "ENV DOCROOT="/data/web/html/"COPY index.html${DOCROOT}VOLUME${DOCROOT}CMD /bin/httpd-f-h${DOCROOT}

提供index.html并创建要挂载的目录

[root@docker bbox]# echo hello Docker > index.html[root@docker bbox]# cat index.htmlhello Docker

创建镜像文件:

[root@docker bbox]# docker build -t web:v0.1 ./Sending build context to Docker daemon  3.072kBStep 1/6 : FROM busybox ---> 8c811b4aec35Step 2/6 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56f723d6220cStep 3/6 : ENV DOCROOT="/data/web/html/" ---> Using cache ---> c095f8dd8418Step 4/6 : COPY index.html ${DOCROOT} ---> Using cache --->ee77cd16629aStep 5/6 : VOLUME ${DOCROOT} ---> Using cache ---> d51ea735fdd3Step 6/6 : CMD /bin/httpd -f -h ${DOCROOT} --->Runninginf2fa2b284306Removing intermediate container f2fa2b284306 ---> b8613217ad3cSuccessfully built b8613217ad3cSuccessfully tagged web:v0.1

以新创建的镜像文件运行容器并查看

[root@docker bbox]# docker run --name web -d --rm web:v0.17b71084ebd922728ebf21d22a4e5ff3462443761c82bc22c640764c6d4925b2a[root@docker bbox]# docker container inspect -f {{.Config.Cmd}} web[/bin/sh-c /bin/httpd -f -h ${DOCROOT}][root@docker bbox]# docker exec -it web /bin/sh/# ps auxPID  USER    TIME  COMMAND1root0:00/bin/httpd -f -h /data/web/html/7root0:00/bin/sh13root0:00ps aux/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address          Foreign Address        State      tcp00:::80:::*LISTEN

示例3:docker run 时不运行镜像默认进程,运行指定指令

查看当前镜像文件:

[root@docker bbox]#dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEwebv0.1b8613217ad3c2hoursago1.15MB

以web:v0.1创建容器,不运行默认命令

[root@docker bbox]# docker run --name web -it --rm web:v0.1 /bin/sh/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address          Foreign Address        State      /# ps auxPID  USER    TIME  COMMAND1root0:00/bin/sh7root0:00ps aux

15. ENTRYPOINT

类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序

与CMD不同的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,而且,这些命令行参数会被当作参数传递给ENTRYPOINT指定指定的程序

不过,docker run命令的--entrypoint选项的参数可覆盖ENTRYPOINT指令指定的程序

Syntax

ENTRYPOINT

ENTRYPOINT ["", "", ""]

docker run命令传入的命令参数会覆盖CMD指令的内容并且附加到ENTRYPOINT命令最后做为其参数使用

Dockerfile文件中也可以存在多个ENTRYPOINT指令,但仅有最后一个会生效

示例1:

编辑Dockerfile文件

FROM busyboxLABEL maintainer="lixinkuan "VOLUME/data/web/html/COPY index.html/data/web/html/EXPOSE80/tcpENTRYPOINT ["/bin/httpd","-f","-h","/data/web/html"]

创建镜像

[root@docker bbox]# docker build -t web:v0.2 ./Sending build context to Docker daemon  3.072kBStep 1/6 : FROM busybox ---> 8c811b4aec35Step 2/6 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56f723d6220cStep 3/6 : VOLUME /data/web/html/ --->Runningin3095065d0ebbRemoving intermediate container 3095065d0ebb ---> 36dc68fabc6fStep 4/6 : COPY index.html /data/web/html/ ---> e47f81ec7728Step 5/6 : EXPOSE 80/tcp --->Runninginf86f957ec882Removing intermediate container f86f957ec882 ---> 01a005644fe6Step 6/6 : ENTRYPOINT ["/bin/httpd","-f","-h","/data/web/html"] --->Runningin7a5f8b4f4acfRemoving intermediate container 7a5f8b4f4acf ---> 43d514096d34Successfully built 43d514096d34Successfully tagged web:v0.2

创建容器运行并查看:

[root@docker bbox]# docker exec -it web /bin/sh/# ps auxPID  USER    TIME  COMMAND1root0:00/bin/httpd -f -h /data/web/html7root0:00/bin/sh13root0:00ps aux/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address          Foreign Address        State      tcp00:::80:::*LISTEN      /#

运行容器时指定执行/bin/sh

[root@docker bbox]# docker run --name web -it --rm web:v0.2 /bin/sh

换另一tty查看

[root@docker bbox]# docker exec -it web /bin/sh/# ps auxPID  USER    TIME  COMMAND    1 root      0:00 /bin/httpd-f-h /data/web/html /bin/sh    7 root      0:00 /bin/sh  13 root      0:00 ps aux

并未执行/bin/sh,而是执行默认程序,/bin/sh被当作参数传递给/bin/httpd

示例:在docker run时使用entrypoint的时候更换默认运行的程序

--entrypoint string Overwrite the default ENTRYPOINT of the image

使用镜像web:v0.2创建容器运行时添加--entrypoint选项

[root@docker bbox]# docker run --name web -it --rm --entrypoint /bin/sh web:v0.2/# ps auxPID  USER    TIME  COMMAND1root0:00/bin/sh7root0:00ps aux/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address          Foreign Address        State      /#

示例

编辑Dockerfile文件

FROM busyboxLABEL maintainer="lixinkuan "ENV DOCROOT="/data/web/html/"MYPORT="80"COPY index.html ${DOCROOT} COPY entrypoint.sh /bin/COPY test.conf /etc/VOLUME ${DOCROOT}EXPOSE80/tcp#CMD /bin/httpd -f -h ${DOCROOT}#CMD ["/bin/sh","-c","/bin/httpd","-f","-h","${DOCROOT}"]ENTRYPOINT ["/bin/entrypoint.sh"]CMD["/bin/httpd","-f","-h","/data/web/html/"]

提供必须文件(脚本文件需加执行权限)

[root@docker bbox]# cat entrypoint.sh #!/bin/shsed -i"s@^PORT=.*@PORT=${MYPORT}@g"/etc/test.confexec"$@"[root@docker bbox]# cat test.conf PORT=8080

制作镜像:

[root@docker bbox]# docker build -t web:v0.3 ./Sending build context to Docker daemon  5.12kBStep 1/10 : FROM busybox ---> 8c811b4aec35Step 2/10 : LABEL maintainer="lixinkuan " ---> Using cache ---> 56f723d6220cStep 3/10 : ENV DOCROOT="/data/web/html/" MYPORT="80" --->Runninginf237100ec645Removing intermediate container f237100ec645 ---> f754b5dcea84Step 4/10 : COPY index.html ${DOCROOT} ---> 3c31424c9b3dStep 5/10 : COPY entrypoint.sh /bin/ ---> 46ec2f5ede8cStep 6/10 : COPY test.conf /etc/ ---> 7db53e00338aStep 7/10 : VOLUME ${DOCROOT} --->Runningin5ae02469f585Removing intermediate container 5ae02469f585 ---> 0e1e3e966318Step 8/10 : EXPOSE 80/tcp --->Runninginae76bcf870caRemoving intermediate container ae76bcf870ca ---> dea89896460dStep 9/10 : ENTRYPOINT ["/bin/entrypoint.sh"] --->Runningin6862bf4a336eRemoving intermediate container 6862bf4a336e ---> ca568e1ff983Step 10/10 : CMD ["/bin/httpd","-f","-h","/data/web/html/"] --->Runningin2aa5dea11848Removing intermediate container 2aa5dea11848 ---> 26bb44795880Successfully built 26bb44795880Successfully tagged web:v0.3

运行容器并查看配置文件是否被修改

[root@docker bbox]# docker run --name web -d --rm web:v0.36ec1f5a008e6a08047e8666f6ed3ad4673360805148789faf780baf335ee5637[root@docker bbox]# docker exec -it web /bin/sh/# netstat -tnlActive Internet connections (only servers)Proto Recv-Q Send-Q Local Address          Foreign Address        State      tcp00:::80:::*LISTEN      /# cat /etc/test.confPORT=80/# exit

示例:通过传递变量更改配置文件的方法:

[root@docker bbox]# docker run --name web1 -d --rm -e MYPORT=10080 web:v0.37e3b353e423839d598ee9423e881673066cf99626940b6590e78f34b7622834d[root@docker bbox]# docker exec -it web1 /bin/sh/# cat /etc/test.conf PORT=10080/#

你可能感兴趣的:(【转一个朋友的dockerfile笔记)