Docker镜像构建
- [Docker 镜像](#Docker 镜像)
- [Docker 镜像构建](#Docker 镜像构建)
- Dockerfile
- 镜像构建完整示例
Docker 镜像
Docker 镜像是容器化应用的基础,它将应用程序、系统库、配置文件以及所有运行时所需的依赖封装为一个可执行的单元。这样,应用程序能够在任何兼容 Docker 的环境中一致地运行,无论是在开发、测试还是生产环境。
Docker 镜像采用分层文件系统设计,由多个只读层(Layer)按顺序叠加构成。每一层代表镜像构建过程中的一个操作,镜像层是增量式的,仅记录与前一层相比的差异。通过这种设计,Docker 镜像具备高效的存储和传输能力,同时减少存储空间占用。每层镜像都可以被多个容器和镜像共享,从而提高资源利用率,增强可重用性。在镜像更新时,Docker 仅重新构建发生变化的层,无需全量重建,从而显著提升构建速度。
Docker 镜像构建
Docker 镜像构建是一个通过编写一系列指令来创建容器镜像的过程,这些指令定义了应用程序及其依赖的安装、配置和初始化过程,构建 Docker 镜像的核心工具是 Dockerfile。
Dockerfile 是描述 Docker 镜像构建流程的纯文本文件,包含一系列有序的构建指令(Instructions),详细描述了如何从基础镜像开始,逐步安装应用程序及其所需的依赖、配置环境变量,并最终生成目标镜像。Docker 引擎根据这些指令逐条执行,生成目标镜像。
镜像构建的核心优势来自镜像的分层缓存机制:所有生成文件系统层的指令其构建结果都会被缓存。
如果 Dockerfile 中的某些指令及其上下文没有发生变化,Docker 会复用缓存中的层,避免重复构建,从而加快后续构建的速度。这种机制显著提高了构建效率,尤其是在镜像频繁更新的情况下。当 Dockerfile 中的某个层指令与上下文没有变化时,Docker 会直接使用缓存层,而不是重新执行该指令。例如,如果某个依赖已经安装并且没有变化,Docker 会跳过该步骤,复用缓存中的层,避免重新安装依赖。
Dockerfile
官方的 CentOS 镜像在 Docker Hub 上的公开仓库中,可以直接通过 docker pull centos 获取。其 Dockerfile 可能会涉及很多系统配置和优化,通常它们会放在 GitHub 仓库 或 Docker Hub 的页面中公开,具体内容可以参考 CentOS 官方发布的 Dockerfile,如图:

Tomcat docker File:
Redis docker File:
https://github.com/docker-library/redis/blob/231905d0841f52ee4f3a5b8b42d62cd6d14a1a93/6.2/Dockerfile
Dockerfile 核心指令
FROM:指定构建镜像的基础镜像,除注释外必须是 Dockerfile 的第一个有效指令;:
LABEL:声明镜像的维护者、版本、描述等结构化元数据(可通过 docker inspect 查看镜像的元数据);
ENV:设置环境变量,在镜像构建阶段和容器运行阶段都生效;
WORKDIR:设置后续所有指令的工作目录(构建阶段),同时也是容器启动后默认的工作目录(运行阶段);
ADD:将本地文件 / 目录、远程 URL 资源复制到镜像指定路径,支持自动解压本地 tar 格式文件;
COPY:功能类似 ADD,但仅支持复制本地文件 / 目录到镜像,不会自动解压任何文件,也不支持访问网络资源;
RUN:在镜像构建阶段(docker build 时) 执行命令,执行后结果会被打包进新的镜像层;
ENTRYPOINT:容器入口点,不可被 docker run 命令行后追加的参数直接覆盖;
CMD:定义容器启动时默认执行的命令,仅最后一条 CMD 生效,可被 docker run 命令行后追加的参数覆盖;
EXPOSE:声明容器打算对外暴露的端口(仅作文档说明,无实际端口映射效果);
VOLUME:声明容器的匿名数据卷(指定目录),容器启动时该目录会自动挂载为卷(数据不存于容器可写层)。
镜像构建完整示例
我们下载并运行官方 CentOS 镜像,发现进入容器后会默认进入根目录,且容器内默认无法使用 vim 工具,如图:

接下来将演示完整实操流程:以 Docker Hub 上的 centos:7 官方镜像为基础,编写 Dockerfile 来定制自定义 CentOS 镜像(该镜像内置 vim 工具,且容器启动后默认进入 /usr 目录),流程涵盖 Dockerfile 编写、自定义镜像构建、以及容器启动运行的完整流程。
先创建一个名为 Dockerfile 的文件,编写内容如下:
bash
FROM centos:7
LABEL maintainer="jiayingchen"
ENV MYPATH /usr
WORKDIR $MYPATH
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo && yum -y install vim
EXPOSE 80
CMD /bin/bash
需要注意的是 CentOS 7 官方源已停止维护,导致容器内无法解析官方镜像源地址(mirrorlist.centos.org),yum 工具无法获取 vim 的安装包,最终构建镜像失败,将 CentOS 7 的 yum 源替换为阿里云的 CentOS 7 镜像源,就能正常安装 vim。
执行 docker build 命令打包镜像,构建自定义镜像
bash
docker build -f Dockerfile -t mycs:1 .
docker build 是 Docker 的核心子命令,用于根据指定的 Dockerfile 和构建上下文构建镜像。
-f 是 --file 的简写,用于指定用于构建的 Dockerfile 文件路径。
-t 是 --tag 的简写,用于为构建的镜像打标签(tag),mycs:1 是镜像的名称和版本标签。
最后的参数 . 用于指定构建镜像时的上下文目录(. 代表当前目录)。构建时,Docker 会将该目录中的所有文件和子目录传送给 Docker 守护进程,Dockerfile 中涉及文件复制的指令(如 COPY 或 ADD)都会基于这个上下文路径读取相应的文件。

执行 docker run 启动容器,运行自定义镜像的容器
bash
docker run -it mycs:1

下面再进行一个案例示范,将自定义的 springboot 项目打包部署到 docker 中
首先需要对项目执行 mvn package,会将所有依赖打入 JAR,最终生成可执行 JAR,并存放在 target 目录下。
其次需要本地验证,在 JAR 包所在目录下执行命令 java -jar JAR包名称,如图:

本地验证通过后在服务器上制作镜像
在 /usr/local/src/docker 下创建 springbootDemo 文件夹
编写配置文件 vi Dockerfile
bash
FROM openjdk:8
VOLUME /tmp
WORKDIR /app
COPY mavenSpringBoot0817-1.0-SNAPSHOT.jar springbootDemo.jar
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app/springbootDemo.jar"]
EXPOSE 8080
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/springbootDemo.jar"] 用于定义容器启动的核心入口命令,启动时执行 Java 命令运行 Spring Boot JAR 包。其中 -Djava.security.egd=file:/dev/./urandom 是优化 Java 随机数生成策略,解决 Spring Boot 启动时因等待随机数生成导致的启动缓慢问题。
VOLUME /tmp 用于容器启动时 /tmp 目录会自动挂载为卷,Docker 会自动在宿主机生成一个匿名卷(路径一般是 /var/lib/docker/volumes/随机字符串/_data);容器往 /tmp 目录写入的数据,会实际存储到宿主机的这个匿名卷中;宿主机向该匿名卷写入数据时,容器内的 /tmp 目录也能实时看到这些数据。
bash
docker build -f Dockerfile -t springboot:1 .
根据当前目录下的 Dockerfile 构建一个名为 springboot 标签为 1 的镜像

基于 springboot:1 镜像创建并执容器
bash
docker run -p 8080:8080 springboot:1

开放端口后进行访问测试

Docker 会自动在宿主机生成的匿名卷,如图所示:
