Создаем приложение: Docker, VueJs и Python-Sanic. Часть 1

В рамках статьи мы создадим одностраничное (SPA) приложение с использованием VueJs. Оно будет общаться с WebSocket-сервером, предварительно авторизировавшись через backend api. WebSocket-сервер и api реализуем при помощи фреймворка Sanic.

В этом материале хочу поделиться наработками и изложить свое субъективное видение связки технологий, которая, как мне кажется, наиболее эффективна для fullstack разработчика с акцентом на Python. Постараюсь быть максимально кратким.

Кратко обо мне

Я вошел в веб 15 лет назад, во времена тотального доминирования PHP в качестве серверной платформы. Впоследствии я перешел на Python. Разработка web-приложений из монолитного кода начала «растекаться», сначало на серверную и интерфейсную части, потом стало модным растягивать по микросервисам еще и backend. Сейчас зачастую мне приходиться брать на себя роль бекенд- и фронтенд-разработчика. При этом сильно прокачиваются навыки DevOps, чтобы заставить кучу всего разрозненного работать вместе.

Стек, который я использую в работе сейчас:

  • Python framework: Flask; Sanic;
  • DB: PostgreSQL, Redis, RebbitMQ, MongoDB, MySQL;
  • JavaScript: VueJs, Jquery;
  • DevOps: Docker, Ansible.

Постановка задачи

Пишем приложение для http://localhost:

  1. По ссылке /db открывается web-клиент adminer для работы с PostgreSQL.
  2. По ссылке /app открывается web-клиент на VueJs, который содержит форму авторизации и после ее успешного выполнения позволяет получать/отправлять сообщения через webSocket.
  3. По ссылке /api реализовать API (python-Sanic):
    • авторизовывать пользователя из PostgreSQL;
    • данные сессии записывать в Redis.
  4. По ссылке /ws реализовать WebSocket server, принимающий запросы от авторизованного через API клиента и отвечающий ему.

Аргументация выбранного стека

Почему Redis? — Тут без комментариев.

Почему PostgreSQL? — Благодаря огромному опыту работы с MySQL, эмпирическим путем пришел к наиболее оптимальному решению.

Почему VueJs? — Не хотелось бы священных войн, изложу кратко свое видение. Для меня, как для fullstack разработчика с упором на backend, VueJs оказался весьма прост в освоении и понятен в своей концепции. Более популярные фреймворки React и особенно Angular имеют, на мой взгляд, несопоставимо более высокий порог вхождения. Они требуют гораздо больше времени на изучение и удержание достаточного уровня квалификации.

Почему backend на Sanic? — В среде Python в последнее время произошла довольно серьезная революция, связанная с развитием асинхронного программирования. У меня был опыт написания кода на Twisted и Tornado, но современная реализация async/await выше всяких похвал. Как грибы после дождя появились различные асинхронные веб-фреймворки. Но мой выбор пал на Sanic, потому как он практически полностью копирует интерфейсность Flask (в котором у меня наибольший опыт работы последних лет), при этом добавляет приложению огромную производительность и функциональность (тот же WebSockets).

Нюанс: Sanic еще весьма молод, под него мало пакетов. Производятся попытки миграции c Flask такого полезного расширения, как Restfull. На момент написания статьи там еще далеко даже до бета-релиза. Но, по моему мнению, сам фреймворк стабилен и великолепен — можно пользоваться.

Реализация и вводные данные

Мой рабочий компьютер:

Этап 1: Инициализация проекта

Этап 2. Как это все будет работать

Согласно постановки задачи, у нас есть 2 приложения: Redis, PostgreSQL, которые должны быть изолированы от доступа извне, но должны быть доступны для использования из Python. C другой стороны, есть 4 точки входа, которые коммуницируют с внешним миром, то есть доступны через браузер. Это /app, /api, /ws, /db -за каждым из этих интерфейсов стоит свой работающий процесс.

Для /app — это процесс webpack watcher, задача которого — остлеживать изменение кода, который мы будем вносить, и налету преобразовывать его при помощи подключенных плагинов (broserify, cssminify и т. д.) в исполняемый браузером код.

Для /api и /ws — это будет один общий python worker, который также будет отслеживать изменения и перезапускать самого себя.

Все вышеописанные правила довольно просто реализовать при помощи Nginx, проксируя URL-запросы к им соответствующим демонам, которые работают на выделенных портах.

Этап 3. Контейнеризация

Поместим в файл .env, созданный ранее, несколько переменных окружения, которые понадобятся нам при построении контейнеров:

