Написание снапшот-воркфлоу
Вы уже достаточно часто пользовались dwe snapshot create и restore, чтобы знать их с точки зрения потребителя (см. switching-tasks-with-snapshots.md). Теперь вы хотите написать workspace/snapshot.yml, который ими управляет, — решить, что захватывается, что восстанавливается, что переживает восстановление и что подчищается при удалении.
Это руководство проходит по файлу от минимально полезной формы до тонких настроек для боевого использования, которые понадобятся, когда коллеги начнут обмениваться снапшотами.
Разделы
Заголовок раздела «Разделы»- Минимальный воркфлоу
- Шаблонный неймспейс
${snapshot.*} - Воркфлоу переиспользуют ваши пользовательские команды
- Варианты — альтернативные списки шагов
require_matching_configиconfig_hash- Политика
services_mismatch local_yml.preserve_keys— сохранить машинно-локальные оверрайдыpack.exclude— не включать временные файлы в архивыrollback_target— откат одной командойremove:— подчистка внешних ресурсов
Минимальный воркфлоу
Заголовок раздела «Минимальный воркфлоу»Достаточно snapshot.yml с одним шагом, чтобы захватить и восстановить базу:
create: description: Capture the main DB steps: - command: db.dump with: { out: ${snapshot.path}/db/main.sql.gz }
restore: description: Restore the main DB steps: - command: db.restore with: { in: ${snapshot.path}/db/main.sql.gz }db.dump и db.restore — это ваши собственные пользовательские команды; DWE не поставляет бэкенд для баз данных (см. author-project-commands.md, если вы их ещё не написали). Подсистема снапшотов лишь оркеструет процесс: берёт локи проекта, создаёт ./snapshots/<имя>/, запускает ваши create-шаги с подставленным ${snapshot.path} и затем пишет манифест.
Справочник: ../reference/config/snapshot.md.
Шаблонный неймспейс ${snapshot.*}
Заголовок раздела «Шаблонный неймспейс ${snapshot.*}»${snapshot.path} — это абсолютный путь к ./snapshots/<имя>/; именно туда ваш create-воркфлоу пишет артефакты и откуда restore-воркфлоу их читает. Воркфлоу должны писать внутри этого пути; симлинки, положенные внутрь каталога снапшота, отклоняются при сканировании сразу после создания.
Полный неймспейс:
| Переменная | create | restore / remove |
|---|---|---|
${snapshot.name} | ✓ | ✓ |
${snapshot.path} | ✓ | ✓ |
${snapshot.description} | ✓ | ✓ |
${snapshot.variant} | ✓ | ✓ |
${snapshot.created_at} | ошибка (ещё не существует) | ✓ |
Вне блоков снапшот-воркфлоу ${snapshot.*} вызывает ошибку на этапе компиляции: проверка области видимости срабатывает до рендера шаблона. Случайно прочитать ${snapshot.path} из обычной команды db.dump, вызванной вне контекста снапшота, не получится; та же db.dump подхватывает ${snapshot.path}, только когда её вызывают через блок with: снапшот-воркфлоу.
Воркфлоу переиспользуют ваши пользовательские команды
Заголовок раздела «Воркфлоу переиспользуют ваши пользовательские команды»Шаги снапшот-воркфлоу имеют ту же форму WorkflowStep, что и у пользовательских команд type: workflow: command:, with:, when:, confirm:, parallel:, continue_on_error:. Никакого особого синтаксиса для снапшотов и никакой отдельной модели исполнения нет: всё, что вы заложили в свои пользовательские команды (параметры, валидация, уведомления), работает и здесь.
Это значит, что снапшот с несколькими хранилищами строится просто как больше шагов, вызывающих больше команд:
create: description: Capture full env steps: - command: db.dump with: { out: ${snapshot.path}/db/main.sql.gz } - command: opensearch.snapshot with: { out: ${snapshot.path}/search/index.tar } - command: redis.dump with: { out: ${snapshot.path}/redis/dump.rdb }restore: устроен так же, но вызывает соответствующие пользовательские команды *.restore. Условное восстановление — «только если файл есть» — задаётся предикатом when: на шаге:
restore: steps: - command: opensearch.restore when: file-exists ${snapshot.path}/search/index.tar with: { in: ${snapshot.path}/search/index.tar }Полный справочник workflow-шага — в ../reference/config/commands/types.md.
Варианты — альтернативные списки шагов
Заголовок раздела «Варианты — альтернативные списки шагов»Блок воркфлоу может объявить именованные альтернативные списки шагов в variants:. Используйте их, когда «захватить всё» и «захватить только базу» должны сосуществовать, не дублируя родительский воркфлоу копипастой:
create: description: Capture full env steps: - command: db.dump with: { out: ${snapshot.path}/db/main.sql.gz } - command: opensearch.snapshot with: { out: ${snapshot.path}/search/index.tar } variants: db-only: description: Capture DB only steps: - command: db.dump with: { out: ${snapshot.path}/db/main.sql.gz } with-search: description: Capture DB + search steps: - command: db.dump with: { out: ${snapshot.path}/db/main.sql.gz } - command: opensearch.snapshot with: { out: ${snapshot.path}/search/index.tar }Выбор варианта на create:
dwe snapshot create wip-x # дефолтный блокdwe snapshot create wip-x --using=db-onlyВыбранный вариант фиксируется в манифесте снапшота, так что dwe snapshot restore wip-x автоматически берёт restore.variants.db-only, если он есть. Если соответствующего варианта восстановления нет, restore откатывается к блоку restore: по умолчанию — удобно, когда асимметрия сводится к «захватить меньше, восстановить тем же способом».
Имена вариантов должны соответствовать [a-z0-9][a-z0-9._-]{0,30}. Запрос несуществующего варианта при create завершается ошибкой ещё до каких-либо изменений в файловой системе, поэтому создать наполовину сломанный снапшот невозможно.
require_matching_config и config_hash
Заголовок раздела «require_matching_config и config_hash»Каждый снапшот фиксирует config_hash проекта на момент создания (дайджест от итогового deploy-конфига). При восстановлении DWE сравнивает его с хешем текущего состояния деплоя. По умолчанию несовпадение — мягкое предупреждение в stderr.
Включите строгий режим, когда восстановление поверх несовпадающего конфига было бы заведомо опасным — например, если ваш db.restore-воркфлоу рассчитан на конкретную версию схемы:
require_matching_config: trueПри строгой проверке restore прерывается (exit 1), если хеши расходятся. Пустой config_hash в манифесте — снапшот создан до того, как прошёл хоть один деплой — считается совпадением и никогда не блокирует.
Несовпадение config_hash на практике означает одно из:
- снапшот сделан на другой ветке, где содержимое
workspace/deploy.ymlилиservice.ymlотличается, - снапшот коллеги сделан на другой версии проектного конфига,
- проект был перебазирован вперёд или назад через коммит, меняющий deploy-конфиг.
Чтобы разобраться с расхождением, используйте require_matching_config: true вместе с dwe snapshot inspect <name> (она показывает зафиксированный хеш).
Политика services_mismatch
Заголовок раздела «Политика services_mismatch»Снапшоты фиксируют итоговый набор сервисов (имя + флаг enabled, отсортированные по имени) на момент создания. При восстановлении этот набор сравнивается с текущим итоговым набором проекта. Блок политики определяет, что делать, когда есть различия:
services_mismatch: policy: warn # warn (по умолчанию) | block | ignore| Политика | Поведение |
|---|---|
warn (по умолчанию) | Восстановление продолжается. Различия выводятся в запросе подтверждения; с -y они идут в stderr, и restore продолжается. |
block | Любые различия прерывают восстановление ещё до изменения workspace/local.yml (exit 1). |
ignore | Различия не показываются; восстановление продолжается молча. |
Различия группируются в три категории — только в снапшоте, только локально, различается enabled — и та же группировка появляется в dwe snapshot inspect и валидаторе snapshot.<name>.services_diff. Выбирайте block, когда снапшот используется неинтерактивно (CI или скрипты) и молчаливое продолжение при несовпадении приведёт к сбою дальше по цепочке, который трудно диагностировать.
local_yml.preserve_keys — сохранить машинно-локальные оверрайды
Заголовок раздела «local_yml.preserve_keys — сохранить машинно-локальные оверрайды»workspace/local.yml входит в снапшот. В большинстве случаев это и нужно: восстановление снапшота должно вернуть локальные переключатели, которые были у коллеги на момент создания. Но машинно-локальные значения (порты, переназначенные из-за того, что 5432 локально занят; хосты, указывающие на приватный DNS) переноситься не должны.
local_yml.preserve_keys — это список dot-путей, чьи текущие локальные значения переживают восстановление:
local_yml: preserve_keys: - services.main.ports - services.db.ports - vars.host.shell- Dot-пути указывают на вложенные ключи маппингов. Сегменты с индексами массива (
services[0].ports) не поддерживаются. - Пути, которых нет ни с одной из сторон, просто молча игнорируются.
- Порядок и YAML-комментарии на нетронутых узлах сохраняются там, где их удерживает
yaml.v3; flow/block-стиль и отступы при сериализации могут нормализоваться.
При создании перечисленные пути вырезаются из захваченного local.yml. При восстановлении захваченный local.yml накладывается поверх текущей копии, а сохраняемые ключи вставляются обратно из вашего рабочего файла. Если снапшот не содержит local.yml вовсе, но у вас локально есть сохраняемые значения, записывается минимальный local.yml только с сохраняемыми ключами.
Типичный выбор: что-нибудь под services.<name>.ports, что-нибудь под services.<name>.hosts, пути к локальным инструментам разработки, различающиеся в зависимости от ОС.
pack.exclude — не включать временные файлы в архивы
Заголовок раздела «pack.exclude — не включать временные файлы в архивы»dwe snapshot pack <name> создаёт один файл ./snapshots/<name>.tar.gz. Если ваш create-воркфлоу оставляет временные файлы, промежуточные дампы или что-то ещё, чем вы не хотите делиться с коллегой, исключите их с помощью doublestar-шаблонов:
pack: exclude: - "**/*.tmp" - ".cache/**" - "**/*.log"Шаблоны вычисляются относительно каталога снапшота. CLI-флаг dwe snapshot pack --exclude=<glob> дополняет этот список, а не заменяет его — то есть exclude в snapshot.yml задаёт базовый набор, который можно расширять при каждом вызове, а не значение по умолчанию, которое можно переопределить.
При распаковке архив проверяется по содержимому относительно manifest.yml. Исключённые файлы не попадают в манифест и не участвуют в проверке целостности, поэтому исключать временный вывод безопасно.
rollback_target — откат одной командой
Заголовок раздела «rollback_target — откат одной командой»Если один из снапшотов — это эталонное «безопасное» состояние (обычно baseline, снятый сразу после чистого деплоя), объявите его целью отката:
rollback_target: baselineТогда dwe snapshot rollback — это краткая форма dwe snapshot restore baseline. Команда явно завершается ошибкой, если целевого снапшота нет, а валидатор snapshot.rollback_target_exists выдаёт предупреждение при dwe validate snapshot, когда rollback_target задан, но указанного снапшота на диске нет.
baseline — это просто соглашение; подойдёт любое существующее имя снапшота. Соглашение окупается тем, что каждое руководство, runbook и привычка могут однозначно ссылаться на «откат». См. switching-tasks-with-snapshots.md — взгляд со стороны потребителя.
remove: — подчистка внешних ресурсов
Заголовок раздела «remove: — подчистка внешних ресурсов»dwe snapshot remove <name> удаляет ./snapshots/<name>/ с диска. Если снапшоту соответствует ещё и внешнее состояние — объекты в S3-бакете, строки в таблице метаданных, тег в registry — объявите воркфлоу remove:, который запускается перед удалением каталога:
remove: description: Drop external artifacts for this snapshot steps: - command: s3.remove with: { prefix: snapshots/${snapshot.name}/ } - command: registry.untag when: file-exists ${snapshot.path}/registry-tag with: { tag: "${snapshot.name}" }remove: опционален. Без него dwe snapshot remove просто вызывает os.RemoveAll(snapshotDir) и сбрасывает указатель current, если тот ссылался на этот снапшот. С ним сначала запускается воркфлоу — ${snapshot.*} доступны в области видимости restore (поэтому ${snapshot.created_at} тоже доступен), — а затем удаляется каталог. Сбой воркфлоу прерывает удаление: каталог остаётся на месте, чтобы вы могли разобраться и перезапустить.
Сочетайте remove: с pack.exclude, когда вы поставляете артефакты, на которые ссылаются внешние системы: локальный файл — это маркер, который воркфлоу читает, чтобы понять, что нужно подчистить на удалённой стороне.
См. также
Заголовок раздела «См. также»- switching-tasks-with-snapshots.md — взгляд со стороны потребителя: когда создавать, восстанавливать, откатывать, упаковывать
../reference/config/snapshot.md— полный справочник поsnapshot.yml../reference/config/commands/types.md— форма workflow-шага, переиспользуемая блоками снапшота- author-project-commands.md — написание команд
db.dump/db.restore, которые вызывают снапшот-воркфлоу