在Docker中运行Django迁移

5
我正在使用docker构建Python+Django开发环境。我在docker-compose.yml中定义了Dockerfile文件和服务,用于Web服务器(nginx)和数据库(postgres)容器,以及一个将使用uwsgi运行我们的应用程序的容器。由于这是一个开发环境,我从主机系统挂载应用程序代码,这样我就可以轻松地在我的IDE中进行编辑。
我的问题是在哪里/如何运行迁移命令。
如果您不知道Django,迁移命令会创建数据库结构,并根据项目需要随后更改它。我已经看到有人将迁移作为compose指令command: python manage.py migrate && uwsgi --ini app.ini的一部分运行,但我不希望迁移在每次容器重新启动时运行。我只想让它在创建容器时运行一次,除非我重建。
那么我应该在哪里/如何做呢?
编辑:现在有一个开放性的问题与组合团队。带着任何的运气,一次性命令容器将得到组成支持。 https://github.com/docker/compose/issues/1896

为什么不在 Dockerfile 中使用 RUN 指令,在构建镜像时运行它呢? - Yaron Idan
有两个原因。迁移命令在一个容器中运行(应用服务器),但影响另一个容器(Posgres数据库),而Compose构建是顺序的。第二个原因是,在构建过程中不会挂载共享卷。 - Mad Wombat
4个回答

0

你不能使用 RUN,因为正如你在评论中提到的那样,你的源代码在容器运行期间被挂载。

你也不能使用 CMD,因为你不想每次重新启动容器时都运行它。

我建议在运行容器后手动使用 docker exec。我认为由于我上面提到的两个原因,无法在 dockerfiledocker-compose 中自动化此过程。


我发现一个建议是使用一个依赖于数据库的一次性容器,启动后挂载包含代码的共享卷,运行命令并退出。这听起来像一个好计划,但我不确定如何防止这个容器在下一次 docker-compose up 时再次启动。也许你是对的,手动操作可能是解决方法。如果我没有得到其他建议,我会接受你的答案。 - Mad Wombat
一种独立于Docker的方法是编写一个脚本,每次容器运行时都会运行该脚本。在脚本内部,在运行migrate命令后创建一个空文件,该文件指示挂载位置中标志的状态。下次容器启动时,脚本将检查文件是否存在,如果存在则跳过运行migrate命令,否则创建该文件并运行您的migrate命令。 - Griffin
这或许是个好主意。我在考虑写一个shell脚本来检查数据库中的表,但那似乎很复杂。如果我要写复杂的脚本的话,不如直接编写容器创建脚本,并完全跳过compose。检查文件会更容易一些,并且可能可以直接在compose配置的命令指令中完成。 - Mad Wombat

0

听起来你需要的是一个管理项目任务的工具。dobi 是一个专门处理这些任务的工具(免责声明:我是这个工具的作者)。

你可以在这里看到如何运行迁移的示例:https://github.com/dnephin/dobi/tree/master/examples/init-db-with-rails。这个示例使用了 Rails,但基本上和 Django 的思路是一样的。

你可以设置一个名为 migrate 的任务,它会在容器中运行命令并将数据写入卷中。然后当你启动 docker-compose 容器时,使用该卷作为数据库服务的源。


有趣的工具。我会研究一下它。虽然我不做CI,但我可能会使用shell别名来执行一些docker exec命令。 - Mad Wombat

0

https://github.com/docker/compose/issues/1896现在终于通过docker-compose 1.28.0引入的新服务配置文件得到解决。使用profiles,您可以将服务标记为仅在特定配置文件中启动:

services:
  nginx:
    # ...

  postgres:
    # ...

  uwsgi:
    # ...

  migrations:
    profiles: ["cli-only"] # profile name chosen freely
    # ...

docker-compose up # start only your app services, no migrations
docker-compose run migrations # run migrations on-demand

-2

docker exec -it container-name bash

然后你就会进入容器内部,可以像平常开发时一样运行任何命令,而不需要使用 Docker。


我需要在应用程序容器启动之前运行它。此外,我希望有一个单一的命令解决方案。 - Mad Wombat

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