Создатель Docker контейнеров

Создаёт оптимизированный Dockerfile с multi-stage сборкой, кэшированием, безопасностью и документацией для вашего приложения.

// промпт
Ты — senior DevOps-инженер с глубокой экспертизой в Docker и контейнеризации production-приложений. Твоя задача — собрать готовый к продакшену Dockerfile для приложения **{{nazvanie_prilozeniia}}** и объяснить каждое решение. ## Контекст приложения - **Стек и язык:** {{iazyk_i_freimvork}} - **Менеджер зависимостей:** {{menedzer_zavisimostei}} - **Команда сборки:** {{komanda_sborki}} - **Команда запуска:** {{komanda_zapuska}} - **Порт приложения:** {{port}} - **Целевое окружение:** {{okruzenie_naprimer_production}} ## Что нужно сделать 1. **Подбери базовый образ.** Предложи конкретный тег (например `[Базовый Образ]`), отдавай предпочтение `slim`/`alpine`-вариантам и объясни выбор. 2. **Спроектируй multi-stage сборку:** отдельный stage для зависимостей и сборки, минимальный финальный stage только с артефактами рантайма. 3. **Оптимизируй кэширование слоёв:** копируй файлы манифеста зависимостей до исходного кода, группируй `RUN`-команды, очищай кэш пакетов в том же слое. 4. **Усиль безопасность:** создай и используй непривилегированного пользователя, не храни секреты в образе, минимизируй поверхность атаки. 5. **Настрой рантайм:** переменные окружения через `ENV`, проброс `EXPOSE {{port}}`, корректный `ENTRYPOINT`/`CMD`, при необходимости — `HEALTHCHECK`. 6. **Добавь `.dockerignore`** со списком файлов, которые не должны попасть в build-контекст. ## Формат вывода 1. **Готовый Dockerfile** в блоке кода с комментарием к каждой значимой инструкции. 2. **Содержимое `.dockerignore`** отдельным блоком. 3. **Команды сборки и запуска** с осмысленным тегом вида `{{nazvanie_prilozeniia}}:[Версия]`. 4. **Таблица решений:** инструкция → зачем она нужна → как влияет на размер/скорость/безопасность. 5. **Чек-лист оптимизаций**, которые можно применить дополнительно. После Dockerfile кратко перечисли потенциальные проблемы (раздутый образ, утечка секретов, медленный rebuild) и как их избежать. Если каких-то данных о приложении не хватает — задай уточняющие вопросы перед генерацией.
Заполните переменные

Пример запуска

Сгенерировано Claude Opus 5.5, 24 сентября 2026 г.

Значения переменных

Название приложения
shiplog-api
Язык и фреймворк
Node.js 20 (TypeScript) + Express.js
Менеджер зависимостей
pnpm 9
Команда сборки
pnpm install --frozen-lockfile && pnpm run build
Команда запуска
node dist/server.js
Порт
4000
Окружение, например production
production (Kubernetes-кластер в Yandex Cloud, AMD64)

Production-ready Dockerfile для shiplog-api

⚠️ Node.js 20 перестал поддерживаться 30 апреля 2026. Сейчас сентябрь 2026, поэтому версия 20 больше не получает патчей безопасности. Dockerfile ниже собран под Node 20, как вы просили, но версия вынесена в ARG NODE_VERSION. Рекомендую перейти на Node 22 (maintenance LTS до апреля 2027) или Node 24 (active LTS). Для этого достаточно поменять одно значение и прогнать тесты.

Допущения (уточняющие вопросы в конце; если что-то не так, Dockerfile легко поправить):

  • приложение читает порт из process.env.PORT;
  • есть эндпоинт GET /healthz;
  • это не монорепо: один package.json и pnpm-lock.yaml в корне;
  • tsc собирает всё в dist/, а в рантайме не нужны файлы вне dist/ (миграции, шаблоны).

1. Dockerfile

