Docker容器Postgres数据丢失:提交镜像后为何数据库为空?
Postgres容器提交镜像后数据丢失的原因及解决办法
问题描述
我用以下docker-compose配置创建了Postgres容器:
services: db: image: postgres restart: always # set shared memory limit when using docker-compose shm_size: 128mb # or set shared memory limit when deploy via swarm stack #volumes: # - type: tmpfs # target: /dev/shm # tmpfs: # size: 134217728 # 128*2^20 bytes = 128Mb ports: - "5433:5432" environment: POSTGRES_PASSWORD: example
连接容器修改数据库内容后,执行docker commit f3a8955f3df6提交容器,再用docker tag f3a8955f3df6 myimage打标签。但运行该镜像后,数据库却是清空状态,这是为什么?(采用手动操作方式)
原因分析
核心问题在于Postgres官方镜像的Dockerfile中,已经将数据库数据目录(默认是/var/lib/postgresql/data)声明为了VOLUME。Docker卷有两个关键特性:
- 卷的数据独立于容器的可写层,容器运行时卷内的数据不会写入到容器自身的可写层中
docker commit命令只会提交容器的可写层内容,卷里的所有数据都不会被包含到新生成的镜像里
你修改的数据库数据实际存在于这个独立卷中,commit后的镜像不包含这些数据,运行新容器时会重新初始化一个空卷,自然看不到之前的修改内容。
解决办法
推荐的持久化方式
不要用docker commit保存数据库数据,应该通过数据卷或绑定挂载来持久化:
- 在docker-compose中添加卷配置,把数据目录挂载到命名卷:
services: db: # 其他配置保持不变 volumes: - postgres_data:/var/lib/postgresql/data volumes: postgres_data: - 后续启动新容器时,只要复用这个
postgres_data卷,就能直接读取之前的数据
生成包含数据的镜像(不推荐)
如果一定要生成带数据的镜像,需要修改官方镜像的Dockerfile:
- 复制官方Postgres的Dockerfile,删除其中的
VOLUME /var/lib/postgresql/data声明 - 用修改后的Dockerfile重新构建自定义镜像
- 运行该自定义镜像的容器,修改数据后再执行
docker commit,此时数据会被包含进新镜像
这种方式不推荐,因为数据和镜像耦合后会导致镜像体积过大,备份、迁移数据也会变得繁琐,不符合Docker的最佳实践。
内容的提问来源于stack exchange,提问作者Андрей Дов
相关产品推荐
相关产品推荐

