为什么我无法通过“docker-compose run web”命令运行Django迁移?

18

我正在使用docker-compose部署Django、PostgreSQL和Nginx容器,但遇到了一个问题无法解决。

为了解决Django应用程序中的以下错误,我知道只需运行Django迁移即可。

docker@postgres ERROR:  relation "accounts_myprofile" does not exist

为了运行迁移,我尝试了以下操作:

docker-compose run web python manage.py makemigrations 
docker-compose run web python manage.py migrate

返回了以下内容:

Migrations for 'accounts':
  accounts/migrations/0001_initial.py:
    - Create model Entry
    - Create model MyProfile

Running migrations:
  No migrations to apply.

我只能在Django容器内成功迁移数据,举个例子:

docker exec -i -t 6dc97c6a305c /bin/bash
python manage.py makemigrations
python manage.py migrate

虽然我已经解决了问题,但我仍然不明白为什么通过docker-compose run运行迁移实际上没有迁移任何内容。我希望有人可以指点一下我。

此外,我不知道这是否是相关的问题,但当我运行那些docker-compose run web命令时,它们似乎会创建新的容器,除非我手动停止它们,否则它们不会关闭,docker-compose stop无法删除它们。

CONTAINER ID        IMAGE                     COMMAND                  CREATED             STATUS                          PORTS                    NAMES
a7bb3c7106d1        accounts_web            "python manage.py che"   4 hours ago         Restarting (0) 41 minutes ago   8000/tcp                 accounts_web_run_62
ee19ca6cdf49        accounts_web            "python manage.py mig"   4 hours ago         Restarting (0) 43 minutes ago   8000/tcp                 accounts_web_run_60
2d87ee35de3a        accounts_web            "python manage.py mak"   4 hours ago         Restarting (0) 43 minutes ago   8000/tcp                 accounts_web_run_59
1c6143c13097        accounts_web            "python manage.py mig"   4 hours ago         Restarting (1) 44 minutes ago   8000/tcp                 accounts_web_run_58
6dc97c6a305c        b1cb7debb103              "python manage.py run"   3 days ago          Up 4 hours                      8000/tcp                 accounts_web_1

注意:Docker-compose stop 命令将会妥善地停止底部的容器(按照应有的方式),但是由docker-compose run web python manage.py migrate 创建的其他容器需要手动停止。
我的docker-compose文件:
web:    
  restart: always
  build: ./web
  expose:
    - "8000"
  links:
    - postgres:postgres

  volumes:
    - /usr/src/app
    - /usr/src/app/static

  env_file: .env
  environment:
    DEBUG: 'true'
  command: python manage.py runserver 0.0.0.0:8000


postgres:
  restart: always
  image: kartoza/postgis:9.4-2.1
  ports:
    - "5432:5432"
  volumes:
    - pgdata:/var/lib/postgresql/data/

1
另外,https://dev59.com/mF8e5IYBdhLWcg3wNYUn#25959632 可能会有所帮助。 - VonC
5个回答

46

docker-compose run创建新容器

您已经注意到了问题。使用docker-compose run时,会创建一个新容器。

当您运行第一个命令(makemigrations)时,会创建一个新容器,然后运行makemigrations,并将迁移文件写入(新)容器的文件系统中。

当您运行第二个命令(migrate)时,又创建了另一个新容器。迁移运行了,但它无事可做。这是因为迁移文件不可用 - 它们是在与此新容器不同的容器中编写的。

您可以通过几种方法来解决这个问题。

使用docker-compose exec

首先,您可以像之前一样操作,但使用docker-compose exec而不是run

docker-compose exec web python manage.py makemigrations 
docker-compose exec web python manage.py migrate

exec 命令将使用已经运行的容器,而不是创建新的容器。

使用入口脚本

另一个选择是使用入口脚本,在启动服务器之前运行迁移。如果你希望自动化程度更高,这就是最佳选择。

Dockerfile:

COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh

entrypoint.sh:

#!/bin/sh
python manage.py makemigrations
python manage.py migrate
exec "$@"

docker-compose.yml(在“ web”下):

entrypoint: /entrypoint.sh

在这种情况下,容器启动时将运行entrypoint脚本,处理您的迁移,然后交给command(在此示例中为Django runserver)。

新容器循环运行

正如您所注意到的,新容器保持运行状态。这通常是意外的,因为您用一个应该退出(而不是继续运行)的命令覆盖了原有的命令。但是,在docker-compose.yml中,您指定了restart: always。因此,每次命令退出时,它们都会重复运行迁移命令,重新启动。


2
但我认为自动运行迁移不是一个好主意(例如,有时Django会询问您是否已重命名模型,这可能会破坏自动化)。 - Afshin Mehrabani
1
但是如果您使用entrypoint.sh文件,那么像python manage.py createsuperuser这样的命令将被忽略,您该如何处理呢? - Jesus Almaral - Hackaprende
@JesusAlmaral,您也可以在入口脚本中完成此操作。但在这种情况下,您必须与普通方式不同地执行该命令,因为该命令将期望输入。请参见此答案,该答案可能有助于完成该任务。 - Dan Lowe
你可以通过编写数据迁移来将超级用户的创建作为迁移的一部分,参见这里 @JesusAlmaral - Hendrik F
2019年有任何变化吗?我想做同样的事情,不知道答案是否会改变。 - Brian

3

丹·洛给出了一个非常好的答案,但入口脚本对我不起作用。问题在于一些“makemigrations”需要您的输入,例如“是” / “否”。

您可以结合丹·洛的回答,使用以下方法:

python manage.py makemigrations --noinput

代替
python manage.py makemigrations

(至少对于简单的“是/否”问题)这有效。

2

这篇回答是对Dan Lowe和Rexcirus回答的补充。

为了在CodeBuild和Fargate中正常工作,我做了一些更改:

Dockerfile:

COPY ./docker/entrypoint.sh /usr/local/bin/
COPY ./docker/entrypoint.sh /${projectName}/
# backwards compat
RUN ln -s usr/local/bin/entrypoint.sh /

ENTRYPOINT ["entrypoint.sh"]
CMD ["entrypoint.sh"]

./docker/entrypoint.sh

#!/bin/sh
python manage.py makemigrations --noinput
python manage.py migrate
python manage.py runserver 0.0.0.0:8000

现在一切都运行正常。


0
python manage.py makemigrations

python manage.py migrate

#Crear usuario root

DJANGO_SUPERUSER_PASSWORD=*your-passwd* python manage.py createsuperuser --username *root* --email *youremail@gamil.com* --noinput

0

我已经通过更改docker-compose.yml和DockerFile中“myProject”路径的目录来解决了这个问题。

在Docket文件中

拉取基础镜像

FROM python:3.7

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Set work directory
WORKDIR /myProject

# Install dependencies
COPY Pipfile Pipfile.lock /myProject/
RUN pip install pipenv && pipenv install --system

复制项目

COPY . /myProject/

在docker-compose.yml文件中

version: '3.7'

services:
  web:
    build: .
    command: python /myProject/manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/myProject
    ports:
      - 8000:8000

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