Добавление сервиса
В проекте уже есть приложение web, и теперь вы хотите добавить рядом worker — фоновый процесс, который разбирает задачи из очереди. Это руководство показывает минимальный набор файлов, необходимый для нового сервиса: где какой файл лежит и как проверить результат до коммита.
Тот же рецепт работает и при добавлении базы, админ-панели или любого другого контейнера, общего для всей команды, — меняется только type:.
Выберите тип сервиса
Заголовок раздела «Выберите тип сервиса»Каждый сервис объявляет один из трёх типов. Выберите подходящий по роли:
type: | Когда использовать | Пример |
|---|---|---|
app | Сервис, исходный код которого лежит в репозитории, собирается и может рендерить IDE/AI/git-конфиг. | web, worker, api |
infra | Вспомогательный контейнер без исходников. Другие сервисы могут указывать его в depends_on. | db, redis, minio |
tool | Самостоятельный служебный контейнер — UI для базы, перехватчик почты, фронтенд для observability. Не может быть целью depends_on. | adminer, mailpit |
Если сомневаетесь — выбирайте app, когда код сервиса лежит в репозитории, и infra, когда это готовый образ. Воркер, выполняющий ваш собственный код, — это app.
Справочник: ../reference/config/services/index.md — полный список допустимых полей для каждого типа.
Раскладка папки
Заголовок раздела «Раскладка папки»Каждый сервис живёт в собственной папке внутри workspace/services/. Имя папки и есть ключ сервиса — поля name: нет.
workspace/services/ web/ # уже есть service.yml worker/ # новый service.ymlМинимальный service.yml для воркера-приложения:
type: appcontainer: app-workerdir: ./services/workerdir_internal: /workspaceicon: "⚙️"Этого достаточно для загрузки: без портов, без хостов (воркер не обслуживает трафик), а container: становится именем docker-контейнера. Если container: опустить, оно по умолчанию совпадает с именем папки.
Для infra-сервиса с портом:
type: infrarequired: true # постоянно работающий вспомогательный сервисcontainer: queueports: amqp: 5672См. ../reference/config/services/fields.md — описание каждого поля и того, на что оно влияет.
Наследование полей через extends:
Заголовок раздела «Наследование полей через extends:»Если у вашего нового приложения большая часть настроек совпадает с существующим (тот же базовый образ, те же монтирования, тот же шелл), используйте extends: для наследования:
type: appextends: web # наследуем dir_internal, dirs, cli, configs, render…container: app-workerrequired: false # web — required: true; worker — опциональныйdir: ./services/worker # потомок задаёт свой dirЧто наследуется, а что нет:
- Наследуется, если потомок его не задаёт:
dir_internal,work_dir_internal,dirs,configs,cli,render,compose. - Никогда не наследуется:
container,required,depends_on. Каждый потомок обязан объявлять их явно. - Поля-списки (
dirs,cli.env) — родитель задаёт значения по умолчанию, потомок добавляет к ним свои записи. compose:— список потомка целиком заменяет родительский, а не объединяется с ним.
extends: работает только для приложений. Для tool и infra он отклоняется при загрузке.
Справочник: ../reference/config/services/extends.md.
Подключение compose-оверлея
Заголовок раздела «Подключение compose-оверлея»service.yml описывает метаданные в формате DWE. Сам контейнер — образ, команда, монтирования, сети — описывается в Docker Compose-оверлее, на который ссылается service.yml:
type: appcontainer: app-workerdir: ./services/workercompose: - compose/services/worker/overlay.ymlservices: app-worker: image: ${DWE_PROJECT_PREFIX}/worker:latest build: context: ./services/worker dockerfile: Dockerfile command: ["node", "worker.js"] depends_on: - queue volumes: - ./services/worker:/workspaceCompose-файл — это обычный Docker Compose YAML; DWE не переписывает Compose, а компонует оверлеи. Команда dwe compose files показывает полный порядок, в котором DWE объединяет оверлеи.
Регистрация переключателя в defaults.yml
Заголовок раздела «Регистрация переключателя в defaults.yml»Если сервис опциональный (не required: true), задайте, включён ли он по умолчанию, в workspace/defaults.yml:
services: worker: enabled: true # включён у всех по умолчанию; каждый может переопределить в local.ymlРазработчик, которому воркер не нужен, выполняет dwe services disable worker, и это записывает services.worker.enabled: false в workspace/local.yml.
Обязательные сервисы (required: true в service.yml) включены всегда и не переключаются — для них этот шаг пропускайте.
Справочник: ../reference/config/workspace.md.
Опционально: шаги деплоя для сервиса
Заголовок раздела «Опционально: шаги деплоя для сервиса»Если вашему сервису нужна подготовка во время деплоя — установка зависимостей, прогон миграций, сборка ассетов — добавьте deploy.yml рядом с service.yml:
phases: - name: setup steps: - name: install-deps type: shell cmd: | $DWE_BIN shell worker -c "npm install" - name: run-migrations type: shell when: { type: template, expr: "{{ .Services.queue.Enabled }}" } cmd: | $DWE_BIN shell worker -c "npm run migrate"Эти шаги выполняются при dwe deploy для каждого включённого сервиса, у которого есть deploy.yml, в порядке, который вычисляет пайплайн деплоя. Шаг может быть пропущен через журнал, если соответствующий хеш конфига не изменился, — это происходит автоматически.
Отдельный deploy.yml допустим для сервиса любого типа (app / tool / infra), не только для приложений. Применяйте его экономно: простым контейнерам, которым достаточно up, он не нужен.
Справочник: ../reference/config/deploy/index.md.
Опционально: render-паки (config / IDE / AI / git)
Заголовок раздела «Опционально: render-паки (config / IDE / AI / git)»Для сервисов с type: app DWE может рендерить для каждого сервиса файлы из общих наборов шаблонов: рантайм-конфиги (.env, env.php, …), IDE-конфиг, AGENTS.md и фрагменты .gitignore. Подключите это в service.yml:
render: config: { template: node } ide: { enabled: true, template: node } ai: { enabled: true, template: node } git: { enabled: true, template: node }Значение template: — это имя набора в workspace/templates/{config,ide,ai,git}/<pack>/. Запустите dwe render config (а также dwe render ide, dwe render ai, dwe render git), чтобы посмотреть, что выдаст каждый из рендереров.
Пак config стоит особняком, и это важно отметить:
- Он пишет прямо в смонтированный hub-каталог сервиса (его
dir), режим replace — это файлы, которые контейнер реально читает в рантайме, а не метаданные для редактора/агента. - Его шаблоны используют сокращение
${...}(например,DB_HOST=${services.db.hosts.main}) — ту же форму, что и правила экспорта, а не «сырой» субстрат{{ }}, который применяют паки ide/ai/git. - Он поддерживает секреты generated-once (Laravel
APP_KEY, Magentocrypt.key, …): значение чеканит сам сервис, DWE харвестит его в.dwe/generated.ymlи переигрывает при каждом последующем рендере через${generated.<name>}. - Рендер config также запускается автоматически как преамбула
dwe runи как шаг деплоя;dwe render configнужен в основном для предпросмотра и для разового прохода--harvest.
Если ничего из этого не нужно — целиком опустите блок render:.
См. shared-ide-and-agent-config.md — воркфлоу работы с наборами шаблонов IDE/AI/git, и ../reference/render/config.md — про субстрат config-пака, хранилище сгенерированных значений и pipeline-билтины.
Проверка
Заголовок раздела «Проверка»Написав файлы, проверьте их перед деплоем:
dwe validate config servicesКоманда прогоняет проверки схемы для каждого сервиса: обязательные поля по типу, допустимые поля по типу, корректные диапазоны портов, правильно сформированная цепочка extends:, отсутствие циклов в depends_on.
Если валидация прошла, включите сервис и запустите стек:
dwe services enable worker # если он был выключен в local.ymldwe run # поднять стекdwe status # убедиться, что новый сервис поднялсяЕсли вы добавили deploy.yml для worker, можно сначала прогнать только его шаги деплоя:
dwe deploy run --service worker # только если у worker есть deploy.ymldwe rundwe statusdwe deploy run --service <имя> завершается ошибкой, если у сервиса нет deploy.yml: это не замена dwe run и не способ запустить сервис, у которого нет пайплайна деплоя.
Если что-то падает — смотрите dwe logs worker и troubleshooting.md о типичных причинах сбоев.