面向RPM升级的Docker镜像构建及生产环境更新方案咨询
嘿,这个场景在Docker生产运维里挺常见的——既要升级应用的RPM包,又得保住现有容器的数据,还得解决“停服务就终止容器”的麻烦。我给你分两种方案,一种是符合Docker immutable理念的最佳实践,另一种是应急情况下的临时操作,你按需选择:
一、优先推荐:重新构建新镜像+迁移数据(正统做法)
Docker的核心设计就是镜像不可变,直接改运行中的容器再生成镜像很容易导致环境混乱、无法追溯,所以最稳妥的方式是重新构建新版本镜像,再把原有数据迁移过去。
1. 调整Dockerfile构建新版本镜像
假设你原来的Dockerfile里安装RPM的部分是这样的:
COPY application-version-1.rpm /tmp/ RUN rpm -ivh /tmp/application-version-1.rpm && rm /tmp/application-version-1.rpm
现在把它改成用新版本RPM的升级命令:
COPY application-version-2.rpm /tmp/ RUN rpm -Uvh /tmp/application-version-2.rpm && rm /tmp/application-version-2.rpm
然后执行构建命令生成新镜像:
docker build -t my-app:version-2 .
2. 备份现有容器的数据(可选但强烈推荐)
先确认你的容器数据存在哪里——是Docker数据卷还是本地绑定挂载的目录:
docker inspect <你的容器名> | grep -E "Mounts|Source"
如果是数据卷,备份一下:
docker run --rm -v <数据卷名>:/data -v $(pwd):/backup busybox tar czf /backup/container-data-backup.tar.gz /data
如果是本地绑定目录,直接复制那个目录到安全位置就行。
3. 切换到新容器
先停掉旧容器:
docker stop <旧容器名>
然后用新镜像启动容器,同时挂载原来的数据卷/目录,这样数据就保留下来了:
# 用数据卷的情况 docker run -d --name my-app-v2 -v <原数据卷名>:/app/data my-app:version-2 # 用本地绑定目录的情况 docker run -d --name my-app-v2 -v /本地数据目录路径:/app/data my-app:version-2
启动后检查一下服务和数据,没问题的话就可以把旧容器删掉了。
二、应急场景:在容器内升级后提交为新镜像(不推荐)
如果暂时没法重新构建镜像(比如临时补丁没来得及更新Dockerfile),可以用这个方法解决“停服务就终止容器”的问题,但记住这只是临时方案,长期还是要回归最佳实践。
1. 启动一个临时容器绕开原Entrypoint
原容器的Entrypoint是应用服务,一停服务容器就没了,所以我们先开一个基于原镜像的临时容器,把Entrypoint换成shell,让它能一直运行:
docker run -d --name temp-container --volumes-from <原容器名> my-app:version-1 /bin/bash
--volumes-from会把原容器的数据卷挂载过来,保证数据能访问到。
2. 在临时容器内升级RPM
先把新RPM包复制到临时容器里:
docker cp application-version-2.rpm temp-container:/tmp/
进入临时容器的shell:
docker exec -it temp-container /bin/bash
现在可以放心停服务了(因为容器的Entrypoint是bash,不会因为服务停止而终止):
# 用系统服务命令或者应用自身的停止命令,比如 systemctl stop my-app-service # 或者 my-app stop
然后执行RPM升级:
rpm -Uvh /tmp/application-version-2.rpm
升级完清理临时文件,再验证服务能正常启动:
rm /tmp/application-version-2.rpm systemctl start my-app-service systemctl status my-app-service
验证没问题后把服务停掉,因为后续提交镜像后,Entrypoint还是原服务,启动时会自动运行:
systemctl stop my-app-service
3. 提交临时容器为新镜像
退出容器后,把临时容器提交成新版本镜像:
docker commit temp-container my-app:version-2
然后删掉临时容器:
docker stop temp-container && docker rm temp-container
4. 用新镜像启动容器
和最佳实践的步骤3一样,用新镜像启动容器并挂载原数据卷/目录即可。
重要提醒
- 别直接改生产容器:直接修改运行中的生产容器会让环境变得不可重现,后续排查问题会非常麻烦,尽量用重新构建镜像的方式。
- 数据一定要存在容器外部:如果你的数据是存在容器内部的(没有用卷或绑定挂载),那不管哪种方案都可能丢数据,赶紧把数据迁移到外部卷里!
- 升级前必备份:哪怕你觉得万无一失,备份数据也是保住生产环境的最后一道防线。
内容的提问来源于stack exchange,提问作者SANITH




