Архитектура
Высокоуровневый взгляд на то, как DWE и Docker устроены вместе: DWE — это CLI, который превращает YAML-дерево проекта в вызовы Docker Compose, журналирует результат локально и даёт разработчику способ работать с контейнерами. Эта страница — о границе между ними: что относится к DWE, что — к Docker, и где одно заканчивается, а другое начинается.
Содержание
Заголовок раздела «Содержание»- Общая картина
- Распределение ответственности
- От команды до контейнера
- Где что живёт
- Границы, которые DWE не пересекает
- Что читать дальше
Общая картина
Заголовок раздела «Общая картина»DWE стоит между разработчиком и Docker-стеком. Он читает проект с диска, пишет рядом небольшое количество сгенерированного состояния и управляет Docker Compose, который реально поднимает контейнеры. Разработчик никогда не набирает docker compose напрямую.
flowchart LR
Dev["Разработчик<br/>(терминал + браузер)"]
subgraph Project["Проект на диске"]
Cfg["workspace.yml<br/>+ workspace/"]
Comp["compose/<br/>оверлеи"]
Gen[".dwe/<br/>+ .env<br/>(генерируется)"]
end
subgraph DWEBox["DWE CLI"]
CLI["dwe"]
end
subgraph Engine["Docker engine"]
Compose["docker compose"]
Containers["контейнеры<br/>сети<br/>тома"]
end
Dev -->|"dwe run / deploy / stop"| CLI
CLI -->|читает| Cfg
CLI -->|читает| Comp
CLI -->|пишет| Gen
CLI -->|shell-вызов| Compose
Compose --> Containers
Dev -->|"http://*.localhost<br/>tcp-порты"| Containers
Сам CLI — это один статически слинкованный бинарник со встроенными документацией и пайплайнами. Нет компаньон-процесса, нет загрузчика плагинов — каждый запуск короткоживущий и не имеет состояния, кроме того, что пишется в .dwe/. Единственный резидентный компонент — опциональный демон хост-бриджа: stateless-форвардер, который запускается, пока стек поднят, чтобы dev-контейнеры могли обращаться к dwe на хосте, и сам останавливается вместе со стеком.
Распределение ответственности
Заголовок раздела «Распределение ответственности»У DWE и Docker — каждый свой чёткий участок системы. Именно это разделение позволяет заменять DWE вокруг существующего Compose-стека и сохраняет работоспособность стека без установленного DWE.
| Область | Отвечает DWE | Отвечает Docker / Compose |
|---|---|---|
| Модель проекта | workspace.yml + дерево workspace/, включение/выключение сервисов | — |
| Список compose-файлов | Упорядоченный список -f (база + оверлеи), детерминированный порядок мержа | Семантика мержа |
| Имя проекта | Разрешается из ${project.prefix}-${project.name} и передаётся как -p | Именование ресурсов (<project>_<svc>_<n>) |
| Команды жизненного цикла | Оркестрация dwe run / deploy / stop / restart / reset | Реальные up / down / stop / rm / wait |
| Env контейнеров | Рендерит .env перед up, run, exec, restart, build | Читает .env и environment: в контейнеры |
| Сети | Объявлены в compose-файлах | Создаются при up, удаляются при down |
| Тома | Конвенция именования (<project>_<vol>), политика shared/non-shared, sweep при reset | Реальная персистентность данных |
| Health / готовность | Опрашивает через docker compose ps и docker inspect | Сообщает состояние health |
| Хуки / скрипты | Рендерит Git-хуки, запускает пайплайны deploy/reset/lifecycle | — |
| Журнал состояния | .dwe/deploy/state.yml, решения о пропуске, блокировки | — |
| Логи | Зеркалит вывод пайплайнов в .dwe/logs/ | Логи контейнеров (через docker compose logs) |
| Сборка / pull образов | Драйвит docker compose build / pull с policy-аргументами | Слои образа, I/O с реестром |
Между ними нет общего изменяемого состояния: DWE пишет YAML и .env, Docker пишет состояние контейнеров. Единственный контакт — это argv, который DWE передаёт в docker compose, и код возврата, который Docker возвращает.
От команды до контейнера
Заголовок раздела «От команды до контейнера»Вызов dwe run — это канонический цикл: прочитать конфиг, отрендерить env, собрать argv, вызвать compose, дождаться health, напечатать info. Всё остальное (dwe deploy run, dwe stop, dwe reset run) повторяет ту же форму с другими пайплайнами и другими compose-подкомандами.
sequenceDiagram autonumber participant Dev as Разработчик participant CLI as dwe participant FS as ФС проекта participant Engine as Docker engine Dev->>CLI: dwe run CLI->>FS: читает workspace.yml + workspace/ CLI->>FS: пишет .env (envfile.Regenerate) CLI->>FS: захватывает .dwe/deploy/deploy.lock CLI->>Engine: docker compose -p <proj> -f base -f svc1 -f svc2 up -d --wait Engine-->>CLI: контейнеры готовы CLI->>Engine: docker compose ps --services --status running Engine-->>CLI: имена запущенных сервисов CLI->>FS: освобождает lock, дописывает .dwe/logs/run.log CLI-->>Dev: info-панель (URL, хосты, порты, команды) Dev->>Engine: http://my-project.localhost:8080
Три свойства этого цикла критичны:
- Детерминированный argv. Список compose-файлов отсортирован (tools → infra → apps, по алфавиту внутри каждой группы). Имя проекта шаблонизируется один раз и переиспользуется. Два вызова
dwe runна одинаковом конфиге дают побайтово идентичные командыdocker compose. - Env свежий перед каждым релевантным вызовом. DWE перегенерирует
.envнепосредственно передup/run/exec/restart/build. Переменные, видимые контейнеру, всегда синхронизированы с разрешённым конфигом. - Никакого долгоживущего процесса. CLI завершается, как только Docker принял команду (или после того, как
--waitотработал). Docker engine держит контейнеры живыми; DWE за ними не следит.
Полный пайплайн деплоя разворачивает этот цикл в фазы — preflight, шаги деплоя по сервисам, создание томов, up --wait, info — но форма каждого листового вызова в Docker та же.
Где что живёт
Заголовок раздела «Где что живёт»Полезная ментальная модель: есть три концентрических хранилища, у каждого свой владелец.
| Хранилище | Живёт в | Владелец | Переживает dwe reset? |
|---|---|---|---|
| Исходники проекта | workspace.yml, workspace/, compose/, ваш код | Вы / git | Да |
| Сгенерированные артефакты | .env, .dwe/, логи, журнал состояния | DWE | .dwe/ пересобирается; .env ре-рендерится при следующем run |
| Runtime-состояние | Контейнеры, именованные тома, сети, образы | Docker engine | Non-shared тома сметаются; shared тома выживают |
Два следствия, которые стоит знать:
- Удаление DWE не ломает ваш стек. Файлы в
compose/остаются валидным входом дляdocker compose. Можно поднять руками:docker compose -f compose/base.yml -f ... up. Ценность DWE — в автоматизации, а не в привязке к инструменту. - Клонирование проекта не требует состояния Docker.
.dwe/и.envгенерируются. Свежий клон проходит путь от нуля до запущенного состояния черезdwe deploy run— копировать какие-либо снапшоты engine не нужно.
Границы, которые DWE не пересекает
Заголовок раздела «Границы, которые DWE не пересекает»Несколько жёстких линий, которые держат архитектуру предсказуемой:
- DWE не заменяет
dockerилиdocker compose. Любая операция с контейнерами — это вызов через shell. Никакого встроенного compose-движка. - DWE не устанавливает Docker. Ожидается, что на хосте есть
dockerиdocker composeв$PATH. DWE вызывает их через настраиваемые переопределения (binary_dockerв ~/.config/dwe/config), но не разворачивает сам engine. - DWE не работает как демон. Никакого фонового процесса, сокета, tray-приложения. Каждая команда начинается заново, читает конфиг, делает свою работу, выходит. Единственное исключение — хост-бридж: пока стек поднят, per-project демон-форвардер обслуживает вызовы
dweиз dev-контейнеров и автоматически останавливается вместе с последним контейнером. - DWE не делает сетевых вызовов на штатном пути. Никаких обращений к внешним серверам, проверок обновлений, скачиваний шаблонов. Сетевой трафик возникает только из того, что пользователь сам положил в шаг пайплайна или пользовательскую команду (
curlв шагеtype: shell,docker pullиз реестра,git pushв хуке). - DWE не управляет
/etc/hostsили прокси. Имена вродеmy-project.localhostрезолвятся через системный резолвер (*.localhost— это loopback по RFC) или через локальный DNS / reverse proxy, который запускает разработчик. DWE рендерит имена в конфиг и в info-панель; маршрутизация — вне его зоны ответственности.
Эта узкая граница — то, что делает DWE полезным в CI, на изолированных машинах и рядом с существующими Compose-воркфлоу.
Что читать дальше
Заголовок раздела «Что читать дальше»- Интеграция с Docker — глубокое погружение в сборку compose-файлов, именование проекта, проброс env, конвенции для томов и несколько случаев, когда DWE обходит compose и вызывает
docker stop/docker rmнапрямую. - Раскладка проекта — для чего каждая папка под
workspace/и что генерируется под.dwe/. - Пайплайны — модель выполнения phase / step / condition, которую разделяют deploy, reset и lifecycle.
- Состояние и блокировки — что записывает
state.ymlи какdeploy.lock/snapshot.lockсериализуют мутации. - Интеграция с Git — что DWE рендерит в
.git/hooks/проекта и как собирается обзор workspace. - Для контрибьюторов:
docs/internals/architecture.md— внутреннее разделениеcli/↔core/↔shared/внутри бинарника, иdocs/internals/packages.mdдля ответственностей пакетов.