使用 Docker-Compose 时如何执行 Django 数据库迁移?

我已经紧跟 Django Docker 站点上的快速启动说明设置了一个 Docker Django/PostgreSQL 应用程序。

我第一次使用 sudo docker-compose run web python manage.py migrate命令运行 Django 的 manage.py 迁移时,它的工作方式与预期的一样。数据库构建在 Docker PostgreSQL 容器中。

对 Django 应用程序本身所做的更改同样反映在 Docker Django 容器中,当我保存它们的时候。太棒了!

但是如果我在 Django 中更改模型,并尝试更新 Postgres 数据库以匹配模型,则不会检测到任何更改,因此无论我再次运行 makemigrationsmigrate多少次,都不会发生迁移。

基本上,每次更改 Django 模型时,都必须删除 Docker 容器(使用 sudo docker-compose rm)并重新开始新的迁移。

我还在努力理清多克的思路我还有很多事不明白它是怎么运作的但这事快把我逼疯了。迁移为什么没有看到我的变化?我做错了什么?

130520 次浏览

您只需登录到正在运行的 docker 容器并运行命令即可。

  1. 建立你的堆栈: docker-compose build -f path/to/docker-compose.yml
  2. 启动你的堆栈: docker-compose up -f path/to/docker-compose.yml
  3. 显示正在运行的码头容器: docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                         NAMES
3fcc49196a84        ex_nginx          "nginx -g 'daemon off"   3 days ago          Up 32 seconds       0.0.0.0:80->80/tcp, 443/tcp   ex_nginx_1
66175bfd6ae6        ex_webapp         "/docker-entrypoint.s"   3 days ago          Up 32 seconds       0.0.0.0:32768->8000/tcp       ex_webapp_1
# postgres docker container ...
  1. 获取您的 django 应用程序的 集装箱编号并登录:
docker exec -t -i 66175bfd6ae6 bash
  1. 现在您已经登录,然后转到正确的文件夹: cd path/to/django_app

  2. 现在,每次编辑模型时,在容器中运行: python manage.py makemigrationspython manage.py migrate

我还建议您对 django docker 容器文件使用 docker-entrypoint 来自动运行:

  • 喜欢收藏
  • 迁徙
  • Runserver 或用 gunicorn 或 uWSGI 启动它

下面是一个例子(docker-entrypoint.sh) :

#!/bin/bash


# Collect static files
echo "Collect static files"
python manage.py collectstatic --noinput


# Apply database migrations
echo "Apply database migrations"
python manage.py migrate


# Start server
echo "Starting server"
python manage.py runserver 0.0.0.0:8000

我使用这种方法:

services:
web:
build: .
image: uzman
command: python manage.py runserver 0.0.0.0:8000
ports:
- "3000:3000"
- "8000:8000"
volumes:
- .:/code
depends_on:
- migration
- db
migration:
image: uzman
command: python manage.py migrate --noinput
volumes:
- .:/code
depends_on:
- db

使用我们创建的 docker层次结构,服务迁移在设置数据库之后和运行主服务之前运行。现在当你运行你的服务 docker会在运行服务器之前运行迁移; 看看 migration服务器是应用在相同的映像作为网络服务器,这意味着所有的迁移将从你的项目,避免问题。

这样可以避免进入点或者其他什么地方。

让你的堆栈运行,然后发射一个一次性码头组合运行命令

#assume django in container named web
docker-compose run web python3 manage.py migrate

这对于内置(默认) SQLite 数据库非常有用,对于列为依赖项的外部停靠的数据库也是如此。下面是一个码头组合的例子。Yaml 档案

version: '3'


services:
db:
image: postgres
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
ports:
- "8000:8000"
depends_on:
- db

Https://docs.docker.com/compose/reference/run/

可以使用 docker exec命令

docker exec -it container_id python manage.py migrate

我知道这是旧的,也许我错过了一些东西在这里(如果是这样,请启发我!),但为什么不只是添加命令到您的 start.sh脚本,由 Docker 运行,以启动您的实例?只需要几秒钟。

注意: 我设置了 DJANGO_SETTINGS_MODULE变量以确保使用了正确的数据库,因为我使用不同的数据库进行开发和生产(尽管我知道这不是“最佳实践”)。

这解决了我的问题:

#!/bin/bash
# Migrate the database first
echo "Migrating the database before starting the server"
export DJANGO_SETTINGS_MODULE="edatool.settings.production"
python manage.py makemigrations
python manage.py migrate
# Start Gunicorn processes
echo "Starting Gunicorn."
exec gunicorn edatool.wsgi:application \
--bind 0.0.0.0:8000 \
--workers 3

通过使用 docker exec,我得到了以下错误:

AppRegistryNotReady("Models aren't loaded yet.")

因此,我使用了以下命令:

docker-compose -f local.yml run django python manage.py makemigrations

如果你的 docker-compose.yml里有这样的东西

version: "3.7"


services:


app:
build:
context: .
dockerfile: docker/app/Dockerfile
ports:
- 8000:8000
volumes:
- ./:/usr/src/app
depends_on:
- db


db:
image: postgres
restart: always
environment:
POSTGRES_USER: docker
POSTGRES_PASSWORD: docker
POSTGRES_DB: docker

然后你可以简单地跑..。

~$ docker-compose exec app python manage.py makemigrations
~$ docker-compose exec app python manage.py migrate

您可以使用 docker-entrypoint.sh或更新的解决方案将在您的 docker-compose.yml多个注释

version: '3.7'


services:
web:
build: ./
command: >
sh -c "python manage.py collectstatic --noinput &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"
volumes:
- ./:/usr/src/app/
ports:
- 8000:8000
env_file:
- ./.env
depends_on:
- postgres


postgres:
image: postgres:13.0-alpine
ports:
- 5432:5432
volumes:
- ./data/db:/var/lib/postgresql/data
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres

如果只想使用 Dockerfile,可以添加 ENTRYPOINT []命令。 示例如何运行. sh 脚本:

FROM python:3.9.4
RUN apt-get update
RUN apt-get install libpq-dev --assume-yes
RUN pip3 install psycopg2


COPY . /app
WORKDIR /app


RUN pip install -r requirements.txt
RUN pip3 install debugpy


ENTRYPOINT ["/app/docker-entrypoint.sh"]


CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]