自定义镜像制作------从Dockerfile到镜像
🎯 系列介绍
🔔 本文是 《Docker实战入门与部署指南:从核心概念到网络与数据管理》 系列的第五篇!
本系列将从零开始,带你系统性地学习 Docker 的核心概念、安装部署、容器管理、镜像制作、数据持久化与网络配置,最终具备构建和运维容器化应用的能力。
⚠️ 该系列所有涉及的配置脚本、Dockerfile示例和离线安装包都可以私信博主免费获取。
📚 系列篇章总览
-
第一章:初识Docker------概念与优势
核心: 理解Docker是什么,它与传统虚拟机的本质区别,以及为何要使用容器化技术。 -
第二章:环境准备与Docker安装
核心: 掌握在CentOS系统上搭建Docker运行环境,从操作系统准备到Docker CE的安装、配置与优化。 -
第三章:Docker基础操作------镜像与容器管理
核心: 理解Docker是什么,它与传统虚拟机的本质区别,以及为何要使用容器化技术。 -
第四章:深入Docker架构------C/S模式解析
核心: 理解Docker客户端与守护进程如何协同工作,这是掌握Docker运行原理和高级管理(如远程连接)的基础 -
第五章:自定义镜像制作------从Dockerfile到镜像
核心: 掌握制作自定义镜像的四种方式,重点学习使用Dockerfile进行标准化、可复用的镜像构建。 -
第六章:数据持久化------Volume与Bind Mount
核心:解决容器内数据易失性问题,学习如何通过Volume和绑定挂载实现数据的持久化存储与跨容器共享。 -
第七章:容器网络配置------从互联到自定义桥接
核心: 掌握容器间的通信方式,学习默认Bridge、Host网络,并最终通过自定义网络和Pipework实现容器与宿主机网络的无缝集成。
🚀 系列最终成果
当你完整学完并实操本系列,你将拥有:
✅ 扎实的Docker理论基础,清晰理解容器、镜像、仓库等核心概念。
✅ 独立部署Docker环境的能力,并完成常用配置优化(如镜像加速)。
✅ 熟练的容器与镜像管理技能,能够进行日常的运维操作。
✅ 制作自定义业务镜像的能力,为应用容器化打下基础。
✅ 解决数据持久化问题的方案,确保应用数据安全。
✅ 配置复杂容器网络的能力,实现容器内外的灵活通信。
真正实现: 概念理解 → 环境搭建 → 日常操作 → 镜像定制 → 数据管理 → 网络配置,一站式掌握Docker核心技能。
一:方式一(commit)
docker commit的作用是把一个正在运行或已停止的容器,保存为一个新的镜像 。可以理解为: 把"容器当前状态拍成快照,做成镜像"。
参数说明:
-m:提交说明-a:作者信息
bash
[root@hadoop108 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e96bbaf327e8 nginx:1.19 "/docker-entrypoint...." 22 minutes ago Up 22 minutes 0.0.0.0:80->80/tcp nginx
[root@hadoop108 ~]# docker commit -m "nginx images" -a "@礼拜天没时间" e96bbaf327e8 mynginx:1.0
sha256:1d582a4eeca4c67f73a3e92a9d164d242fe97ddb0e049ce5fe3123a90eecd86f
[root@hadoop108 ~]# docker images | grep mynginx
mynginx 1.0 1d582a4eeca4 12 seconds ago 133MB
二:方式二(import)
docker import用来把一个"文件系统包(tar)"直接导入成镜像 ,本质是:从一个干净的根文件系统创建镜像,而不是从容器提交。
bash
# 1. 查看容器
[root@hadoop108 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e96bbaf327e8 nginx:1.19 "/docker-entrypoint...." 27 minutes ago Up 27 minutes 0.0.0.0:80->80/tcp nginx
# 2. 导出容器
[root@hadoop108 ~]# docker export -o export-nginx-1.19.tar nginx
# 3. 导入容器
[root@hadoop108 ~]# docker import export-nginx-1.19.tar import-nginx:1.0
sha256:94b55db2a37b567e1ef0d38d3bdc68071a76e3640fb9bba365618033c0e6d294
or
[root@hadoop108 ~]# cat export-nginx-1.19.tar | docker import - import-nginx:1.0
sha256:2f7ba5d17abd8d119e117e0efb392534935086e4fa9646aa5db04f398d0f8e53
# 4. 查看镜像
[root@hadoop108 ~]# docker images | grep import-nginx
import-nginx 1.0 94b55db2a37b 16 seconds ago 131MB
三:方式三(load)
docker load= 从 tar 包恢复镜像(包含镜像名、tag、历史层)
bash
# 1. 查看镜像
[root@hadoop108 ~]# docker images | grep nginx
nginx 1.24 b6c621311b44 2 years ago 142MB
nginx 1.24-alpine 55ba84d7d539 2 years ago 41.1MB
nginx 1.19 f6d0b4767a6c 5 years ago 133MB
# 2. 导出镜像
[root@hadoop108 ~]# docker save -o save-nginx-1.24 nginx:1.24
[root@hadoop108 ~]# ls -l | grep save
-rw------- 1 root root 146631168 1月 14 10:08 save-nginx-1.24
[root@hadoop108 ~]# docker rmi nginx:1.24
Untagged: nginx:1.24
Deleted: sha256:b6c621311b44ae45292790dd4a8004a830c3c251177e5f87f278e294ea05f9ca
Deleted: sha256:afee24779206129160d513f587cdfc8a165f3ce4699e3010bb5c70c660a47c49
Deleted: sha256:af250d7a3cb5aa80b47b8d54c5dc11ea43f39c234a7cde812a8d803be1ccf601
Deleted: sha256:36152eed3589e78b808efc0b3c5514a273dab10d2d3f2e7218f07ee096ef701f
Deleted: sha256:82039c33f32713fa33f2690ac73d7777559224be6fe1db318fcfc94507fe2649
Deleted: sha256:f295954d2d680b19a09e64d960ae09e1e8513d40b07f30c40f6459cf07bd8e45
# 3. 导出镜像
[root@hadoop108 ~]# docker load -i save-nginx-1.24
6310117db5a7: Loading layer [==================================================>] 62.55MB/62.55MB
e543857b2aef: Loading layer [==================================================>] 3.584kB/3.584kB
629fd7b81c65: Loading layer [==================================================>] 4.608kB/4.608kB
0b27f1638f81: Loading layer [==================================================>] 3.584kB/3.584kB
f62590d48fe5: Loading layer [==================================================>] 7.168kB/7.168kB
Loaded image: nginx:1.24
[root@hadoop108 ~]# docker images | grep nginx
nginx 1.24 b6c621311b44 2 years ago 142MB
nginx 1.24-alpine 55ba84d7d539 2 years ago 41.1MB
nginx 1.19 f6d0b4767a6c 5 years ago 133MB
四:方式四(Dockerfile)
Dockerfile 是一个 用于描述 Docker 镜像构建过程的文本文件 ,
通过一条条指令,声明式地定义:
- 使用什么基础镜像
- 安装哪些软件
- 拷贝哪些文件
- 设置哪些环境变量
- 容器启动时执行什么命令
1)常用指令
| 指令 | 含义 | 应用 | 建议 |
|---|---|---|---|
| FROM | 指定基础镜像,作为当前镜像构建的起点 | 如 FROM centos:7、FROM openjdk:8-jdk |
必须是第一条指令(ARG 除外),优先选择官方、体积小的基础镜像 |
| MAINTAINER | 指定镜像维护者信息 | MAINTAINER admin@example.com |
已被废弃,建议使用 LABEL 代替 |
| LABEL | 为镜像添加元数据说明 | 记录作者、版本、用途等信息 | 推荐使用,可用于镜像管理和自动化识别 |
| RUN | 构建镜像时执行命令 | 安装软件、配置环境、创建目录 | 尽量合并多条 RUN,减少镜像层数 |
| CMD | 指定容器启动时默认执行的命令 | 启动服务进程,如 nginx、java | 一个 Dockerfile 只能有一个 CMD,容易被覆盖 |
| ENTRYPOINT | 设置容器启动时的主命令 | 固定容器运行行为,如启动核心服务 | 更适合生产环境,不易被覆盖 |
| EXPOSE | 声明容器内部监听端口 | 如 EXPOSE 80 8080 |
仅用于说明,不会自动映射端口 |
| ENV | 设置环境变量 | 设置 JAVA_HOME、PATH 等 | 常用于参数化配置,避免硬编码 |
| ADD | 添加文件到镜像中,支持 URL 和自动解压 | 拷贝安装包、远程资源 | 行为不够透明,官方更推荐 COPY |
| COPY | 将本地文件复制到镜像中 | 拷贝配置文件、程序文件 | 推荐优先使用,语义清晰、可控 |
| VOLUME | 声明数据卷,实现数据持久化 | 保存日志、数据文件 | 会生成匿名卷,生产环境需注意 |
| WORKDIR | 指定工作目录 | 后续 RUN、CMD 的默认路径 | 推荐使用,避免大量 cd |
| USER | 指定容器运行用户 | 以非 root 用户运行服务 | 提升安全性,生产环境建议使用 |
| ARG | 定义构建阶段变量 | 构建时传参,如版本号 | 仅 build 阶段有效,运行时不可用 |
| ONBUILD | 设置触发器指令 | 用于构建基础镜像 | 使用场景少,新手慎用 |
| STOPSIGNAL | 指定容器停止信号 | 优雅停止服务进程 | 适合需要平滑关闭的服务 |
| HEALTHCHECK | 定义容器健康检查 | 判断服务是否正常 | 对编排系统(K8s)非常重要 |
| SHELL | 指定默认 shell | 修改 RUN 使用的 shell | 特殊场景使用,一般不用 |
-
FROM (基础镜像)
- 每个 Dockerfile 必须有 FROM
- 第一条指令
- 可以理解为"继承"
🔍问:基础镜像必须在 docker images 里吗?
✅答:不必须在本地有,如果本地没有,Docker 会自动从远程镜像仓库拉取
当你执行:
bashdocker build -t myimage:v1 .Docker 在解析到:
bashFROM centos:7会按顺序做三件事:
- 先在本地
docker images查找centos:7 - 如果本地存在 → 直接使用
- 如果本地不存在 → 自动从远程仓库(默认 Docker Hub)拉取
整个过程是自动的 ,不需要你手动
docker pullbashFROM nginx:1.24特殊情况
表示从 空镜像 开始构建(制作极简镜像)
bashFROM scratch -
RUN(构建时执行)
-
在 镜像构建阶段执行
-
每条 RUN 都会生成一个镜像层(layer)
-
yum clean all用来清理 yum 缓存,显著减小镜像体积
bashRUN yum install -y nginx && yum clean all -
-
COPY / ADD(拷贝文件)
区别说明:
指令 说明 COPY 只做文件拷贝(推荐) ADD 支持自动解压、URL(不推荐) bashCOPY app.jar /app/app.jar -
WORKDIR(工作目录)
作用:
- 设置后续容器里指令的默认目录
- 相当于
cd /app
bashWORKDIR /app -
ENV(环境变量)
作用:
- 设置环境变量
- 容器运行时依然有效
bashENV JAVA_HOME=/usr/local/java ENV PATH=$JAVA_HOME/bin:$PATH -
EXPOSE(声明端口)
注意:
- 只是声明
- 不会自动做端口映射
- 需要
docker run -p
bashEXPOSE 8080 -
CMD(指定容器启动时的"默认命令")
特点:
- 一个 Dockerfile 只能有一个 CMD
- 可以被
docker run覆盖
🔍问:CMD是做什么的?
✅答:CMD 用来指定容器启动时的"默认命令"
示例
Dockerfile
FROM centos:7 CMD ["/bin/bash"]启动容器(默认)
docker run -it centos_cmd执行的是:
/bin/bash覆盖 CMD
docker run -it centos_cmd ls /此时:
/bin/bash不再执行- CMD 被
ls /覆盖
bashCMD ["java","-jar","app.jar"] -
ENTRYPOINT(固定入口)
特点:
- 不容易被覆盖
- 常用于服务型容器
🔍问:ENTRYPOINT 是做什么的?
✅答:ENTRYPOINT 用来指定容器启动时的"固定入口命令"

bashENTRYPOINT ["java","-jar","app.jar"] -
VOLUME
VOLUME用来在镜像里声明容器中的某些目录是"数据卷" ,这些目录的数据不属于容器本身的可写层。
在宿主机/var/lib/docker/volumes/下创建 匿名 volume (如果想要有名字的VOLUME,那就要先
docker volume create [卷名],然后用docker run -v)并挂载到:
/dataVolumeContainer1/dataVolumeContainer2
bashVOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"]
2)docker build
一句话:
docker build用来"根据 Dockerfile 把镜像一步一步做出来"
-
基本语法
docker build
执行构建镜像-t myimage:v1
给镜像起名字和 tag- 镜像名:
myimage - tag:
v1
- 镜像名:
.
构建上下文目录(非常重要)
bashdocker build [选项] 镜像构建上下文bashdocker build -t myimage:v1 . -
镜像构建上下文
bashdocker build -t app:v1 .这里的
.表示:Docker 只能使用当前目录及其子目录里的文件
例如:
bash. ├── Dockerfile ├── app.jar └── conf/Dockerfile 里的:
bashCOPY app.jar /app/app.jar只能拷贝当前目录里的
app.jar -
执行过程
bashdocker build -t test:v1 .- 找到 Dockerfile
- 读取第一条指令
FROM - 检查基础镜像是否存在
- 有 → 直接用
- 没有 → 自动 pull
- 按顺序执行每一条指令
- 每一条指令生成一个镜像层
- 最终生成一个完整镜像
3)示例
-
创建目录
bash[root@hadoop108 nginx-1.12.2]# pwd /opt/module/dockerfile/nginx-1.12.2 -
上传相关资源
bash[root@hadoop108 nginx-1.12.2]# ll 总用量 86824 -rw-r--r-- 1 root root 2523 1月 14 16:36 aliyun.repo -rw-r--r-- 1 root root 981687 1月 14 16:36 nginx-1.12.2.tar.gz -rw-r--r-- 1 root root 87906191 1月 14 16:36 nginxlibrpm.tar.gz -rw-r--r-- 1 root root 1003 1月 14 16:36 yum.conf -
编写 Dockerfile
bash[root@hadoop108 nginx-1.12.2]# vim Dockerfile # 基于那个镜像 FROM centos:7.5.1804 # 描述 MAINTAINER lmc@lmc.com # 把宿主机的压缩包,直接解压到容器里面 ADD nginx-1.12.2.tar.gz /usr/local/src # 拷贝宿主机的文件,到容器里面 COPY aliyun.repo /etc/yum.repos.d/ # 运行一个命令, 把CentOS-Base.repo重命名一下 RUN mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak # 通过拷贝的方式,设置离线位置 COPY yum.conf /etc/ # 安装依赖并清理(合并RUN减少层数) RUN yum install -y gcc gcc-c++ glibc make autoconf openssl openssl-devel \ libxslt-devel gd gd-devel GeoIP GeoIP-devel pcre pcre-devel && \ yum clean all && \ rm -rf /var/cache/yum # 创建虚拟用户 RUN useradd -M -s /sbin/nologin nginx # 设置工作空间目录 WORKDIR /usr/local/src/nginx-1.12.2 # 源码编译并清理源码目录 RUN ./configure --user=nginx --group=nginx \ --prefix=/usr/local/nginx \ --with-file-aio \ --with-http_ssl_module \ --with-http_realip_module \ --with-http_addition_module \ --with-http_xslt_module \ --with-http_image_filter_module \ --with-http_geoip_module \ --with-http_sub_module \ --with-http_dav_module \ --with-http_flv_module \ --with-http_mp4_module \ --with-http_gunzip_module \ --with-http_gzip_static_module \ --with-http_auth_request_module \ --with-http_random_index_module \ --with-http_secure_link_module \ --with-http_degradation_module \ --with-http_stub_status_module && \ make && \ make install && \ cd / && \ rm -rf /usr/local/src/nginx-1.12.2 # 添加Nginx到PATH环境变量 ENV PATH=/usr/local/nginx/sbin:$PATH # 暴露端口 EXPOSE 80 # 设置工作目录为nginx目录 WORKDIR /usr/local/nginx # 执行命令后端运行 CMD ["nginx", "-g", "daemon off;"] -
创建镜像
bash[root@hadoop108 nginx-1.12.2]# docker build -t my-nginx:1.12.2 . -
查看镜像
bash[root@hadoop108 nginx-1.12.2]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE my-nginx 1.12.2 e2f7db555fa3 3 minutes ago 586MB
总结
🛠️ 四种镜像制作方式
| 方式 | 核心命令 | 适用场景 | 特点 |
|---|---|---|---|
| commit | docker commit |
容器快照保存 | 快速但不可重复,适合临时调试 |
| import | docker import |
tar包导入 | 仅含文件系统,无历史层 |
| load | docker load |
镜像备份恢复 | 完整镜像结构,含所有层 |
| Dockerfile | docker build |
生产环境推荐 | 声明式、可重复、版本控制 |