概述
将代码打包成 docker 镜像的一个文件,文件包含各种指令。
语法及规则
# 注释符
instruction arguments #指令 参数
不区分大小写,但习惯于大写
指令按写的顺序执行
做镜像第一行非注释信息必须是 from base image
指令
每条指令都会形成一层镜像层,所以能合成一条指令尽量合成一条指令。层越多,联合挂载的效率越差
-
copy
用于从docker主机复制文件至创建的新镜像文件
语法:
COPY <src>...<dest>
或COPY ["<src>",......"<dest>"]
说明:<src>
要复制的源文件或目录,支持使用通配符,通常使用相对路径;
<dest>
目标路径。指正在创建的image的文件系统路径。一般使用绝对路径,或者COPY指定以WORKDIR为起始路径;
路径中有空白字符时,通常使用相对路径;
<src>
必须是build上下文中的路径,不能是其父目录中的文件;
如果<src>
是目录,则其内部文件或子目录会被递归复制,但<src>
目录本身不会被复制;
如果指定了多个<src>
,或在<src>
中使用了通配符,则<dest>
必须是一个目录。且必须以/
结尾;
如果<dest>
事先不存在,它将会被自动创建,这包括其父目录路径;
docker build -h #建立镜像帮助
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker build -t myBusybox:v0.1 ./
invalid argument "myBusybox:v0.1" for "-t, --tag" flag: invalid reference format: repository name must be lowercase
See 'docker build --help'.
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker build -t mybusybox:v0.1 ./ #镜像名不可大写
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# cat Dockerfile
#Description: test image
FROM busybox:latest
MAINTAINER "Loe <loe@qq.com>"#作者信息-元数据维护 新版本废弃后使用LABEL
#LABEL maintainer="Loe <loe@qq.com>"
COPY index.html /data/web/html/
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]#
打包完成后启动容器并查看文件
docker run --name myweb1 --rm mybusybox:v0.1 cat /data/web/html/index.html
打包完成后启动容器并查看文件
说明成功了。
那如果要把目录下的所有文件都复制过去呢?(比如 /etc/yum.repos.d/)
首先在Dockerfile文件加入一条COPY指令,然后打包成镜像,再启动镜像查看目录文件是否存在
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# cat Dockerfile
#Description: test image
FROM busybox:latest
MAINTAINER "Loe <loe@qq.com>"#作者信息-元数据维护 新版本废弃后使用LABEL
#LABEL maintainer="Loe <loe@qq.com>"
COPY index.html /data/web/html/
COPY yum.repos.d /ect/yum.repos.d/
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker build -t mybusybox:v0.2 ./
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker run --name myweb1 --rm mybusybox:v0.2 ls /ect/yum.repos.d/
只复制了目录下的文件,目录没有复制过去,说明Success!
- add
类似于COPY, 但ADD支持使用TAR文件和URL路径
Dockerfile: ADD http://nginx.org/download/nginx-1.19.4.tar.gz /sur/local/src/
docker build -t mybusybox:v0.3 ./
docker run --name myweb1 --rm mybusybox:v0.3 ls /sur/local/src
URL路径时不会展开压缩文件,当为本地路径的压缩文件时,在容器中会被解压成目录文件展开
- volume
用于在image中创建一个挂载点目录,以挂载Docker hosts上的卷或其他容器上的卷(只能指定容器内的卷,宿主机的卷自动生成)
语法:VOLUME <mountpoint>
或VOLUME ["<mountpoint>"]
- expose
为容器打开指定要监听的端口以实现与外部通信,不会直接暴露需要执行容器时加上"-P"才能暴露
语法:EXPOSE <port>[/<protocol>]
<protocol>
用于指定传输层协议,可为TCP或者UDP二者之一,默认是TCP协议
可一次指定多个端口,如: EXPOSE 11211/udp 11211/tcp
在Dockerfile中加入EXPOSE 80/tcp
打包镜像并启动,验证是否成功
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker build -t mybusybox:v0.5 ./
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker run --name myweb1 --rm mybusybox:v0.5 /bin/httpd -f -h /data/web/html
[root@iZ8vbi4t4rsi4lb9e7bkckZ ~]# curl 10.0.0.3
[root@iZ8vbi4t4rsi4lb9e7bkckZ img1]# docker port myweb1
docker port myweb1 #可查看容器暴露的端口
上述说明未暴露端口
那停止再重启容器,重启的时候加上 -P 就能看到暴露的端口了
docker run --name myweb1 --rm -P mybusybox:v0.5 /bin/httpd -f -h /data/web/html
- env
为镜像定义所需的环境变量,并可被Dockerfile文件中位于其后的其它指令所调用(如ENV
,COPY
,ADD
等),调用格式为$variable_name
或${variable_name}
语法:ENV <key> <value>
或ENV <key>=<value>...
第一种格式中,<key>
之后的所有内容均会被视作其<value>
的组成部分。因此,一次只能设置一个变量;
第二种格式中可用一次设置多个变量,每个变量为一个<key>=<value>
的键值对,如果<value>
中包含空格,可以以反斜杠\
进行转义,也可通过对<value>
加引号进行标识;另外反斜杠也可用于续行;
定义多个变量时,建议使用第二种方式,以便在同一层中完成所有功能。
ENV DOC_ROOT=/data/ \
WEB_SERVER_PAKEAGE="busybox-1.3"
printenv 启动容器时,打印出环境变量
docker run ... printenv
- run
用于指定docker build过程中运行的程序,其可以是任何命令。
语法:RUN <command>
RUN ["<excutable>", "<param1>","<param2>"]
第一种格式中,<command>
通常是一个shell
命令,且以/bin/sh -C
来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,因此,当使用docker stop <container>
命令停止容器时,此进程接收不到SIGTERM信号;
第二种格式中的参数是一个json格式的数组,其中<excutable>
为要运行的命令,后面的<paramN>
为传递给命令的选项或参数;然而此种格式指定的命令不会以/bin/sh -c
来发起,因此常见的shell操作如变量替换以及通配符(?,*等)等替换将不会进行;如果要运行的命令依赖于此shell特性的话,可以将其替换为类似下面的格式。
RUN ["/bin/sh","-c","<excutable>","<param1>"]
FROM busybox:latest
LABEL maintainer="Loe <loe@qq.com>" app="httpd"
ENV WEB_DOC_ROOT="/data/web/html"
RUN mkdir -p $WEB_DOC_ROOT && \
echo '<h1>hello busybox</h1>' > ${WEB_DOC_ROOT}/index.html
CMD /bin/httpd -f -h ${WEB_DOC_ROOT}
- cmd
类似RUN指令,CMD指令也可用于运行任何命令或应用程序,但RUN指令运行于镜像文件构建过程中,而CMD指令运行于基于Dockerfile构建出来的新镜像文件启动一个容器时;
在Dockerfile中可以定义多个CMD
,但是只有最后一个CMD
生效;
CMD
指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;CMD
指定的命令可以被docker run
的命令行选项所覆盖
语法:CMD <command>
CMD ["<excutable>", "<param1>", "<param2>"]
CMD ["<param1>", "<param2>"]
前两种语法格式的意义同RUN
,第三种用于为ENTRYPOINT
指令提供默认参数
docker run --name myweb1 -it --rm -P myhttpd:v0.1 #此处由于 /bin/httpd 替代了默认的 /bin/sh,所以进不去容器没法交互
在Dockerfile中加入CMD ["/bin/httpd","-f","-h ${WEB_DOC_ROOT}"] #需注意中括号中的逗号前后不能有空格,否则会出现异常
打包成镜像后,查看镜像信息docker image inspect myhttpd:v0.2
,并启动
从上图可看出, 镜像CMD中默认的 /bin/sh 被替换没了,启动时异常,因为${DOC_WEB_ROOT}
是shell变量,但是容器没有shell命令。
那么怎么解决这个问题呢?
首先,在Dockerfile文件中 CMD 后面数组里面加入 /bin/sh -c
, 即CMD ["/bin/sh","-c","/bin/httpd","-f","-h ${WEB_DOC_ROOT}"]
打包运行,发现还是无法启动,那么试试是否是变量问题,把变量${WEB_DOC_ROOT}
改成固定目录/data/web/html/
- entrypoint
类似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序;可定义多个ENTRYPOINT,但仅有最后一个会生效;
与CMD
不同的是由ENTRYPOINT
启动的程序不会被docker run
命令行指定的参数覆盖,而且这些命令行参数会被当做参数传递给ENTRYPOINT
指定的程序,但是docker run
命令的--entrypoint
选项的参数可覆盖ENTRYPOINT
指定的程序!
如果ENTRYPOINT 和CMD 同时定义,那么看CMD的第三种格式,CMD的参数将会被当成参数传给 ENTRYPOINT;
如果非要在启动容器时覆盖容器中的ENTRYPOINT指令,那么在运行命令后加上--entrypoint "ls /"
;
如果使用ENTRYPOINT指令,那么启动容器时所带的参数也会当做ENTRYPOINT后面的参数执行;
语法:ENTRYPOINT <command>
ENTRYPOINT ["<command>", "<param1>", "<param2>"]
按上图所说,命令启动时,由于容器中的各种环境变量等指令是启动报错的。可使用docker ps -a
查看command的第一运行程序是/bin/sh
那么可以在启动容器的命令后加上 shell命令来验证一下
docker run --name myweb2 myhttpd:v0.7 "ls /data"
此时CMD指令的/bin/httpd
没有给ENTRYPOINT当默认参数,因为启动容器命令传了参数给ENTRYPOINT
"$@" #传递给shell脚本的所有参数列表
[root@iZ8vbi4t4rsi4lb9e7bkckZ img2]# docker run --name myweb2 -it myweb:0.3 /bin/sh
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"/bin/entrypoint.sh\": permission denied": unknown.
出现此问题的原因是,sh文件没有权限,chmod 777 entrypoint.sh
即可。
启动成功后,docker exec -it myweb3 /bin/sh
进入容器,wget -O - -q 65d22eb53aea
查看主页显示是否为添加的index.html
entrypoint 带参数启动,比如改变监听端口为8080 docker run --name myweb3 --rm -P -e "PORT=8080" myhttpd:v0.6
进入容器检验(略)
- user
用于指定运行image或运行Dockerfile中RUN
和RUN
、CMD
或ENTRYPOINT
指令指定的程序时的用户名或UID。默认情况下,container的运行身份为root
语法:USER <UID>|<USERNAME>
注意:USER后跟的必须为有效用户 - healthcheck
只要进程不停,容器就不停
意义:比如程序出现bug,意外删除目录。用这个去检查
docker healthcheck -help #查看帮助
--start-period
指容器运行起来之后的等待时长 0s:立即执行健康检查
DockerfileHEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${port:-80}/
每隔30s,启动检查
[root@iZ8vbi4t4rsi4lb9e7bkckZ img2]# docker run --name myweb3 --rm -P -e "PORT=8080" myhttpd:v0.7
127.0.0.1 - - [06/Nov/2020:08:59:59 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:00:29 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:01:00 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:01:30 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:02:01 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:02:32 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:03:02 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:03:33 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
127.0.0.1 - - [06/Nov/2020:09:04:03 +0000] "GET / HTTP/1.1" 200 612 "-" "Wget" "-"
- shell
不常用,了解即可----linux默认["/bin/sh","-c"]
windows默认["cmd", "/S", "/C"]
语法:SHELL ["excutable", "parameters"]
- stopsignal
不常用,了解即可
stop停止容器时,接收的信号。只有pid为1的进程才能接收stop的信号从而停止容器
语法:STOPSIGNAL signal
- arg
只在build使用,制作多版本时可用到
比如环境变量只能在run时传参,那么可以定义ARG,build的时候传入
语法:ARG <name>[=<value>]
在Dockerfile修改为
FROM nginx:1.14-alpine
ARG author="ooo <o@o.com>"
LABEL maintainer="${author}"
ENV NGX_DOC_ROOT="/data/web/html/"
ADD index.html ${NGX_DOC_ROOT}
ADD entrypoint.sh /bin/
EXPOSE 80/tcp
HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${port:-80}/
CMD ["/usr/sbin/nginx","-g","daemon off;"]
ENTRYPOINT ["/bin/entrypoint.sh"]
docker image inspect myhttpd:v0.8 #验证是否成功注入
- onbuild
在镜像build的时候,不会执行。当镜像被当做base镜像时,才会执行onbuild。即FROM base
语法:ONBUILD instruction
1. Dockerfile用于build镜像文件,此镜像文件亦可作为base image被另一个Docker用作FROM
指令的参数,并以之构建新的镜像文件;
2. 在后面的这个Dockerfile中的FROM指令在build过程中被执行时,将会“触发”创建其base image的Dockerfile文件中的ONBUILD
指令定义的触发器;
3. Dockerfile用于build镜像文件,此镜像文件亦可作为base image被另一个Docker用作FROM
指令的参数,并以之构建新的镜像文件;
4. 尽管任何指令都可注册成为触发器指令,但ONBUILD
不能自我嵌套,且不会触发FROM
和MAINTAINER
指令;
5. 使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,例如busybox:2.0-onbuild
;
6. 在ONBUILD
指令中使用ADD
或COPY
指令应该格外小心,因为新构建过程的上下文在缺少指定的源文件时会失败。