Dockerfile编写

2,008 阅读6分钟

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忽略路径下的目录和文件。