Давайте сделаем крупное приложение на Flask (язык Python)
На Хабре я часто вижу статьи о реализации тех или иных фич на Python-фреймворках. Я объединил все эти фичи в реальный проект с открытым исходным кодом, чтобы у вас сложилась целостная картина. Мы с вами создадим UX/UI на Figma, напишем фронтенд на HTML, CSS, SASS, Bootstrap и JavaScript, создадим ER-диаграмму в MySQL Workbench, напишем бекэнд на Flask, создадим регистрацию через социальные сети OAuth 2.0 в один клик, используем брокер сообщений и асинхронную очередь Celery для отправки писем на электронную почту, сделаем WYSIWYG-редактор, реализуем полнотекстовый поиск Elasticsearch, закешируем Redis, покроем тестами pytest и запустим в Docker-контейнерах, поговорим о многопроцессности для WSGI-шлюза Gunicorn.
План работы и технологии
Здесь я приведу последовательность шагов, которые мы будем последовательно выполнять:
Номер шага | Что делаем | Технология |
1 | Изучаем техническое задание | |
2 | Создаём дизайн веб-приложения UX/UI | Figma |
3 | Пишем HTML версию веб-приложения, подключаем CSS и JavaScript, делаем адаптивную верстку | HTML, CSS, JavaScript, Bootstrap |
4 | Разрабатываем ER-диаграмму базы данных | MySQL Workbench |
5 | Создаем структуру приложения: точку входа и соответствующие пакеты | Flask |
6 | Разбиваем HTML версию веб-приложения на шаблоны | Jinja2 |
7 | Создаем модели базы данных на основе ER-диаграммы | SQLAlchemy |
8 | Создаем view-функции для генерации шаблонов, а также формы для диалога с пользователем | Flask |
9 | Реализуем регистрацию через OAuth 2.0 и классическую регистрацию через сайт | Flask, requests |
10 | Реализуем WYSIWYG-редактор для создания контента | CKEditor |
11 | Реализуем полнотекстовый поиск по контенту сайта | Elasticsearch |
12 | Реализуем обход блокирующих операций (отправка писем по электронной почте) | Redis, Celery |
13 | Протестируем веб-приложение | pytest |
14 | Реализуем кэширование страниц | Redis |
15 | Реализуем логирование | logging |
16 | Подключим синхронный серверный WSGI-шлюз на нескольких логических ядрах центрального процессора | Gunicorn |
17 | Подключим HTTP-сервер и обратный прокси-сервер | nginx |
18 | Создадим docker compose для объединения всех компонентов в единое целое | Docker |
19 | Развернём веб-приложение на удаленном сервере | VPS |
20 | Сделаем взаимодействие между репозиторием нашего проект и удаленным сервером посредством CI/CD | GitHub Actions |
Самое главное преимущество всех этих технологий в том, что они бесплатные (кроме VPS, за который платит заказчик). Поэтому от нас потребуется только время — именно это самый главный ресурс в процессе разработки.
Здесь я описал свой персональный алгоритм работы, который для меня является наиболее оптимальным. Ваш алгоритм может отличаться.
ШАГ 1. Изучаем техническое задание
Любая разработка начинается с получения технического задания от заказчика. При изучении ТЗ необходимо максимально вчитываться в каждую строку и если что-то звучит двусмысленно или непонятно, нужно как можно раньше провести бриф с заказчиком для уточнения.
В данном случае заказчиком выступил мой друг с высший медицинским образованием, закончивший ординатуру по специальности «Психиатрия». Сайт будет посвящён оказанию психотерапевтической помощи.
На сайте должны быть новости, статьи, авторский учебник психотерапии, сервис «Вопрос-Ответ», сервис «Записаться на консультацию», а также возможность регистрации в один клики через популярные сервисы Goggle и Яндекс, социальные сети VK (Вконтакте) и Одноклассники, а также через мессенджер Telegram. Регистрация дает пациенту вести дневник и отслеживать прогресс по изучению статей и учебника. Также должен быть реализован полнотекстовый поиск по учебнику. Сайт должен красиво выглядеть и быстро работать.
ШАГ 2. Создаём дизайн веб-приложения UX/UI
UX (User Experience) — это опыт пользователя при взаимодействии с приложением. Это именно те эмоции, которые испытывал пользователь, когда им пользовался. Наша задача в заключается в том, чтобы пользователь имел положительный опыт от использования приложения.
Совет 1: Копируйте расположение элементов на странице с популярных сайтов (VK, YouTube). Например, расположение кнопки регистрации в верхней правой части экрана.
Совет 2: Используйте теорию цвета. Цвета сайта должны сочетаться друг с другом. Лично я для определения сочетаемости использую данные палитры
Мы разобрались с UX, теперь перейдём к UI
UI (User Interface) — это интерфейс пользователя, то есть визуальные элементы и дизайн, через которые пользователь взаимодействует с приложением.
Для создания интерфейса на данный момент самым удобным инструментом является онлайн-приложение Figma. Если вы никогда не работали с Figma, то вам потребуется где-то 3–4 часа, чтобы во всем разобраться.
Я приведу скриншот работы с Figma на раннем этапе разработки дизайна
Проектирование дизайна в Figma на раннем этапе разработки
ШАГ 3. Пишем HTML версию веб-приложения, подключаем CSS и JavaScript, делаем адаптивную верстку
Дальше от нас требуется создать HTML версию сайта. То есть надо создать набор связанных HTML-страниц. Тем самым мы получим статическую версию приложения. Потом мы эти страницы «нарежем» на шаблоны.
Прелесть HTML и CSS заключается в том, что это декларативные языки. То есть мы пишем то, что хотим увидеть. Но главное даже не это. Научиться верстать можно буквально за месяц, благо в интернете огромное количество бесплатных ресурсов.
Современный CSS дает огромные возможности и в частных случаях может полностью заменить JavaScript. Но не всегда…
JavaScript — это императивный язык с Си-подобным синтаксисом (Си — язык программирования). Мы его будем использовать потому, что в нашем приложении будет интерактивность и асинхронные запросы, без перезагрузки страницы. А только с помощью CSS это невозможно реализовать.
JavaScript можно изучать очень долго. Для нашего случая достаточно освоить базовый синтаксис и принципы работы с DOM (Document Object Model — это программный интерфейс для работы с документами, представленными в виде HTML).
И еще по поводу JavaScript: как-то мой друг-фронтендер сказал фразу, которая у меня отпечатались на все жизнь в голове: «Все JS-скрипты уже давно написаны». И это действительно так. Есть наборы уже готовых JS-скриптов. Для их получения мы воспользуемся фреймворком Bootstrap от Twitter.
Bootstrap хорош тем, что позволяет создавать верстку, которая уже является адаптивной — то есть автоматически подстраивается под разрешение экрана пользователя.
Теперь я дам несколько советов:
Совет 3: Никогда не реализуйте загрузку из интернета CSS и JS-файлов при открытии страницы (CDN и т. п.). Скачайте эти файлы один раз, сохраните на SSD и именно оттуда подключайте, то есть из локального хранилища. Мы живем в мире блокировок ресурсов для «дорогих россиян» и если ваша страница не сможет загрузить эти файлы из интернета, то приложение развалится.
Совет 4: Используйте автоопределение светлой и темной темы приложения, а также дайте пользователю возможность спокойно их переключать. Это напрямую связано с UX. Вечером и ночью пользователю комфортнее пользоваться темной темой, а утром и днем — светлой.
Совет 5: Грамотно реализуйте адаптивную верстку. У браузера Google Chrome сочетание клавиш Ctrl + Shift + I вызывает «Инструменты разработчика». Здесь мы можем посмотреть как будет выглядеть наше приложение на разных устройствах: компьютерах, планшетах, смартфонах. Если что-то где-то выглядит плохо — смело идём в CSS и переопределяем @media правила.
Совет 6: Если сами не можете написать JS-скрипт, спрашивайте у нейросетей (например, ChatGPT). С простыми скриптами нейросеть справляется отлично. Но, как говорится, доверяй, но проверяй.
ШАГ 4. Разрабатываем ER-диаграмму базы данных
ER-диаграмма (Entity-Relationship Diagram) — это графическое представление структуры базы данных, которое показывает объекты (сущности) и связи между ними. Лично мне выделять сущности помогает визуальное представление веб-приложения (что мы реализовывали в ШАГЕ 2 и ШАГЕ 3).
Именно на этом этапе начинается оптимизация нашего веб-приложения. Наша задача — выбрать наиболее оптимальную ER-диаграмму, которая обеспечивает эффективное взаимодействие между сущностями. Этот подход позволяет минимизировать избыточность данных и улучшить производительность запросов в базе данных.
Совет 7: Не переживайте, что в процессе разработки вы можете по 15 раз на дню менять схему базы данных. Это нормально. Миграции данных со старой схемы на новую никто не отменял.
Теперь поговорим про инструменты для создания схемы базы данных. Я пробовал, как онлайн-инструменты, там и desktop приложения. Лично мне самым лучшим инструментом показался MySQL Workbench
Работа в MySQL Workbench
ШАГ 5. Создаем структуру приложения: точку входа и соответствующие пакеты
И вот здесь мы переходим к нашему любимому бекенду. Если я утверждал, что вам не нужны глубокие знания JavaScript для реализации фронтенда данного приложения, то здесь я скажу следующее: вам НУЖНЫ глубокие знания Python для реализации бекенда. Причем я говорю не только о базовом синтаксисе и ООП, я имею ввиду еще навыки решения алгоритмических задач, выбор алгоритма наиболее приближенного к O(1)
, умение работать с библиотекой re для регулярных выражений, умение выполнять HTTP-запросы с помощью библиотеки requests, знать и понимать, что такое глобальная блокировка интерпретатора GIL, и многое другое.
Если выбирать между Django и Flask, то мне предпочтительнее Flask. Django — это гигантский фреймворк с огромным количеством магии и функций, которые вы никогда не будете использовать. Flask, напротив, очень минималистчен, и вы сами решаете какие расширения подключать: хотите админку — flask-admin
, хотите миграции — flask-migrate
и так делее. Также мне нравится система маршрутизации во Flask с помощью Blueprints. Поставил декоратор на view-функцию с названием эндпоинта и не надо писать никаких urls.py
.
Вначале определим точку входа конструкцией if __name__ == "__main__”
, из-под этой конструкции будет запускаться наше приложение. Это определим в файле manage.py (привет всем, кто любит Django). А также файл с конфигурациями config.py.
Далее создаем пакеты — это такие папки, где присутствует файл __init__.py
. Без этого файла Python не будет рассматривать папку как пакет, и мы не сможем импортировать модули из этой папки. Как раз таки в главной директории приложения в файле __init__.py
мы и реализуем функцию создания приложения.
И здесь надо вспомнить про паттерн проектирования «Фабричный метод» (Factory Method). Такой подход к организации создания экземпляра приложения помогает управлять конфигурацией, расширяемостью и тестируемостью. Данный паттерн особенно полезен при работе над большими проектами.
Например, один экземпляр приложения со своей конфигурацией будет относится к стадии разработки, другой — к стадии тестирования, а третий — к стадии Production.
Ссылка на организацию файлов внутри проекта
ШАГ 6. Разбиваем HTML версию веб-приложения на шаблоны
Когда вы устанавливаете Flask в своё виртуальное окружение, то можете заменить, что вместе с ним была установлена библиотека Jinja2.
Jinja2 — это мощный и гибкий шаблонизатор Python для создания динамических веб-приложений с чистым разделением логики и представления. Он используется во многих веб-фреймворках, включая Flask. У Jinja2 есть встроенный механизм защиты от XSS-атак.
Теперь мы должны превратить наш статический HTML-сайт (например, http://localhost/news.html) в динамически генерируемый (http://localhost/news).
Здесь мы делаем разбиение элементов статического сайта на отдельные узлы и помещаем их в шаблоны.
{% if g.search_form %}
{% endif %}
Совет 8: Не прописывайте в шаблона относительные пути к локальным файлам. Пользуйтесь функцией url_for с указанием этим локальных файлов. Пример ниже:
ШАГ 7. Создаем модели базы данных на основе ER-диаграммы
Теперь необходимо создать нашу базу данных. Ранее мы создали ER-диаграмму. И здесь самым лучшим вариантом является выбор ORM SQLAlchemy.
Есть 2 способа реализации алхимии во Flask: 1) Использование дополнения Flask-SQLAlchemy
2) Использование чистой SQLAlchemy
.
В чем разница? У Flask-SQLAlchemy
есть автоматическое управление жизненным циклом сессий, избавляя нас от необходимости явно открывать и закрывать сессии, а также упрощенная конфигурация. Хорошо ли это? Не всегда. Если мы хотите иметь полный контроль над использованием SQLAlchemy, тогда стандартная версия SQLAlchemy
будет лучшим выбором. Конкретно для нашего приложения я принял решение, что полный контроль будет избыточным, а поэтому использовал Flask-SQLAlchemy
.
Совет 9: Если вам нужен полный контроль над сессиями баз данных, в случае работы с большими данными, в микросервисной архитектуре, в проектах с высокой производительностью и оптимизацией, то используйте чистую SQLAlchemy. В всех остальных случаях используйте Flask-SQLAlchemy.
Принцип создания моделей такой же как в Django ORM. Помните в Django атрибут модели ForeignKey для указания внешнего ключа и параметр related_name. В SQLAlchemy все реализуется с помощью функции relationship, в параметры которой прописываются все необходимые данные. Одним из таких параметров является lazy — тип загрузки. Различают 3 типа загрузки: ленивую (lazy loading), жадную (eager loading) и явную загрузку (explicit). Что и когда применять?
Тип загрузки | Значение параметра lazy в relationship (lazy=» значение») |
Ленивая загрузка (lazy) | — select (используется по умолчанию) |
Жадная загрузка (eager) | — joined |
Явная загрузка (explicit) | — write_only |
Совет 10. Установите Flask Debug Toolbar (аналог Django Debug Toolbar) и посмотрите на количество запросов и время отклика для «ленивой», «жадной» и «явной» загрузок. Выберите тип загрузки с наименьшим временем и количеством запросов в базу данных.
ШАГ 8. Создаем view-функции для генерации шаблонов, а также формы для диалога с пользователем
Здесь все предельно просто. Мы создаем функции представлений (view-функции), которые будут отрисовывать шаблон и передавать в него необходимую информацию из базы данных, если требуется. Также мы создаем формы и прописываем валидацию форм. И здесь надо помнить о следующем: информация записывается в базу данных только в самую последнюю очередь — когда данные прошли валидацию формы. Но если даже данные успешно прошли валидацию формы, то могут сработать какие-нибудь ограничения в базе данных. Мы получим ошибку на уровне базы данных.
Совет 11. Помимо валидаторов форм из «коробки» прописывайте свои кастомные валидаторы, чтобы полностью покрыть проверку данных. Не надо допускать возбуждения исключения на уровне базы данных.
Ссылка на views.py проекта
ШАГ 9. Реализуем регистрацию через OAuth 2.0 и классическую регистрацию через сайт
Весь интернет забит гайдами по реализации регистрации через сайт. Также существует расширение Flask-login
, которое упрощает управление пользовательскими сессиями и аутентификацией. Оно предоставляет инструменты для обработки входа, выхода и хранения состояния сессии пользователя.
Что качается авторизации через социальные сети по протоколу OAuth 2.0, то это обширная и огромная тема.
Чтобы длина статьи не стремилась в бесконечность, я создал подробнейший PDF-гайд о реализации авторизации через Goggle, VK, Одноклассники, Яндекс, Telegram. Там я шаг за шагом в мельчайших подробностях объясняю куда переходить, что вводить, как регистрировать приложение, как получать токены, куда их оправлять и т. д. Все шаги проиллюстрированы скриншотами.
Также для лучшей наглядности я также записал видео с подробным объяснением теории и практики на примере Google по этой теме:
ШАГ 10. Реализуем WYSIWYG-редактор для создания контента
Вы читаете эту статью на Хабре, где авторы выкладивают свои статьи и сообщество их оценивает. Ядром бизнес-логики Хабра является инструмент для создания статей, или WYSIWYG-редактор.
WYSIWYG-редактор (What You See Is What You Get) — это тип редактора, который позволяет пользователям создавать и редактировать контент (например, текстовые документы, веб-страницы или электронные письма) в визуальном формате, где-то, что они видят на экране, соответствует тому, как будет выглядеть конечный продукт. Это делает процесс редактирования более интуитивным и доступным, особенно для людей, не обладающих знаниями в области программирования или веб-разработки.
Хорошая новость в том, что нам ничего самим создавать не придется. Существует встроенные WYSIWYG-редакторы. И самым популярным является CKEditor, который предоставляет все необходимые функции.
Наша задача только интегрировать CKEditor во Flask. И тут нам на помощь приходит расширение Flask-CKEditor.
Когда мы установим это расширение нам необходимо его правильно настроить и у нас на выбор есть 2 способа подключения: онлайн-подключение CKEditor и подключение CKEditor с нашего SSD (локальной версии).
Совет 11: Всегда используйте локальную версию CKEditor с вашего SSD и никогда не загружайте онлайн-версию CKEditor.
Здесь принцип такой же как в совете 3. Удаленный ресурс могут заблокировать. Даже если его никогда не заблокируют, я читал форум, когда у разработчика загружалась онлайн-версия CKEditor 4. А потом эту онлайн-версию обновили до 5 и начала загружаться CKEditor 5. И у него поломалась вся логика проекта. Напоминает обновления Windows.
Использование WYSIWYG-редактора CKEditor
Здесь есть один очень интересный момент: это организация файлов картинок. Я создал алгоритм для автоматической конвертации картинки из любого формата изображения в формат WEBP. Это современный формат растровой графики, который пришел на смену PNG.
Также у нас в ER-диаграмме есть отдельная сущность Image. Для чего она создана? Когда мы добавляем какие-нибудь картинки в статью, они сохраняются на SSD, а также в базе данных появляется соответствующая запись. В случае, если мы редактируем статью и у нас уже нет этого изображения, база данных регистрирует, что изображение удалено из неё и у нас срабатывает регистрация событий SQLAlchemy, которая берет абсолютный адрес удаленной картинки и удаляет картинку с SSD. Таким образом, у нас нет лишнего «мусора» на SSD — локально хранятся только те картинки, которые используются. Логика удаления довольно сложная.
Ссылка на файл по реализации логики WYSIWYG-редактора
ШАГ 11. Реализуем полнотекстовый поиск по контенту сайта
Полнотекстовый поиск — это важная задача в разработке веб-приложений, и реализация его во Flask может быть выполнена различными способами. Два распространенных подхода — это использование полного сканирования таблицы базы данных и применение специализированного инструмента для поиска Elasticsearch.
Выбор инструмента зависит от нашего проекта и того, что мы ищем. Самое главное помнить, что при полном сканировании таблиц мы нагружаем нашу базу данных.
Совет 12: Если объем данных небольшой, а требования к поиску просты, выбираем полное сканирование таблицы. Если приложение требует высокой производительности, масштабируемости и гибкости в поисковых запросах, выбираем Elasticsearch.
Elasticsearch — это распределенная поисковая система на базе Apache Lucene, которая предоставляет мощные возможности для полнотекстового поиска. Существует специальная библиотека для Python.
Настройка довольно сложна, и ей должна быть посвящена отдельная статья. На Хабре такая статья существует.
Пример вывода результатов поиска на сайте с помощью Elasticsearch
ШАГ 12. Реализуем обход блокирующих операций (отправка писем по электронной почте)
Что является одним из самых плохих явлений с точки зрения UX? Я ответил бы так: когда сайт долго обрабатывает запросы. Пользователь ждет, а потом закрывает вкладку и никогда больше на ваш сайт заходит, зная что сайт «глючный».
У нас в коде могут встречаться длительные операции, которые требуют ожидания. Одной из таких операций является отправка письма на электронную почту. Мы должны обойти эту блокирующую операцию. Каким образом? Здесь стоит обратиться к официальной документации Flask, которая нам в таких случаях рекомендует использовать асинхронную очередь Celery и NoSQL СУБД Redis. Именно их мы применим в нашем проекте.
ШАГ 13. Протестируем веб-приложение
Точно не помню в какой книге я это встречал, но мне запомнилась одна фраза: «Если код не протестирован, значит он нерабочий». В Python для тестирования существует стандартная библиотека unittest. Также на практике часто можно встретить использование сторонней библиотеки pytest
Совет 13: Unittest может быть полезна для простых случаев и тех, кто предпочитает более традиционный подход к тестированию. Для более сложных проектов благодаря своей гибкости и мощным возможностям используем pytest.
Я использовал библиотеку pytest из-за возможностей фикстур.
Вначале нам надо в корне проекта создать папку «tests» и сделать её пакетом, то есть поместить туда файл __init__.py. Далее необходимо создать файл conftest.py. Это специальный файл в библиотеке pytest, который используется для настройки тестов и их окружения. Он позволяет определять фикстуры и конфигурации, которые могут быть доступны во всех тестах в директории и ее поддиректориях.
Ну, а дальше создаем сами файлы тестов, начинающиеся с «test_что_тестируем»
Автотесты проекта лежат здесь
ШАГ 14. Реализуем кэширование страниц
У нас пользователь может несколько раз посещать один и тот же ресурс. В первый раз данные для этого ресурса будут выгружены из базы данных, а для всех последующих посещений — из специального хранилища, в котором хранятся эти данные. Такие хранимые данные называются кешем, а запись этих данных в локальное хранилище называют кэшированием.
У Flask есть расширения для все случаи жизни. Поэтому мы будем использовать библиотеку Flask-Caching.
Есть несколько инструментов для кеширования. Например, кэширование в памяти — это стратегия, при которой данные временно хранятся в оперативной памяти для обеспечения быстрого доступа к ним. Проблема в том, что объем оперативной памяти ограничен, и при увеличении объема данных кэширование в памяти может стать неэффективным. Эту проблему решает использование Redis в качестве кэш-сервера.
Когда занимаемый объём кэша приближается к критическому значению, Redis может сохранять данные на диск, что позволяет восстанавливать состояние кэша даже после перезапуска приложения или сбоя. Мало того Redis разработан для высокой производительности и может обрабатывать миллионы запросов в секунду, обеспечивая быструю доступность к кэшированным данным.
В нашем проекте будет использоваться Redis для кэширования. Расширение Flask-Caching предоставляет очень удобный интерфейс для управления Redis.
ШАГ 15. Реализуем логирование
В Production никакой отладки нет, она отключена. Но приложения тем не менее иногда падают. И нам надо бы знать причины — почему? Поэтому мы создаем специальный файл-журнал, куда будут прописываться все события, которые происходят в приложении. Процесс записи событий в этот файл называется логированием. Кстати, логирование можно включать и в процессе разработки, выводя логи в консоль.
Совет 14: При реализации логирования всегда ограничивайте размер файла логов (например, 100 МБ).
Если не установить ограничения файла логирования, то он может разрастись до неописуемых масштабов. Также необходимо определить уровень логирования. Логи какого именно приоритета будут записываться в файл
Организацию логирования можно посмотреть здесь
ШАГ 16. Подключим синхронный серверный WSGI-шлюз на нескольких логических ядрах центрального процессора
WSGI (Web Server Gateway Interface) — это стандартный интерфейс между веб-серверами и Python-приложениями или фреймворками. Он позволяет разработчикам создавать веб-приложения, которые могут работать с любым WSGI-совместимым сервером, обеспечивая гибкость и совместимость.
Самым популярным WSGI-шлюзом является Gunicorn. В соврменном мире почти все процессоры имеют несколько физических ядер. Физическим ядрам соответсвует удвоенное количество логических ядер. Мы можем использовать эти ядра для параллельной обработки запросов. Причем речь идет об истинном параллелизме. Каждый рабочий процесс может обрабатывать свои собственные запросы независимо от других. Это позволяет значительно увеличить пропускную способность приложения, особенно при обработке большого количества одновременных запросов.
Мы можем посмотреть на сайте-хостинге, сколько ядер у нашей виртуальной машины. Но лучше автоматизировать этот процесс, чтобы автоматически определялось количество ядер.
Для этого необходимо реализовать следующий скрипт gunicorn.conf.py:
import multiprocessing
import socket
import fcntl
import struct
def get_ip_address(ifname):
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
return socket.inet_ntoa(fcntl.ioctl(
s.fileno(),
0x8915,
struct.pack('256s', bytes(ifname[:15], 'utf-8'))
)[20:24])
ip_address = get_ip_address('eth0')
bind = f'{ip_address}:5000'
workers = multiprocessing.cpu_count()*2 + 1
timeout = 2
preload = True
loglevel = 'info'
И подключить его:
gunicorn -c ./gunicorn.conf.py manage:app
ШАГ 17. Подключим HTTP-сервер и обратный прокси-сервер
Мы на финишной прямой. Теперь надо сделать так, чтобы наше Python-приложение было доступно по определенному URL по протоклу HTTPS. Для этого мы должны создать наш собственный сервер nginx с нашей конфигурацией.
Совет 15: Не пользуйтесь стандартной конфигурацией nginx. В интернете полно гайдов как улучшить конфигурацию, чтобы nginx работал намного быстрее и безопаснее.
ШАГ 18. Создадим docker compose для объединения всех компонентов в единое целое
Теперь мы должны объединить все компоненты нашего приложения в единое целое, связанное одной сетью. Docker — это система для запуска приложения в контейнерах. Самым главным преимущество такого подхода является то, что будь то вы работает на Windows, будь то на MacOS, будь то на Ubuntu — везде результат запуска Docker контейнеров будет одинаковым.
Особое внимание здесь следует уделить подключаемым томам. Это так называемые SSD внутри вашего приложения. Вы можете менять СУБД, пересоздавать образы и контейнеры. Но информация в томах останется не тронутой. Поэтому мы создаем подключаемые тома для хранения картинок и базы данных. И еще дополнительно для Elasticsearch и Redis.
Совет 16: Следите за сохранностью данных, используя подключаемые тома к контейнерам, делайте бекапы.
ШАГ 19. Развернём веб-приложение на удаленном сервере
Пришло время аренды виртуальной машины. Когда вы регистрируетесь на каком-нибудь хостинге, помимо виртуальной машины вам предлагают получить SSL-сертификат и доменное имя. И, как правило, вам дают бонус — бесплатное получение сертификата и имени на полгода.
SSL-сертификат (Secure Sockets Layer) — это цифровой сертификат, который используется для обеспечения безопасного соединения между веб-сервером и браузером. Он шифрует данные, передаваемые между клиентом и сервером, защищая их от перехвата и несанкционированного доступа.
Совет 17: Если на вашем сайте есть аутентификация всегда получайте и подключайте SSL-сертификат
SSL-сертификат дает возможность передавать данные по защищенному протоколу HTTPS, что является необходимым требованием почти к любому современному сайту.
Далее на сервере необходимо установить Git или Docker.
Доменное имя, указанное в сертификате, необходимо привязать к IP-адресу виртуальной машины. Это можно также сделать на хостинге.
Совет 18: Если хостинг предлагает виртуальную машину с уже установленным Git и Docker — соглашайтесь. Там уже будет все настроено и вам ничего не придется дополнительно настраивать.
Далее необходимо настроить вход на удаленный сервер по протоколу SSH. Как это делается должно подробно быть написано в документации хостинга. После этого мы создаем на удаленном сервере SSH ключи — публичный и приватный. И эти ключи указываем на GitHub, чтобы можно было скачивать репозитории с GitHub.
Далее необходимо клонировать наш репозиторий с GitHub на удаленный сервер, и выполнить docker compose. С этого момента мы можем при вводе нашего доменного имени переходить на сайт из любого браузера.
ШАГ 20. Сделаем взаимодействие между репозиторием нашего проект и удаленным сервером посредством CI/CD
Все работает, что нам еще надо? А что если мы хотим добавлять новые фичи в наш проект и НЕ хотим вручную все перезаливать на удаленный сервер. Эту проблему решает GitHub Actions, на которых реализуется CI/CD.
CI (Continuous Integration) — это практика, при которой разработчики регулярно объединяют свои изменения в центральный репозиторий. Каждый коммит запускает автоматическое тестирование, что позволяет быстро выявлять и исправлять ошибки.
CD (Continuous Deployment / Continuous Delivery) — полная автоматизация, где каждое изменение, прошедшее тесты, автоматически разворачивается в производственной среде без ручного вмешательства.
Совет 19: На поздних этапах разработки можно создать проект-заглушку для реализации nginx, CI/CD и на этом проекте протестировать и отработать все интеграции и деплоймены.
Все, теперь все изменения в нашем проекте при пуше на GitHub будут автоматически отражаться на удаленном сервере.
Заключение
Напоследок я дам вам совет 20: лично по моему мнению, глубокое изучение бэкэнд технологий имеет более высокий приоритет, чем фронтенд. Если вы поймете как работает бэкэнд, глубоко изучите язык программирования бекэнда, то освоить фронтенд будет довольно просто.
Проект имеет открытый исходный код и полностью доступен здесь
Если у вас возникнут какие-нибудь вопросы, буду рад на них ответить. Спасибо за внимание.