docker commit提交容器后改动未持久化,新postgres实例无已创建数据库对象
问题根因
- 官方PostgreSQL Docker镜像默认将数据库数据存储目录
/var/lib/postgresql/data声明为了卷(Volume),而docker commit命令只会提交容器文件系统中不属于卷挂载点的内容,你之前创建的表、数据库对象都存储在这个卷目录里,自然不会被打包到提交的user/mypostgres镜像中。 - 你第二次启动新容器时指定了新的
POSTGRES_DB=correntista,即使数据被保留,默认连接的数据库也从原来的db_uso变成了新的correntista,也会出现找不到原有对象的情况。
解决方案
方案一:使用数据卷持久化数据(生产环境推荐)
这是PostgreSQL容器的标准使用方式,不要依赖docker commit保存数据库数据,操作步骤如下:
- 先停止原有
mypostgres容器,导出已有数据备份:docker exec mypostgres pg_dump -U postgres db_uso > backup.sql - 启动新容器时挂载本地目录或者命名卷作为数据存储目录,导入备份数据即可:
# 创建命名卷专门存储postgres数据 docker volume create pgdata # 启动新容器,挂载数据卷 docker run --name mypostgres2 \ --publish 5432:5432 \ --net=apinetwork \ -e POSTGRES_PASSWORD=mysecretpassword \ -e POSTGRES_DB=correntista \ -v pgdata:/var/lib/postgresql/data \ -d postgres # 导入之前的备份数据到新库 cat backup.sql | docker exec -i mypostgres2 psql -U postgres correntista
后续只要不删除pgdata卷,数据就不会丢失,不需要每次修改都提交镜像。
方案二:强制将数据打包到镜像中(仅适用于测试、预打包初始化数据场景)
如果你确实需要把初始化好的数据库对象直接打包到镜像里,不需要每次启动再导入,可以修改镜像的VOLUME配置,操作步骤如下:
- 从原有
mypostgres容器里把数据目录拷贝到本地:docker cp mypostgres:/var/lib/postgresql/data ./pg_data - 新建Dockerfile自定义postgres镜像,取消默认VOLUME配置,把拷贝出来的数据打包进去:
FROM postgres # 取消官方镜像默认的VOLUME声明 VOLUME [] # 拷贝本地预初始化的数据库数据到镜像内 COPY ./pg_data /var/lib/postgresql/data # 调整目录权限适配postgres用户运行要求 RUN chown -R postgres:postgres /var/lib/postgresql/data - 构建自定义镜像:
docker build -t user/mypostgres:withdata . - 用新镜像启动容器即可,不需要再传
POSTGRES_PASSWORD、POSTGRES_DB环境变量,这些配置已经和你预打包的数据保持一致:docker run --name mypostgres2 \ --publish 5432:5432 \ --net=apinetwork \ -d user/mypostgres:withdata
注意事项
docker commit本身不是为持久化数据库这类有状态应用数据设计的,生产环境不要用这种方式管理数据库数据。- 第二种打包数据到镜像的方案仅适合分发预初始化的测试环境镜像,镜像体积会随数据量增大,更新数据需要重新构建镜像。
内容的提问来源于stack exchange,提问作者pomer
相关产品推荐
相关产品推荐

