Dockerfile

掘金小册 开发者必备的 Docker 实践指南

Dockerfile

1. Dockerfile 文件

我们可以将 Dockerfile 理解为一个由上往下执行指令的脚本文件。当我们调用构建命令让 Docker 通过我们给出的 Dockerfile 构建镜像时,Docker 会逐一按顺序解析 Dockerfile 中的指令,并根据它们不同的含义执行不同的操作。

2. Dockerfile 指令

2.1 FROM: 指定基础镜像

在 Dockerfile 中可以多次出现 FROM 指令,当 FROM 第二次或者之后出现时,表示在此刻构建时,要将当前指出镜像的内容合并到此刻构建镜像的内容里。

FROM <image> [AS <name>]
FROM <image>[:<tag>] [AS <name>]
FROM <image>[@<digest>] [AS <name>]

2.2 RUN: 用于向控制台发送命令

RUN <command>
RUN ["executable", "param1", "param2"]

RUN 指令是支持 \ 换行的,如果单行的长度过长,建议对内容进行切割,方便阅读。

2.3 ENTRYPOINT 和 CMD: 指定基于镜像启动的容器 启动时 启动 1 号进程的命令

ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2

CMD ["executable","param1","param2"]
CMD ["param1","param2"]
CMD command param1 param2

ENTRYPOINT 和 CMD 设计的目的是不同。ENTRYPOINT 指令主要用于对容器进行一些初始化,而 CMD 指令则用于真正定义容器中主程序的启动命令

当 ENTRYPOINT 与 CMD 同时给出时,CMD 中的内容会作为 ENTRYPOINT 定义命令的参数,最终执行容器启动的还是 ENTRYPOINT 中给出的命令。

2.4 EXPOSE: 指定容器要暴露端口

EXPOSE <port> [<port>/<protocol>...]

2.5 VOLUME: 定义容器的数据卷

2.6 COPY 和 ADD: 从宿主文件系统拷贝,添加文件到镜像

COPY [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] <src>... <dest>

COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]

对比 COPY 与 ADD,两者的区别主要在于 ADD 能够支持使用网络端的 URL 地址作为 src 源,并且在源文件被识别为压缩包时,自动进行解压,而 COPY 没有这两个能力。

3 构建镜像

sudo docker build -t XXX:TAG -f .../Dockerfile 基础文件目录

基础文件目录:
    Dockerfile 所在的文件目录
    Dockerfile 文件中 COPY, ADD 命令的文件路径也是基于此文件夹

4 Dockerfile 使用技巧

4.1 构建中使用变量

在 Dockerfile 里,我们可以用 ARG 指令来建立一个参数变量,我们可以在构建时通过构建指令传入这个参数变量,并且在 Dockerfile 里使用它。

ARG PHP_VERSION

FROM php:${PHP_VERSION}-fpm

# 构建镜像
sudo docker build --build-arg PHP_VERSION=7.2 --build-arg XXX=111 ./workspace

4.2 环境变量

ARG MYSQL_VERSION=latest
FROM mysql:${MYSQL_VERSION}

LABEL maintainer="Mahmoud Zalt <mahmoud@zalt.me>"

#####################################
# Set Timezone
#####################################

ARG TZ=UTC
ENV TZ ${TZ}
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && chown -R mysql:root /var/lib/mysql/

# ...

EXPOSE 3306

# 1. 使用: -e 或 ---env 在容器启动时指定
sudo docker run -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# 2. 在 Dockerfile 中指定环境变量

环境变量的使用方法与参数变量一样,也都是能够直接替换指令参数中的内容。
与参数变量只能影响构建过程不同,环境变量不仅能够影响构建,还能够影响基于此镜像创建的容器。环境变量设置的实质,其实就是定义操作系统环境变量,所以在运行的容器里,一样拥有这些变量,而容器中运行的程序也能够得到这些变量的值。

另一个不同点是,环境变量的值不是在构建指令中传入的,而是在 Dockerfile 中编写的。

ENV 指令所定义的变量,永远会覆盖 ARG 所定义的变量,即使它们定时的顺序是相反的。

4.3 构建缓存

Docker 在镜像构建的过程中,还支持一种缓存策略来提高镜像的构建速度。

由于镜像是多个指令所创建的镜像层组合而得,那么如果我们判断新编译的镜像层与已经存在的镜像层未发生变化,那么我们完全可以直接利用之前构建的结果,而不需要再执行这条构建指令,这就是镜像构建缓存的原理。

那么 Docker 是如何判断镜像层与之前的镜像间不存在变化的呢?这主要参考两个维度,第一是所基于的镜像层是否一样,第二是用于生成镜像层的指令的内容是否一样。

基于这个原则,我们在条件允许的前提下,更建议将不容易发生变化的搭建过程放到 Dockerfile 的前部,充分利用构建缓存提高镜像构建的速度。另外,指令的合并也不宜过度,而是将易变和不易变的过程拆分,分别放到不同的指令里。

在另外一些时候,我们可能不希望 Docker 在构建镜像时使用构建缓存,这时我们可以通过 --no-cache选项来禁用它。

sudo docker build --no-cache ./webapp
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!