镜像是容器的只读模板,容器是镜像的可写运行实例;镜像分层复用、需精简固化,容器本质是进程隔离而非虚拟机,改造关键在Dockerfile设计与启动逻辑优化。
镜像和容器不是两个并列概念,而是“模板”和“实例”的关系。做容器化改造时,真正要动手的其实是围绕镜像设计和容器运行展开的一整套动作——从代码打包、环境固化,到启动参数调优、网络与数据配置。理解这点,才能避开“能跑但不稳”“本地行线上崩”的典型陷阱。
镜像不是压缩包,是分层可复用的运行环境模板
很多人把镜像当成一个大 tar 包,构建完就扔,结果镜像越打越大、更新慢、安全扫描一堆高危漏洞。其实 Docker 镜像由多层只读文件系统叠加而成:基础 OS 层(如 alpine:3.20)、运行时层(如 python:3.11-slim)、依赖层(pip install 的库)、应用层(你的代码和配置)。每一层都可被多个镜像共享。
- 优先选精简基础镜像,比如用 python:3.11-slim 而非 python:3.11,体积减少 60% 以上,攻击面更小
- 把变动少的部分(系统工具、Python 版本)放在前面,变动频繁的(代码、配置)放后面,提升构建缓存命中率
- 用 multi-stage build 分离构建环境和运行环境,比如前端项目用 node 镜像构建,最终只把 dist 目录复制进 nginx 镜像
容器不是虚拟机,是进程隔离+资源约束的运行态
容器本质是 Linux namespace + cgroups 控制下的一个或多个进程。它没有独立内核,也不模拟硬件,所以启动快、开销低。但这也意味着:容器崩溃 = 进程退出;容器里改系统时间、装软件、写 /tmp,重启就丢——这些都不是 bug,是设计如此。
- 不要在容器里执行 apt update && apt install,所有依赖必须打进镜像,否则上线后环境不可控
- 用 --read-only 启动容器,强制只读根文件系统,配合 --tmpfs /run --tmpfs /tmp 提供必要临时空间
- 避免以 root 用户运行,通过 USER 1001 指令切换非特权用户,并确保应用目录权限适配
容器化改造的关键动作不在 docker run,而在 Dockerfile 和启动逻辑
很多团队卡在“Docker 能跑,但上不了生产”,问题往往出在没把传统部署逻辑平移成容器友好方式。比如 Java 应用硬编码了 /opt/app/config,而容器里该路径根本不存在;又或者 Python 服务依赖本地 /etc/timezone,但 Alpine 镜像默认没装 tzdata。
- 配置外置:用 -e ENV=prod 或挂载 -v ./config:/app/config,别把配置编译进镜像
- 日志输出到 stdout/stderr:删掉 log4j 写文件配置,让 Docker 原生采集日志,方便对接 ELK 或云平台
- 健康检查必须加:HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost:8080/health || exit 1,否则编排工具无法判断服务是否就绪
一次构建,处处运行的前提是镜像内容完整且确定
所谓“一致”,不是指镜像能在不同机器上启动,而是指启动后行为完全相同。这要求镜像里不能有随机生成的内容、不能依赖宿主机 DNS 或时区、不能靠容器启动时动态下载远程资源。
- 构建阶段禁用网络:加 --network=none 参数防止 RUN 指令偷偷联网,保证构建可重现
- 固定依赖版本:requirements.txt 显式写死 numpy==1.24.4,而非 numpy>=1.24
- 设置时区和语言:在 Dockerfile 中加入 RUN apk add --no-cache tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime


















