Запуск нескольких (Flask) сайтов с одной установкой Docker
Разделяя код и (опционально) шаблоны, мы избегаем копирования и сокращаем время обслуживания.
Я разработал один сайт Flask на Docker , но через некоторое время, когда мой код стал более стабильным, я захотел использовать такую же установку для других сайтов. Для одного сайта я сделал копию, потому что он должен был работать вчера. Но на самом деле я хотел поделиться всем кодом и некоторыми шаблонами. Конечно, каждый сайт имеет свой собственный статический каталог, каталог логов, шаблоны и т.д. Основная причина для обмена заключается в том, что код все еще находится в тяжелой разработке, и я не хочу поддерживать несколько копий одного и того же кода.
Расширение моего скрипта для сборки и запуска Docker
Я написал интерактивный сценарий, который я использую для сборки Docker image и запуска контейнера Docker с соответствующей версией. С их помощью я могу запускать разработку, тестирование и staginglocal, и staging , а производственные, контейнеры даже параллельные. Я просто открываю другое окно терминала и запускаю свой стартовый скрипт Docker . Мне пришлось использовать этот скрипт для поддержки нескольких сайтов. В главном каталоге есть два подкаталога:
- docker-templates
- docker-versions
Docker-templates содержит шаблоны Docker-compose при создании новой версии для сайта. Версия всегда означает новый набор файлов docker-compose и файл с переменными окружения. Кроме того, для staging и производственной версии, она также будет содержать (tarred) Docker image и, опционально, статический дамп каталога и базы данных.
Сценарий Docker собирает файлы из соответствующей директории docker-templates , генерирует новый номер версии, исправляет новый номер версии в файлах, создает директорию новой версии в docker-versions и помещает файлы туда. Эта установка позволяет мне вносить изменения в Docker-compose и файлы окружения в docker-templates. Новые версии включают последние изменения, а старые версии остаются неизменными. Для разработки и тестирования все файлы приложения находятся вне контейнера, что означает, что генерация нового образа необходима только при добавлении или удалении пакетов (requirements.txt). Новая структура каталогов:
.
|-- docker-templates
| `-- sites
| |-- peterspython
| | |-- docker-compose_development.yml
| | |-- docker-compose_production.yml
| | |-- docker-compose_shared.yml
| | |-- docker-compose_staginglocal.yml
| | |-- docker-compose_staging.yml
| | |-- docker-compose_testing.yml
| | |-- env_development
| | |-- env_production
| | |-- env_staging
| | |-- env_staginglocal
| | `-- env_testing
| `-- anothersite
| |-- docker-compose_development.yml
| |-- docker-compose_production.yml
| |-- docker-compose_shared.yml
| |-- docker-compose_staginglocal.yml
| |-- docker-compose_staging.yml
| |-- docker-compose_testing.yml
| |-- env_development
| |-- env_production
| |-- env_staging
| |-- env_staginglocal
| `-- env_testing
|-- docker-versions
| `-- sites
| |-- peterspython
| | |-- 1.821_development
| | | |-- deployment.env
| | | |-- docker-compose_deployment.yml
| | | `-- docker-compose_shared.yml
| | | ...
| | |-- 1.829_production
| | | |-- deployment.env
| | | |-- docker-compose_deployment.yml
| | | |-- docker-compose_shared.yml
| | | `-- peterspython_web_production_image_1.829.tar
| `-- anothersite
| |-- 1.778_development
| | |-- deployment.env
| | |-- docker-compose_deployment.yml
| | `-- docker-compose_shared.yml
| `-- 1.779_development
| |-- deployment.env
| |-- docker-compose_deployment.yml
| `-- docker-compose_shared.yml
|-- project
Стартовый скрипт Docker позволяет мне выбрать веб-сайт (peterspython, anothersite), а затем представляет мне меню всех версий. Когда я выбираю версию, мне представляется меню со списком действий, таких как запуск контейнера, выполнение в контейнер и т.д. Перед началом действия стартовый скрипт Docker копирует файлы из каталога docker-версии в основной каталог так, чтобы у нас всегда были файлы в том же месте, как если бы мы запускали один сайт.
Обратите внимание, что эта установка не конфликтует с тем, как работает Docker . После того, как мы запустим контейнер Docker с Docker-compose, мы можем удалить файлы docker-compose и переменные окружения. Когда вы перезапускаете Docker в определенный момент, он просто перезапускает ранее запущенные контейнеры без необходимости использования этих файлов.
Расширение структуры каталога проекта
Я хотел поделиться всем кодом между сайтами, но хотел, чтобы у них были свои собственные шаблоны, статический каталог, лог-файлы и т.д. Новая структура каталогов проекта:
.
|-- app
| |-- blueprints
| |-- factory.py
| |-- services.py
| `-- templates
|-- sites
| |-- peterspython
| | |-- docker-volumes
| | |-- static
| | |-- stylesheets
| | `-- templates
| `-- anothersite
| |-- docker-volumes
| |-- static
| |-- stylesheets
| `-- templates
|
|-- app_run.py
|-- Dockerfile
|
Код в приложении является общим. Docker-volumes - это монтирование тома для лог-файлов и т.д. Отличием от односайтовой установки является расположение файла конфигурации Flask config.py. Я загружаю этот файл в create_app() с помощью метода from_object(). Чтобы убедиться, что файл может быть найден, я добавляю директорию файла, указанную переменными окружения Docker , в sys.path:
def create_app(deploy_config):
...
# to find config.py
sys.path.insert(0, project_docker_volume_config_dir)
# load config
app.config.from_object(all_configs[deploy_config])
Другое отличие от единой настройки сайта - это шаблоны. Я хочу, чтобы он работал следующим образом. Когда каталог сайта не содержит шаблона, то он возвращается в каталог шаблонов приложений. Очень легко сказать Jinja , где искать шаблоны. Jinja поддерживает множество загрузчиков, я выбрал ChoiceLoader:
from jinja2 import (
ChoiceLoader,
)
def create_app(deploy_config):
...
# set template paths
template_loader = ChoiceLoader([
# site templates
app.jinja_loader,
# default templates
FileSystemLoader('/home/flask/project/app/templates')
])
app.jinja_loader = template_loader
...
Заключение
Здесь я представил способ, как поделиться кодом и (опционально) шаблонами между несколькими сайтами, не делая копию всего дерева каталогов для нового сайта. Хотя есть много вещей, которые можно улучшить, я использую этот способ и счастлив, что на это уделил время.
Ссылки / кредиты
API
https://jinja.palletsprojects.com/en/2.11.x/api/
Подробнее
Docker Docker-compose Flask
Недавний
- Скрытие первичных ключей базы данных UUID вашего веб-приложения
- Don't Repeat Yourself (DRY) с Jinja2
- SQLAlchemy, PostgreSQL, максимальное количество строк для user
- Показать значения в динамических фильтрах SQLAlchemy
- Безопасная передача данных с помощью шифрования Public Key и pyNaCl
- rqlite: альтернатива dist с высокой степенью готовности и SQLite
Большинство просмотренных
- Используя Python pyOpenSSL для проверки SSL-сертификатов, загруженных с хоста
- Использование UUID вместо Integer Autoincrement Primary Keys с SQLAlchemy и MariaDb
- Подключение к службе на хосте Docker из контейнера Docker
- Использование PyInstaller и Cython для создания исполняемого файла Python
- SQLAlchemy: Использование Cascade Deletes для удаления связанных объектов
- Flask Удовлетворительный запрос API проверка параметров запроса с помощью схем Маршмэллоу