dockerfile是构造Docker images的一行行命令的集合,是一个纯文本文件。html
#
注释信息node
INSTRUCTION
指令,指令不区分大小写,但约定使用大写linux
非注释行的第一行必须是FROM
指令nginx
使用Dockerfile制做镜像时须要一个干净的工做目录,该目录结构以下:git
Dockerfile文件 可选的 .dockerignore,用于存放要打包进镜像的文件目录中须要排除的文件 文件1,文件2,... 目录1,目录2,...
要打包进镜像的文件或目录都存放在与Dockerfile
文件同级。github
更多的dockerfile指令相关信息请参考:https://docs.docker.com/engine/reference/builderweb
FROM
docker
Dockerfile文件开篇的第一个非注释行,用于为镜像文件构建过程指定基准镜像,后续的指令运行于此基准镜像所提供的运行环境。shell
语法 FROM <repository>[:<tag>]或 FROM <repository>@<digest> <repository>: 基础镜像名称 <tag>: 基础镜像的标签,省略时默认为latest <digest>: 能够不指定镜像的名称而使用镜像的惟一识别hash码
LABLE
json
为Dockerfile提供key,value对的源数据信息,是MAINTAINER
的替代指令
LABEL <key>=<value> <key>=<value> <key>=<value> ...
COPY
从Docker主机复制文件至建立的新镜像文件中
有两种方式 COPY [--chown=<user>:<group>] <src>... <dest> COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] --chow只适用于类linux系统的镜像 <src>: 要复制的源文件或目录,支持通配符 <dest>: 目标路径,即正在建立的image的文件系统路径,使用绝对路径,不然是以WORKDIR为其起始路径 文件复制准则: <src> 必须是Dockerfile文件所在目录中的文件,不能是其父目录中的文件 若是<src>是目录,则其内部的文件或子目录会被递归复制,但<src>目录自身不会被复制 若是指定了多个<src>,或使用了通配符,则<dest>必须是一个目录,且以“/”结尾 若是<dest>事先不存在,会被递归建立
ADD
相似COPY指令,ADD支持使用tar文件和url路径
两种语法格式 ADD [--chown=<user>:<group>] <src>... <dest> ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] --chow只适用于类linux系统的镜像 操做准则 1. 同COPY指令 2. 若是<src>为URL且<dest>不以/结尾,则<src>指定的文件将被下载而且直接被建立为<dest>;若是<des>以/结尾,则文件名URL指定的文件将被直接下载并保存为<des>/<filename> 3. 若是<src>是一个本地系统上的压缩格式的tar文件,它将被展开为一个目录,其行为相似于“tar -x”命令;然而,经过URL获取到的tar文件将不会自动展开; 4. 若是<src>有多个,或其间接或直接使用了通配符,则<dest>必须为一个以/结尾的目录路径;若是<dest>不以/结尾,其被视为一个普通文件,<src>的内容将被直接写入到<des>;
WORKDIR
用于为Dockerfile中全部的RUN、CMD、ENTRYPOINT、COPY和ADD指定设定的工做目录。
语法 WORKDIR /path/to/workdir 在Dockerfile文件中,WORKDIR指令能够出现屡次,其路径也能够为相对路径,不过,其是相对此前一个WORKDIR指令指定的路径。另外,WORKDIR也可调用由ENV指令指定的变量。 如: ENV DIRPATH /path WORKDIR $DIRPATH/
VOLUME
用于在image中建立一个挂载点目录,以挂载Docker host上的卷或其它容器上的卷,该卷属于Docker managed volume
类型的卷,即宿主机上要挂载的目录由dockerd管理。
语法 VOLUME ["/data"] 若是挂载点目录路径下此前有文件存在,docker run命令会在卷挂载完成后将此前的全部文件复制到新挂载的卷中。
EXPOSE
用于为容器打开指定要监听的端口以实现与外部通讯
语法 EXPOSE <port> [<port>/<protocol>...] <protocol> 用于指定传输层协议,可为tcp或udp两者之一,默认为tcp协议 可一次指定多个端口,如: EXPOSE 80/tcp 8080/udp EXPOSE指令并不会真正把相应的端口暴露到宿主机上,而是说明以该镜像运行的容器具备该种能力,须要在`docker run`命令时使用`-P`(大写的字母p)选项就可把EXPOSE指定的端口进行暴露,宿主机使用的随机端口,也可使用`-p <hostPort>:<containerPort>`来指定宿主机上使用的端口。
ENV
用于为镜像定义所须要的环境变量,并可被Dockerfile文件中位于其后的其它指令(如ENV、ADD、COPY等)所调用。
语法 ENV <key> <value> ENV <key>=<value> ... 第一种格式中,<key>以后的全部内容均会被视做其<value>的组成部分,所以,一次只能设置一个变量; 第二种格式中可一次设置多个变量,每个变量为一个“<key>=<value>”键值对,若是<value>有空格,使用反斜线(\)进行转义,可经过对<value>加引号进行标识;另外反斜线也可用于续行; 如: ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy 引用时使用“$myName”或“${myName}” 定义多个变量时,建议使用第二种方式。
RUN
用于指定docker build过程当中运行的程序,其能够是任何命令
语法 RUN <command> RUN ["executable", "param1", "param2", ...] 第一种格式中,<command>一般是一个shell命令,且以“/bin/sh -c”来运行它,这意味着此进程在容器中的PID不为1,不能接收Unix信号,所以,当使用“docker stop <container>”命令中止容器时,此进程接收不到SIGTERM信息; 第二种格式中的参数是一个JSON格式的数组,其中<executable>为要运行的命令,后面的<paramN>为传递给命令的选项或参数;然而,此种格式指定的命令不会以“/bin/sh -c”来发起,所以常见的shell操做如变量替换以及通配符(?,*等)替换将不会进行;不过,若是要运行的命令依赖此shell特性话,能够将其替换为相似下面的格式。 RUN ["/bin/bash", "-c", "<executable>", "param1"] JSON数组中必定要使用双引号
CMD
相似RUN指令,CMD指令也可用于运行任何命令或程序,不过两者的运行时间点不一样。
RUN指令运行于镜像文件构建过程当中,而CMD指令运行于基于Dockerfile构建出的新镜像文件启动一个容器时;
CMD指令的首要目的在于为启动的容器指定默认要运行的程序,且其运行结束后,容器也将终止;不过,CMD指定的命令能够被“docker run”的命令行选项所覆盖;
在Dockerfile中能够存在多个CMD指令,但仅最后一个会生效。
语法 CMD ["executable","param1","param2"] (exec的形式, 首选使用这种) CMD ["param1","param2"] (为ENTRYPOINT指代默认参数) CMD command param1 param2 (同RUN同样)
ENTRYPOINT
相似CMD指令的功能,用于为容器指定默认运行程序,从而使得容器像是一个单独的可执行程序。与CMD不一样的是,由ENTRYPOINT启动的程序不会被docker run命令行指定的参数所覆盖,并且,这些命令行参数会被看成参数传递给ENTRYPOINT指定的程序。不过,docker run命令的--entrypoint选项的参数能够覆盖ENTRYPOINT指令指定的程序。
语法 ENTRYPOINT ["executable", "param1", "param2"] ENTRYPOINT command param1 param2 docker run命令传入的命令参数会覆盖CMD指令的内容,而且附加到ENTRYPOINT命令最后作为其参数使用,若是docker run命令行未传入命令参数,那ENTRYPOINT会以CMD指令中的内容做为其默认参数 Dockerfile文件中也能够存在多个ENTRYPOINT指令,但仅有最后一个会生效
USER
用于指定运行image时的或运行Dockerfile中任何RUN、CMD或ENTRYPOINT指令指定的程序时的用户名或UID
默认状况下,container的运行身份为root用户
语法 USER <user>[:<group>] USER <UID>[:<GID>] UDI,GID必须为镜像系统中有效用户的UID,GID,不然,docker run命令将运行失败。
HEALTHCHECK
用于Docker如何测试容器是否仍在正常工做。
语法 HEALTHCHECK [OPTIONS] CMD command (经过在容器内部运行命令来检查容器的运行情况) HEALTHCHECK NONE (禁用从基本映像继承的任何运行情况检查) [OPTIONS]: --interval=DURATION(默认值:30s) 表示检查间隔时间 --timeout=DURATION(默认值:30s) 表示检查超时时间 --start-period=DURATION(默认值:0s) 表示container运行后等待主进程起动程序,开始健康检查前的等待时长 --retries=N(默认值:3) 当检查失败时,须要连续检查多少次才断定该服务处于不健康状态 检查命令的退出状态,可能的值为: 0:成功-容器健康且可使用 1:不健康-容器没法正常工做 2:保留-请勿使用此退出代码 事例 HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1
SHELL
用于覆盖RUN,CMD,ENTRYPOINT等指令运行的默认shell。
语法 SHELL ["executable", "parameters"] linux默认使用["/bin/sh", "-c"],windows默认使用["cmd", "/S", "/C"]
STOPSIGNAL
向容器发送退出的信号
语法 STOPSIGNAL signal signal为系统合法的无符号的信号数字,如9
ARG
用于给docker build
时传递变量
语法 ARG <name>[=<default value>] 在“docker build”时使用“--build-arg <varname>=<value>”传递参数 如: FROM busybox ARG user USER ${user:-some_user} USER $user 在build时使用 $ docker build --build-arg user=what_user ./
ONBUILD
用于在Dockerfile中定义一个触发器
Dockerfile用于build映像文件,此映像文件亦可做为base image被另外一个Dockerfile用做FROM指令的参数,并以之构建新的映像文件,在后面的这个Dockerfile中的FROM指令在build过程当中被执行时,将会“触发”建立其base image的Dockerfile文件中的ONBUILD指令定义的触发器。
语法 ONBUILD <INSTRUCTION> 尽管任何指令均可注册为触发器指令,但ONBUILD不能自我嵌套,且不会触发FROM和MAINTAINER指令。 使用包含ONBUILD指令的Dockerfile构建的镜像应该使用特殊的标签,如 ruby:2.0-onbuild,来告诉用户会触发ONBUILD 在ONBUILD指令中使用ADD或COPY指令应该格外当心,由于新构建过程的上下文在缺乏指定的源文件时会失败
root@node01:~/img01# pwd /root/img01 root@node01:~/img01# ls -al total 20 drwxr-xr-x 2 root root 4096 Jul 20 09:58 . drwx------ 5 root root 4096 Jul 20 09:58 .. -rw-r--r-- 1 root root 513 Jul 20 09:32 Dockerfile -rwxr-xr-x 1 root root 195 Jul 20 09:58 entrypoint.sh -rw-r--r-- 1 root root 35 Jul 20 09:22 index.html root@node01:~/img01# cat Dockerfile FROM nginx:1.14-alpine # ARG定义的变量能够在build时经过--build-arg 传递参数替换 ARG author="Jack <jack@qq.com>" LABEL maintainer="${author}" ENV NGX_DOC_ROOT="/data/web/html/" ADD index.html ${NGX_DOC_ROOT} ADD entrypoint.sh /bin/ EXPOSE 80/TCP 8080/TCP # 健康检查 HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/ # 触发器 ONBUILD RUN echo "Hello Word!" > /tmp/readme.txt CMD ["/usr/sbin/nginx","-g","daemon off;"] ENTRYPOINT ["/bin/entrypoint.sh"] root@node01:~/img01# cat entrypoint.sh #!/bin/sh cat > /etc/nginx/conf.d/www.conf << EOF server { server_name ${HOSTNAME}; listen ${IP:-0.0.0.0}:${PORT:-10080}; root ${NGX_DOC_ROOT:-/usr/share/nginx/html}; } EOF exec "$@" root@node01:~/img01# cat index.html <h1>This is a nginx test page</h1>
entrypoint.sh
文件中末尾的exec "$@"
尤其重要,因为Dockerfile中同时定义了ENTRYPOINT和CMD指令,因此容器运行时执行的程序为/bin/entrypoint.sh "/usr/sbin/nginx" "-g" "daemon off;"
然后边的参数都会entrypoint.sh脚本末尾的“$@”收集,即成了exec "/usr/sbin/nginx" "-g" "daemon off;"
,因使用了exec
来执行,因此启动nginx的进程ID会替代运行/bin/entrypoint.sh
脚本时的sh
进程的ID。
build生成镜像
root@node01:~/img01# docker build --build-arg 'author="Tom <tom@163.com>"' -t mynginx:v0.1-1 ./ Sending build context to Docker daemon 4.608kB Step 1/11 : FROM nginx:1.14-alpine ---> 8a2fb25a19f5 Step 2/11 : ARG author="Jack <jack@qq.com>" ---> Running in ffe97dc263b2 Removing intermediate container ffe97dc263b2 ---> 48cccb2b3ac2 Step 3/11 : LABEL maintainer="${author}" ---> Running in e31958e5d9eb Removing intermediate container e31958e5d9eb ---> b2c494b442d5 Step 4/11 : ENV NGX_DOC_ROOT="/data/web/html/" ---> Running in 1aabf04d1295 Removing intermediate container 1aabf04d1295 ---> 4fdb24fa67f2 Step 5/11 : ADD index.html ${NGX_DOC_ROOT} ---> e334aa452daa Step 6/11 : ADD entrypoint.sh /bin/ ---> ad5488c7c47c Step 7/11 : EXPOSE 80/TCP 8080/TCP ---> Running in 773ae947ecd7 Removing intermediate container 773ae947ecd7 ---> 23c16ae625fe Step 8/11 : HEALTHCHECK --start-period=3s CMD wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/ ---> Running in 7be92e4c77a7 Removing intermediate container 7be92e4c77a7 ---> 544097889172 Step 9/11 : ONBUILD RUN echo "Hello Word!" > /tmp/readme.txt ---> Running in 3f121c8e23d0 Removing intermediate container 3f121c8e23d0 ---> 6d80a88f95ee Step 10/11 : CMD ["/usr/sbin/nginx","-g","daemon off;"] ---> Running in b5dbfb4a6c46 Removing intermediate container b5dbfb4a6c46 ---> 7eaa7434d331 Step 11/11 : ENTRYPOINT ["/bin/entrypoint.sh"] ---> Running in f3d78245e25a Removing intermediate container f3d78245e25a ---> 3a250eefa3a7 Successfully built 3a250eefa3a7 Successfully tagged mynginx:v0.1-1
查看镜像详细信息
root@node01:~/img01# docker image inspect mynginx:v0.1-1 ... "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "NGINX_VERSION=1.14.2", "NGX_DOC_ROOT=/data/web/html/" ], "Cmd": [ "/usr/sbin/nginx", "-g", "daemon off;" ], "Healthcheck": { "Test": [ "CMD-SHELL", "wget -O - -q http://${IP:-0.0.0.0}:${PORT:-80}/" ], "StartPeriod": 3000000000 }, "Image": "sha256:7eaa7434d331cfc56db82b03ee9472eca1dd4ee3411252fb0155d86debb5fa78", "Volumes": null, "WorkingDir": "", "Entrypoint": [ "/bin/entrypoint.sh" ], "OnBuild": [ "RUN echo \"Hello Word!\" > /tmp/readme.txt" ], "Labels": { "maintainer": "\"Tom <tom@163.com>\"" }, ...
其中Labels中的maintainer是docker build
使用--build-arg
传递的值Tom <tom@163.com>
,再也不是Docerfile中定义的值Jack <jack@qq.com>
。
基于镜像mynginx:v0.1-1
运行一个容器
root@node01:~# docker container run --rm --name nginx01 -e "PORT=8080" mynginx:v0.1-1 127.0.0.1 - - [20/Jul/2020:14:43:44 +0000] "GET / HTTP/1.1" 200 35 "-" "Wget" "-" 127.0.0.1 - - [20/Jul/2020:14:44:14 +0000] "GET / HTTP/1.1" 200 35 "-" "Wget" "-" ......
因配置了HEALTHCHECK,在容器运行后,运行进程运行3秒后每隔30秒都会检查nginx的主页。
另起终端链接到容器中
root@node01:~# docker container exec -i -t nginx01 /bin/sh / # cat /etc/nginx/conf.d/www.conf server { server_name eaf2cfb1eece; listen 0.0.0.0:8080; root /data/web/html/; } / # netstat -tanl Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8080 127.0.0.1:33032 TIME_WAIT tcp 0 0 127.0.0.1:8080 127.0.0.1:33030 TIME_WAIT / # ps PID USER TIME COMMAND 1 root 0:00 nginx: master process /usr/sbin/nginx -g daemon off; 8 nginx 0:00 nginx: worker process 44 root 0:00 /bin/sh 66 root 0:00 ps / # ls /tmp/ / #
生成了配置文件,监听8080
端口是docker run
命令行传递的PORT
变量的值。
再来测试一下ONBUILD指令,以生成的新镜像mynginx:v0.1-1
为基础镜像再来制做一个镜像
root@node01:~/img02# pwd /root/img02 root@node01:~/img02# ls Dockerfile root@node01:~/img02# cat Dockerfile FROM mynginx:v0.1-1 RUN /bin/touch /tmp/1.txt root@node01:~/img02# docker build -t test:v0.1-1 ./ Sending build context to Docker daemon 2.048kB Step 1/2 : FROM mynginx:v0.1-1 # Executing 1 build trigger ---> Using cache ---> 8fd69355802f Step 2/2 : RUN /bin/touch /tmp/1.txt ---> Running in 2e123d9c7683 Removing intermediate container 2e123d9c7683 ---> cce488581509 Successfully built cce488581509 Successfully tagged test:v0.1-1
以此镜像运行一个容器
root@node01:~# docker container run -i -t --rm --name test01 test:v0.1-1 /bin/sh / # ls /tmp/ 1.txt readme.txt / # cat /tmp/readme.txt Hello Word! / #
/tmp/readme.txt
生成了,说明基础镜像里定义的ONBUILD指令被触发了。
docker官方在github在还有许多Dockerfile事例,能够参考:https://github.com/docker-library
Registry用于保存docker镜像,包括镜像的层次结构和元数据。用户能够自建Registry,也可使用官方的Docker Hub。
分类:
官方提供了docker-distribution
软件包来搭建一个Private Registry
,也提供了一个名为registry
的镜像,只须要pull该镜像,启动容器就能够搭建起来,若是要提供http
的请求,那客户端须要修改/etc/docker/daemon.json
文件,配置insecure-registries
这样一个key
"insecure-registries": ["192.168.101.41/myreposition"]
此key表示访问192.168.101.41/myreposition
这个Private Registry
可使用http协议。
官方提供的registry过于简陋,vmware对该软件进行了二次开发,名为Harbor
为其增长了许多特性,还提供了一个web界面,详细信息请参考:https://github.com/goharbor/harbor