Проблемы с 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.
Прежде чем обратиться за помощью, я попробовал несколько способов решить эту проблему самостоятельно.
Я попытался запустить/перезапустить psql-сервер или запустить его снова с помощью команд
RUN service postgresql start
RUN service postgresql restart
Сервер попытался запуститься/перезапуститься и после долгого ожидания выдал ошибку таймаута.
Я попытался изменить DJANGO settings.py -> Конфиг базы данных. Изменил "localhost" на "0.0.0.0" и на "127.0.0.1". Затем я попытался указать PORT в виде строки. -> Не помогло.
Я попытался запустить
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 вы хотите запустить скрипт точки входа. Это должно
- Запустите базу данных
- Выполните миграцию
- Запустите сервер разработки.
Это очень много для настройки. Но будьте внимательны к работе, которую вы проделаете. Потому что даже после настройки, как я уже сказал, это не самое лучшее решение. Когда контейнер умрет, ваша база данных исчезнет. Вам нужно где-то настроить том. Сервер разработки называется сервером разработки не просто так. Значит, когда вы перейдете на продакшн, вам понадобится еще и третий сервис (например, nginx для обработки статических файлов). Это приведет к появлению еще одной третьей службы.
Я не знаю, чем обусловлен подход "все в одном контейнере", и я не рекомендую его, но ответ на ваш вопрос - это сервис типа supervisord.