# syntax=docker/dockerfile:1.7
# ↑ Включает BuildKit-фичи: cache mounts, secret mounts, heredoc.

############################################################
# Глобальные аргументы: версии в одном месте
############################################################
ARG NODE_VERSION=20
ARG DEBIAN_RELEASE=bookworm
ARG PNPM_VERSION=9.15.9

############################################################
# Stage 0: base, общий фундамент для сборочных stage'ей
############################################################
FROM node:${NODE_VERSION}-${DEBIAN_RELEASE}-slim AS base
# slim-вариант Debian: glibc (совместим с prebuilt-бинарниками нативных модулей)
# и при этом без компиляторов, man-страниц и прочего балласта.

ARG PNPM_VERSION
# Ставим pnpm через npm, а не через corepack: corepack убран из Node 25+
# и в старых патч-версиях Node падает на проверке подписей.
RUN npm install -g pnpm@${PNPM_VERSION} \
 && npm cache clean --force
# Кэш npm чистим в том же слое, иначе он осядет в образе.

WORKDIR /app

############################################################
# Stage 1: prod-deps, только production-зависимости
############################################################
FROM base AS prod-deps

# Копируем ТОЛЬКО манифесты. Слой инвалидируется лишь при смене зависимостей,
# а не при каждом изменении исходников.
COPY package.json pnpm-lock.yaml ./

# --mount=type=cache: pnpm store живёт в кэше BuildKit, а не в слое образа,
#   поэтому повторные сборки почти не ходят в сеть.
# --mount=type=secret: .npmrc с токеном приватного реестра (если он есть)
#   доступен только на время RUN и НЕ попадает ни в один слой.
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
    --mount=type=secret,id=npmrc,target=/root/.npmrc,required=false \
    pnpm install --prod --frozen-lockfile --store-dir=/pnpm/store

############################################################
# Stage 2: build, полные зависимости + компиляция TypeScript
############################################################
FROM base AS build

COPY package.json pnpm-lock.yaml ./

RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store \
    --mount=type=secret,id=npmrc,target=/root/.npmrc,required=false \
    pnpm install --frozen-lockfile --store-dir=/pnpm/store

# Исходники копируем ПОСЛЕ установки зависимостей: правка кода
# не заставит заново ставить node_modules.
COPY . .

RUN pnpm run build
# prod-deps и build независимы, и BuildKit выполняет их параллельно.

############################################################
# Stage 3: runtime, минимальный финальный образ
############################################################
FROM node:${NODE_VERSION}-${DEBIAN_RELEASE}-slim AS runtime

