Проблемы с postgres при сборке контейнера docker

Я пытаюсь запустить DJANGO + POSTGRES в одном контейнере с помощью DOCKERFILE. У меня есть следующий dockerfile, который в основном устанавливает все зависимости python и postgresql. Затем он запускает скрипт для создания базы данных и пользователя (представлен ниже).

FROM python

WORKDIR /app

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

RUN apt update && apt -y install postgresql postgresql-contrib 

RUN service postgresql start && su -c "bash config.db.bash" postgres

WORKDIR /app/psql

RUN python manage.py makemigrations && python manage.py migrate #Error

EXPOSE 8000

CMD service postgresql start && python manage.py runserver 0.0.0.0:8000

Здесь находится скрипт "config.db.bash"

#!/bin/bash

psql <<-INPUT
    CREATE USER docker;
    ALTER USER docker WITH PASSWORD 'password';
    CREATE DATABASE docker;
    GRANT ALL PRIVILEGES ON DATABASE docker TO docker
INPUT

requirements.txt

asgiref==3.7.2
Django==5.0.2
sqlparse==0.4.4
tzdata==2024.1
psycopg2

Здесь находится файл DJANGO`s settings.py -> Конфиг базы данных (установлен модуль psycopg_2)

DATABASES = {
    "default": {
        "ENGINE": "django.db.backends.postgresql",
        "NAME": "docker",
        "USER": "docker",
        "PASSWORD": "password",
        "HOST": "localhost",
        "PORT": 5432,
    }
}

Все работает нормально до этой строки

RUN python manage.py makemigrations && python manage.py migrate

Затем docker сообщает, что во время этой операции произошла ошибка. В журнале в основном говорится, что DJANGO не может подключиться к postgress DB.

Прежде чем обратиться за помощью, я попробовал несколько способов решить эту проблему самостоятельно.

  1. Я попытался запустить/перезапустить psql-сервер или запустить его снова с помощью команд

    RUN service postgresql start
    
    RUN service postgresql restart 
    

    Сервер попытался запуститься/перезапуститься и после долгого ожидания выдал ошибку таймаута.

  2. Я попытался изменить DJANGO settings.py -> Конфиг базы данных. Изменил "localhost" на "0.0.0.0" и на "127.0.0.1". Затем я попытался указать PORT в виде строки. -> Не помогло.

  3. Я попытался запустить

    RUN service postgresql status

    Он сказал, что после этой команды в dockerfile...

    RUN service postgresql start && su -c "bash config.db.bash" postgres
    

    ... сервер каким-то образом вышел из строя! И, как я уже говорил, когда я пытался запустить его снова, произошла ошибка таймаута!

Я ищу решение с использованием DOCKERFILE, а не Docker-Compose. Также я не хочу использовать DIFFERENT BASE IMAGE в DOCKERFILE.

Давайте начнем с самого начала: Dockerfile используется для сборки контейнера, то есть для установки всего, создания структуры каталогов и т.д. Dockerfile не должен уже запускать сервисы. Как правило, их нужно запускать при старте контейнера. Каждая промежуточная команда в ваших Dockerфайлах требует "начала и конца", так же как и команда RUN в этом месте. Но как база данных может успешно работать рядом с контейнером, который еще даже не полностью собран?

Зная, что база данных не может работать там, где вы пытаетесь ее запустить, легко выяснить, почему команда миграции не работает. Вы пытаетесь подключиться к базе данных, которая в данный момент не запущена.

Так как же смягчить последствия? Отказ от ответственности: То, что я вам сейчас рассказываю, не является лучшей практикой. Как правило, вы хотите запускать один процесс в одном контейнере. Один контейнер для одной задачи. Это постепенно переходит в направление к docker compose. В любом случае, чтобы ответить на ваш вопрос:

Вы захотите запустить менеджер процессов, например supervisord. Помните, что в одном контейнере один главный процесс. В данном случае этим главным процессом будет supervisord (который управляет вашим postgres и сервером разработки).

То есть в конце вашего Dockerfile вы хотите запустить скрипт точки входа. Это должно

  1. Запустите базу данных
  2. Выполните миграцию
  3. Запустите сервер разработки.

Это очень много для настройки. Но будьте внимательны к работе, которую вы проделаете. Потому что даже после настройки, как я уже сказал, это не самое лучшее решение. Когда контейнер умрет, ваша база данных исчезнет. Вам нужно где-то настроить том. Сервер разработки называется сервером разработки не просто так. Значит, когда вы перейдете на продакшн, вам понадобится еще и третий сервис (например, nginx для обработки статических файлов). Это приведет к появлению еще одной третьей службы.

Я не знаю, чем обусловлен подход "все в одном контейнере", и я не рекомендую его, но ответ на ваш вопрос - это сервис типа supervisord.

Докеры к этой теме

Вернуться на верх