【问题标题】:How to execute docker-entrypoint-initdb.d/init.sql files AFTER database is created?创建数据库后如何执行 docker-entrypoint-initdb.d/init.sql 文件?
【发布时间】:2021-01-16 06:23:39
【问题描述】:

我有一个带有 Docker 的 Django 应用程序

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

2 个容器已正确构建,init.sql 文件在 db_container 中可用

docker logs db_container 显示错误,表明数据库尚未迁移:

错误:关系表 1 不存在

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

不明白init.db什么时候执行?

Dockerfile

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" ]

entrypoint.sh

#!/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 "$@"

docker-compose.yml

version: '3.7'

services:
    web:
        ...
        depends_on: 
            - db
    db:
        image: postgres:12.0-alpine
        restart: always
        volumes:
            - postgres_data:/var/lib/postgres/data/
            - ./imports/init.sql:/docker-entrypoint-initdb.d/init.sql
        environment:
            - POSTGRES_USER=user
            - POSTGRES_PASSWORD=user
            - POSTGRES_DB=db_dev
volumes:
    postgres_data:

init.sql

\c db_dev

INSERT INTO table1 (field1,field2,field3) VALUES ('value1','value2','value3');
...

【问题讨论】:

    标签: django docker docker-compose


    【解决方案1】:

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

    换句话说,你想要的都是不可能的。

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

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

    【讨论】:

      【解决方案2】:

      事情通常会按以下顺序运行:

      1. webbuild: 块和 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 "$@" 运行主容器命令。

      换一种说法:在 PostgreSQL 容器完全完成其首次启动(包括运行docker-entrypoint-initdb.d 脚本)之后,Django 迁移命令才会运行。这意味着在迁移中创建的表永远不会存在。

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

      【讨论】:

        【解决方案3】:

        感谢两位。

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

        我禁止使用 docker-entrypoint-initdb.d 脚本 执行入口点时初始化我的数据库(manage.py migrate 应用所有迁移)

        【讨论】:

          猜你喜欢
          • 2020-06-12
          • 1970-01-01
          • 2018-06-12
          • 1970-01-01
          • 1970-01-01
          • 2023-03-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多