Найти в Дзене
Computer Pro

Flask + Gunicorn + Postgresql и всё это чудо завёрнуто в Docker контейнеры и собрано docker-compose

Оглавление

Медленно, но верно я двигаюсь к завершению курса python_advanced. Казалось бы, всё понимаешь, но не так что бы на лету решать возникающие проблемы. Для того и пишу все эти статьи, чтобы пока их пишешь - в голове информация лучше укладывалась. Который раз пытаюсь собрать в единое целое 27 домашнюю работу и очередной раз у меня всё развалилось.

И тут я подумал: Так, надо начать сначала, по пунктам пройтись, разложить всё по полочкам. Для этого создал в Pycharm новый проект и поехали...

Описание docker-контейнеров

Опишите docker-контейнер для flask-приложения, развёрнутого с помощью Gunicorn с описанием network для взаимодействия с СУБД.
Опишите docker-контейнер СУБД PostgreSQL с указанием настроек:log_destination=stderr (направление логов в поток вывода ошибок);
logging_collector=on (включение сборщика логов из stderr в log-файлы);
log_directory (путь к директории, в которой будут лежать логи).
Что оценивается
Умение описывать docker-контейнеры для использования PostgreSQL и запускать СУБД с учётом кастомных настроек.

Итак, для чистоты эксперимента, начинаю с создания нового проекта в Pycharm и нового git-репозитория в gitverse.ru (Российская платформа контроля версий).

-2
-3

Как можно видеть - установленных пакетов пока нет, нужно установить лишь то, что в будущем понадобится для запуска вебсервера и реализации эндпойтов (первый будет примитивным, типа "hello world", второй - обращение к базе данных для записи туда каких либо данных и считывание от туда этих данных).

Первым делом создам приложение Flask с эндпойнтом ("hello world") и запущу его с помощью gunicorn, а не встроенного веб сервера.

Вот минимально рабочий код для запуска приложения на фласк (пока что со встроенным веб-сервером:

-4

Запустив приложение, из консоли запускаю запрос:

-5

Пока всё просто, всё запускается и работает. Усложняем, запустим этот же код но уже с использованием веб-сервера gunicorn (который сначала нужно установить с помощью pip install gunicorn):

-6
-7

Ну вот, всё работает, "повышаем градус", установим с помощью docker сервер postgres, в котором будет храниться наша база данных. У меня служба докера не запускается с загрузкой компьютера, поэтому я ее каждый раз запускаю вручную...

-8

Запустим контейнер следующей командой:

-9

Если всё норм, то в конце длинной "портянки" логов должно быть примерно так:

-10

Что означает сервер баз данных postgres запущен и готов к приёму и выдаче данных. Войдем в консоль postgres, для этого запустим второе окно терминала и выполним следующую команду:

решетка командной строки говорит о том что мы в режиме командной оболочки докер контейнера skillbox-postgres
решетка командной строки говорит о том что мы в режиме командной оболочки докер контейнера skillbox-postgres

Запустим psql -U postgres:

-12
-13

Выберем базу данных postgres и посмотрим какие там есть таблицы:

-14

Попробуем создать в консоли таблицу, добавить туда данные и затем считать эти данные:

-15

Ну вот, вроде бы всё работает. Переходим к следующему шагу - реализуем подключение к базе данных, создадим модель таблицы, наполним ее данными и сделаем выборку этих данных при помощи инструмента sqlalchemy. Так как асинхронная реализация данной задачи не требуется - буду делать простую, синхронную.

Дабы сильно не запутаться в таблицах, моя таблица будет простой - таблицей пользователей (id, name, surname, email) без каких либо связей.

Устанавливаю sqlalchemy: pip install sqlalchemy

Создаю модель пользователя:

нервирует подчеркивание self.__table__.columns, вроде как не ошибка и сама функция работает... поискал решение не нашел, оставил как есть...
нервирует подчеркивание self.__table__.columns, вроде как не ошибка и сама функция работает... поискал решение не нашел, оставил как есть...

Теперь нужно создать связь с базой данных и выполнение базовых операций с базой данных:

вначале я хотел это сделать отдельно от основного кода (в отдельном файле database.py) но так как кода тут немного, то решил всё уместить в main.py
вначале я хотел это сделать отдельно от основного кода (в отдельном файле database.py) но так как кода тут немного, то решил всё уместить в main.py

Был использован декоратор с методом before_request, который перед тем как делать запрос на считывание из базы данных наполняет эту БД какой-то информацией:

-18

Все три пользователя - сохранены в базе данных.

-19

Ну вот осталось сделать реакцию на эндпойнт (пусть будет "/data") и селект из БД и выдать это всё в виде списка JSON:

-20

Запускаем gunicorn и проверяем консольной утилитой http:

-21

Пока всё красиво, пробую делать запрос, предварительно удалив не только данные из таблицы users, но и саму таблицу users!

-22

Всё чудесно создалось (таблица и наполнение её данными), после чего не менее чудесно выдалось в ответе при консольном запросе.

Ну теперь надо на базе всего этого чуда написать правильный Dockerfile и docker-compose.yaml файл.

Я сделал pip freeze и он мне выдал вот такие зависимости, из которых сформировался файл requirements.txt:

хотя, по большому счету тут это всё можно было бы порезать, но я этого делать не буду...
хотя, по большому счету тут это всё можно было бы порезать, но я этого делать не буду...

Недолго думая наваял вот такой Dockerfile, правда от директории app в проекте пришлось отказаться и оба файла main.py и modules.py закинул в корень проекта, там же где и остальные файлы.

версию python решил использовать по максимуму, как у меня, только с префиксом slim (может хоть как то уменьшит это размер образа)
версию python решил использовать по максимуму, как у меня, только с префиксом slim (может хоть как то уменьшит это размер образа)

Попробовал было запустить контейнер - запускается, но тут же падает в ошибку, т.к. postgres еще не прописан, еще нужно покумекать над docker-compose.yaml

поэтому остановил контейнер и пошел писать композитум-файлум
поэтому остановил контейнер и пошел писать композитум-файлум

По времени можно увидеть когда я узрел ошибку связанную с postgres. Спецом, для поисковых систем, сюда засуну текст ошибки:

sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) connection to server at "0.0.0.0", port 5432 failed: Connection refused
Is the server running on that host and accepting TCP/IP connections?

Решение этой задачи искал долго и упорно, перепробовал кучу разных средств. Хоть ты тресни не мог понять почему контейнер фласка не видит контейнер постгрес. Хотя я в контейнеры захожу, делаю любые манипуляции, а между собой не хотят взаимодействовать.

Дело оказалось в адресе подключения к базе данных:

-26

Ну и собственно, сам файл docker-compose.yaml:

-27

И тут произошло чудо, почти в девять часов вечера я таки получил заветный ответ от сервера, такой же как и был без контейнера:

-28

Вот кажется и всё. И это только первая (из трёх) часть домашней работы №27...

-29

Если вам понравилась статья, ставьте лайки и подписывайтесь на мой канал!