Dockerfile

什么是Dockerfile?

Dockerfile是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

自定义一个镜像

举个栗子,我们需要自定义这么一个镜像:基于Python基础镜像,当容器运行时,会自动打印一些图案。

如何实现呢?

1、首先,编写Dockerfile文件。

1
2
3
4
5
6
7
8
FROM python:alpine
LABEL maintainer="ancientone"
LABEL description="This is simple example."
WORKDIR /app
COPY requirements.txt ./
RUN pip install -i https://pypi.douban.com/simple --no-cache-dir -r requirements.txt
COPY . .
CMD ["python", "fun.py"]

具体指令含义下文详解,先梳理流程。

2、将Dockerfile中需要的文件(Dockerfilerequireents.txtfun.py)放到一个目录下。

1
2
[root@VM-0-2-centos docker-demo] ls
Dockerfile fun.py requirements.txt

requirements.txt文件内容

1
cowpy==1.1.0

fun.py文件内容

1
2
3
from cowpy import cow

print(cow.milk_random_cow("Hello, Everyone!"))

3、然后,执行命令开始构建镜像。

1
docker build -t test:v1 .

构建过程如下:

可以看到,其实构建过程中的每一个step对应的就是Dockerfile文件中的一条指令。

4、构建完成后,通过docker images查看新构建的镜像。

5、启动容器。

执行命令docker run --rm test:v1启动容器。(加上**–rm**退出容器以后,这个容器就被删除了,方便在临时测试使用)

可以看到,每次启动容器后,都会打印一个图案,这是因为该镜像文件中有一行指令CMD ["python", "fun.py"],即当容器启动时,会在命令行中执行python fun.py,而这个py文件其实就是应用cowpy模块执行了一句print(cow.milk_random_cow("Hello, Everyone!"))来完成图案打印。

ok,构建自定义镜像的整体流程如上,下面来详解Dockerfile中的常用指令。

FROM

定制的镜像都是基于FROM的镜像,上文的python:alpine就是基础镜像。

格式:FROM 镜像名:版本

注意两点:

  • 如果基础镜像本地没有,会自动去docker hub中下载
  • 一个Dockerfile文件中通常只有一个FROM指令(多阶段构建除外)

LABEL

LABEL指定docker中的元数据信息,maintainer指定当前Dockerfile文件的作者(维护者),description指定功能描述信息。

WORKDIR

相当于cd命令,切换到容器中的某个目录,如果指定的目录不存在,那么会自动创建。

COPY

相当于cp命令,将宿主机中的目录或文件复制粘贴到容器中。

1
COPY requirements.txt ./dir/

注意:如果是./dir会把dir当做一个文件。

将宿主机当前目录下的requirements.txt文件复制到容器内的当前目录下的dir目录下。

  • 第一个参数为宿主机中的目录或文件(相对路径或绝对路径)
  • 第二个参数为容器中的目录或文件(相对路径或绝对路径)

注:容器内的路径如果不存在,会自动创建。

ADD

COPY功能类似,如果第一个参数为本地的压缩文件,那么会自动解压,将解压之后的文件复制粘贴到容器中;如果是路径,那么会自动下载,将下载后的文件复制粘贴到容器中。

RUN

用于执行RUN后面跟着的命令,等同于在命令行执行shell命令。

值得注意的是,RUN指令越多,构建出来的镜像层级就会很多,镜像尺寸就会很大。

若有多个RUN指令,可以用&&连接成一条指令,如:

1
RUN pip install -i https://pypi.douban.com/simple --no-cache-dir -r requirements.txt && ls / && ls /root && ps aux

ENV

设置环境变量,定义了环境变量后,后续的指令就可以使用这个环境变量。

1
ENV username=ancientone

VOLUME

指定容器运行时,需要映射出去的目录(容器中)。

1
VOLUME /app

只有在Dockerfile中指定了VOLUME映射目录,才能在docker run时加参数-v映射到宿主机。

EXPOSE

指定容器运行时,需要映射出去的端口号(容器中)。

1
EXPOSE 8088

CMD

类似于RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMD在docker run时运行,即容器启动时。
  • RUN在docker build时运行,即镜像构建时。

CMD指令后面可以跟两种类型的命令:

  • shell类型的命令,如CMD python fun.pyCMD ls /root
  • exec类型的命令:[“指令”,”参数1”,”参数2”],为json数组,必须得用双引号,如CMD ["python","fun.py"]CMD ["ls","/root"]

注意:

  • 如果在容器运行时(docker run)有指定的命令,那么CMD会被忽略。
  • 如果 Dockerfile中如果存在多个 CMD 指令,仅最后一个生效。

优先使用exec类型的命令,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

ENTRYPOINT

类似于CMD命令,区别在于:

  • CMD会被docker run的命令行参数指定的指令所覆盖,而ENTRYPOINT不会。

如果ENTRYPOINTCMD连用,那么CMD会作为ENTRYPOINT的默认参数,如:

1
2
ENTRYPOINT ["ping"]
CMD ["114.114.114.114"]

即当容器运行时,会在shell执行ping 114.114.114.114

注意:如果 Dockerfile中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。