[Python, IT-инфраструктура, Администрирование баз данных, DevOps, Микросервисы] Vault+Pydantic: продолжение саги, локальная разработка
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Предыстория
Предыдущая статья
В предыдущей статье я писал о том, как сконфигурировать ваше приложение с помощью Sitri, однако, упустил момент с локальной разработкой, так как согласитесь, что не очень удобно разворачивать vault локально, да и хранить локальный конфиг в общем vault, особенно, если над проектом работают несколько человек — неудобнее вдвойне.
В Sitri данная проблема решается достаточно просто — с помощью локального режима для ваших классов настроек, то есть вам не придётся даже переписывать ничего или дублировать код, да и структура json файла для локального режима будет почти полностью повторять структуру секретов.
Итак, ну а теперь, давайте добавим в наш проектик буквально пару строк кода + я покажу, как со всем этим можно работать, если ваш проект локально запускается в docker-compose.
Готовим код
Для начала, давайте договоримся, что local_mode действует тогда, когда ENV = "local" :) Далее, я предлагаю немного отредактировать наш provider_config.py и создать там класс BaseConfig от которого мы будем наследовать в наших настройках Config классы. Мы сделаем это для того, чтобы не дублировать код, то есть в самих классах настроек будет только то, что специфично для них.
import hvac
from sitri.providers.contrib.system import SystemConfigProvider
from sitri.providers.contrib.vault import VaultKVConfigProvider
from sitri.settings.contrib.vault import VaultKVSettings
configurator = SystemConfigProvider(prefix="superapp")
ENV = configurator.get("env")
is_local_mode = ENV == "local"
local_mode_file_path = configurator.get("local_mode_file_path")
def vault_client_factory() -> hvac.Client:
client = hvac.Client(url=configurator.get("vault_api"))
client.auth_approle(
role_id=configurator.get("role_id"),
secret_id=configurator.get("secret_id"),
)
return client
provider = VaultKVConfigProvider(
vault_connector=vault_client_factory,
mount_point=f"{configurator.get('app_name')}/{ENV}",
)
class BaseConfig(VaultKVSettings.VaultKVSettingsConfig):
provider = provider
local_mode = is_local_mode
local_provider_args = {"json_path": local_mode_file_path}
Немного про local_provider_args в этом поле мы указываем аргументы для создания экземпляра JsonConfigProvider, они будут провалидированы и данный словарь должен соотвествовать схеме, поэтому не волнуйтесь — это не какой-то грязный приём. Однако, если вы хотите создать экземпляр локального провайдера сами, то вы просто положить его в опциональное поле local_provider.
Теперь, мы можем спокойно наследовать конфиг классы от базового. Например, класс настроек для соединения с Kafka будет выглядеть так:
from typing import Any, Dict
from pydantic import Field
from sitri.settings.contrib.vault import VaultKVSettings
from superapp.config.provider_config import BaseConfig, configurator
class KafkaSettings(VaultKVSettings):
mechanism: str = Field(..., vault_secret_key="auth_mechanism")
brokers: str = Field(...)
auth_data: Dict[str, Any] = Field(...)
class Config(BaseConfig):
default_secret_path = "kafka"
default_mount_point = f"{configurator.get('app_name')}/common"
local_mode_path_prefix = "kafka"
Как видите требуемые изменения минимальны. local_mode_path_prefix мы указываем, чтобы в нашем json файле сохранялась структура общего конфига. А теперь, давайте напишем этот самый json файл для локальной конфигурации:
{
"db":
{
"host": "testhost",
"password": "testpassword",
"port": 1234,
"user": "testuser"
},
"faust":
{
"agents":
{
"X":
{
"concurrency": 2,
"partitions": 5
}
},
"app_name": "superapp-workers",
"default_concurrency": 5,
"default_partitions_count": 10
},
"kafka":
{
"auth_data":
{
"password": "testpassword",
"username": "testuser"
},
"brokers": "kafka://test",
"mechanism": "SASL_PLAINTEXT"
}
}
… Ну, или просто скопипастим его из конца прошлой статьи. Как видите, тут всё весьма просто. Для наших дальнейших изысканий, переименуем main.py в корне проекта на __main__.py, чтобы можно было запустить пакет командой из docker-compose.
Запихиваем приложение в контейнер и наслаждаемся сборкой
Первое, что мы должны сделать — это написать небольшой Dockerfile:
FROM python:3.8.3-buster
ENV PYTHONUNBUFFERED=1 \
POETRY_VIRTUALENVS_CREATE=false \
POETRY_VIRTUALENVS_IN_PROJECT=false \
POETRY_NO_INTERACTION=1
RUN pip install poetry
RUN mkdir /superapp/
WORKDIR /superapp/
COPY ./pyproject.toml ./poetry.lock /superapp/
RUN poetry install --no-ansi
WORKDIR /
Здесь мы просто устанавливаем зависимости и всё, так как он для локальной разработки, то код проекта мы не копируем.
Далее, нам понадобиться env-файл с необходимыми для local-mode переменными:
SUPERAPP_ENV=local
SUPERAPP_LOCAL_MODE_FILE_PATH=/config.json
SUPERAPP_APP_NAME=superapp
Как видите, ничего лишнего, никакой конфигурационной информации для Vault не нужно, так как при локальном режиме, приложение даже не попытается постучаться в Vault.
Ну и последнее, что мы должны написать — сам docker-compose.yml файл:
# docker-compose config for local development
version: '3'
services:
superapp:
command: python3 -m superapp
restart: always
build:
context: ./
dockerfile: Dockerfile
volumes:
- ./superapp:/superapp
- ./config.json:/config.json
env_file:
- .env.local
Как видите, тут тоже всё просто. Наш json-файл мы кладём в корень, как и указали выше в переменной окружения для контейнера.
Ну а теперь, запуск:
docker-compose up
Creating article_sitri_vault_pydantic_superapp_1 ... done
Attaching to article_sitri_vault_pydantic_superapp_1
superapp_1 | db=DBSettings(user='testuser', password='testpassword', host='testhost', port=1234) faust=FaustSettings(app_name='superapp-workers', default_partitions_count=10, default_concurrency=5, agents={'X': AgentConfig(partitions=5, concurrency=2)}) kafka=KafkaSettings(mechanism='SASL_PLAINTEXT', brokers='kafka://test', auth_data={'password': 'testpassword', 'username': 'testuser'})
superapp_1 | {'db': {'user': 'testuser', 'password': 'testpassword', 'host': 'testhost', 'port': 1234}, 'faust': {'app_name': 'superapp-workers', 'default_partitions_count': 10, 'default_concurrency': 5, 'agents': {'X': {'partitions': 5, 'concurrency': 2}}}, 'kafka': {'mechanism': 'SASL_PLAINTEXT', 'brokers': 'kafka://test', 'auth_data': {'password': 'testpassword', 'username': 'testuser'}}}
Как видите, всё успешно запустилось и информация из нашего json-фала успешно прошла все проверки и стала настройками для локальной версии приложения, юхху!
Код этой статьи я положил в отдельную ветку, так что можете зайти, склонить и протестировать всё самолично :)
branch
===========
Источник:
habr.com
===========
Похожие новости:
- [IT-инфраструктура, Amazon Web Services, DevOps, Облачные сервисы] Анонс видеокурса «Администрирование и разработка в облачных системах на примере AWS»
- [Информационная безопасность, DevOps] Вебинар «Опыт участия в кибербитве The Standoff: анализ атак и обзор инструментов»
- [CSS, JavaScript, IT-инфраструктура, HTML] Больше, больше фронтенда — доклады c ЮMoneyDay
- [IT-инфраструктура, Управление проектами] Как попадает товар в магазины «Леруа Мерлен» с точки зрения математики заказа
- [Разработка на Raspberry Pi, Робототехника, DIY или Сделай сам] Как мы сделали простого WebRTC робота в домашних условиях
- [Программирование, Java, Администрирование баз данных, API] Java и базы данных: обзор библиотек и API (перевод)
- [Python, Django, Микросервисы, Kubernetes] Микросервисы на монолите
- [Информационная безопасность, IT-инфраструктура, IT-стандарты] Аттракцион неслыханной щедрости
- [Python, IT-инфраструктура, Терминология IT] Немного про трекинг и сервис переходов Admitad
- [Git, DevOps, Kubernetes] HelmWave v0.5.0 – GitOps для твоего Kubernetes
Теги для поиска: #_python, #_itinfrastruktura (IT-инфраструктура), #_administrirovanie_baz_dannyh (Администрирование баз данных), #_devops, #_mikroservisy (Микросервисы), #_vault, #_pydantic, #_python, #_configuration_management, #_config, #_hashicorp, #_hashicorp_vault, #_python, #_itinfrastruktura (
IT-инфраструктура
), #_administrirovanie_baz_dannyh (
Администрирование баз данных
), #_devops, #_mikroservisy (
Микросервисы
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:51
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Предыстория Предыдущая статья В предыдущей статье я писал о том, как сконфигурировать ваше приложение с помощью Sitri, однако, упустил момент с локальной разработкой, так как согласитесь, что не очень удобно разворачивать vault локально, да и хранить локальный конфиг в общем vault, особенно, если над проектом работают несколько человек — неудобнее вдвойне. В Sitri данная проблема решается достаточно просто — с помощью локального режима для ваших классов настроек, то есть вам не придётся даже переписывать ничего или дублировать код, да и структура json файла для локального режима будет почти полностью повторять структуру секретов. Итак, ну а теперь, давайте добавим в наш проектик буквально пару строк кода + я покажу, как со всем этим можно работать, если ваш проект локально запускается в docker-compose. Готовим код Для начала, давайте договоримся, что local_mode действует тогда, когда ENV = "local" :) Далее, я предлагаю немного отредактировать наш provider_config.py и создать там класс BaseConfig от которого мы будем наследовать в наших настройках Config классы. Мы сделаем это для того, чтобы не дублировать код, то есть в самих классах настроек будет только то, что специфично для них. import hvac
from sitri.providers.contrib.system import SystemConfigProvider from sitri.providers.contrib.vault import VaultKVConfigProvider from sitri.settings.contrib.vault import VaultKVSettings configurator = SystemConfigProvider(prefix="superapp") ENV = configurator.get("env") is_local_mode = ENV == "local" local_mode_file_path = configurator.get("local_mode_file_path") def vault_client_factory() -> hvac.Client: client = hvac.Client(url=configurator.get("vault_api")) client.auth_approle( role_id=configurator.get("role_id"), secret_id=configurator.get("secret_id"), ) return client provider = VaultKVConfigProvider( vault_connector=vault_client_factory, mount_point=f"{configurator.get('app_name')}/{ENV}", ) class BaseConfig(VaultKVSettings.VaultKVSettingsConfig): provider = provider local_mode = is_local_mode local_provider_args = {"json_path": local_mode_file_path} Немного про local_provider_args в этом поле мы указываем аргументы для создания экземпляра JsonConfigProvider, они будут провалидированы и данный словарь должен соотвествовать схеме, поэтому не волнуйтесь — это не какой-то грязный приём. Однако, если вы хотите создать экземпляр локального провайдера сами, то вы просто положить его в опциональное поле local_provider. Теперь, мы можем спокойно наследовать конфиг классы от базового. Например, класс настроек для соединения с Kafka будет выглядеть так: from typing import Any, Dict
from pydantic import Field from sitri.settings.contrib.vault import VaultKVSettings from superapp.config.provider_config import BaseConfig, configurator class KafkaSettings(VaultKVSettings): mechanism: str = Field(..., vault_secret_key="auth_mechanism") brokers: str = Field(...) auth_data: Dict[str, Any] = Field(...) class Config(BaseConfig): default_secret_path = "kafka" default_mount_point = f"{configurator.get('app_name')}/common" local_mode_path_prefix = "kafka" Как видите требуемые изменения минимальны. local_mode_path_prefix мы указываем, чтобы в нашем json файле сохранялась структура общего конфига. А теперь, давайте напишем этот самый json файл для локальной конфигурации: {
"db": { "host": "testhost", "password": "testpassword", "port": 1234, "user": "testuser" }, "faust": { "agents": { "X": { "concurrency": 2, "partitions": 5 } }, "app_name": "superapp-workers", "default_concurrency": 5, "default_partitions_count": 10 }, "kafka": { "auth_data": { "password": "testpassword", "username": "testuser" }, "brokers": "kafka://test", "mechanism": "SASL_PLAINTEXT" } } … Ну, или просто скопипастим его из конца прошлой статьи. Как видите, тут всё весьма просто. Для наших дальнейших изысканий, переименуем main.py в корне проекта на __main__.py, чтобы можно было запустить пакет командой из docker-compose. Запихиваем приложение в контейнер и наслаждаемся сборкой Первое, что мы должны сделать — это написать небольшой Dockerfile: FROM python:3.8.3-buster
ENV PYTHONUNBUFFERED=1 \ POETRY_VIRTUALENVS_CREATE=false \ POETRY_VIRTUALENVS_IN_PROJECT=false \ POETRY_NO_INTERACTION=1 RUN pip install poetry RUN mkdir /superapp/ WORKDIR /superapp/ COPY ./pyproject.toml ./poetry.lock /superapp/ RUN poetry install --no-ansi WORKDIR / Здесь мы просто устанавливаем зависимости и всё, так как он для локальной разработки, то код проекта мы не копируем. Далее, нам понадобиться env-файл с необходимыми для local-mode переменными: SUPERAPP_ENV=local
SUPERAPP_LOCAL_MODE_FILE_PATH=/config.json SUPERAPP_APP_NAME=superapp Как видите, ничего лишнего, никакой конфигурационной информации для Vault не нужно, так как при локальном режиме, приложение даже не попытается постучаться в Vault. Ну и последнее, что мы должны написать — сам docker-compose.yml файл: # docker-compose config for local development
version: '3' services: superapp: command: python3 -m superapp restart: always build: context: ./ dockerfile: Dockerfile volumes: - ./superapp:/superapp - ./config.json:/config.json env_file: - .env.local Как видите, тут тоже всё просто. Наш json-файл мы кладём в корень, как и указали выше в переменной окружения для контейнера. Ну а теперь, запуск: docker-compose up
Creating article_sitri_vault_pydantic_superapp_1 ... done
Attaching to article_sitri_vault_pydantic_superapp_1 superapp_1 | db=DBSettings(user='testuser', password='testpassword', host='testhost', port=1234) faust=FaustSettings(app_name='superapp-workers', default_partitions_count=10, default_concurrency=5, agents={'X': AgentConfig(partitions=5, concurrency=2)}) kafka=KafkaSettings(mechanism='SASL_PLAINTEXT', brokers='kafka://test', auth_data={'password': 'testpassword', 'username': 'testuser'}) superapp_1 | {'db': {'user': 'testuser', 'password': 'testpassword', 'host': 'testhost', 'port': 1234}, 'faust': {'app_name': 'superapp-workers', 'default_partitions_count': 10, 'default_concurrency': 5, 'agents': {'X': {'partitions': 5, 'concurrency': 2}}}, 'kafka': {'mechanism': 'SASL_PLAINTEXT', 'brokers': 'kafka://test', 'auth_data': {'password': 'testpassword', 'username': 'testuser'}}} Как видите, всё успешно запустилось и информация из нашего json-фала успешно прошла все проверки и стала настройками для локальной версии приложения, юхху! Код этой статьи я положил в отдельную ветку, так что можете зайти, склонить и протестировать всё самолично :) branch =========== Источник: habr.com =========== Похожие новости:
IT-инфраструктура ), #_administrirovanie_baz_dannyh ( Администрирование баз данных ), #_devops, #_mikroservisy ( Микросервисы ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:51
Часовой пояс: UTC + 5