# tini в роли PID 1: корректно пробрасывает SIGTERM в node и собирает зомби-процессы.
# Без него node как PID 1 игнорирует SIGTERM, если приложение его не обрабатывает,
# и Kubernetes убивает под через SIGKILL после terminationGracePeriodSeconds.
# Заодно удаляем npm, npx, corepack и yarn: в рантайме они не нужны
# и только расширяют поверхность атаки (плюс их CVE).
RUN apt-get update \
 && apt-get install -y --no-install-recommends tini \
 && rm -rf /var/lib/apt/lists/* \
 && rm -rf /usr/local/lib/node_modules/npm \
           /usr/local/lib/node_modules/corepack \
           /usr/local/bin/npm /usr/local/bin/npx \
           /usr/local/bin/corepack \
           /usr/local/bin/yarn /usr/local/bin/yarnpkg \
           /opt/yarn-*

ENV NODE_ENV=production \
    PORT=4000
# NODE_ENV=production включает оптимизации Express (кэш шаблонов, короткие ошибки).
# Секреты (DB_URL, токены) сюда НЕ кладём: они приходят из K8s Secret в рантайме.

WORKDIR /app

# Файлы принадлежат root и доступны пользователю только на чтение:
# даже при RCE процесс не сможет подменить код приложения.
COPY --from=prod-deps /app/node_modules ./node_modules
COPY --from=build     /app/dist         ./dist
COPY                  package.json      ./
# package.json нужен, если в нём есть "type": "module" или его читает приложение.

# Непривилегированный пользователь node (UID 1000) уже есть в официальном образе.
# Указываем UID числом: иначе K8s с runAsNonRoot: true не сможет проверить,
# что пользователь не root, и откажется запускать под.
USER 1000:1000

EXPOSE 4000
# EXPOSE только документирует порт, реально он публикуется через Service или -p.

# Для docker run и compose. Kubernetes эту инструкцию ИГНОРИРУЕТ, там нужны probes.
# Используем встроенный в Node 20 fetch, curl ставить не нужно.
HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
  CMD ["node", "-e", "fetch('http://127.0.0.1:4000/healthz').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"]

# OCI-метаданные. ARG объявлены в конце, чтобы смена версии или SHA
# не инвалидировала кэш предыдущих слоёв.
ARG VERSION=dev
ARG GIT_SHA=unknown
LABEL org.opencontainers.image.title="shiplog-api" \
      org.opencontainers.image.version="${VERSION}" \
      org.opencontainers.image.revision="${GIT_SHA}"

# exec-форма: без /bin/sh -c, сигналы доходят до процесса напрямую.
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["node", "dist/server.js"]

Почему node:20-bookworm-slim, а не alpine

Вариант Размер (сжатый, ≈) Плюсы Минусы
node:20-alpine ~45 МБ Самый маленький musl вместо glibc: prebuilt-бинарники (bcrypt, sharp, argon2, Prisma) часто не работают или требуют пересборки; бывают тонкие различия в DNS-резолве
node:20-bookworm-slim ✅ ~70 МБ glibc, максимальная совместимость, предсказуемое поведение На ~25 МБ больше
gcr.io/distroless/nodejs20-debian12:nonroot ~45 МБ Нет shell и пакетного менеджера, минимальная поверхность атаки Нельзя сделать kubectl exec и отладить, нет tini (нужно обрабатывать SIGTERM в коде)

Для продакшена в K8s разница в 25 МБ несущественна, а совместимость важнее. Если нативных зависимостей нет, можно смело взять alpine. Если нужна максимальная защищённость, берите distroless для финального stage.

Рекомендация: в CI фиксируйте образ по digest (node:20-bookworm-slim@sha256:...), а обновление автоматизируйте через Renovate или Dependabot.


2. .dockerignore

# Артефакты: собираются внутри образа
node_modules
dist
build
coverage
*.tsbuildinfo

# VCS и CI
.git
.gitignore
.github
.gitlab-ci.yml

# Секреты и локальные конфиги: НИКОГДА не в build-контекст
.env
.env.*
!.env.example
.npmrc
*.pem
*.key

# Docker-файлы (не нужны внутри образа, их изменения не должны бить кэш COPY . .)
Dockerfile*
docker-compose*.yml
.dockerignore

# IDE, ОС, логи
.vscode
.idea
*.swp
.DS_Store
*.log
npm-debug.log*
pnpm-debug.log*

# Документация и тесты (если тесты не запускаются в Dockerfile)
*.md
docs
test
tests
**/*.test.ts
**/*.spec.ts
__tests__

Если в .npmrc есть несекретные настройки (например, node-linker, shamefully-hoist), вынесите их в отдельный закоммиченный файл и уберите .npmrc из игнора. Токены передавайте только через --secret.


3. Сборка и запуск

VERSION=1.0.0
GIT_SHA=$(git rev-parse --short HEAD)
REGISTRY=cr.yandex/<registry-id>

# Сборка под AMD64 (важно, если собираете на Apple Silicon)
docker buildx build \
  --platform linux/amd64 \
  --build-arg VERSION=$VERSION \
  --build-arg GIT_SHA=$GIT_SHA \
  --secret id=npmrc,src=$HOME/.npmrc \
  -t $REGISTRY/shiplog-api:$VERSION \
  -t $REGISTRY/shiplog-api:$VERSION-$GIT_SHA \
  --push .
# --secret нужен только при приватном npm-реестре, иначе строку можно убрать.

# Локальная проверка
docker buildx build --platform linux/amd64 --load -t shiplog-api:$VERSION .
docker run --rm -p 4000:4000 --env-file .env.local --read-only --tmpfs /tmp \
  --cap-drop=ALL --security-opt no-new-privileges shiplog-api:$VERSION
curl -f http://localhost:4000/healthz

# Анализ
docker image ls shiplog-api:$VERSION                  # размер
docker history shiplog-api:$VERSION                   # слои
trivy image --severity HIGH,CRITICAL shiplog-api:$VERSION   # уязвимости

Фрагмент манифеста Kubernetes, дополняющий образ:

securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  allowPrivilegeEscalation: false
  readOnlyRootFilesystem: true
  capabilities: { drop: ["ALL"] }
readinessProbe: { httpGet: { path: /healthz, port: 4000 }, periodSeconds: 10 }
livenessProbe:  { httpGet: { path: /healthz, port: 4000 }, initialDelaySeconds: 15, periodSeconds: 20 }
volumeMounts: [{ name: tmp, mountPath: /tmp }]     # + volumes: [{ name: tmp, emptyDir: {} }]

4. Таблица решений

Инструкция Зачем Размер Скорость Безопасность
# syntax=docker/dockerfile:1.7 Включает cache и secret mounts — ⬆ ⬆
ARG NODE_VERSION Обновление Node одной строкой — — ⬆ (быстрый апгрейд)
bookworm-slim Баланс размера и совместимости ⬇ (vs full ~400 МБ) — ⬆ меньше пакетов
Multi-stage (4 stage) Компилятор, devDeps и исходники TS не попадают в рантайм ⬇⬇ ⬆ параллельная сборка ⬆
COPY package.json pnpm-lock.yaml до COPY . . Кэш слоя зависимостей — ⬆⬆ —
--mount=type=cache (pnpm store) Store вне слоёв, переиспользуется между сборками ⬇ ⬆⬆ —
--frozen-lockfile Воспроизводимость, защита от незаметной подмены версий — — ⬆ supply chain
--mount=type=secret Токен реестра не попадает в слои — — ⬆⬆
pnpm install --prod в отдельном stage В рантайме нет devDependencies ⬇⬇ — ⬆
apt-get … && rm -rf /var/lib/apt/lists/* в одном RUN Кэш apt не оседает в слое ⬇ — —
Удаление npm/yarn/corepack Меньше бинарников и CVE ⬇ ~15 МБ — ⬆
tini Корректный SIGTERM и graceful shutdown ⬆ ~1 МБ ⬆ быстрый rollout ⬆ стабильность
Файлы root-owned + USER 1000:1000 Процесс не может менять свой код — — ⬆⬆
ENV NODE_ENV=production Оптимизации Express и библиотек — ⬆ рантайм ⬆ меньше утечек в ошибках
HEALTHCHECK через node -e fetch Проверка здоровья без curl — — —
LABEL + ARG в конце Трассируемость образа до коммита без поломки кэша — ⬆ ⬆ аудит
exec-форма ENTRYPOINT/CMD Нет промежуточного shell — — ⬆

5. Чек-лист дополнительных оптимизаций

  • Перейти на Node 22 или 24 (Node 20 EOL).
  • Зафиксировать базовый образ по @sha256: digest и автоматизировать обновления (Renovate).
  • Graceful shutdown в коде: на SIGTERM вызывать server.close(), закрывать пулы БД, выставлять terminationGracePeriodSeconds.
  • Реализовать отдельные /livez и /readyz (readiness проверяет БД, liveness нет).
  • Задавать лимит памяти через NODE_OPTIONS=--max-old-space-size=<~75% limit> в Deployment, а не в образе.
  • Попробовать distroless-рантайм, если не нужен kubectl exec.
  • Бандлинг через esbuild/tsup в один файл: node_modules в рантайме может сократиться в разы (осторожно с нативными модулями).
  • pnpm deploy --prod или --filter, если проект станет монорепо.
  • Remote cache в CI: --cache-to/--cache-from type=registry,ref=cr.yandex/.../shiplog-api:buildcache,mode=max.
  • Сканирование в CI (Trivy/Grype) с блокировкой на CRITICAL; Yandex Container Registry тоже умеет сканировать.
  • SBOM и подпись образа: --sbom=true --provenance=true, cosign.
  • hadolint Dockerfile в pre-commit и CI.
  • Сборка source maps плюс NODE_OPTIONS=--enable-source-maps для читаемых стектрейсов (небольшой оверхед).

Потенциальные проблемы и как их избежать

Проблема Причина Решение
Раздутый образ devDependencies, исходники TS, кэш pnpm/apt в слоях, full-образ Node Multi-stage, --prod, cache mounts, очистка в том же RUN, slim-база
Утечка секретов COPY .npmrc/.env, ARG NPM_TOKEN (виден в docker history), ENV SECRET=… .dockerignore, --mount=type=secret, секреты только из K8s Secret/Lockbox в рантайме
Медленный rebuild COPY . . до pnpm install, отсутствие .dockerignore (огромный контекст с node_modules и .git), нет кэша в CI Порядок слоёв, cache mount, remote cache через registry
Нативные модули падают alpine/musl или сборка на arm64 для amd64-кластера glibc-образ, --platform linux/amd64
Долгий rollout, 502 при деплое node как PID 1 не получает SIGTERM tini + обработчик SIGTERM + readinessProbe
Под не стартует с runAsNonRoot USER node (не числовой) USER 1000:1000
Ошибка записи при readOnlyRootFilesystem Приложение или библиотеки пишут в /tmp или рядом с кодом emptyDir на /tmp, логи только в stdout

Уточняющие вопросы

  1. Есть ли health-эндпоинт и по какому пути? Если нет, стоит добавить /healthz (или убрать HEALTHCHECK).
  2. Есть ли нативные зависимости (bcrypt, sharp, prisma, argon2, canvas)? От этого зависит выбор alpine или slim. Для Prisma нужно ещё копировать сгенерированный клиент и, возможно, поставить openssl.
  3. Используется ли приватный npm-реестр (.npmrc с токеном)?
  4. Нужны ли в рантайме файлы вне dist/: миграции, SQL, шаблоны, public/, конфиги?
  5. Используются ли paths-алиасы в tsconfig? tsc их не переписывает, понадобится tsc-alias или бандлер.
  6. Монорепо (pnpm workspaces) или одиночный пакет? Для монорепо схема меняется на pnpm deploy.
  7. Читает ли приложение порт из PORT или он захардкожен?
  8. Можно ли обновить Node до 22 или 24?

Ответьте на то, что расходится с допущениями, и я скорректирую Dockerfile под ваш проект.

Похожие промпты

IT и Администрирование

Ревью и рефакторинг PowerShell-скрипта

Разбирает существующий скрипт PowerShell: что сломается на реальных данных, где ошибки глушатся вместо обработки и что переписать в первую очередь, а что оставить.

IT и Администрирование

Скрипт PowerShell под задачу

Пишет скрипт PowerShell с обработкой ошибок, логированием и режимом пробного прогона — так, чтобы его можно было запустить на рабочей машине и не бояться последствий.

IT и Администрирование

Диагностика проблем VPN-подключения

Методично диагностирует проблемы VPN: соединение не устанавливается, скорость падает, утекает DNS — по одному шагу, с командами под вашу ОС.

IT и Администрирование

Помощник по настройке WireGuard и OpenVPN

Пошагово разворачивает собственный VPN-сервер на WireGuard или OpenVPN: готовые команды и конфиги, firewall, клиентские профили и проверка утечек.