当前位置: 首页 > news >正文

Docker镜像构建进化论:从手工操作到多阶段构建的实战指南

Docker镜像构建进化论:从手工操作到多阶段构建的实战指南

在容器化时代,镜像构建是每个开发者必须掌握的技能。手工构建虽然能让你理解镜像本质,但效率低下、不可重复;而多阶段构建则能大幅减小镜像体积、提升安全性。本文将带你从零开始,逐步掌握从手工构建到Dockerfile、再到多阶段构建的完整进化路径,最终落地企业级最佳实践。

一、手工构建:理解镜像的本质

在自动化之前,我们先手工走一遍流程,深刻理解镜像的组成。手工构建能让你直观感受到镜像的每一层是如何叠加的,以及为什么需要优化。

1.1 运行基础容器

首先,基于CentOS 7.9启动一个基础容器:

# 启动Ubuntu容器
[root@hadoop108 ~]# docker run -itd --name ubt_tengine_2.3.3 ubuntu:20.04 /bin/bash
# 进入容器
[root@hadoop108 ~]# docker exec -it ubt_tengine_2.3.3 /bin/bash

1.2 配置基础环境

安装编译工具和依赖库:

# 替换apt源为阿里云(国内加速)
root@16552f5daf21:/# sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list
# 更新缓存并安装基础工具
root@16552f5daf21:/# apt update && apt install -y wget vim curl

1.3 编译安装Tengine

下载源码并编译安装:

# 创建规范目录
root@16552f5daf21:/# mkdir -p /opt/module /opt/software
# 下载源码
root@16552f5daf21:~# wget -P /opt/software/ http://tengine.taobao.org/download/tengine-2.3.3.tar.gz
# 安装编译依赖
root@16552f5daf21:~# apt install -y libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev
# 解压并编译
root@16552f5daf21:/opt/software# tar -xzvf tengine-2.3.3.tar.gz
cd tengine-2.3.3/
# 配置(开启所需模块)
./configure --prefix=/opt/module/tengine-2.3.3/ \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module \
--with-http_mp4_module \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=modules/ngx_http_upstream_check_module/ \
--add-module=modules/ngx_http_upstream_session_sticky_module
# 编译安装
make -j `nproc` && make install

1.4 运行时配置优化

调整配置文件以提升性能:

# 创建nginx用户
root@16552f5daf21:~# groupadd nginx && useradd -g nginx nginx
# 创建软链接(便于使用)
root@16552f5daf21:~# ln -s /opt/module/tengine-2.3.3 /opt/module/tengine
root@16552f5daf21:~# ln -s /opt/module/tengine/sbin/nginx /sbin/nginx
# 日志重定向(Docker最佳实践)
root@16552f5daf21:~# ln -s /dev/stdout /opt/module/tengine/logs/access.log
root@16552f5daf21:~# ln -s /dev/stderr /opt/module/tengine/logs/error.log
# 测试页面
root@16552f5daf21:~# echo 'docker tengine' > /opt/module/tengine/html/index.html
# 启动测试
root@16552f5daf21:~# nginx && curl localhost
docker tengine

1.5 生成镜像

将容器提交为镜像:

# 清理无用文件
root@16552f5daf21:~# rm -rf /opt/software/* /var/cache/*
# 提交为镜像
[root@hadoop108 ~]# docker commit ubt_tengine_2.3.3 tengine:2.3.3
# 查看镜像大小
[root@hadoop108 ~]# docker images
REPOSITORY       TAG           IMAGE ID       CREATED         SIZE
tengine          2.3.3         25f29f6c517a   9 seconds ago   389MB

手工构建的痛点:

  • 操作繁琐,容易遗漏步骤
  • 镜像体积大(389MB)
  • 无法版本控制
  • 不可重复构建

二、Dockerfile自动化构建:迈出第一步

Dockerfile将构建过程代码化,实现可重复、可版本控制的构建。这是从手工到自动化的关键一步。

