编写 DockerFile

前言

Dockerfile 是一个文本文件,其中包含我们为了构建 Docker 镜像而手动执行的所有命令。Docker 可以从 Dockerfile 中读取指令来自动构建镜像。我们可以使用 docker build 命令来创建一个自动构建。

Dockerfile 基本语法

首先创建一个目录,以便开始后面的进程:

mkdir dir1 && cd dir1

使用 FROM 指令指定一个基础镜像,后续指令将在此镜像的基础上运行:

FROM ubuntu:18.04

在 Dockerfile 中可以指定一个用户,后续的 RUN,CMD 以及 ENTRYPOINT 指令都会使用该用户去执行,但是该用户必须提前存在。

USER XXX

除了指定用户之外,还可以使用 WORKDIR 指定工作目录,对于 RUN,CMD,COPY,ADD 指令将会在指定的工作目录中去执行。也可以理解为命令执行时的当前目录。

WORKDIR /

RUN 指令用于执行命令,该指令有两种形式:

  • RUN (command),使用 shell 去执行指定的命令 command,一般默认的 shell 为 /bin/sh -c。
  • RUN [“executable”, “param1”, “param2”, …],使用可执行的文件或程序 executable,给予相应的参数 param。

例如我们执行更新命令:

RUN apt-get update

CMD 的使用方式跟 RUN 类似,不过在一个 Dockerfile 文件中只能有一个 CMD 指令,如果有多个 CMD 指令,则只有最后一个会生效。该指令为我们运行容器时提供默认的命令,例如:

CMD echo "hello world"

在构建镜像时使用了上面的 CMD 指令,则可以直接使用 docker run image,该命令等同于 docker run image echo “hello world”。即作为默认执行容器时默认使用的命令,也可在 docker run 中指定需要运行的命令来覆盖默认的 CMD 指令。

除此之外,该指令还有一种特殊的用法,在 Dockerfile 中,如果使用了 ENTRYPOINT 指令,则 CMD 指令的值会作为 ENTRYPOINT 指令的参数:

CMD ["param1", "param2"]

ENTRYPOINT 指令会覆盖 CMD 指令作为容器运行时的默认指令,并且不会在 docker run 时被覆盖,如下示例:

FROM ubuntu:latest
ENTRYPOINT ["ls", "-a"]
CMD ["-l"]

上述构建的镜像,在我们使用 docker run 时等同于 docker run ls -a -l 命令。使用 docker run -i -s 命令等同于 docker run ls -a -i -s 指令。即 CMD 指令的值会被当作 ENTRYPOINT 指令的参数附加到 ENTRYPOINT 指令的后面,并且如果 docker run 中指定了参数,会覆盖 CMD 中给出的参数。
COPY 和 ADD 都用于将文件,目录等复制到镜像中。使用方式如下:

ADD <src>... <dest>
ADD ["<SRC>",... "<dest>"]

COPY <src>... <dest>
COPY ["<src>",... "<dest>"]

src 可以指定多个,但是其路径不能超出上下文的路径,即必须在跟 Dockerfile 同级或子目录中。

dest 不需要预先存在,不存在路径时会自动创建,如果没有使用绝对路径,则 dest 为相对于工作目录的相对路径。

COPY 和 ADD 的不同之处在于,ADD 可以添加远程路径的文件,并且 src 为可识别的压缩格式,如 gzip 或 tar 归档文件等,ADD 会自动将其解压缩为目录。
ENV 指令用于设置环境变量:

ENV <key> <value>
ENV <key>=<value> <key>=<value>...

VOLUME 指令将会创建指定的挂载目录,在容器运行时,将创建相应的匿名卷:

VOLUME /data1 /data2

上述指令将会在容器运行时,创建两个匿名卷,并挂载到容器中的 /data1 和 /data2 目录上。

EXPOSE 指定在容器运行时监听指定的网络端口,它与 docker run 命令的 -p 参数不一样,并不实际映射端口,只是将该端口暴露出来,允许外部或其它的容器进行访问。

要将容器端口暴露出来,需要在 dcoker run 命令中使用 -p 或者 --publish 参数。如果采用 -P 随机映射端口的方式,Docker 会将在 DockerFile 中声明的所有 EXPOSE 的端口随机映射。

EXPOSE port

Dockerfile 创建镜像流程

构建镜像时,该过程的第一件事是将 Dockerfile 文件所在目录下的所有内容递归的发送到守护进程。所以在大多数情况下,最好是创建一个新的目录,在其中保存 Dockerfile,并在其中添加构建 Dockerfile 所需的文件。而 Dockerfile 文件所在的路径也被称为上下文(context)。

了解了上面一些常用于构建 Dockerfile 的指令之后,可以通过这些指令来构建一个镜像。如下所示,搭建一个 ssh 服务:

# 指定基础镜像
FROM ubuntu:18.04

# 安装软件
RUN apt-get update && apt-get install -y openssh-server && mkdir /var/run/sshd

# 添加用户 shiyanlou 及设定密码
RUN useradd -g root -G sudo XXX && echo "XXX:123456" | chpasswd XXX

# 暴露 SSH 端口
EXPOSE 22

CMD ["/usr/sbin/sshd", "-D"]

首先,我们在之前创建的一个空目录 dir1 中编辑 Dockerfile 文件,并将上面的内容复制到该文件中,相关的命令如下所示:

# 创建目录
mkdir dir1 && cd dir1

# 编辑 Dockerfile,将上面的内容写入
vim Dockerfile

# 最后执行构建命令
docker build -t sshd:test .

在上面的命令执行完成之后,该镜像就构建成功了,直接使用该镜像启动一个容器就可以运行一个 ssh 的服务,如下所示:

docker run -itd -p 10001:22 sshd:test

这时就可以通过公网的 IP 地址,以及端口 10001,并且使用用户 XXX,密码 123456,远程通过 ssh 连接到该容器中了。


版权声明:本文为weixin_44853840原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。