В этом уроке мы узнаем, что такое конфигурация и как настраивать и деплоить приложение.
Конфигурация
Любое нетривиальное приложение взаимодействует с внешним миром: использует базу данных, обращается к внешним сервисам (например, платежным), отправляет письма и получает список друзей, например, из Facebook. Для подавляющего большинства этих операций необходимы специальные параметры: ключи, пароли, адреса серверов и порты. Все эти параметры называются конфигурацией приложения.
Возникает вопрос, где хранить конфигурацию? Самый простой и самый неправильный ответ – прямо в приложении. Проблем у такого подхода две:
Часть этих данных секретная. Хранить их в репозитории просто нельзя из-за возможных проблем с безопасностью. Любой кто имеет доступ к репозиторию сможет получить любой доступ.
При изменении этих параметров придется заново деплоить приложение, хотя, по сути, ничего не изменилось, нет новых фич, нет исправления старых багов. Просто изменилась конфигурация.
В 2011 году разработчики компании Heroku выложили в интернете сайт, который называется 12factors. Он описывает методологию для создания веб-приложений. Она уменьшает затраты на установку и настройку приложения, повышает переносимость между средами исполнения, позволяет масштабироваться без существенных изменений в инструментах, архитектуре и практике разработки. С тех пор эта методология фактически стала стандартом в индустрии.
Рекомендуем полностью изучить этот документ. Сейчас же нас интересует один его аспект — конфигурация. Двенадцать факторов требуют строгого разделения конфигурации и кода. Конфигурация может меняться между развертываниями: локальное окружение разработчика, продакшен, среда для тестирования. Код не меняется.
Конфигурация должна передаваться в приложение снаружи. Единственный универсальный способ сделать это — использовать переменные окружения.
Переменные окружения
У Flask большое количество настроек для разных подсистем. Все они задаются в объекте app.config
. Например, так можно запустить фреймворк в режиме отладки:
# При запуске устанавливается переменная DEBUG со значением True
app.config["DEBUG"] = True
Таких переменных может быть довольно много — от настроек логгирования до путей к базе данных. Все они указываются в коде и могут загружаться из окружения.
Некоторые такие настройки конфиденциальны и должны храниться отдельно от основного кода проекта. Для этих целей используются переменные окружения:
import os
from flask import Flask
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]
У данного способа есть несколько недостатков:
- Переменные загружаются только из окружения
- Необходимо обрабатывать исключения
KeyError
- Необходимо конвертировать типы вручную (например,
DEBUG=True
из строки в bool)
Для простоты конфигурации Flask можно использовать стороннюю библиотеку python-dotenv. Она позволяет загружать переменные не только из окружения, но и из специального файла .env, который находится в корне проекта. Этот файл не должен храниться в репозитории, ведь в нем конфидециальные данные: ключи, пароли. Он специфичен для окружения, в котором идет запуск. Вот его пример:
DEBUG=True
SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///my-local-sqlite.db
CACHE_URL=memcache://127.0.0.1:11211
REDIS_URL=redis://127.0.0.1:6379/1
Это обычный текстовый файл, в каждой строке которого находится имя переменной и ее значение. python-dotenv автоматически подгружает его, и затем эти переменные используются в коде, если это необходимо.
Чтобы подключить python-dotenv, необходимо в файле инициализации приложения (например, app.py) произвести следующие настройки:
from dotenv import load_dotenv # Импортируем dotenv
import os
load_dotenv() # Загрузка переменных окружения из файла .env
Теперь можно использовать переменные окружения, которые описаны в файле .env:
from flask import Flask
import os
app = Flask(__name__)
app.config["SECRET_KEY"] = os.getenv("SECRET_KEY")
app.config["DEBUG"] = os.getenv("DEBUG", "False") == "True"
app.config["DATABASE_URL"] = os.getenv("DATABASE_URL")
WSGI
Любое веб-приложение, которое написано с использованием Flask, является WSGI-приложением — Web Server Gateway Interface. Оно используется практически всеми веб-фреймворками для Python. Это соглашение об описании веб-приложения в виде обычной функции request -> response
.
Приложение-функцию может вызывать любой WSGI-сервер, который берет на себя работу с сетью, запуск нужного количества копий приложения и раздачу им запросов.
Обычно в продакшене используют сервер с многоядерным процессором, а одновременных запросов может приходить помногу каждую секунду. Интерпретатор Python в силу особенностей реализации многопоточности не слишком эффективно работает с большим количеством одновременных задач.
WSGI-сервер знает об этих особенностях и позволяет эффективно использовать ресурсы железа. Он запускает одновременно несколько работающих интерпретаторов, следит за каждым из них и раздает им запросы поровну. А WSGI-интерфейс позволяет веб-разработчикам использовать всю возможность WSGI-серверов вне зависимости от выбранного фреймворка.
До этого момента мы запускали приложение с помощью команды flask
. Эта команда запускает WSGI-приложение на упрощенном сервере разработчика. Этот сервер может обрабатывать только один запрос за раз и не позволяет запускать несколько интерпретаторов. При этом его не нужно настраивать, а приложение он умеет перезапускать сам, как только код будет изменен.
Это очень важные качества на этапе разработки. Поэтому веб-разработчик обычно использует и dev-сервер и полноценный WSGI-сервер — один при разработке, а второй в разработке для продакшена. Запустим наше приложение на продакшен-сервере.
Gunicorn
Один из самых популярных WSGI-серверов — Gunicorn. Установим его в наш проект — в то же виртуальное окружение, в которое установили flask
:
uv add gunicorn
Когда Gunicorn будет установлен, для запуска приложения вместо команды flask
можно будет запустить приложение так:
uv run gunicorn --workers=4 --bind=127.0.0.1:8000 hello_world:app
Это пример типичной команды для запуска. Он показывает две самых важных опции Gunicorn:
- Количество интерпретаторов, которые будут выполнять код приложения — воркеры
- Адрес, запросы к которому и будет обслуживать сервер
Вот соответствующие опции в приведенной команде:
--workers=4
— использовать четыре воркера--bind=127.0.0.1:8000
— слушать порт 8000 на хосте 127.0.0.1
WSGI-приложение указывается в виде полное.имя.модуля:переменная
. Нужно указывать не имя файла, а имя модуля или пакета, который экспортирует переменную, ссылающуюся на WSGI-приложение — объект Flask.
Доставка приложений до сервера
Когда сайт написан, его нужно выложить в интернет. Стандартный путь включает три пункта:
- Покупка домена
- Покупка хостинга и его настройка
- Деплой
Рассмотрим эти пункты более подробно.
Покупка домена
Чтобы приобрести домен, необходимо обратиться в компании-регистраторы. Домен оплачивается раз в год и закрепляется за определенным человеком или компанией. Иногда хостер и регистратор — одна и та же компания. Тогда домен и сервер связываются одновременно. Иначе нужно производить определенные настройки на стороне сервера и подтверждать свое право владения доменом.
Покупка хостинга и его настройка
Хостинг — это ресурсы для размещения и обслуживания сайта в интернете. Хостинг бывает разным. Он может представлять уже полностью готовую среду, в которую заливается код сайта. Также он может быть просто железными серверами, которыми можно и нужно управлять самостоятельно.
Обычно работа с хостингом выглядит следующим образом:
- Производится регистрации на сайте хостинга
- Выбирается подходящий тариф и вид хостинга (On-Prem, IaaS, PaaS, SaaS) и привязывается банковская карточка
- Предоставляется доступ к ресурсам, например, IP-адрес и пара логин/пароль для ssh- или ftp-доступа
- При необходимости производится настройка хостинга и деплой проекта
Деплой
Деплой — процесс выкладки новой версии сайта на сервер. Этот процесс может быть довольно сложным и зависит от используемых технологий. Во время деплоя могут выполняться следующие задачи:
- Код проекта скачивается на сервер — обычно через клонирование Git
- Ставятся все необходимые зависимости
- Выполняется процесс сборки, например, собирается фронтенд-часть
- Выполняются миграции — SQL-скрипты, которые изменяют структуру базы данных
- Запускается новая версия кода
Во многих компаниях этот процесс выполняется руками. Программист заходит на сервер, запускает git pull
и далее проходится по списку выше. Это худший способ деплоить. Деплой относится к тем задачам, которые должны быть автоматизированы.
Несмотря на разнообразие способов деплоя, есть одно важное правило для всех — деплоить можно только вперед. Деплой нельзя откатывать. И в первую очередь это касается миграций. Если после или во время деплоя что-то пошло не так, то правильно деплоить снова, но предыдущую версию.
Также деплои можно классифицировать по способу обновления и отката:
- Последовательное обновление — сервера обновляются по очереди
- Сине-Зеленый деплой — полное дублирование инфраструктуры с подменой
Отдельно стоит сказать про канареечный релиз — canary release. При таком подходе переключение на использование новой версии происходит постепенно — сначала для небольшого процента пользователей, а затем и для всех.
Способ деплоя зависит от используемого хостинга и способа настройки серверного окружения. Выделяют следующие типы хостингов:
- Виртуальный хостинг (Shared Hosting) — самый дешевый способ размещать сайт в интернете. Такая услуга включает доступ на сервер с уже настроенным программным обеспечением под конкретный стек, например, Linux + Python + MySQL. Этот способ подходит для самых простых сайтов и требует минимальной настройки
- VPS/VDS — наиболее сбалансированная услуга, в рамках которой предоставляется виртуальная машина. Плюс в том, что такой вид хостинга позволяет задействовать больше серверных мощностей: ЦПУ, память и диск. Предустановленного ПО нет, все нужно делать самостоятельно. По сравнению с виртуальным хостингом мы не ограничены в правах и можем настраивать сервер как угодно
- Выделенный сервер (Dedicated Server) — сервер либо свой, либо арендованный. Такой хостинг требует больше всего участия, но зато мы получаем лучшее соотношение производительность/цена
- IaaS (Infrastructure as a Service) — инфраструктура как сервис. Вид хостинга, при котором большая часть возможностей представляется как сервис, например, Amazon Web Service (AWS)
- PaaS (Platform as a Service) — платформа как сервис. Наиболее дорогой и самый автоматизированный способ из коробки по размещению сайтов. Выкладка сайта происходит по команде
git push
. Кроме цены важно учитывать используемые технологии и подходы. PaaS обладает наибольшим числом ограничений по тому, что и как можно делать, но в обмен мы получаем не просто автоматизированный хостинг, но и платформу, которая автоматически масштабируется под нагрузку
Все способы деплоя можно разбить на две большие категории: деплой на PaaS и деплой на все остальное.
Деплой на PaaS
Самый простой способ начать деплоить. Большинство PaaS-хостеров имеют бесплатные планы, достаточные для публикации учебных проектов. Из плюсов: не придется покупать адрес, домен третьего уровня предоставляется бесплатно.
Самое популярное PaaS-решение на текущий день — Heroku. Также в качестве бесплатной альтернативы Heroku мы предлагаем Render. Он поддерживает деплой как из Github репозиториев, так и из локальных с помощью cli-утилиты.
Деплой на все остальное
Если не брать в расчет самый примитивный виртуальный хостинг, который не позволяет настраивать серверное окружение, все остальные виды хостингов имеют схожие задачи для публикации.
Самая первая задача — настроить окружение. Если в виртуальном хостинге всегда есть набор предустановленных программ, то в остальных видах хостинга нет ничего, кроме голой операционной системы. Установка необходимого ПО такой же автоматизируемый процесс, как процесс деплоя, и у него есть даже собственное название — Управление конфигурациями (Configuration Management).
Рекомендуем использовать Ansible — популярное решение для настройки. На Хекслете есть соответствующий курс.
Ключевое понятие Ansible — Playbook (плейбук). Это файл или файлы в формате YAML. В них описывается, что нужно сделать на указанной машине. В каждом плейбуке используются готовые модули, которые поставляются вместе с Ansible. Этих модулей сотни, с помощью них можно делать практически всё: от установки программ до настройки сети и управления правами файловой системы.
Например, для установки python нужно воспользоваться следующим playbook:
- hosts: all
tasks:
- lineinfile:
create: yes
regexp: ~/.local
path: ~/.bash_profile
line: "export PATH=$PATH:~/.local/bin"
- name: install packages
apt: pkg=python3-pip state=latest update_cache=yes
tags: pip
become: yes
- pip:
name: pip
state: latest
become: yes
Ansible — универсальный инструмент, с его помощью можно не только настраивать окружение, но и деплоить. При этом для деплоя есть готовый модуль — deploy helper.
В более продвинутых случаях, там где используется, например, Docker, развертывание осуществляется системами оркестрации, среди которых выделяется Kubernetes.
Самостоятельная работа
Выложите на Render тот код, который вы написали в течение этого курса
Эталонный проект
Дополнительные материалы
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.