使用 Dockerfile 构建镜像
本文介绍基于 Dockerfile 和 docker build
命令构建新的 Docker 镜像。
1 第一个 Dockerfile
让我们创建一个目录并编写一个 Dockerfile 文件吧,这是一个包含简单 Web 服务器的 Docker 镜像。
static_web 是存储 Dockerfile 文件的文件夹,称这个目录为构建上下文(build context),Docker 会在构建竟像时将上下文中的文件和目录上传到 Docker 守护进程。
mkdir static_web
cd static_web
vim Dockerfile
Dockerfile 的内容如下:
# Version: 0.0.1
FROM ubuntu:24.04
LABEL maintainer="lwg0452 "
RUN apt-get update && apt-get install -y nginx
RUN echo 'Hi, I am in your container' >usr/share/nginx/html/index.html
EXPOSE 80
WORKDIR /usr/sbin
ENTRYPOINT ["nginx"]
CMD ["-h"]
WORKDIR /root
ENV TEST=1
USER nginx
LABEL version="0.0.1" role="Web Server"
Dockerfile 由一系列的指令和参数构成,每条指令都必须为大写字母(例如 FROM),Dockerfile 中的指令会按照顺序由上到下执行。每条指令都会创建一个新的镜像层,并对镜像进行提交。Docker 答题上按照如下流程执行 Dockerfile 中的指令:
- Docker 从基础镜像运行一个容器;
- 执行一条指令,对容器进行修改;
- 执行类似
docker commit
的操作,提交一个新的镜像层; - Docker 再基于刚提交的镜像运行一个新容器;
- 执行 Dockerfile 中的下一条指令,知道所有指令都执行完毕。
Dockerfile 中以 #
开头的行是注释,Dockerfile 不支持行内注释,例如如下的注释是不合法的:
yum install -y nginx # 安装 Nginx
2 使用 docker build 命令构建新镜像
docker build
命令示例如下:
# 进入 Dockerfile 所在的目录
cd static_web
# 执行 docker build 命令,注意命令最后的".",它表示在当前目录寻找 Dockerfile 文件
docker build -t lwg0452/static_web:0.0.1 .
命令输出如下:

docker build
命令构建镜像会用到缓存机制来加速构建过程,当构建步骤没有变化时,Docker 会跳过这些步骤,直接使用之前的构建结果,例如重新执行以上命令,输出如下:

如果希望在构建过程不使用缓存,可以使用 --no-cache
参数:
docker build --no-cache -t "lwg0452/static_web:0.0.1" .
如果希望查看新镜像的构建过程,可以使用 docker history
命令:
docker history lwg0452/static_web:0.0.1
输出如下,其中 <missing>
表示该层已被合并或优化,无法直接看到中间层 ID,但仍然可以看到每个步骤的执行情况:
=> => naming to docker.io/lwg0452/static_web:0.0.1 0.0s
root@lwg0452-VMware-Virtual-Platform:~/static_web# docker history lwg0452/static_web:0.0.1
IMAGE CREATED CREATED BY SIZE COMMENT
8aa7a50dd409 4 minutes ago LABEL version=0.0.3 role=Web Server 0B buildkit.dockerfile.v0
4 minutes ago USER nginx 0B buildkit.dockerfile.v0
4 minutes ago ENV TEST=1 0B buildkit.dockerfile.v0
4 minutes ago WORKDIR /root 0B buildkit.dockerfile.v0
4 minutes ago CMD ["-h"] 0B buildkit.dockerfile.v0
4 minutes ago ENTRYPOINT ["nginx"] 0B buildkit.dockerfile.v0
4 minutes ago WORKDIR /usr/sbin 0B buildkit.dockerfile.v0
4 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
4 minutes ago RUN /bin/sh -c echo 'Hi, I am in your contai… 27B buildkit.dockerfile.v0
4 minutes ago RUN /bin/sh -c apt-get update && apt-get ins… 55.6MB buildkit.dockerfile.v0
4 minutes ago LABEL maintainer=lwg0452 0B buildkit.dockerfile.v0
2 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
2 months ago /bin/sh -c #(nop) ADD file:6df775300d76441aa… 78.1MB
2 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
2 months ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
2 months ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
2 months ago /bin/sh -c #(nop) ARG RELEASE 0B
root@lwg0452-VMware-Virtual-Platform:~/static_web#
3 Dockerfile 指令
Dockerfile 文件中需要用到许多 Dockerfile 指令,以下表格总结了各个指令的作用和用法:
指令 | 作用 | 示例 |
---|---|---|
FROM | 指定基础镜像 | FROM ubuntu:24.04 |
LABEL | 添加元数据(如维护者信息) | LABEL maintainer="[email protected]" |
RUN | 运行命令并创建新镜像层 | RUN apt-get update && apt-get install -y nginx |
COPY | 复制本地文件到容器(不会自动解压) | COPY index.html /usr/share/nginx/html/ |
ADD | 复制文件(支持自动解压 .tar.gz 和 URL 下载) | ADD my_archive.tar.gz /app/ |
WORKDIR | 设置工作目录 | WORKDIR /app |
CMD | 指定默认启动命令(可被 docker run 覆盖) | CMD ["nginx", "-g", "daemon off;"] |
ENTRYPOINT | 指定入口点(不会被 docker run 覆盖) | ENTRYPOINT ["python", "app.py"] |
ENV | 设置环境变量 | ENV APP_ENV=production |
EXPOSE | 声明容器暴露的端口(但不会自动映射) | EXPOSE 80 |
VOLUME | 定义数据卷(持久化存储) | VOLUME /data |
ARG | 定义构建时变量(仅 docker build 期间有效) | ARG BUILD_VERSION=1.0 |
ONBUILD | 继承该镜像时执行的指令 | ONBUILD COPY . /app |
USER | 指定容器运行的用户 | USER nginx |
HEALTHCHECK | 定义健康检查机制 | HEALTHCHECK CMD curl --fail http://localhost || exit 1 |
COPY
和ADD
指令复制的文件必须在 Docker 构建上下文(build context) 中,构建上下文是指docker build
命令的当前目录或-f
指定的 Dockerfile 所在目录。Docker 只能访问 上下文内的文件,无法直接访问上下文外的文件。ONBUILD
只会在继承该镜像的 Dockerfile 中触发,不会影响当前构建的镜像。如果子镜像
Dockerfile
里FROM
了my_base
,但不希望执行ONBUILD
指令,可以手动 清除它们:
FROM my_base
ONBUILD OFF
4 将镜像推送到 DockerHub
可以通过 docker push
命令将镜像推送到 DockerHub,这样所有人就能使用这个镜像了。
docker push lwg0452/static_web:0.0.1
lwg0452
需要替换成自己的镜像 ID。