创建数据库后如何执行docker-entrypoint-initdb.d / init.sql文件?

时间:2020-09-30 14:39:56

标签: django docker docker-compose

我有一个带有Docker的Django应用

我想在运行docker-compose up时基于init.sql文件初始化数据库

正确构建了2个容器,并且db_container中提供了init.sql文件

但是'a'显示一个错误,指示数据库尚未迁移:

错误:关系table1不存在

执行entrypoint.sh文件时创建数据库(命令python manage.py migration)

我不明白何时执行init.db?

Dockerfile

POINTS

entrypoint.sh

docker logs db_container

docker-compose.yml

FROM python:3.8.3-alpine

WORKDIR /usr/src/app

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

RUN apk update && apk add postgresql-dev gcc python3-dev musl-dev
RUN apk --update add libxml2-dev libxslt-dev libffi-dev gcc musl-dev libgcc openssl-dev curl
RUN apk add jpeg-dev zlib-dev freetype-dev lcms2-dev openjpeg-dev tiff-dev tk-dev tcl-dev
RUN pip3 install psycopg2 psycopg2-binary

COPY requirements/ requirements/
RUN pip install --upgrade pip && pip install -r requirements/dev.txt

COPY ./entrypoint.sh .
COPY . .

# Run entrypoint.sh
ENTRYPOINT [ "/usr/src/app/entrypoint.sh" ]

init.sql

#!/bin/sh

if [ "$DATABASE" = "postgres" ]
then
    echo "Waiting for postgres..."
    # nc = netcap -z = scanning
    while ! nc -z $SQL_HOST $SQL_PORT; do
      sleep 0.1
    done

    echo "PostgreSQL started"
fi

python manage.py flush --no-input
python manage.py migrate

exec "$@"

3 个答案:

答案 0 :(得分:0)

/docker-entrypoint-initdb.d/init.sql在数据库容器开始运行时执行,而entrypoint.sh在Web容器开始运行时执行。由于您的Web容器取决于数据库容器,因此SQL脚本将始终在入口点之前执行。

换句话说,想要什么是不可能的。

您需要在init.sql中创建数据库和table1,并告诉Django不要尝试创建它们(如果它们已经存在),或者以某种方式将您的INSERT..添加到要运行的迁移列表中。

我从没使用过Django,所以我不知道以上两种方法是否可行。

答案 1 :(得分:0)

事物通常按以下顺序运行:

  1. 您执行的web build:块和Dockerfile执行。这将永远无法访问数据库。
  2. db容器已创建。
  3. web容器已创建。
  4. 应用程序映像的入口点脚本到达nc -z循环,并在此处有效地暂停。
  5. postgres映像的入口点脚本将启动一个临时PostgreSQL实例。
  6. postgres图像的入口点脚本创建db_dev环境变量中命名的POSTGRES_DB数据库。
  7. postgres图像的入口点脚本运行/docker-entrypoint-initdb.d中的所有文件(包括您显示的init.sql脚本)。
  8. postgres映像的入口点脚本将停止临时PostgreSQL实例,并启动真正的可通过网络访问的实例。
  9. 应用程序映像的入口点脚本成功连接到PostgreSQL,并经过nc循环。
  10. 应用程序映像的入口点脚本运行python manage.py migrate
  11. 应用程序映像的入口点脚本exec "$@"用于运行主容器命令。

采用另一种方式:Django迁移命令要等到PostgreSQL容器完全完成其首次启动(包括运行docker-entrypoint-initdb.d脚本)后才能运行。这意味着在迁移中创建的表将永远不存在。

需要在初始化时加载到数据库中的数据(例如,运行测试或为知名的“ admin”用户运行)通常称为“种子数据”。 How to seed Django project ? - insert a bunch of data into the project for initialization包含添加自定义manage.py命令或fixtures文件以加载种子数据的示例。在显示的入口点脚本中,您将在运行迁移之后但在最后启动主服务器之前添加python manage.py seedload data命令。

答案 2 :(得分:0)

感谢双方。

我使用数据迁移https://docs.djangoproject.com/en/3.1/howto/writing-migrations/

我取消了docker-entrypoint-initdb.d脚本 执行入口点时,我的数据库已初始化(manage.py migration应用所有迁移)