Docker不能持久化Postgres卷[django]

5

这里有很多类似我遇到问题的提问,例如这个这个这个这个。虽然它们非常相似,但没有一个解决我的问题。请不要关闭这个问题。

问题:

我使用docker运行django、nginx和postgres,并将机密信息存储在.env文件中。我的postgres数据无法在docker-compose up/startdocker-compose down/stop/restart时持久化。

这是我的docker-compose文件:

version: '3.7'

services:
  web:
    build: ./app
    command: gunicorn umngane_project.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - ./app/:/usr/src/app/
    expose:
      - 8000
    environment:
      - SECRET_KEY=${SECRET}
      - SQL_ENGINE=django.db.backends.postgresql
      - SQL_DATABASE=postgres
      - SQL_USER=${POSTGRESQLUSER}
      - SQL_PASSWORD=${POSTGRESQLPASSWORD}
      - SQL_HOST=db
      - SQL_PORT=5432
      - SU_NAME=${SU_NAME}
      - SU_EMAIL=${SU_EMAIL}
      - SU_PASSWORD=${SU_PASSWORD}
    depends_on:
      - db
  db:
    image: postgres:11.2-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data/
  nginx:
    build: ./nginx
    volumes:
      - static_volume:/usr/src/app/assets
    ports:
      - 1337:80
    depends_on:
      - web

volumes:
  postgres_data:
    external: true # I tried running without this and the result is the same
  static_volume:

我的入口脚本是这样的:

python manage.py flush --no-input
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser --user "${SU_NAME}" --email "${SU_EMAIL}" --password "${SU_PASSWORD}"
python manage.py collectstatic --no-input

exec "$@"

createsuperuser 是一个自定义模块,用于在应用程序中创建超级用户。

但是这个设置没有将信息持久化到 postgres_data 中。

额外信息:

在执行任何操作之前,我使用 docker volume ls 检查是否存在名为 postgres_data 的卷,确保不存在。

接下来,我运行 docker-compose up -d/docker-compose up -d --build,一切都正常且没有错误发生。

然后我运行 docker inspect postgres_data,它显示 "CreatedAt": "X1"

我可以登录超级用户,并创建管理员用户。登出超级用户后,我用任何一个管理员用户登录都没问题。我运行 docker exec -it postgres_data psql -U <postgres_user> 来确认管理员用户在数据库中,结果正常。

接着,我运行 docker-compose down/docker-compose stop,没有问题。我再次运行 docker volume ls,它显示 postgres_data 仍然存在。

我又运行 docker inspect postgres_data,它显示 "CreatedAt": "X2"

为了测试所有东西是否按预期工作,我运行 docker-compose up -d/docker-compose up -d --build/docker-compose start/docker-compose restart

然后,我运行 docker inspect postgres_data,它显示 "CreatedAt": "X3"

最后,我尝试作为管理员用户登录,但登录失败。我再次运行 docker exec -it postgres_data psql -U <postgres_user>,但这一次只看到超级用户,没有管理员用户。

(说明:我在这里使用正斜杠来显示我在不同尝试中尝试的所有不同命令组合。我尝试了这里显示的每种命令组合。)


1
你的入口点中有 "python manage.py flush --no-input"。每次容器重新创建时,它都会运行并删除所有数据。如果这解决了你的问题,请告诉我,我会为此创建一个答案。 - Trent
请不要只输入“postgres_data”,而是将您的主机路径完整地输入,以“postgres_data”结尾。 - Felipe Toledo
@Trent,那解决了我的问题。 - dot64dot
@FelipeToledo 如果我理解你的意思正确,你是说我应该像 @Bogsan 给出的答案一样创建一个本地路径? - dot64dot
@dot64dot - 我把我的评论加为一个答案。 - Trent
2个回答

11

问题在于你在入口脚本中运行了"flush"命令,它会清除数据库。当你启动或重新创建容器时,入口点将运行该命令。


2

一种持久化数据的方法是指定磁盘上的实际路径而不是创建一个卷:

Original Answer翻译成"最初的回答"

...
  db:
    image: postgres:11.2-alpine
    volumes:
      - "/local/path/to/postgres/data:/var/lib/postgresql/data/"
...

这种方式将容器的Postgres数据位置映射到您指定的路径。这样,除非有意删除,否则数据会直接持久化在磁盘上。

据我所知,Docker卷在容器删除时会被删除。

“Original Answer”翻译成中文是“最初的回答”。


这会带来哪些安全隐患?如果我在服务器上启动我的系统,那么这是否意味着我会有一个额外的故障点? - dot64dot
就我而言,只要您的服务器访问受到保护,使用这种方式或使用卷之间不应该有任何区别。攻击者如果能够访问您的计算机,将能够读取数据库文件夹并获得容器的访问权限。总之,我认为这与您最初使用卷的方法一样安全。 - Bogsan
非常感谢您详细的回复,十分感激。 - dot64dot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接