Skip to content

Docker-образи

У кожного проєкту — власний Dockerfile у корені, що запускається на Kubernetes. CI збирає кожен образ, пушить у registry, а GitOps бампає тег у Helm-values (див. GitOps).

застосунокбазазбираєзапускається якk8s-об'єктпорт
apinode:22-alpineNestJS → distnode dist/main.jsDeployment + Service + HPA + Ingress (пул core)3333
appnode:22-alpineNuxt → .outputnode .output/server/index.mjsDeployment + Service + Ingress3000
adminnode:22-alpineNuxt → .outputnode .output/server/index.mjsDeployment + Service + Ingress3001
workerPlaywright/Chromium (heavy)цикл агента + тулиодна задача, потім вихідk8s Job (без Service) — на задачу

Загальні принципи

  • Multi-stage збірки — стадія build (повні залежності + компіляція) і тонка runtime (лише prod-залежності + артефакти). Малий фінальний образ, швидкі пули.
  • Non-root юзер; пінований тег базового образу; .dockerignore (без node_modules, .git, dist).
  • Healthcheck для довгоживучих сервісів (Deployments); k8s readinessProbe/livenessProbe.
  • Конфіг через env (12-factor); секрети не вшиваємо — інжектить k8s у рантаймі. Інфра-креди приходять з HashiCorp Vault через External Secrets Operator, а не з Sealed Secrets (див. GitOps); секрети агента резолвляться з Postgres.
  • Один образ на теку репо — з двома поправками до рядка, який тут був раніше. У app/ немає Dockerfile, хоча helm/agentfy-app в Agentfy/gitops фіксує реальний тег ghcr.io/agentfy/agentfy-app, тобто цей образ збирається там, де не записано в жодному з репозиторіїв. А в worker/ їх три: Dockerfile (shell-воркер), Dockerfile.browser (той самий образ плюс Chromium, AGNT2-212) і Dockerfile.control — навмисно незахищений образ, який існує лише для того, щоб можна було показати scripts/verify-image.sh таким, що падає. Контрольний образ ніколи не збирається для деплою.

api — Core + ефемерний мозок

dockerfile
# build
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate && npm run build
# runtime
FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
COPY --from=build /app/node_modules/.prisma ./node_modules/.prisma
USER node
EXPOSE 3333
CMD ["node", "dist/main.js"]

api — це stateless, горизонтально масштабований Deployment (HPA скейлить репліки за навантаженням). «Ефемерний агент = api» означає немає пода на агента — кожен турн це stateless-запит, який вантажить стан агента з Postgres і відповідає; спільний флот api скейлиться за трафіком. (Літеральний под-на-задачу — це Job воркера.) Prisma-міграції не в образі: їх планували як PreSync-хук GitOps, а сьогодні вони виконуються в initContainer у Deployment api (helm/agentfy-api/templates/deployment.yaml в Agentfy/gitops).

app / admin — Nuxt

dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build               # → .output (Nitro server build)
FROM node:22-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
COPY --from=build /app/.output ./.output
USER node
EXPOSE 3000                     # admin: 3001
CMD ["node", ".output/server/index.mjs"]

SSR (Nitro Node-сервер) за Ingress. Якщо набір сторінок повністю статичний — альтернатива nuxt generate → образ nginx:alpine, що віддає статику — та сама форма Deployment.

worker — руки агента (heavy-образ)

Відрізняється від інших: важка база зі справжньою ОС — bash, файлова система та Chromium (Playwright) — плюс цикл агента + тул-виконавці + WS-клієнт. Не довгоживучий сервер; образ виконує одну задачу і виходить, використовується k8s Job на задачу.

dockerfile
# Важка база з готовим Chromium + deps (образ Playwright, або
# oven/bun:alpine + chromium, як у Dockerfile cleanslice/runtime).
FROM mcr.microsoft.com/playwright:v1.49.0-jammy
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER pwuser
# Підключається до Core по WS через SESSION_ID/CORE_WS_URL/SESSION_TOKEN, тягне
# задачу, ганяє bash/fs/browser тули, вивантажує результати, потім виходить.
ENTRYPOINT ["node", "dist/worker.js"]
  • Бере цикл агента + тул-виконавці з cleanslice/runtime.
  • Запускається в Job: restartPolicy: Never, ttlSecondsAfterFinished, emptyDir-workspace, read-only root fs (запис лише /workspace), короткоживучий projected secret. Див. Worker на Kubernetes.
  • Не керується GitOps як Deployment — Argo тримає лише ref образу воркера + RBAC + шаблон NetworkPolicy + пресети RuntimeProfile; екземпляри Job створюються в рантаймі.

Потік збірки та доставки

git push → docker build <app>/Dockerfile → push ghcr.io/agentfy/<app>:<sha>
        → бамп image.tag у Agentfy/gitops helm/<chart>/values.dev.yaml → ArgoCD синкає

Друга половина справжня, і шлях точний. Перша не підтверджена: у жодному з репозиторіїв немає workflow, який би збирав чи пушив образ застосунку, а в цьому репозиторії немає .github/ взагалі, — при цьому values-файли несуть реальні теги. Див. Два репозиторії.

Локальна розробка — ті самі Dockerfile через compose; прод — на Hetzner k8s. Через середовища рухається єдиний артефакт (образ) — відтворювано й відкочувано.

Один виняток із контексту <app>/ (AGNT2-248). Образ api збирається з КОРЕНЯ репозиторію — docker build -f api/Dockerfile . — бо каталог інструментів воркера, який api показує моделі до підняття пода, генерується з worker/src під час збірки. Вихідники воркера тут вхід збірки й у жоден шар готового образу не потрапляють; .dockerignore у корені не дає контексту стати всіма node_modules репозиторію.