Dockerfile是一个文本配置文件,可以使用它快速创建自定义镜像,他有一个基本的结构,并支持众多的指令,因此在项目使用Dockerfile来构建自己应用的镜像是常用的手段。
基本结构
Dockerfile由一行行的命令语句组成,注释可以在每行的开头加上#号。
Dockerfile分为四部分:
- 基础镜像信息
- 维护者信息
- 镜像操作指令
- 容器启动时执行的指令
指令
指令格式为INSTRUCTION arguments。
FROM
格式:
FROM <image> [AS <name>]FROM <image>[:<tag>] [AS <name>]FROM <image>[@<digest>] [AS <name>]
注意: Dockerfile的第一条指令必须为FROM指令,指明由哪个镜像构建。 当需要在一个Dockerfile构建多个镜像的时候,可以多次使用FROM指令,但每个镜像只能使用一次。
LABEL
为镜像添加元信息,可以使用docker inspect来查看。
格式:LABEL <key>=<value> <key>=<value> <key>=<value> ...
RUN
每条RUN指令会在FROM指明的镜像上执行指定的命令,并打包进新的镜像中,以后以新镜像创建容器的时候,都会在拉取FROM指定镜像完成后逐一执行。
格式: RUN 或者RUN ["executable", "arg1", "arg2"]。
RUN 这种格式的指令将在shell终端运行命令,例如/bin/sh -c
RUN ["executable", "arg1", "arg2"] 则使用exec执行。也可以使用 RUN ["/bin/bash", "c", "arg1", "arg2"]这种格式来指定终端执行命令。
当一条RUN指令较长时可以使用
\来换行。
CMD
CMD指令用于在启动容器时执行的命令,每一个Dockerfile只能有一条CMD指令。如果指定了多条CMD指令,则会执行最后一条指令。
如果用户在启动容器的时候指定了运行的命令,则会覆盖Dockerfile的CMD指令
CMD指令的格式如下:
- CMD ["executable", "arg1", "arg2"],使用exec执行,推荐使用。
- CMD executeable arg1 arg2,在/bin/sh中执行,提供需要交互的应用。
- CMD ["arg1", "arg2"],提供给ENTRYPOINT的默认参数。
EXPOSE
在启动容器时所要暴露的端口,跟指定-p或-P参数一样。
格式:EXPOSE 22 80 443
ENV
指定一个环境变量,可以供RUN指令使用,并在容器运行时保持。
格式:ENV
例如:
ENV VERSION 1.0
ENV PATH /home/kt/www
RUN curl -SL https://www.lenkuntang.cn/api$VERSION/test
ADD
ADD指令可以将指定的目标(远程或本机)内容到对应的目录下。
格式:ADD
可以是Dockerfile所在目录的一个相对路径(文件或目录),也可以是一个URL,还可以是一个tar文件(自动解压出来的目录)。
COPY
COPY指令可以复制本机上指定目录的内容到目标目录下,当目标目录不存在时会自动创建。这个指令通常用于将临时目录下的文件转移到服务器的目标目录。
当使用本地目录为源目录时,应该使用COPY
ENTRYPOINT
配置容器启动后执行的命令,且不可被docker run提供的参数覆盖。
每个Dockerfile中只能有一个ENTRYPOINT,当存在多个时只会执行最后一个。
当指定了ENTRYPOINT的时候,Dockerfile里的RUN命令将不会直接运行,而是将CMD的内容作为参数传递到ENTRYPOINT中,就如上面CMD指定的第三种格式所示。也就是说实际上会变成如下命令:
<ENTRYPOINT> "<CMD>"
一个很流行的用法是,在ENTERPOINT中指定一个脚本文件做预处理工作,这个脚本会将接到的参数(也就是 CMD 命令)作为命令,在脚本最后执行。 比如 mysql 类的数据库,可能需要一些数据库配置、初始化的工作,这些工作要在最终的 mysql 服务器运行之前解决。 这些准备工作是和容器 CMD 无关的,无论 CMD 为什么,都需要事先进行一个预处理的工作。 引《docker-RUN CMD ENTRYPOINT的区别》。
VOLUME
创建一个从本地或远端的挂载点,一般用来放数据库数据和保持的数据等。
格式: VOLUME ["/data"]
USER
指定运行容器时的用户名或UID,后续的RUN也可以使用指定用户。
格式: USER tommi。
当服务不需要管理员权限时可以通过该集合指定用户运行。但应该要在之前创建所以需要的用户,例如:
RUN groupadd -r xingkong && useradd -r -g xingkong tommi
要临时获取管理员权限可以使用gosu,不推荐使用sudo。
WORKDIR
为后续的RUN、CMD、ENTRYPOINT指令配置工作目录。
格式:WORKDIR /path/to/workdir
可以使用多个WORKDIR指令,后续的命令如果使用参数是相对路径,则会在当前目录的路径上跳转(一个WORKDIR指定相当于执行一次cd操作)
WORKDIR /data WORKDIR www WORKDIR test-docker RUN pwd
最终路径为/data/www/test-docker
ONBUILD
配置当所创建的镜像作为其它新创建镜像的基础镜像时,所执行的操作命令。例如,以下是含有ONBUILD指令的Dockerfile:
...
ONBUILD ADD . /app/src
ONBUILD RUN /user/local/bin/python-build --dir /app/src
...
使用以上的Dockerfile创建了一个名为iamge1的镜像。现在当我使用iamge1为基础镜像时,即新的Dockerfile中使用了FROM image1,会自动执行ONBUILD指令的内容。等价于在新的Dockerfile后面添加了ONBUILD指令的内容。
FROM image1
# run command from ONBUILD of base image
ADD . /app/src
RUN /user/local/bin/python-build --dir /app/src
在使用ONBUILD指令时,应该添加备注信息说明目的。
实战事例
以下面的Dockerfile为例:
# 指定基础镜像
FROM hub.c.163.com/public/centos:6.7-tools
# 镜像信息
LABEL email="kuntang@163.com"
LABEL author="kuntang"
LABEL version="1.0"
LABEL description="This is a image of dockerfile-example"
# 在打包新镜像之前,对基础镜像进行的操作
# 1. 更新源并且安装git、node
RUN yum update -y && yum install git -y && yum install nodejs -y
# 2. 新建一个工作目录
RUN mkdir -p /data/www
# 3. 进入到工作目录
WORKDIR /data/www
# 4. 把示例工程从git仓库中拷贝到工作目录
RUN git clone https://gitee.com/kunkuntang/dockerfile-example.git
# 5. 安装示例工程的依赖
RUN npm install
# 6. 当容器启动时执行的命令
CMD [ "npm", "start"]
# 7. 暴露的端口
EXPOSE 8080
根据上面的dockerfile,我们可以使用docker build命令来创建镜像。
build命令基本格式为: docker build [选项] 路径,该命令将寻找指定目录下(包括子目录)的Dockerfile,并将该目录下的所有内容发送到Docker服务端,并由服务端创建镜像。一般我们推荐放dockerfile的目录为空目录。对于不想打包进镜像的文件,可以添加.dockerignore文件(一行匹配一条规则)来让Docker忽略路径下的目录和文件。