使用Dockerfile构建自己的镜像
格式
- 所有的指令是非大小写敏感的,但习惯写为大写有助于与你的参数做区分
- 所有的指令按照Dockerfile文件顺序执行
- 一个Dockerfile必须以FROM指令开始(但可以在解析器指令
parse derictive
、注释comments
或全局参数ARGs
后) - FROM前可以有一个或多个ARG,这些ARG中声明的变量将会在FROM行中使用
- 与shell,python等脚本语言类似Dockerfile中以#开头的行会被当做注释,如果它出现在Dockerfile文件的最上方并且是合法的解析器指令。它将会当作解析器处理,同一个解析器只会处理一次,第二次声明也将会当作注释处理。(合法的解析器包括syntax和escape)
.dockerignore
构建docker镜像时有上下文概念,例如以docker build -t 镜像名 .
命令构建镜像是上下文即为Dockerfile所在目录(当然执行该命令的工作目录也在Dockerfile所在目录)。
docker 构建镜像时会将上下文中的所有文件拷贝到docker的构建进程中,就像.gitignore一样声明在.dockerignore中的文件或文件夹在拷贝时会被忽略。
构建指令
-
FROM
所有Dockerfile最先执行的指令(当然最先是在排除前文提到的解析器指令和参数等的前提下,因为这几个指令都是可选的)
该指令指定一个基础镜像(也可以理解为父镜像)。为之后一系列操作提供基础运行环境。
该指令可以使用已定义过的ARG,使用方式为${参数名},与shell很想对吗?没错之后还会有很多相似之处。 -
RUN
RUN指令用于在构建容器时执行你指定的任意命令。
RUN指令有两种格式
shell格式
RUN /bin/bash -c 'source \$HOME/.bashrc; \
echo $HOME'
改格式下你可以使用 \ 来在另一行编写你未完成的单个命令,并且可以使用${}操作符,json格式则不可以。
exec格式
RUN ["/bin/bash", "-c", "echo hello"]
exec格式会被转换为一个json数组,所以你因该使用双引号"
来包裹你额单词而不是单引号'
,另外在该格式中应避免反斜杠 \
尤其是在windows中\
标识了windows的文件目录。
-
CMD
一个Dockerfile中只能有一个CMD
命令,如果写了多个那么只有最后一个生效。它的目的是为容器提供一个默认执行应用。
该命令会被命令行参数所替换例如如果启动时执行命令为docker run -it 容器名 /bin/sh
则CMD内容将被替换为/bin/sh
CMD命令一共有三种格式
exec格式
CMD ["executable","param1","param2"]
该格式是最推荐使用的格式
作为ENTRYPOINT的默认参数
CMD ["param1","param2"]
当它作为ENTRYPOINT的参数的时候ENTRYPOINT和CMD都必须是json数组的格式。
shell格式
CMD command param1 param2
使用改格式默认会在/bin/sh -c
中执行,如果不想使用/bin/sh -c
执行命令请使用exec格式
-
LABLE
LABLE为构建的镜像添加一些key-value格式的元数据,和RUN一样可以使用反斜杠\
在下一行完成单条过长的元数据。
例:
FROM ubuntu:18.04
WORKDIR /usr/local
LABEL wxm="wxm530" \
alming="alming530"
构建完成后 docker inspect 镜像名
"WorkingDir": "/usr/local",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"alming": "alming530",
"wxm": "wxm530"
}
LABLE包包括前镜像和父镜像的LABLE,如果重复了以最新的为准.
-
EXPOSE
EXPOSE指定Docker容器运行时向外暴露的端口,可以指定TCP或UDP协议端口,默认采用TCP协议。指令格式EXPOSE 80/tcp EXPOSE 80/udp
-
ENV
ENV即环境变量,它有两种格式
ENV <key> <value>
该格式设置一个单个的环境变量,第一个完整的字符串是key key+空格后的所有值都是value,
它会被其他环境变量所解析,如果没有转义不应该在改格式中写引号"
。(这里不理解,只是翻译了一下官方文档)
ENV <key>=<value> ...
改格式允许在一行定义多个环境变量,以空格分隔。如果环境变量本身需要空格将有空格的变量使用引号"
括起来或使用\
来转义空格。
注意ENV
添加的环境变量对于容器来说是持久的。如果需要临时的变量则使用RUN <key>=<value> <command>.
ADD
- ADD指令用于将主机或者某个url上的文件资源拷贝到将要构建的镜像当中。
- 源文件地址可以使用
Go’s filepath.Match rules.
解析规则的通配符。 - 目的地址是目标容器的绝对地址或者是
WORKDIR
的相对地址(关于WORKDIR
参照WORKDIR
文档)。 - 如果源地址中包含特殊字符则需要按照Go语言的转义规则将它们转义。
- 添加到容器中的文件默认由GID和UID为0的用户创建,如果想改变使用
--chown
参数,这一部分详细参照官方文档。 - 如果添加的文件是归档文件还会被默认加压。
该指令有两种格式。
ADD [--chown=<user>:<group>] <src>... <dest>
-
COPY
COPY指令与ADD基本一致,但它不会解压添加到容器中的归档文件 -
ENTRYPOINT
ENTRYPOINT和CMD类似都用于指定容器启动时容器内执行的命令或执行可执行文件,CMD中的指令最终都会以参数的形式传递给ENTRYPOINT(前提是ENTRYPOINT是exec格式)。
ENTRYPOINT有两种格式
shell格式
ENTRYPOINT command param1 param2
改格式不会接收CMD作为参数,但有一个缺点就是使用docker stop
命令无法正常关闭容器内正在运行的应用,(个人理解为对于容器中运行的应用来说容器停止时它们都是强制退出的,也就是说如果程序中有结束程序的钩子函数可能无法被正常执行)
所以使用改格式时需要在命令前添加exec例如ENTRYPOINT exec top -b
exec格式
ENTRYPOINT ["executable", "param1", "param2"]
该格式下每个参数都是一个字符不能连写例如有两个参数-c
和-t
则不能写成["command","-c -t" ]
因该写成["command","-c","-c"]
并且所有参数都要使用双引号""
,所有写在CMD中的命令将会自动添加在数组的尾部作为参数,同时CMD内容可被启动时命令行内容替换,所以可以使用命令行替换CMD内容继而追加道ENTRYPOINT中。
例:
//Dockerfile
FROM ubuntu:18.04
WORKDIR /usr/local
ENTRYPOINT ["echo"]
CMD wxm
执行docker build -t wxm .
构建镜像
先不加参数运行docker run -it wxm
运行结果
[alming@localhost docker]$ docker run -it wxm
/bin/sh -c wxm
[alming@localhost docker]$
可以看到wxm被打印说明CMD中内容确实被追加到ENTRYPOINT中了,同时看到还打印了/bin/sh -c侧面说明了CMD中命令默认由/bin/sh -c
执行,这一点官方文档中也有提及
接下来运行容器时指定自定义参数
docker run -it wxm alming
[alming@localhost docker]$ docker run -it wxm alming
alming
[alming@localhost docker]$
可以看到参数被正确替换并传递。
另外如果要为容器中的可执行文件编写可执行脚本以在ENTRYPOINT中执行需要注意使用exec加gosu启动可执行文件这样可以保证启动的进程的PID为1从而可以接收到docker stop
传过来的停止信号从而优雅的结束该进程。目的也是为了保证程序退出前的准备工作正常完成。
下面是官方示例:
#!/usr/bin/env bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
-
VOLUME
在容器中创建你声明的挂载点,即创建一个目录。并且会默认关联到宿主机/var/lib/docker/volume下的一个文件夹下的_data文件夹。该文件夹由docker生成名称是一个hash码
[root@192 volumes]# pwd
/var/lib/docker/volumes
[root@192 volumes]# ls
0a31112d023a994c3dc4ed945a75fa4c55ce9d94ff80c200d2574bb0270df3d3
0f61fd7fdf69653ab4d5dc6c576b5e809553c83914c8c295bfc3511c56ac50eb
10b2add0f578d26f79fc9ac69df126ab93793314d98ebe37c93e97aa545486bf
17c764a4a52320ce2a85ec7ccab81c6b3845e53225bfc955d3308dc09ead7618
和手使用-v指定的文件夹一样和容器内的文件夹内容同步。
其值可以是纯字符转也可以是json数组
-
USER
USER指令用来设置用户名(或UID)组名(或GID)。设置完成后,接下来的RUN
,ENTRYPOINT
,CMD
中所执行的命令都有该用户完成。
格式
USER <UID>[:<GID>]
or
USER <user>[:<group>]
-
WORKDIR
WORKDIR指令为RUN
,CMD
,ENTRYPOINT
,ADD
,COPY
指定工作空间
格式
WORKDIR /path/to/workdir
它可以定义多次并且每次都会以上一个WORKDIR指令为相对目录,官方示例为
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
最终打印结果为/a/b/c
WORKDIR 还可以解析之前定义过的ENV中的内容,但注意只能解析Dockerfile中定义的ENV系统环境变量是取不到的,官方示例:
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
最总打印结果为/path/$DIRNAME
-
ARG
用户在使用docker build指令时可通过--build-arg <varname>=<value>
将参数传递给Dockerfile中声明的ARG中以供之后通过$参数名
使用。
同时它可以有默认值ARG user1=someuser
,并且其他指令只能调用在它本身之前声明过的ARG。
注意如果ENV定义的变量名和ARG重复了ENV的值将会覆盖ARG的值
Docker中有一些预定义的ARG这些ARG不需要你声明也可以使用包括
- HTTP_PROXY
- http_proxy
- HTTPS_PROXY
- https_proxy
- FTP_PROXY
- ftp_proxy
- NO_PROXY
- no_proxy
这些预定义变量将不会被docker history输出
-
ONBUILD
ONBUILD指定当子镜像被构建时需要执行的指令,其中声明的指令将会被插入到子镜像的FROM指令之后执行。
注意,ONBUILD不可嵌套使用并且不会触发FROM指令。 -
STOPSIGNAL
STOPSIGNAL指定使用docker stop停止容器时容器内应用程序的终止行为,格式为
STOPSIGNAL signal
以下内容出自stackoverflow非官方文档,文档未对此指令做细致解释。原文
可选取值为
SIGKILL
,SIGTERM
,SIGINT
其中SIGTERM
和SIGINT
可以正常关闭正在运行的应用,SIGKILL
则不能
SIGKILL
相当于kill -9 <PID>
SIGTERM
相当于kill <PID>
SIGINT
相当于Ctrl + c
即
-
HEALTHCHECK
HEALTHCHECK目的是在容器中运行特定的指令以检查容器中的应用设否正常工作,他也有两种格式:
HEALTHCHECK [OPTIONS] CMD command
HEALTHCHECK NONE
继承自父镜像,默认不进行任何检测
例如以下指令规定每5分钟像web服务器发送请求并判断是否在3s内返回从而判断web服务器是否正常工作。
-
SHELL
SHELL指令用于切换RUN
,CMD
,ENTRYPOINT
的默认shell,默认情况下linux使用的是["/bin/sh", "-c"]
Windows使用的是["cmd", "/S", "/C"]
通常用于当默认shell执行不了某个命令时使用SHELL
指令切换shell执行完成后再通过SHELL
指令切回原来的shell.