Consul
Consul служит хранилищем конфигурации ключей-значений (KV) для Meduza. Конфигурация приложений — URL баз данных, API-ключи, feature-флаги — хранится в виде JSON в KV-хранилище Consul и инжектится в контейнеры при деплое через блок template в Nomad.
Структура KV-хранилища
Конфигурация организована по сервисам и окружениям:
hub/
├── prod/
│ └── config → {"DATABASE_URL": "...", "API_KEY": "...", ...}
├── stage/
│ └── config → {"DATABASE_URL": "...", "API_KEY": "...", ...}
└── dev/
└── config → {"DATABASE_URL": "...", "API_KEY": "...", ...}Каждый ключ config содержит один JSON-объект, где ключи — это имена переменных окружения, а значения — соответствующие значения:
{
"DATABASE_URL": "postgresql://user:pass@db-host:5432/hub_prod",
"REDIS_URL": "redis://redis-host:6379/0",
"API_KEY": "sk-prod-abc123",
"LOG_LEVEL": "info",
"FEATURE_NEW_DASHBOARD": "true"
}WARNING
Значения Consul KV хранятся незашифрованными по умолчанию. Чувствительные данные (пароли к базам данных, API-ключи) видны любому, кто имеет доступ к UI или API Consul. Ограничьте доступ к порту Consul (8500) и используйте SSH-туннелирование.
Как Nomad читает конфигурацию Consul
Блок template в Nomad связывает данные Consul KV с работающими контейнерами. Вот паттерн, используемый в задаче backend для hub:
task "backend" {
driver = "docker"
# ...
template {
data = <<-TPL
{{ with consulKey "hub/${var.env}/config" }}
{{ range $key, $value := .Data | parseJSON }}
{{ $key }}={{ $value }}
{{ end }}
{{ end }}
TPL
destination = "secrets/env.env"
env = true
}
}Что это делает
consulKey "hub/${var.env}/config"— читает необработанное значение из пути Consul KV (например,hub/prod/config).parseJSON— парсит JSON-строку в Go-карту.range $key, $value— итерирует по каждой паре ключ-значение.$key=$value— записывает каждую пару в форматеKEY=VALUE.destination = "secrets/env.env"— результат рендеринга записывается в этот файл внутри директории аллокации.env = true— указывает Nomad парсить файл как переменные окружения и инжектить их в окружение контейнера.
Результат рендеринга
Для JSON-конфигурации выше файл secrets/env.env будет выглядеть так:
DATABASE_URL=postgresql://user:pass@db-host:5432/hub_prod
REDIS_URL=redis://redis-host:6379/0
API_KEY=sk-prod-abc123
LOG_LEVEL=info
FEATURE_NEW_DASHBOARD=trueЭти значения становятся переменными окружения, доступными приложению внутри контейнера.
flowchart LR
Consul["Consul KV\nhub/prod/config\n(JSON)"]
Template["Nomad Template\nBlock"]
EnvFile["secrets/env.env\nKEY=VALUE lines"]
Container["Container\nEnvironment"]
Consul -->|"consulKey"| Template
Template -->|"parseJSON + range"| EnvFile
EnvFile -->|"env = true"| ContainerОбновление конфигурации
Через Consul CLI
# Read current config
consul kv get hub/prod/config | jq .
# Update config (replace entire JSON blob)
consul kv put hub/prod/config @config.json
# Update config inline
consul kv put hub/prod/config '{
"DATABASE_URL": "postgresql://user:pass@db-host:5432/hub_prod",
"REDIS_URL": "redis://redis-host:6379/0",
"API_KEY": "sk-prod-new-key",
"LOG_LEVEL": "debug",
"FEATURE_NEW_DASHBOARD": "true"
}'Через Consul HTTP API
# Read
curl -s http://localhost:8500/v1/kv/hub/prod/config?raw | jq .
# Write (value must be the raw body)
curl -X PUT \
-d '{"DATABASE_URL":"postgresql://...","LOG_LEVEL":"debug"}' \
http://localhost:8500/v1/kv/hub/prod/configЧерез Consul UI
- SSH-туннель к хосту:
ssh -L 8500:localhost:8500 user@kvm-host - Откройте
http://localhost:8500в браузере - Перейдите в Key/Value >
hub>prod>config - Отредактируйте JSON и нажмите Save
TIP
После обновления значения Consul KV необходимо переразвернуть Nomad-задачу, чтобы изменения вступили в силу. Блок template вычисляется при деплое, а не во время выполнения.
# Re-deploy to pick up new config
nomad job run -var-file=prod.vars.hcl hub.nomad.hclРабочий процесс: добавление новой переменной конфигурации
Определите имя и значение переменной — следуйте конвенции
UPPER_SNAKE_CASE.Прочитайте текущую конфигурацию, чтобы не перезаписать существующие значения:
bashconsul kv get hub/prod/config | jq . > /tmp/config.jsonОтредактируйте JSON, добавив или изменив переменную:
bash# Using jq to add a key jq '. + {"NEW_VARIABLE": "new-value"}' /tmp/config.json > /tmp/config-updated.jsonЗапишите обратно в Consul:
bashconsul kv put hub/prod/config @/tmp/config-updated.jsonПереразверните Nomad-задачу:
bashnomad job run -var-file=prod.vars.hcl hub.nomad.hclУбедитесь, что переменная присутствует в работающем контейнере:
bashnomad alloc exec <alloc-id> env | grep NEW_VARIABLE
WARNING
Всегда выполняйте чтение-изменение-запись для всего JSON-блоба. Команда Consul KV put заменяет всё значение целиком — она не объединяет. Если вы запишете частичный JSON-объект, вы потеряете все остальные переменные конфигурации.
Изоляция окружений
Каждое окружение имеет собственный KV-путь, обеспечивая полную изоляцию:
| Окружение | KV-путь | Переменная Nomad |
|---|---|---|
| prod | hub/prod/config | var.env = "prod" |
| stage | hub/stage/config | var.env = "stage" |
| dev | hub/dev/config | var.env = "dev" |
Один и тот же блок template работает для всех окружений, потому что он подставляет ${var.env} в KV-путь:
consulKey "hub/${var.env}/config"Это означает, что один файл задачи (hub.nomad.hcl) может деплоиться в любое окружение, просто изменяя переменную env.
Резервное копирование и восстановление
Данные Consul KV следует регулярно резервировать. Потеря KV-хранилища означает, что всю конфигурацию приложений придётся воссоздавать вручную.
# Export all KV data as JSON
consul kv export hub/ > hub-kv-backup.json
# Import from backup
consul kv import @hub-kv-backup.jsonTIP
Храните резервные копии KV в системе контроля версий или в безопасном месте для бэкапов. Это ваш источник истины для конфигурации приложений.