Обращаю внимание, что этот файл лишь в рамках этой статьи был добавлен в Git-репозиторий. В реальной жизни ему не место в репозитории. На сервере этот файл создается ручками, со своими значениями переменных. Далее:

В конфигурации сервера мы декларируем запуск Nginx на 80-м порту. При этом все запросы, URL которых начинается с /db, перебрасываем на сервис adminer-а, который будет запущен на порту 8080. Я вынесу за рамки статьи информацию о том, что такое Docker, как связан с ним docker-compose и как это все работает. Ознакомиться с этими приложениями можно в официальной документации.

Перейдем непосредственно к реализации. На момент написания статьи версия 3.7 — последняя для спецификации содержимого docker-compose.yml. Ее и будем использовать:

Cети (networks)

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

Создавать разные сети для Dev-окружения совершенно нет необходимости. Но, как уже говорил выше, для одного разработчика хранить и актуализировать параллельно 2 сценария контейнеризации — излишняя трата времени. В рамках ограниченных ресурсов необходимо стараться делать окружение таким, каким оно будет выглядеть в продакшене с минимальными изменениями. Также можно оспорить необходимость делать веб-доступ к базе данных продакшена через adminer. Локально я предпочитаю коннектиться к базе через консоль, но иногда для оперативности — веб-доступ. Это экономит время.

Redis

Строки 9-15: стандартные инструкции создания Redis контейнера. Обратите внимание, что доступ к нему другие контейнеры могут получить из подсети «internal».

PostgreSQL

Строки 18-30: создаем контейнер на базе официального образа PostgreSQL. Обратите внимание на строки 23-25. По умолчанию перед запуском docker-compose автоматически читает переменные, заданные в .env файле, но не передает их дальше в контейнер для создания базы данных, пользователя и пароля. Для этой цели существует 2 способа. Первый — через переменную сервиса environment, где необходимо задать пару ключ-значение. Второй способ — через переменную env_file, когда мы пробрасываем все переменные файла .env непосредственно в контейнер (сделаем это чуть позже на примере серверного приложения).

В строке 29 мы «заставляем» базу данных хранить данные вне контейнера.
В строке 30 мы в момент создания контейнера запускаем SQL-инструкцию по созданию базы данных «test», которую будем использовать при написании тестов.

Adminer

Строки 33-39: поднимаем оффициальный Docker контейнер от Adminer. Обращаем внимание, что в конфигурации нужно явно указать сервис(ы), к которым он будет иметь доступ (в нашем случае это DB). Также указываем internal подсеть, по которой будет идти коммуникация.

Отступление. Наряду с Adminer на продакшене возможна контейнеризация любого другого множества вспомогательных приложений (скажем, redis-commander или phpMyAdmin). Рекомендую поднимать их в отдельной подсети, с доступом к ней только из-под VPN. Можно не заморачиваться с VPN, а ограничить доступ к определенным сервисам по IP, но такой подход менее гибок.

Строки 41-50: запускаем контейнер на базе официального образа Nginx, пробрасывая наш ранее созданный конфигурационный файл. Обратите внимание: необходимо указать связь с контейнером adminer через подсеть internal. Без этого указанный в server.conf сервис http://adminer:8080 доступен не будет.

В следующих частях статьи рассмотрим, как расширить файл server.conf, дополнить для работы с двумя другими сервисами app и api.

Этап 4. Построение и запуск контейнеров

На этапах 1-3 мы полностью подготовили необходимое для разработки окружения. Осталось запустить все и проверить, как это работает.

Теперь:

Открываем в браузере http://localhost/db и видим страницу входа в Adminer. Логинимся в базу данных при помощи значений переменных файла .env. Убеждаемся, что выполнился скрипт из директории db_entrypoint/, создавший базу test.

Итог

Весь исходный код я выложил на GitHub в ветку master. Следующая часть, чтобы можно было сравнить изменения, будет сделана в отдельной ветке. Чтобы покрутить самостоятельно, выполните из консоли:

После чего пробуйте зайти на localhost/db.

Продолжение следует...

Похожие статьи:
18 февраля 2016 года состоится открытие Brain Academy — первой в Одессе комплексной системы подготовки IT-специалистов в соответствии...
24 серпня представники українського бізнесу підписали меморандум про співпрацю та партнерство заради відновлення...
Тарасу 25 лет, он не слышит с рождения. Это не помешало ему стать мастером спорта по шахматам, выучиться...
Оператор мобильной связи МТС и компания Яндекс объявили о федеральном запуске совместного проекта –...
Как известно, программисты — люди творческие, но вместе с тем ревностно придерживающиеся...
Яндекс.Метрика