2.1 项目结构

合理的项目结构有助于维护:

[root@hadoop108 ~]# mkdir -p /opt/module/tengine
[root@hadoop108 ~]# cd /opt/module/tengine
# 准备文件
[root@hadoop108 tengine]# ll
总用量 2792
-rw-r--r-- 1 root root    1447 Dockerfile
-rw-r--r-- 1 root root      32 index.html
-r-------- 1 root root 2848144 tengine-2.3.3.tar.gz

2.2 编写Dockerfile

将手工步骤转化为指令:

# /opt/module/tengine/Dockerfile
FROM ubuntu:20.04
LABEL author="礼拜天没时间" \url="https://blog.csdn.net/weixin_73059914"
# =====================
# 环境变量
# =====================
ENV TENGINE_VERSION=2.3.3
ENV TENGINE_NAME=tengine-${TENGINE_VERSION}
ENV NGINX_USER=nginx
ENV INSTALL_PREFIX=/opt/module
# Tengine编译配置选项
ENV TENGINE_CONFIGURE_OPTS="./configure \--prefix=${INSTALL_PREFIX}/${TENGINE_NAME} \--user=${NGINX_USER} \--group=${NGINX_USER} \--with-http_ssl_module \--with-http_v2_module \--with-http_realip_module \--with-http_stub_status_module \--with-http_mp4_module \--with-stream \--with-stream_ssl_module \--with-stream_realip_module \--add-module=modules/ngx_http_upstream_check_module/ \--add-module=modules/ngx_http_upstream_session_sticky_module"
# =====================
# 1. 替换apt源为阿里云
# =====================
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \&& apt update
# =====================
# 2. 添加源码包
# =====================
ADD ${TENGINE_NAME}.tar.gz /tmp/
# =====================
# 3. 编译安装
# =====================
RUN apt install -y libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev \&& cd /tmp/${TENGINE_NAME} \&& ${TENGINE_CONFIGURE_OPTS} \&& make -j $(nproc) \&& make install
# =====================
# 4. 运行时配置
# =====================
RUN groupadd ${NGINX_USER} \&& useradd -g ${NGINX_USER} ${NGINX_USER} \&& ln -s ${INSTALL_PREFIX}/${TENGINE_NAME} ${INSTALL_PREFIX}/tengine \&& ln -s ${INSTALL_PREFIX}/tengine/sbin/nginx /sbin/nginx \&& ln -sf /dev/stdout ${INSTALL_PREFIX}/tengine/logs/access.log \&& ln -sf /dev/stderr ${INSTALL_PREFIX}/tengine/logs/error.log \&& rm -rf /tmp/* /var/cache/*
# =====================
# 5. 添加网页文件
# =====================
ADD index.html ${INSTALL_PREFIX}/tengine/html/
# =====================
# 6. 暴露端口
# =====================
EXPOSE 80 443
# =====================
# 7. 启动命令
# =====================
CMD ["nginx", "-g", "daemon off;"]

2.3 构建并运行

执行构建命令并启动容器:

# 构建镜像
[root@hadoop108 tengine]# docker build -t "tengine-dockerfile:2.3.3" .
# 查看镜像
[root@hadoop108 tengine]# docker images
REPOSITORY           TAG           IMAGE ID       CREATED         SIZE
tengine-dockerfile   2.3.3         276c35d21239   11 seconds ago  360MB
# 运行容器
[root@hadoop108 tengine]# docker run --name tengine -p 80:80 -d tengine-dockerfile:2.3.3
# 测试访问
curl http://localhost

✅ Dockerfile带来的改进:

  • 可重复构建
  • 版本控制友好
  • 操作文档化
  • 镜像体积略有减小(360MB)

❌ 依然存在的问题:

  • 镜像仍包含gcc、make等编译工具
  • 安全风险(编译工具可能被利用)
  • 体积还是偏大

三、多阶段构建:终极进化

多阶段构建的核心思想是将编译环境和运行环境彻底分离,只把运行必需的结果放进最终镜像。这极大减小了镜像体积,提升了安全性。

3.1 什么是多阶段构建?

阶段1(Builder)安装编译工具并编译源码;阶段2(Final)只拷贝编译产物到精简基础镜像中。

3.2 多阶段Dockerfile

# /opt/module/tengine-multi/Dockerfile
# ==============================
# 阶段1:编译环境
# ==============================
FROM ubuntu:20.04 AS builder
LABEL author="礼拜天没时间" \url="https://blog.csdn.net/weixin_73059914"
# 环境变量
ENV TENGINE_VERSION=2.3.3
ENV TENGINE_NAME=tengine-${TENGINE_VERSION}
ENV NGINX_USER=nginx
ENV INSTALL_PREFIX=/opt/module
# Tengine编译选项
ENV TENGINE_CONFIGURE_OPTS="./configure \--prefix=${INSTALL_PREFIX}/${TENGINE_NAME} \--user=${NGINX_USER} \--group=${NGINX_USER} \--with-http_ssl_module \--with-http_v2_module \--with-http_realip_module \--with-http_stub_status_module \--with-http_mp4_module \--with-stream \--with-stream_ssl_module \--with-stream_realip_module \--add-module=modules/ngx_http_upstream_check_module/ \--add-module=modules/ngx_http_upstream_session_sticky_module"
# 替换apt源
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \&& apt update
# 添加源码
ADD ${TENGINE_NAME}.tar.gz /tmp/
# 编译安装
RUN apt install -y libssl-dev make gcc pcre2-utils libpcre3-dev zlib1g-dev \&& cd /tmp/${TENGINE_NAME} \&& ${TENGINE_CONFIGURE_OPTS} \&& make -j $(nproc) \&& make install
# ==============================
# 阶段2:运行环境
# ==============================
FROM ubuntu:20.04
LABEL author="礼拜天没时间" \url="https://blog.csdn.net/weixin_73059914"
# 环境变量
ENV TENGINE_VERSION=2.3.3
ENV TENGINE_NAME=tengine-${TENGINE_VERSION}
ENV NGINX_USER=nginx
ENV INSTALL_PREFIX=/opt/module
# 1. 只拷贝编译产物
COPY --from=builder ${INSTALL_PREFIX}/ ${INSTALL_PREFIX}/
# 2. 安装运行依赖(只需要运行时库)
RUN sed -ri 's#archive.ubuntu.com|security.ubuntu.com#mirrors.aliyun.com#g' /etc/apt/sources.list \&& apt update \&& apt install -y libssl-dev pcre2-utils libpcre3-dev zlib1g-dev
# 3. 运行时配置
RUN groupadd ${NGINX_USER} \&& useradd -g ${NGINX_USER} ${NGINX_USER} \&& ln -s ${INSTALL_PREFIX}/${TENGINE_NAME} ${INSTALL_PREFIX}/tengine \&& ln -s ${INSTALL_PREFIX}/tengine/sbin/nginx /sbin/nginx \&& ln -sf /dev/stdout ${INSTALL_PREFIX}/tengine/logs/access.log \&& ln -sf /dev/stderr ${INSTALL_PREFIX}/tengine/logs/error.log \&& rm -rf /tmp/* /var/cache/*
# 4. 添加网页文件
ADD index.html ${INSTALL_PREFIX}/tengine/html/
# 5. 暴露端口
EXPOSE 80 443
# 6. 启动命令
CMD ["nginx", "-g", "daemon off;"]

3.3 构建对比

# 构建多阶段镜像
[root@hadoop108 tengine-multi]# docker build -t "tengine-multi:2.3.3" .
# 查看镜像大小
[root@hadoop108 tengine-multi]# docker images
REPOSITORY                 TAG           IMAGE ID       CREATED         SIZE
tengine-multi              2.3.3         e5ecfb93e5b9   58 seconds ago  196MB
tengine-dockerfile         2.3.3         276c35d21239   10 minutes ago  360MB
tengine                    2.3.3         25f29f6c517a   1 hour ago      389MB

3.4 三种方式对比

构建方式镜像大小构建速度安全性可维护性适用场景
手工构建389MB学习理解
Dockerfile360MB简单项目
多阶段构建196MB极好生产环境

多阶段构建的核心优势:

  • 体积减少50%:196MB vs 389MB
  • 安全性提升:没有gcc/make等编译工具
  • 启动更快:更小的镜像拉取快、启动快
  • 依赖隔离:运行时只需要必要的库
[AFFILIATE_SLOT_1]

四、镜像层次架构:企业级最佳实践

在大型企业中,镜像构建遵循严格的层次结构,以实现最大化的复用和标准化。

4.1 三层架构理论

系统层(System)提供操作系统基础;运行时层(Runtime)提供语言环境(如JDK、Python);应用层(Application)包含具体项目代码。

4.2 目录结构实战

[root@hadoop108 module]# tree df/ -L 3
df/
├── project                 # 应用层:具体业务项目
│   ├── aggbook
│   │   ├── build.sh
│   │   └── Dockerfile
│   ├── blog
│   │   ├── build.sh
│   │   └── Dockerfile
│   └── hospital
│       ├── build.sh
│       └── Dockerfile
├── runtime                 # 运行时层:各种语言环境
│   ├── centos-7.9-jdk8
│   │   ├── build.sh
│   │   └── Dockerfile
│   ├── centos-7.9-jdk11
│   │   ├── build.sh
│   │   └── Dockerfile
│   ├── centos-7.9-python-3.8
│   │   ├── build.sh
│   │   └── Dockerfile
│   └── centos-7.9-nodejs-16
│       ├── build.sh
│       └── Dockerfile
└── system                  # 系统层:基础操作系统
├── centos-7.9
│   ├── build.sh
│   └── Dockerfile
├── centos-7.9-ssh
│   ├── build.sh
│   └── Dockerfile
└── ubuntu-20.04
├── build.sh
└── Dockerfile

4.3 层次化Dockerfile示例

系统层:CentOS 7.9基础镜像

# df/system/centos-7.9/Dockerfile
FROM centos:7.9.2009
RUN yum install -y epel-release \&& yum clean all
CMD ["/bin/bash"]

运行时层:JDK8镜像

# df/runtime/centos-7.9-jdk8/Dockerfile
FROM centos-7.9:latest
ENV JAVA_HOME=/usr/local/jdk1.8.0_202
ENV PATH=$PATH:$JAVA_HOME/bin
ADD jdk-8u202-linux-x64.tar.gz /usr/local/
CMD ["/bin/bash"]

应用层:Spring Boot项目

# df/project/shop/Dockerfile
FROM centos-7.9-jdk8:latest
WORKDIR /app
ADD shop.jar /app/
ADD start.sh /app/
EXPOSE 8080
CMD ["/app/start.sh"]

4.4 层次架构的收益

层级复用性变更频率构建次数典型大小
系统层全公司共用极低(季度/年)1次200MB
运行时层部门共用低(月/季度)10+次300-500MB
应用层项目独用高(每天)100+次50-200MB

核心收益:

  • 存储节省:10个Java项目只需要1份系统层+1份JDK层
  • 构建加速:改代码只需重建应用层,利用缓存秒级完成
  • 标准化:统一的基础环境,减少“在我机器能跑”的问题
  • 安全可控:基础镜像由平台组统一维护,打满安全补丁
[AFFILIATE_SLOT_2]

五、生产环境最佳实践总结

5.1 镜像构建演进路线

手工构建 → Dockerfile → 多阶段构建 → 层次化架构 → CI/CD集成

5.2 企业级构建清单

  • 基础镜像:选择官方镜像或自建基础镜像
  • .dockerignore:排除无用文件
  • 多阶段构建:分离编译和运行环境
  • 非root用户:运行容器不使用root
  • 标签规范:版本号+commit+构建时间
  • 镜像扫描:集成trivy/clair扫描漏洞
  • 签名验证:保证镜像完整性

5.3 最终对比数据

指标手工构建Dockerfile多阶段构建层次化架构
镜像大小389MB360MB196MB150MB
构建时间15min8min8min3min
安全风险极低
可维护性极好
存储复用部分完全

结语

从手工构建到多阶段构建,我们见证了Docker镜像构建的完整进化史。手工构建是理解镜像本质的必经之路;Dockerfile是自动化的第一步;多阶段构建是生产环境的标准答案;层次化架构则是企业级大规模实践的终极方案。记住这个原则:编译环境要胖,运行环境要瘦。现在,是时候重构你的Dockerfile了!

思考题:如果你的项目是用apt/yum安装的软件(如MySQL、Redis),多阶段构建还适用吗?为什么?

欢迎在评论区分享你的见解!

http://www.jsqmd.com/news/795841/

相关文章:

  • PostgreSQL数据清洗实战:用string_agg合并地址字段,我这样整理混乱的客户信息
  • 【赵渝强老师】金仓数据库的运行日志文件
  • 5步精通League Akari:高效解锁英雄联盟LCU工具箱的完整指南
  • 码率控制方法详解
  • BetterRTX终极教程:5分钟免费提升Minecraft画质的完整方案
  • 3分钟高效获取百度网盘提取码:开源自动化工具实战指南
  • NoFences:开源免费的Windows桌面围栏管理工具,让杂乱桌面瞬间井然有序
  • pip install -r requirements.txt报错:Collecting PyGObject (from -r requirements.txt (line 26))...如何解决?
  • 用Python+Elasticsearch实时处理Websocket股票数据:保姆级配置与实战分析
  • 考虑电解槽变载启停特性与阶梯式碳交易机制的综合能源系统优化调度研究(Matlab代码实现)
  • League-Toolkit:基于模块化架构的英雄联盟客户端自动化工具深度解析
  • 科技早报|2026年5月11日:AI Agent 开始补验证、分工和落地这三道工程题
  • 从零打造USB-C一拖二数据线:硬件拆解与引脚焊接实战
  • 论mysql的redo_log和bin_log,redis的RDB和AOF的类似记忆
  • Visual C++运行库一键修复工具:告别DLL错误和软件崩溃的终极解决方案
  • 【信息科学工程学】【社会科学】 第五十五篇 人的利益规则04
  • Akari助手:基于LCU API的自动化竞技辅助框架
  • 2026年论文AI率太高怎么办?这几招帮你高效降到安全线 - 降AI实验室
  • 本周补题5/4--5/10
  • 用 python 和 java 分别写出10道经典题
  • 终极指南:如何用Legacy-iOS-Kit拯救你的老旧iPhone/iPad?一站式降级、越狱与备份工具全解析
  • Dell G15终极散热指南:开源温度控制中心完全解析
  • vSphere/ESXi安装虚拟机的10种方法
  • 2026年保定装修厂家口碑推荐榜:保定整装定制、保定家装、保定商业美陈装修、保定别墅设计装修、保定门店装修厂家选择指南 - 海棠依旧大
  • Steam成就管理终极指南:SAM开源工具完整使用教程
  • 宇树GO2机器人ROS2控制实战:从零到自主导航的完整指南
  • 【信息科学工程学】【社会科学】 第五十五篇 人的利益规则05——行业篇04
  • 告别Keil‘瞎眼’调试:手把手教你用CLion+STM32CubeMX配置DSP库(附完整CMakeLists)
  • 跨通道AI智能体开发:从架构设计到实战部署的完整指南
  • GitHub育儿技能库:结构化知识管理在育儿实践中的应用