Dockerfile 由一行行命令语句组成,并且支持以#开头的注释行。一般的,Dockerfile 分为四部分:基础镜像信息、维护者信息、镜像操作指令和容器启动时执行指令。
如果使用Dockerfile来构建镜像,Dockerfile的第一条有效信息(注释除外)必须是基础镜像信息,维护者信息紧随其后。而镜像操作指令则在维护者信息之后因为操作指令的不同,自然会构建出千差万别的镜像来。最后是镜像启动指令,它被用作设置镜像的默认启动命令。
Dockerfile指令
指令的一般格式为 INSTRUCTION arguments
,指令包括 FROM
、 MAINTAINER
、 RUN
等。下面列出常用的几个指令:
FROM:
格式为 FROM <image>
或 FROM <image>:<tag>
。
第一条指令必须为FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个FROM指令(每个镜像一次)。
FROM scratch 制作基础镜像
FROM ubuntu:14.04 使用基础镜像
LABEL/MAINTAINER:
LABEL maintainer="xxx@xxx.com"
LABEL version="1.0"
LABEL description="this is description"
格式为 MAINTAINER <name>
,指定维护者信息。
RUN:
格式为 RUN <command>
或 RUN ["executable", "param1", "param2"]
。
前者将在 shell 终端中运行命令,即 /bin/sh -c ;后者则使用 exec 执行。指定使用其它终端可以通过第二种方式实现,例如 RUN ["/bin/bash", “-c”, “echo hello”] 。
每条 RUN 指令将在当前镜像基础上执行指定命令,并提交为新的镜像。当命令较长时可以使用 \ 来换行。
为避免无用分层,合并多条命令成一行,复杂的RUN用反斜线换行
EXPOSE:
格式为 EXPOSE <port> [<port>...]
告诉 Docker 服务端容器暴露的端口号,供互联系统使用。在启动容器时需要通过 -P
,Docker 主机会自动分配一个端口转发到指定的端口。
CMD:
支持三种格式:
CMD ["executable","param1","param2"]
使用 exec 执行,推荐方式;
CMD command param1 param2
在 /bin/sh 中执行,提供给需要交互的应用;
CMD ["param1","param2"]
提供给 ENTRYPOINT 的默认参数;
指定启动容器时执行的命令,每个 Dockerfile 只能有一条 CMD 命令。如果指定了多条命令,只有最后一条会被执行。如果用户启动容器时候指定了运行的命令,则会覆盖掉CMD指定的命令。
ENTRYPOINT:
两种格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2 (shell中执行)。
配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖。每个 Dockerfile 中只能有一个 ENTRYPOINT ,当指定多个时,只有最后一个起效。
VOLUME:
格式为 VOLUME ["/data"]
。
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据等。如果和host共享目录,Dockerfile中必须先创建一个挂载点,然后在启动容器时通过-v
来挂载。
ENV:
格式为 ENV <key> <value>
。 指定一个环境变量,会被后续 RUN 指令使用,并在容器运行时保持。(尽量使用ENV增加可维护性)
ENV MYSQL_VERSION 5.6 #设置常量
RUN apt-get install -y mysql-server= "${MYSQL_VERSION}"
ADD:
格式为 ADD <src> <dest>
。
该命令将复制指定的 <src>
到容器中的 <dest>
。 其中 <src>
可以是Dockerfile所在目录的一个相对路径;也可以是一个 URL;还可以是一个 tar 文件(自动解压为目录)。
COPY:
格式为 COPY <src> <dest>
。
复制本地主机的 <src>
(为 Dockerfile 所在目录的相对路径)到容器中的 <dest>
。当使用本地目录为源目录时,推荐使用 COPY 。
大部分情况,COPY优于ADD!ADD除了COPY还有自动解压缩功能!添加远程文件/目录请使用curl或者wget
WORKDIR:
格式为 WORKDIR /path/to/workdir
。
为后续的 RUN 、 CMD 、 ENTRYPOINT 指令配置工作目录。可以使用多个 WORKDIR 指令,后续命令如果参数是相对路径,则会基于之前命令指定的路径。例如
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
则最终路径为 /a/b/c
。
USER:
格式为 USER daemon
。
指定运行容器时的用户名或 UID,后续的 RUN 也会使用指定用户。
当服务不需要管理员权限时,可以通过该命令指定运行用户。并且可以在之前创建所需要的用户,例如: RUN groupadd -r postgres && useradd -r -g postgres postgres 。要临时获取管理员权限可以使用 gosu ,而不推荐 sudo 。
ONBUILD:
格式为 ONBUILD [INSTRUCTION]
。
配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作指令。
详细用法请查看:Dockerfile 指令详解
dockerfile参考:https://github.com/docker-library
20181203补充:
RUN && CMD && ENTRYPOINT
RUN:执行命令并创建新的image layer
CMD:设置容器启动后默认执行的命令和参数
ENTRYPOINT:设置容器启动时执行的命令
两种书写格式:
shell格式:
RUN apt-get install -y vim
CMD echo "hello docker"
ENTRYPOINT echo "hello docker"
exec格式:
RUN ["apt-get","install","-y","vim"]
CMD ["/bin/echo","hello docker"]
ENTRYPOINT ["/bin/echo","hello docker"]
说明:
Dockerfile1
FROM centos
ENV name Docker
ENTRYPOINT echo "hello $name"
-----------> hello Docker
Dockerfile2
FROM centos
ENV name Docker
ENTRYPOINT ["/bin/echo","hello $name"]
-----------> hello $name
修改为:
ENTRYPOINT ["/bin/bash","-c","echo hello $name"]
CMD:
容器启动时默认执行的命令
如果docker run指定了其他命令,CMD命令被忽略
如果定义了多个CMD,只有最后一个会执行
ENTRYPOINT:
让容器以应用程序或者服务的形式运行
不会被忽略,一定会执行
最佳实践:写一个shell脚本作为entrypoint
COPY xxx.sh /usr/local/bin/
ENTRYPOINT ["xxx.sh"]
EXPOSE 27017
CMD ["mongod"]
使用Dockerfile制作镜像
使用docker build 命令给定一个Dockerfile可以制作一个镜像,其操作顺序为:
- 解析Dockerfile,并找到基础镜像(可能会从Docker Hub上下载);
- 以基础镜像为基础创建一个容器;
- 在容器中顺序执行dockerfile中的命令;
- 如果不是RUN命令,比如ENV命令,记录下来以便启动的时候执行
- 属性命令记录在Image的属性中;
- 所有指令执行完后,commit该容器为新的镜像。
简单例子:
新建一个目录和Dockerfile:
mkdir -p /opt/dockerfile/nginx/
cd /opt/dockerfile/nginx/
# tree
.
├── Dockerfile
└── index.html
Dockerfile 中每一条指令都创建镜像的一层,如:
# vim Dockerfile
FROM centos
RUN rpm -ivh http://mirrors.aliyun.com/epel/epel-release-latest-7.noarch.rpm
RUN yum install -y nginx
ADD index.html /usr/share/nginx/html/index.html
RUN echo "daemon off;" >>/etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx"]
编写完成 Dockerfile 后可以使用 docker build
来生成镜像。
docker build -t localhost/nginx:v1 /opt/dockerfile/nginx/
查看镜像:
# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/nginx v1 1f18116982c3 2 minutes ago 378 MB
...
后台启动,这时候我们访问服务器的80端口,返回的就是index.html的页面了
docker run -d -p 80:80 localhost/nginx:v1