概要描述
在容器镜像中新增或替换 JAR 包、shell 脚本时,建议始终通过 Dockerfile 生成新镜像,不要直接修改运行中的容器,也不要使用 docker commit 保存临时修改。
本文说明如何使用 Dockerfile 规范地向现有镜像添加或替换 JAR 包,并提供 Yarn 镜像换包示例及常见最佳实践。
详细说明
一、适用范围
本文适用于以下场景:
- 在现有 Docker 镜像中新增 JAR/SHELL 包;
- 使用同名 JAR/SHELL 覆盖镜像中的旧文件;
- 使用新版本 JAR/SHELL 替换旧版本文件;
二、核心原则
1. 如果要上生产环境,需要覆盖原镜像标签
每次换包都应创建一个新的、含义明确的标签,例如:
--
示例:
gts-131081:5000/transwarp/yarn:transwarp-9.3.3-final-inceptor-torc-3.1.1-0f838153
后续测试通过之后,可以将镜像标签修改到原有 final 的生产标签。
示例:
gts-131081:5000/transwarp/yarn:transwarp-9.3.3-final
三、构建前检查
1. 确认基础镜像
查看基础镜像的 ID、标签和仓库信息:
docker images |grep :
2. 确认文件权限
普通 JAR 文件通常只需要 0644 权限,即所有者可读写,其他用户只读。
如果是 shell 脚本,则需要有可执行权限。
chmod 0644
chmod 755
如果应用有明确的属主或属组要求,应使用该账号对应的 UID 和 GID,并在构建后再次验证。
四、准备构建目录
为每次换包创建独立目录,并将 Dockerfile 与补丁文件纳入版本管理或变更记录:
image-patch/
├── Dockerfile
└── patches/
└──
└──
五、编写 Dockerfile
1. 推荐模板
支持较新 Dockerfile 前端的构建环境,可以直接在 COPY 时指定属主和权限:
FROM @
LABEL io.transwarp.yarn.image.description="Add " \
io.transwarp.yarn.patch.artifact=""
COPY patches/ /
2. 使用 COPY,不要滥用 ADD
对于构建上下文中的本地 JAR 文件,应使用 COPY。ADD 还具有远程资源和本地 tar 自动解包等额外行为,不适合仅复制普通 JAR 的场景。
3. 同名替换无需先删除
如果新旧 JAR 的目标路径和文件名完全相同,COPY 会在新镜像层中覆盖该路径,不需要额外执行:
RUN rm -f /
需要注意,覆盖或删除只会改变新镜像的可见文件系统,不会从基础镜像历史层中移除原文件字节。因此,增加一条 RUN rm 不能减小基础层大小。
4. 不同文件名替换时必须处理旧版本
如果新旧 JAR 文件名不同,并且二者同时存在会导致类冲突,应显式删除旧版本,再复制新文件:
FROM @
RUN rm -f /
COPY patches/ /
此时应优先保证运行时只有正确版本,不要为了少一个 layer 而保留冲突 JAR。删除动作、旧文件名和回滚基线都必须记录清楚。
5. 使用 LABEL 记录变更
使用 LABEL 记录基础镜像、补丁名称、校验值、变更单号和构建时间。不要使用已经弃用的 MAINTAINER 指令,也不要在 Dockerfile 中写入个人邮箱、内部群聊或其他不适合对外公开的信息。
历史变更应由版本控制和镜像元数据保存,不建议长期在 Dockerfile 中累积被注释掉的旧命令。回滚时应使用历史镜像 digest,而不是手工取消注释旧步骤后重新构建。
六、构建新镜像
在构建目录中执行,注意这里最后有一个 . 是代表基于当前目录构建:
docker build -t : .
正常情况下,构建日志应显示:
FROM使用预期的基础镜像 digest;- 构建上下文仅包含 Dockerfile 和本次补丁;
COPY成功写入目标路径;- 最终生成并标记新的镜像 ID。
不要在没有原因的情况下每次都使用 --no-cache。固定基础镜像 digest 和补丁 SHA-256 后,正常构建缓存可以安全地复用未变化的层。只有在排查缓存问题或必须重新执行全部步骤时才禁用缓存。
七、验证新镜像
1. 检查镜像历史
docker image history :
对于只新增一个 JAR 的换包,新增加的文件层通常应只有一个。LABEL 等元数据层不增加文件内容大小。
2. 执行功能验证(可选)
启动镜像对应的容器后,确认文件存在只能证明 JAR 已正确进入镜像,不能证明补丁功能有效。推送或部署前还需要在测试环境验证:
八、推送镜像
推送前确认 <NEW_TAG> 在仓库中尚不存在,并确认组织允许向该仓库上传补丁内容。不要通过覆盖现有标签来“替换旧版本”。
如果构建时使用的是本地仓库名,可以先创建目标仓库标签:
docker tag : /:
经确认后推送:
docker push /:
推送成功后记录仓库返回的 digest。部署清单优先引用该 digest:
/@
推送成功不代表已经部署。更新 Kubernetes Deployment、StatefulSet 或其他工作负载前,应另行确认变更窗口、灰度范围和回滚方案。
九、回滚方法
1. 尚未部署
如果新镜像尚未部署,停止后续推送或发布即可。原镜像不需要修改。
2. 已经部署
将工作负载的镜像引用恢复为变更前记录的旧 digest,并按原部署流程发布。回滚后需要检查:
- Pod 或容器全部恢复为旧镜像 digest;
- 服务健康检查通过;
- 原有作业和核心功能正常;
- 没有新镜像与旧镜像混跑造成的兼容问题。
不要删除旧镜像或重用旧标签,直到补丁观察期结束并满足组织的镜像保留策略。
十、Yarn 镜像换包示例
以下示例将 inceptor-torc-3.1.1.jar 加入 Yarn 运行时 classpath。执行前必须根据目标版本确认真实路径;某些环境的 Yarn 类库目录为 /usr/lib/hadoop/share/yarn/lib/,不能直接套用到所有版本。
构建目录:
yarn-image-patch/
├── Dockerfile
└── patches/
└── inceptor-torc-3.1.1.jar
Dockerfile:
FROM @
LABEL io.transwarp.yarn.patch.artifact="inceptor-torc-3.1.1.jar"
COPY patches/inceptor-torc-3.1.1.jar /usr/lib/hadoop/share/yarn/lib/inceptor-torc-3.1.1.jar
构建并验证:
docker build -t : .