You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

面向RPM升级的Docker镜像构建及生产环境更新方案咨询

保留容器数据的前提下更新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

火山引擎 最新活动