Dockerfile 是用于构建镜像的脚本文件。在某些情况下,需要在基础镜像上加装一些软件,就需要使用 Dockerfile 来构建出自己所需的镜像。

Untitled.png

指令介绍

指定基础镜像 ( FROM )

# 不指定版本则默认拉去 latest
FROM nginx
# 指定版本
FROM nginx:1.25.3

执行命令 ( RUN )

FROM nginx
Run apt-get update  \  
&& apt-get install -y --no-install-recommends git vim libpng-dev libjpeg-dev libfreetype6-dev

声明容器运行时监听的端口号( EXPOSE )

FROM nginx

Run apt-get update  \  
&& apt-get install -y --no-install-recommends git vim libpng-dev libjpeg-dev libfreetype6-dev

EXPOSE 80

设置工作目录 ( WORKDIR )

FROM nginx

Run apt-get update  \  
&& apt-get install -y --no-install-recommends git vim libpng-dev libjpeg-dev libfreetype6-dev

EXPOSE 80

WORKDIR /var/www

复制文件到容器目录 ( COPY )

FROM nginx

Run apt-get update  \  
&& apt-get install -y --no-install-recommends git vim libpng-dev libjpeg-dev libfreetype6-dev

WORKDIR /www
COPY . /www
EXPOSE 80

入口点 ( ENTRYPOINT )

ENTRYPOINT 和 CMD 两个指令十分相似,都是通过指定容器运行的脚本/命令。具体区别可以查看扩展阅读。

FROM nginx

Run apt-get update  \  
&& apt-get install -y --no-install-recommends git vim libpng-dev libjpeg-dev libfreetype6-dev

WORKDIR /www
COPY . /www
EXPOSE 80
ENTRYPOINT ["/docker-entrypoint.sh"]

容器启动时执行的命令 ( CMD )

FROM nginx

Run apt-get update  \  
&& apt-get install -y --no-install-recommends git vim libpng-dev libjpeg-dev libfreetype6-dev

WORKDIR /www
COPY . /www
EXPOSE 80
ENTRYPOINT ["/docker-entrypoint.sh"]

CMD ["nginx" "-g" "daemon off;"]

构建镜像

在 Dockerfile 所在目录执行:

# 不指定版本
docker build -t nginx-my .
# 指定构建镜像的版本
docker build -t nginx-my:1.0 .

查看镜像

$ docker images

REPOSITORY       TAG              IMAGE ID       CREATED          SIZE
nginx-my         1.0              10de0a0932b3   50 seconds ago   306MB
nginx-my         latest           10de0a0932b3   50 seconds ago   306MB

使用上述指令就可以满足自己对镜像的定制需求。

指令之外

分层 & 缓存

Docker 使用层 layer 创建镜像,Dockerfile 中每一个命令都会创建一个新的层,每层都包含执行命令前后的状态之间镜像的文件系统更改。

为了加快构建速度,Docker 实现了缓存。如果 Dockerfile 和相关文件未更改,则重建(rebuild)时可以重用本地镜像缓存中的某些现有层。

当您构建 Dockerfile 时,Docker 将查看它是否可以使用先前构建的缓存结果:

  • 对于大多数命令,如果命令文本未更改,则将使用缓存中的版本。
  • 对于COPY,它还会检查您要复制的文件是否未更改。

缓存算法还有一个更重要的规则: 如果某层无法应用层缓存,则后续层都不能从层缓存加载, 因此写 Dockerfile 的时候,可以把不常改动的指令放在上面,频繁改动的放在下面从而更好的利用缓存。

层级过多会导致镜像体积变大,过少可能会导致无法有效的利用缓存。因此写 Dockerfile 的时候,需要平衡好镜像体积和缓存(构建速度)之间的关系。


扩展阅读

Dockerfile: ENTRYPOINT和CMD的区别 - 知乎 (zhihu.com)