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

Posted

技术标签:

【中文标题】使用 Docker-Compose 时如何执行 Django 数据库迁移?【英文标题】:How do you perform Django database migrations when using Docker-Compose? 【发布时间】:2016-03-03 18:00:30 【问题描述】:

我已经在Django Quick Start instructions on the Docker site 之后设置了一个 Docker Django/PostgreSQL 应用程序。

我第一次运行 Django 的 manage.py migrate 时,使用命令 sudo docker-compose run web python manage.py migrate,它按预期工作。数据库构建在 Docker PostgreSQL 容器内就好了。

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

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

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

我仍在尝试了解 Docker,但我对它的工作原理有很多不明白的地方,但是这个让我发疯了。为什么迁移看不到我的更改?我做错了什么?

【问题讨论】:

你知道原因了吗?我得到下面的答案并且它有效:You just have to log into your running docker container and run your commands. 但它的行为方式是什么原因? @LouisBarranqueiro 【参考方案1】:

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

    建立你的堆栈:docker-compose build -f path/to/docker-compose.yml 启动你的堆栈:docker-compose up -f path/to/docker-compose.yml 显示 docker 运行容器: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 ...
    获取您的 django 应用的 CONTAINER ID 并登录:
docker exec -t -i 66175bfd6ae6 bash

    现在您已登录,然后转到正确的文件夹:cd path/to/django_app

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

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

集体静态 迁移 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

【讨论】:

我还建议您使用 docker-entrypoint 让您的 django docker 容器文件自动运行 - 此类操作永远不应该自动运行 - 我的意思是 migrate 特别是。 这是为什么呢?我们在开发环境中。 无论您是在哪个环境中,部署都应该始终保持一致。如果迁移是自动化的,则可能会同时运行,这是非常不鼓励的。例如。在 heroku 上 - 迁移永远不会作为部署的一部分运行。 同意吗?在这里,我们处于开发环境中。我运行makemigrations。下次我启动我的堆栈时,migrate 将使用上次撤消的迁移更新数据库,否则 django 应用程序将无法正常工作......它只是 dev env 中的一个快捷方式,以确保您获得正确的数据库架构当前应用 @LouisBarranqueiro,我的意思是多个实例,单个数据库。【参考方案2】:

我使用这些方法:

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 server 应用在​​与 web server 相同的图像上,这意味着所有迁移都将从您的项目中获取,避免出现问题。

您可以通过这种方式避免创建入口点或其他任何事情。

【讨论】:

build: . 如何与image: 一起工作我收到迁移无法提取命名图像的错误 我通过将build: 放在migration 上解决了这个问题,因为它会在web 之前运行 这不会让 uzman 映像永远运行并消耗 RAM 吗?另外,什么是 uzman 图像? 这是我的自定义 docker 镜像。我还没有测试 RAM。【参考方案3】:

让您的堆栈运行,然后启动一次性 docker-compose run 命令。例如

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

这适用于内置(默认)SQLite 数据库,但也适用于列为依赖项的外部 dockerized 数据库。这是一个示例 docker-compose.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/

【讨论】:

【参考方案4】:

你可以使用docker exec命令

docker exec -it container_id python manage.py migrate

【讨论】:

要获取提到的 container_id,请执行docker ps,然后查找 django 服务器的 COMMAND 列。【参考方案5】:

我知道这是旧的,也许我在这里遗漏了一些东西(如果有,请赐教!),但为什么不直接将命令添加到您的 start.sh 脚本中,由 Docker 运行以启动您的实例?只需要几秒钟的额外时间。

NB我设置了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

【讨论】:

【参考方案6】:

使用 docker exec,我收到以下错误:

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

所以我改用了这个命令:

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

【讨论】:

【参考方案7】:

如果您的 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

【讨论】:

【参考方案8】:

您可以使用docker-entrypoint.sh 或者更新的解决方案是在您的docker-compose.yml 中使用多个 cmets

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

【讨论】:

【参考方案9】:

如果你只想使用 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"]

【讨论】:

这如何解决问题? 在 AWS 上,我没有找到在 ECS 任务中运行 docker-compose.yml 的方法...所以我选择仅使用 Dockerfile 并从中运行迁移(/app/docker-entrypoint.yml)。 sh 包含这些命令)

以上是关于使用 Docker-Compose 时如何执行 Django 数据库迁移?的主要内容,如果未能解决你的问题,请参考以下文章

尝试使用带有自定义 conf.d 的 docker-compose 运行 nginx 时出错

docker-compose 打开存储失败:运行时权限被拒绝错误

docker-compose安装

docker-compose up与docker-compose up -d

如何调试应用程序并使用 nodemon 测试手表

使用 docker 时如何避免“端口冲突”?