deploy.yml / reset.yml
Декларации пайплайнов деплоя и сброса.
Содержание
Заголовок раздела «Содержание»- Назначение
- Роли файлов
- Структура
- Поля верхнего уровня
- Поля фазы
- Поля шага
- Шаблоны в полях шага
- Семантика post-deploy
- Маркер
deploy_services - Идемпотентный деплой и состояние
- Страницы
- Связанные команды
Назначение
Заголовок раздела «Назначение»workspace/deploy.yml объявляет пайплайн деплоя-оркестратора. workspace/reset.yml объявляет деструктивный пайплайн сброса. Пайплайны деплоя отдельных сервисов лежат в workspace/services/<service>/deploy.yml.
Все три файла загружаются отдельно и не участвуют в трёхслойном мердже.
И workspace/deploy.yml, и workspace/reset.yml опциональны. При их отсутствии DWE подставляет встроенный пайплайн по умолчанию и выводит одну info-строку в stderr: Using built-in default <deploy|reset> pipeline (override with workspace/<deploy|reset>.yml). Эта строка подавляется в режиме --output json.
Дефолтный пайплайн деплоя (срабатывает, когда workspace/deploy.yml отсутствует):
Фазы: services (запускает deploy_services: true для встраивания пайплайнов включённых сервисов) → start (type: dwe, cmd: "docker up --wait") → post-deploy (отображение info + сообщение об успехе).
Дефолтный пайплайн сброса (срабатывает, когда workspace/reset.yml отсутствует):
Фазы: pre (промпт подтверждения) → stop (type: dwe, cmd: "docker down") → cleanup (удаление томов, удаление директории services/).
Роли файлов
Заголовок раздела «Роли файлов»| Файл | Роль |
|---|---|
workspace/deploy.yml | Оркестратор верхнего уровня: перечисляет фазы по порядку, ссылается на пайплайны сервисов |
workspace/services/<svc>/deploy.yml | Фазы и шаги отдельного сервиса (встраиваются оркестратором при deploy_services: true). Пайплайн деплоя может быть у сервиса любого типа (app, tool, infra). |
workspace/reset.yml | Отдельный пайплайн сброса, исполняемый через dwe reset run. Фазы deploy_services отвергаются. |
flowchart TB
D[workspace/deploy.yml] -->|phase: deploy_services| INL{Встраивание включённых сервисов}
subgraph svc["workspace/services/<service>/deploy.yml — по одному файлу на сервис"]
direction TB
S1["обязательный сервис<br/>(всегда встраивается)"]
S2["опциональный сервис A<br/>(встраивается, если включён)"]
S3["опциональный сервис B<br/>(встраивается, если включён)"]
SN["…N сервисов"]
end
svc --> INL
INL -->|топосортировка по after:| PLAN[Разрешённый план]
PLAN --> RUN[(PlainReporter — ✓ ✗ ◎ ·<br/>.dwe/logs/deploy.log)]
R[workspace/reset.yml] --> RPLAN[Разрешённый план] --> RUN2[(PlainReporter)]
Сервис любого типа (app, tool или infra) может иметь workspace/services/<name>/deploy.yml. На этапе планирования оркестратор отфильтровывает этот набор до включённых сервисов (обязательные всегда включены) и встраивает их в топологическом порядке after:. Сервисы без файла деплоя молча пропускаются — не каждому сервису он нужен.
Поле after: в workspace/services/<name>/deploy.yml задаёт порядок деплоя между сервисами (отдельно от рантайм-зависимости depends_on:). Подробности см. в Поля верхнего уровня.
Структура
Заголовок раздела «Структура»log: true # optional: tee output to .dwe/logs/<pipeline>.log
phases: # Normal phase: supports when, untracked, and steps - name: <phase-name> description: Human-readable description when: # optional: pre-condition (typed condition) type: builtin|shell|template cmd: <string> # for builtin/shell expr: <string> # for template untracked: true # optional: suppress step output for this phase steps: - name: <step-name> description: Human-readable description type: shell|dwe|command|builtin # execution type (required) cmd: <value> # command payload (required) when: # optional: pre-condition (typed condition) type: builtin|shell|template cmd: <string> # for builtin/shell expr: <string> # for template check: # optional: post-condition (typed action, либо скаляр `auto`) type: shell|dwe|command|builtin cmd: <value> with: # optional: parameters key: value continue_on_error: true # optional: failure does not abort the pipeline skip_confirm: true # optional: bypass confirmation prompts for this step untracked: true # optional: exclude this step from [N/M] counter and suppress its output files_gate: readable # short form: state must be readable|missing # or long form: files_gate: state: readable|missing # required command: <cmd-id> # default: step.cmd (only valid for type: command) require: required|all|[id1, id2] # default: required with: # default: step.with key: value with: # parameters (for command and builtin types) key: value
# deploy_services phase (deploy.yml only): no steps or when allowed - name: services description: Human-readable description deploy_services: true # orchestrator marker; mutually exclusive with steps and whenПоля верхнего уровня
Заголовок раздела «Поля верхнего уровня»| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
log | bool | deploy.yml: true; reset.yml: false | Дублировать статусные сообщения DWE и stdout/stderr дочерних процессов в .dwe/logs/<pipeline>.log (ANSI-коды вырезаются). |
phases | list | — | Упорядоченный список фаз. |
after | list of strings | [] | Только в deploy.yml отдельного сервиса. Декларирует порядок деплоя: данный сервис деплоится после перечисленных. Опущенное или пустое значение означает отсутствие ограничения порядка. Отличается от рантайм-зависимости depends_on: (которая управляет порядком запуска контейнеров) — используйте after:, когда хотите, чтобы шаги деплоя одного сервиса завершились до начала шагов другого. Недопустимо в workspace/deploy.yml, workspace/reset.yml и workspace/services/<name>/reset.yml (ошибка на этапе загрузки). Полный деплой (dwe deploy run) топосортирует сервисы по after:; dwe deploy run --service <name> НЕ каскадирует на объявленные after: зависимости (явный выбор перекрывает порядок). |
Поля фазы
Заголовок раздела «Поля фазы»| Поле | Тип | По умолчанию | Описание |
|---|---|---|---|
name | string | обязательно | Уникальный ключ фазы внутри пайплайна |
description | string | опционально | Показывается в выводе deploy plan |
when | typed condition | — | Предусловие; фаза пропускается при ложном значении (см. Условия). Не допускается на фазах deploy_services. |
untracked | bool | false | Если true, шаги фазы исключаются из счётчика шагов и не дают системного вывода |
deploy_services | bool | false | Маркер оркестратора: CLI встраивает сюда пайплайны сервисов в порядке зависимостей. Фаза deploy_services не должна содержать steps или условие when — оба случая являются жёсткими ошибками на этапе загрузки. |
Поля шага
Заголовок раздела «Поля шага»| Поле | Тип | Описание |
|---|---|---|
name | string | Уникальный ключ шага внутри фазы |
description | string | Показывается в выводе deploy plan |
type | enum | Тип исполнения: один из shell, dwe, command, builtin (обязательно). См. Типы исполнения шагов. |
cmd | string | Полезная нагрузка команды (обязательно); содержимое зависит от type |
with | mapping | Параметры, передаваемые в команду или билтин (опционально; обязательно для большинства билтинов) |
when | typed condition | Предусловие, вычисляемое до запуска шага; шаг пропускается при ложном значении. См. Условия. |
check | typed action, либо скаляр auto | Постусловие, вычисляемое после успеха шага; пайплайн прерывается, если действие провалилось. Пропускается, когда continue_on_error: true и шаг провалился. См. Условия. |
files_gate | typed gate | Предусловие на основе наличия/отсутствия файлов из блока files: команды. Шаг пропускается, если не удовлетворено. См. files_gate:. |
continue_on_error | bool | Если true, упавший шаг фиксируется через FailStep (красный ✗), но пайплайн не прерывается. После такого шага пропускаются check и хук следующего шага. Полезно для опциональных хук-фаз — см. lifecycle.yml. Если тело шага успешно, но check: падает и continue_on_error: true, шаг отмечается как упавший, а пайплайн переходит к следующему шагу (симметрично семантике падения тела). |
skip_confirm | bool | Если true, обходит промпты подтверждения только для этого шага — эквивалент шагового -y / --yes. Распространяется на тело шага и его действие check:. Объединяется по ИЛИ с пайплайновым флагом skip-confirm, поэтому шаг становится неинтерактивным, если задан хотя бы один из них. Полезно, когда основная часть пайплайна интерактивна, но один шаг (например, билтин confirm, защищающий идемпотентное действие, или команда с внутренним перепромптом) должен всегда продолжать. |
untracked | bool | Если true, шаг исключается из счётчика [N/M], а его lifecycle-вывод (строки start/done) подавляется. Падения всё равно показываются. Объединяется по ИЛИ с фазовым untracked — используйте шаговый флаг, чтобы скрыть единственный шаг stack-up или wait-healthy без вынесения в отдельную untracked-фазу. Допустим на шагах параллельной группы; под-шаги наследуют untracked-статус от группы. |
timeout | duration string | Опциональный бюджет по времени на тело этого шага, например 30s, 2m. Опционально — никакого неявного значения по умолчанию нигде: отсутствие поля или timeout: 0 означает отсутствие ограничения, ровно как если бы поля не было вовсе. Положительное значение ограничивает только этот один шаг (или, внутри группы parallel:, только этот под-шаг) через context.WithTimeout вокруг тела шага; действие check: этим не ограничивается. Таймаут работает через отмену контекста, поэтому он ограничивает только тело, которое учитывает ctx, — подпроцессы type: shell/type: dwe (сначала SIGTERM, затем принудительное завершение после паузы), учитывающие ctx билтины (http_check, docker_wait_healthy, tcp_reachable, …), и шаги type: command, чья собственная работа учитывает ctx. Тело, заблокированное на интерактивном вводе (например, билтин confirm, ожидающий stdin), не прерывается принудительно — дедлайн наступает, но горутина остаётся заблокированной до получения ввода; таймаут на человеческом промпте всё равно бессмысленен, так что это осознанное ограничение, а не баг. Отрицательная длительность ("-1s") отклоняется на этапе разрешения пайплайна. Общее поле движка: работает одинаково в deploy.yml, reset.yml, lifecycle.yml и в шагах сценариев workspace/tests/*.yml. |
Шаг также может объявить блок parallel: вместо листовых полей тела (type / cmd). См. Параллельные группы шагов.
Шаблоны в полях шага
Заголовок раздела «Шаблоны в полях шага»cmd, строковые листья with, check, timeout и shell-условие when: рендерятся на этапе разрешения плана — до того, как шаг будет показан или выполнен. Ссылка ${...} с известным пространством имён (vars, services, project, …) подставляется своим фактическим значением; dwe deploy plan поэтому печатает то, что реально будет выполнено, а не буквальный текст ${vars.*} из deploy.yml. Ссылка ${...} с неизвестным пространством имён (shell-подобная ${HOME}, опечатка) — либо запись из одного head’а без dot-path, например shell-переменная ${host} / ${files} — остаётся буквальным текстом и, если она попадает в вывод плана, помечается аннотацией [unresolved: ${...}] в конце строки (также передаётся как поле unresolved в --output json) — эта аннотация — лишь подсказка для отображения и никогда не добавляется в --format shell, который должен оставаться напрямую исполняемым.
Поле шага, содержащее ${...} с известным head’ом, не должно одновременно содержать литеральный {{ }}. Подстановка прогоняет поле через тот же движок Go-шаблонов, в который компилируется shorthand ${...}, поэтому формат-строка docker в той же команде — cmd: 'docker inspect -f "{{.State.Status}}" ${vars.container}' — интерпретируется как шаблон и валит разрешение с ошибкой can't evaluate field State. Весь dwe deploy plan / dwe deploy run на этом останавливается. Либо разведите их (вынесите формат-строку в скрипт или значение ${vars.*} в shell-переменную), либо экранируйте скобки как {{"{{"}}. Поле cmd, check, timeout или when: без ссылок с известным head’ом в движок вообще не попадает, поэтому обычный docker inspect -f "{{.State.Status}}" app — или команда, использующая только shell-переменную вроде ${CONTAINER} — передаётся без изменений.
Единственное исключение — строковые листья with:, и только там, где значение попадает в пользовательскую команду: шаг или action с type: command, собственный with: у files_gate:, а также with: самого шага, когда files_gate: не объявил своего (тогда гейт наследует карту шага как свои параметры). Там лист рендерится, если содержит ${...} с известным head’ом или литеральный {{, потому что это значение with: и раньше всегда проходило через этот шаблонный движок перед попаданием в команду. Поэтому with: {host: '{{ resolve .Raw "vars.db.host" }}'} по-прежнему резолвится, а ограничение на смешанную форму выше распространяется и на такие листья.
У with: шага с type: builtin остаётся узкий гейт: ${...} с известным head’ом подставляется, литеральный {{ }} проходит нетронутым. Это верно и когда карту наследует files_gate:: расширение гейта выше действует для любых других типов шагов, но никогда — для параметров builtin’а. Builtin’ы получают значения with: как есть, и некоторые рендерят их в другом шаблонном пространстве: message рендерит свой text как Go-шаблон над DweConfig ({{ .Project.Name }}), а предикат shell принимает строки формата docker inspect -f "{{.State.Status}}". Оба продолжают работать без изменений.
В шаге пайплайна резолвятся только пути конфига проекта и ${host.uid} / ${host.gid}. Пространства имён, принадлежащие пользовательской команде или проходу рендера конфигов — ${param.*}, ${context.*}, ${files.*}, ${generated.*} и ${args} — здесь источника не имеют, поэтому ссылка на любое из них — ошибка разрешения с указанием пространства имён, а не молчаливая подстановка пустой строки:
step "checkout": cmd: template uses ${param.branch}: the "param" namespace has no source here(only project config paths and ${host.*} resolve on this path)${snapshot.*} вне snapshot-воркфлоу падает точно так же. Чтобы передать значение в шаг, положите его в vars: и ссылайтесь через ${vars.*}; чтобы задать параметры шагу с type: command, используйте его собственный with: — эта карта задаёт ${param.*} целевой команды, а не читает их. То же правило действует для шагов сценариев workspace/tests/*.yml, которые рендерятся через тот же субстрат.
Поскольку фактический текст отрендеренного шага теперь зависит от блока vars:, весь блок vars: включается и в проектный, и в посервисный хеш конфига, поэтому изменение используемого значения перезапускает использующие его шаги, вместо того чтобы деплой отрапортовал устаревшее «already up-to-date». Разовое последствие при обновлении: это меняет хеш конфига проекта для каждого существующего проекта, поэтому первый dwe deploy run после обновления на версию dwe с этим изменением один раз перезапустит все шаги, даже без каких-либо ваших правок в vars:. Шаги по умолчанию должны быть идемпотентными и защищёнными гейтами, так что это безопасно, просто заметно — не пугайтесь, если деплой, неделями остававшийся «up-to-date», вдруг один раз перезапустит всё.
Семантика post-deploy
Заголовок раздела «Семантика post-deploy»Фаза post-deploy (по соглашению — последняя фаза в deploy.yml) выполняется только если все предыдущие фазы успешны. В этом нет магии — это следует из существующего поведения, при котором деплой прерывается на первой ошибке. Назовите финальную фазу-сводку post-deploy, и она естественно получит это свойство.
Используйте untracked: true на фазе post-deploy, чтобы подавить системные сообщения о шагах (билтины сами производят вывод через свой уровень сообщений):
- name: post-deploy description: Post-deploy summary untracked: true steps: - name: info type: dwe cmd: "info" - name: success type: builtin cmd: message with: level: success text: Deploy completed successfullyМаркер deploy_services
Заголовок раздела «Маркер deploy_services»В deploy.yml фаза с deploy_services: true является плейсхолдером. CLI заменяет её встраиваемыми пайплайнами сервисов на этапе выполнения, упорядочивая по зависимостям (поле after: в workspace/services/<name>/deploy.yml каждого сервиса). Включены только активные сервисы.
phases: - name: services deploy_services: true description: Deploy all enabled servicesИдемпотентный деплой и состояние
Заголовок раздела «Идемпотентный деплой и состояние»По умолчанию dwe deploy run отслеживает исход и хеш каждого выполненного шага в .dwe/deploy/state.yml. На следующем запуске деплоя шаги, успешно завершившиеся с неизменным action_hash, пропускаются (если у них нет действия check:, которое всегда выполняется для повторной проверки идемпотентности).
Это делает деплои идемпотентными: повторный запуск неизменённого проекта быстр (неизменённые шаги пропускаются), а правка тела шага автоматически перезапускает его. Правки в конфигурационных файлах сервисов (workspace/services/<name>/service.yml) или в конфигах деплоя (workspace/deploy.yml, workspace/services/<name>/deploy.yml) инвалидируют затронутую область и заставляют эти шаги выполниться заново.
Ключевые модели поведения:
- Изменение хеша шага → шаг перезапускается
- Изменение конфига сервиса → все шаги сервиса перезапускаются
- Изменение конфига проекта → все шаги уровня проекта перезапускаются
- Есть действие
check:→ шаг всегда выполняется (даже если хеш совпадает), чтобы check повторно проверил идемпотентность - Есть
files_gate: state: missing→ пропуск по журналу обходится, а гейт переоценивается на каждом деплое (паттерн «продьюсер»: удаление артефакта должно повторно запустить производство независимо от содержимого журнала) - Есть
files_gate: state: readable→ пропуск по журналу учитывается первым, как у любого другого шага; гейт срабатывает только тогда, когда журнал иначе позволил бы шагу выполниться (паттерн «консьюмер»: деструктивные потребители остаются идемпотентными). Используйте явныйcheck:, чтобы принудительно переоценивать на каждом запуске - В обоих случаях журнал фиксирует шаг для аудита и отображения статуса через
step_hash, который включает конфигурацию гейта — поэтому изменение гейта инвалидирует записанный хеш и перезапускает шаг - Предыдущий шаг провалился → шаг перезапускается на следующем деплое (позволяет
--resumeпродолжить с места падения)
Используйте dwe deploy state show для инспекции журнала, dwe deploy state clear для его сброса и dwe deploy state repair для починки повреждённых агрегатов.
Полные сведения о хешировании, решениях о пропуске и восстановлении после падений посреди деплоя см. в state/index.md.
Страницы
Заголовок раздела «Страницы»- Типы исполнения шагов —
shell,dwe,command,builtin; различие билтинаcmd: shellи шагаtype: shell - Доступные билтины — каждый билтин с входами и примерами; внутренние билтины движка
- Условия — семантика
when:,check:иfiles_gate: - Примеры — оркестратор, отдельный сервис, infra-
after:, параллельные группы, переопределения под-шагов в воркфлоу, типичные ловушки
Связанные команды
Заголовок раздела «Связанные команды»dwe deploy plan— показать разрешённый пайплайн (с встраиваемыми фазами сервисов).--format table(по умолчанию) /--format shell, либо--output jsonдля машиночитаемой формы:{service?, phases[]}, где каждая фаза несётname/service/description/whenи упорядоченныйsteps[]из{name, type, cmd, unresolved[], description, when, files_gate, check, continue_on_error, untracked, parallel{max_concurrent, fail_fast, steps[]}}.--output jsonимеет приоритет над--format.dwe deploy run— выполнить пайплайн деплоя с отслеживанием состоянияdwe deploy state show— инспекция журнала состояния деплояdwe deploy state clear— сброс состояния деплояdwe deploy state repair— пересборка агрегатов состоянияdwe reset plan— показать пайплайн сбросаdwe reset run [--yes]— выполнить пайплайн сброса- См. также lifecycle.yml — пайплайны
run/stopпереиспользуют ту же грамматику фаз/шагов с опциональной пробой обновлений и хук-фазами.