本博客链接:https://security.blog.csdn.net/article/details/111321846
一、基本结构
Dockerfile 由一行行命令语句组成,并且支持以#
开头的注释行。
一般Dockerfile分为四部分:基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令。
例:
# 基础镜像信息,必须放在第一行
FROM ubuntu
# 维护者信息,可以不写
MAINTAINER docker_user docker_user@email.com
# 镜像操作指令
RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
# 容器启动时执行的指令
CMD /usr/sbin/nginx
其中,一开始必须指明所基于的镜像名称,接下来推荐说明维护者信息。
后面则是镜像操作指令,例如RUN
指令,RUN
指令将对镜像执行跟随的命令。每运行一条RUN
指令,镜像添加新的一层,并提交。需要注意的是,一个镜像不能超过127层!
最后是CMD
指令,来指定运行容器时的操作命令。
下面是一个更复杂的例子
FROM ubuntu
MAINTAINER Victor Vieux <victor@docker.com>
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
FROM ubuntu
# 更新并安装一些软件
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir /.vnc
# 设置密码
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# 自动启动火狐
RUN bash -c 'echo "firefox" >> /.bashrc'
EXPOSE 5900
CMD ["x11vnc", "-forever", "-usepw", "-create"]
FROM ubuntu
RUN echo foo > bar
FROM ubuntu
RUN echo moo > oink
# 此时将有两个镜像
二、指令
指令的一般格式为:INSTRUCTION arguments
,指令包括:FROM
、MAINTAINER
、RUN
等。
2.1、FROM
指定基础镜像,必须为第一个命令。如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM
指令(每个镜像一次)。
格式为:FROM <image>
或FROM <image>:<tag>
。
tag
是可选的,如果不使用这个值时,会使用latest
版本的基础镜像。
2.2、MAINTAINER
格式为:MAINTAINER <name>
,指定维护者信息。
2.3、RUN
构建镜像时执行的命令。
格式为:RUN <command>
或RUN ["executable", "param1", "param2"]
。
前者将在shell
终端中运行命令,即/bin/sh -c
;后者则使用exec
执行。指定使用其它终端可以通过第二种方式实现,例如RUN ["/bin/bash", "-c", "echo hello"]
。
每条RUN
指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用\
来换行。
RUN
指令创建的中间镜像会被缓存,并会在下次构建中使用。如果不想使用这些缓存镜像,可以在构建时指定--no-cache
参数,如:docker build --no-cache
2.4、CMD
构建容器后调用,也就是在容器启动时才进行调用。CMD
不同于RUN
,CMD
用于指定在容器启动时所要执行的命令,而RUN
用于指定镜像构建时所要执行的命令。
支持三种格式
1、CMD ["executable","param1","param2"]
使用exec
执行,是推荐方式;
2、CMD command param1 param2
在/bin/sh
中执行,提供给需要交互的应用;
3、CMD ["param1","param2"]
提供给ENTRYPOINT
的默认参数;
指定启动容器时执行的命令,每个Dockerfile
只能有一条CMD
命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时候指定了运行的命令,则会覆盖掉CMD
指定的命令。
2.5、EXPOSE
指定于外界交互的端口。
格式为:EXPOSE <port> [<port>...]
。
告诉Docker服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过-P
,Docker主机会自动分配一个端口转发到指定的端口。
EXPOSE
并不会让容器的端口访问到主机。要使其可访问,需要在docker run
运行容器时通过-p
来发布这些端口,或通过-P
参数来发布EXPOSE
导出的所有端口。
2.6、ENV
设置环境变量。
格式为:ENV <key> <value>
。 指定一个环境变量,会被后续RUN
指令使用,并在容器运行时保持。<key>
之后的所有内容均会被视为其<value>
的组成部分,因此,一次只能设置一个变量。
例:
ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH
2.7、ADD
将本地文件添加到容器中,tar类型文件会自动解压(网络压缩资源不会被解压),可以访问网络资源,类似wget。
格式为:ADD <src> <dest>
。
该命令将复制指定的<src>
到容器中的<dest>
。 其中<src>
可以是Dockerfile
所在目录的一个相对路径;也可以是一个URL;还可以是一个tar文件(自动解压为目录)。
2.8、COPY
功能类似ADD,但是是不会自动解压文件,也不能访问网络资源。
格式为:COPY <src> <dest>
。
复制本地主机的<src>
(为Dockerfile
所在目录的相对路径)到容器中的<dest>
。
当使用本地目录为源目录时,推荐使用COPY
。
2.9、ENTRYPOINT
配置容器,使其可执行化。配合CMD
可省去"application"
,只使用参数。
两种格式:
1、ENTRYPOINT ["executable", "param1", "param2"]
;
2、ENTRYPOINT command param1 param2
(shell中执行)。
配置容器启动后执行的命令,并且不可被docker run
提供的参数覆盖。
ENTRYPOINT
与CMD
非常类似,不同的是通过docker run
执行的命令不会覆盖ENTRYPOINT
,而docker run
命令中指定的任何参数,都会被当做参数再次传递给ENTRYPOINT
。Dockerfile
中只允许有一个ENTRYPOINT
命令,多指定时会覆盖前面的设置,而只执行最后的ENTRYPOINT
指令。
2.10、VOLUME
用于指定持久化目录。
格式为:VOLUME ["/data"]
。
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。
一个卷可以存在于一个或多个容器的指定目录,该目录可以绕过联合文件系统,并具有以下功能:
1、卷可以容器间共享和重用
2、容器并不一定要和其它容器共享卷
3、修改卷后会立即生效
4、对卷的修改不会对镜像产生影响
5、卷会一直存在,直到没有任何容器在使用它
2.11、USER
指定运行容器时的用户名或UID,后续的RUN
也会使用指定用户。使用USER指定用户时,可以使用用户名、UID或GID,或是两者的组合。当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户
格式为:USER daemon
。
当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres
。要临时获取管理员权限可以使用gosu
,而不推荐sudo
。
使用USER
指定用户后,Dockerfile
中其后的命令RUN
、CMD
、ENTRYPOINT
都将使用该用户。镜像构建完成后,通过docker run
运行容器时,可以通过-u
参数来覆盖所指定的用户。
2.12、WORKDIR
工作目录,类似于cd
命令。
格式为:WORKDIR /path/to/workdir
。
为后续的RUN
、CMD
、ENTRYPOINT
指令配置工作目录。
可以使用多个WORKDIR
指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为/a/b/c
。
通过WORKDIR
设置工作目录后,Dockerfile
中其后的命令RUN
、CMD
、ENTRYPOINT
、ADD
、COPY
等命令都会在该目录下执行。在使用docker run
运行容器时,可以通过-w
参数覆盖构建时所设置的工作目录。
2.13、ONBUILD
用于设置镜像触发器。
格式为:ONBUILD [INSTRUCTION]
。
配置当创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
例如,Dockerfile
使用如下的内容创建了镜像image-A
。
[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]
如果基于image-A
创建新的镜像时,新的Dockerfile
中使用FROM image-A
指定基础镜像,会自动执行ONBUILD
指令内容,等价于在后面添加了两条指令。
FROM image-A
# 自动运行以下两条指令
ADD . /app/src
RUN /usr/local/bin/python-build --dir /app/src
使用ONBUILD
指令的镜像,推荐在标签中注明,例如ruby:1.9-onbuild
。
三、创建镜像
编写完成Dockerfile
之后,可以通过docker build
命令来创建镜像。
基本的格式为:docker build [选项] 路径
,该命令将读取指定路径下(包括子目录)的Dockerfile
,并将该路径下所有内容发送给Docker服务端,由服务端来创建镜像。因此一般建议放置Dockerfile的目录为空目录。也可以通过.dockerignore
文件(每一行添加一条匹配模式)来让Docker忽略路径下的目录和文件。
要指定镜像的标签信息,可以通过-t
选项,例如:
# 构建镜像名为test:v1,地址是/tmp/test1/
docker build -t test:v1 /tmp/test1/