使用 DockerFile 的方式修改原始镜像的最佳实现

  其他常见问题
内容纲要

概要描述

在容器镜像中新增或替换 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 文件,应使用 COPYADD 还具有远程资源和本地 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 : .

这篇文章对您有帮助吗?

平均评分 0 / 5. 次数: 0

尚无评价,您可以第一个评哦!

非常抱歉,这篇文章对您没有帮助.

烦请您告诉我们您的建议与意见,以便我们改进,谢谢您。