自定义镜像制作——从Dockerfile到镜像

自定义镜像制作------从Dockerfile到镜像


🎯 系列介绍

🔔 本文是 《Docker实战入门与部署指南:从核心概念到网络与数据管理》 系列的第五篇!

本系列将从零开始,带你系统性地学习 Docker 的核心概念、安装部署、容器管理、镜像制作、数据持久化与网络配置,最终具备构建和运维容器化应用的能力。

⚠️ 该系列所有涉及的配置脚本、Dockerfile示例和离线安装包都可以私信博主免费获取。


📚 系列篇章总览


🚀 系列最终成果
当你完整学完并实操本系列,你将拥有:

✅ 扎实的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:7FROM 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 会自动从远程镜像仓库拉取

    当你执行:

    bash 复制代码
    docker build -t myimage:v1 .

    Docker 在解析到:

    bash 复制代码
    FROM centos:7

    会按顺序做三件事:

    1. 先在本地 docker images 查找 centos:7
    2. 如果本地存在 → 直接使用
    3. 如果本地不存在 → 自动从远程仓库(默认 Docker Hub)拉取

    整个过程是自动的 ,不需要你手动 docker pull

    bash 复制代码
    FROM nginx:1.24

    特殊情况

    表示从 空镜像 开始构建(制作极简镜像)

    bash 复制代码
    FROM scratch
  • RUN(构建时执行)

    • 镜像构建阶段执行

    • 每条 RUN 都会生成一个镜像层(layer)

    • yum clean all 用来清理 yum 缓存,显著减小镜像体积

    bash 复制代码
    RUN yum install -y nginx && yum clean all
  • COPY / ADD(拷贝文件)

    区别说明:

    指令 说明
    COPY 只做文件拷贝(推荐)
    ADD 支持自动解压、URL(不推荐)
    bash 复制代码
    COPY app.jar /app/app.jar
  • WORKDIR(工作目录)

    作用:

    • 设置后续容器里指令的默认目录
    • 相当于 cd /app
    bash 复制代码
    WORKDIR /app
  • ENV(环境变量)

    作用:

    • 设置环境变量
    • 容器运行时依然有效
    bash 复制代码
    ENV JAVA_HOME=/usr/local/java
    ENV PATH=$JAVA_HOME/bin:$PATH
  • EXPOSE(声明端口)

    注意:

    • 只是声明
    • 不会自动做端口映射
    • 需要 docker run -p
    bash 复制代码
    EXPOSE 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 / 覆盖
    bash 复制代码
    CMD ["java","-jar","app.jar"]
  • ENTRYPOINT(固定入口)

    特点:

    • 不容易被覆盖
    • 常用于服务型容器
      🔍问:ENTRYPOINT 是做什么的?

    ✅答:ENTRYPOINT 用来指定容器启动时的"固定入口命令"


    bash 复制代码
    ENTRYPOINT ["java","-jar","app.jar"]
  • VOLUME

    VOLUME 用来在镜像里声明容器中的某些目录是"数据卷" ,这些目录的数据不属于容器本身的可写层
    在宿主机 /var/lib/docker/volumes/

    创建 匿名 volume (如果想要有名字的VOLUME,那就要先 docker volume create [卷名],然后用 docker run -v

    并挂载到:

    • /dataVolumeContainer1
    • /dataVolumeContainer2
    bash 复制代码
    VOLUME ["/dataVolumeContainer1","/dataVolumeContainer2"] 

2)docker build

一句话:docker build 用来"根据 Dockerfile 把镜像一步一步做出来"

  • 基本语法

    • docker build
      执行构建镜像
    • -t myimage:v1
      给镜像起名字和 tag
      • 镜像名:myimage
      • tag:v1
    • .
      构建上下文目录(非常重要)
    bash 复制代码
    docker build [选项] 镜像构建上下文
    bash 复制代码
    docker build -t myimage:v1 .
  • 镜像构建上下文

    bash 复制代码
    docker build -t app:v1 .

    这里的 . 表示:

    Docker 只能使用当前目录及其子目录里的文件

    例如:

    bash 复制代码
    .
    ├── Dockerfile
    ├── app.jar
    └── conf/

    Dockerfile 里的:

    bash 复制代码
    COPY app.jar /app/app.jar

    只能拷贝当前目录里的 app.jar

  • 执行过程

    bash 复制代码
    docker build -t test:v1 .
    1. 找到 Dockerfile
    2. 读取第一条指令 FROM
    3. 检查基础镜像是否存在
      • 有 → 直接用
      • 没有 → 自动 pull
    4. 按顺序执行每一条指令
    5. 每一条指令生成一个镜像层
    6. 最终生成一个完整镜像

3)示例

  1. 创建目录

    bash 复制代码
    [root@hadoop108 nginx-1.12.2]# pwd
    /opt/module/dockerfile/nginx-1.12.2
  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
  3. 编写 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;"]
  4. 创建镜像

    bash 复制代码
    [root@hadoop108 nginx-1.12.2]# docker build -t my-nginx:1.12.2 .
  5. 查看镜像

    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 生产环境推荐 声明式、可重复、版本控制
相关推荐
xixingzhe29 小时前
ubuntu安装gitlab
linux·ubuntu·gitlab
强风7949 小时前
Linux-传输层协议TCP
linux·网络·tcp/ip
luffy54599 小时前
windows下通过docker-desktop创建redis实例
windows·redis·docker·容器
looking_for__9 小时前
【Linux】应用层自定义协议与序列化
linux·服务器·网络
云中飞鸿9 小时前
VS编写QT程序,如何向linux中移植?
linux·开发语言·qt
嵌入小生0079 小时前
Standard IO -- Continuation of Core Function Interfaces (Embedded Linux)
linux·vim·嵌入式·标准io·vscode
Zach_yuan9 小时前
传输层之TCP/UDP 核心原理全解析:从协议基础到实战机制
linux·网络协议·tcp/ip·udp
独自归家的兔9 小时前
Ubuntu 系统 systemd timers 详解:替代 crontab 的定时任务进阶方案
linux·运维·ubuntu
Lsir10110_9 小时前
【Linux】深入解剖页表——分页式存储
linux·运维·服务器