From c32f3e12ec45f2b7896231ddf1efe0689b431165 Mon Sep 17 00:00:00 2001 From: poturaevpetr Date: Wed, 22 Apr 2026 18:27:32 +0500 Subject: [PATCH] add global docker setting update env.example, add docker-compose.yml for start all services --- .dockerignore | 15 +++++++++++++ .env.example | 10 ++++----- apps/api/src/main.ts | 4 +++- apps/web/next.config.ts | 2 ++ docker-compose.yml | 49 ++++++++++++++++++++++++++++++++++++++++ docker/Dockerfile.api | 29 ++++++++++++++++++++++++ docker/Dockerfile.web | 50 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 153 insertions(+), 6 deletions(-) create mode 100644 .dockerignore create mode 100644 docker/Dockerfile.api create mode 100644 docker/Dockerfile.web diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..2cb59c1 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,15 @@ +node_modules +**/node_modules +**/.next +**/dist +.git +.gitignore +*.md +.env +.env.* +!.env.example +coverage +**/.turbo +**/coverage +.DS_Store +apps/web/pnpm-lock.yaml diff --git a/.env.example b/.env.example index 2b63511..51ee517 100644 --- a/.env.example +++ b/.env.example @@ -1,8 +1,8 @@ -# База данных -DATABASE_URL="postgresql://brandbook:brandbook@localhost:5433/brandbook" +# База данных (локально: порт как в docker-compose.yml, маппинг 5434 -> 5432 в контейнере) +DATABASE_URL="postgresql://brandbook:brandbook@localhost:5434/brandbook" -# API (NestJS) -API_PORT=3001 +# API (NestJS) — в коде используется переменная PORT +PORT=3001 -# Web (Next.js) +# Web (Next.js) — URL API в браузере (при docker compose: http://localhost:3001) NEXT_PUBLIC_API_URL=http://localhost:3001 diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index b179239..38b4f6f 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -4,7 +4,9 @@ import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.create(AppModule); - app.enableCors({ origin: [/^http:\/\/localhost:\d+$/] }); + app.enableCors({ + origin: [/^http:\/\/localhost:\d+$/, /^http:\/\/127\.0\.0\.1:\d+$/], + }); await app.listen(process.env.PORT ?? 3000); } bootstrap(); diff --git a/apps/web/next.config.ts b/apps/web/next.config.ts index 4bb47c5..8e50b69 100644 --- a/apps/web/next.config.ts +++ b/apps/web/next.config.ts @@ -4,6 +4,8 @@ import path from "path"; const isDev = process.env.NODE_ENV === "development"; const nextConfig: NextConfig = { + output: "standalone", + outputFileTracingRoot: path.join(__dirname, "../.."), ...(isDev && { turbopack: { root: path.resolve(__dirname, "../.."), diff --git a/docker-compose.yml b/docker-compose.yml index 12574d4..57f0341 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,6 @@ +# Полный стек: docker compose up --build -d → web :3000, api :3001, postgres :5434 (хост) +# Только БД: docker compose up -d postgres + services: postgres: image: postgres:16-alpine @@ -11,6 +14,52 @@ services: - "5434:5432" volumes: - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U brandbook -d brandbook"] + interval: 5s + timeout: 5s + retries: 10 + + api: + build: + context: . + dockerfile: docker/Dockerfile.api + container_name: brandbook_api + restart: unless-stopped + ports: + - "3001:3001" + environment: + DATABASE_URL: postgresql://brandbook:brandbook@postgres:5432/brandbook + PORT: "3001" + depends_on: + postgres: + condition: service_healthy + healthcheck: + test: + [ + "CMD-SHELL", + "wget -qO- http://127.0.0.1:3001/ >/dev/null || exit 1", + ] + interval: 10s + timeout: 5s + retries: 5 + start_period: 40s + + web: + build: + context: . + dockerfile: docker/Dockerfile.web + args: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-http://localhost:3001} + container_name: brandbook_web + restart: unless-stopped + ports: + - "3000:3000" + environment: + PORT: "3000" + depends_on: + api: + condition: service_healthy volumes: postgres_data: diff --git a/docker/Dockerfile.api b/docker/Dockerfile.api new file mode 100644 index 0000000..cd6c161 --- /dev/null +++ b/docker/Dockerfile.api @@ -0,0 +1,29 @@ +FROM node:22-bookworm-slim AS api + +WORKDIR /app + +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends openssl ca-certificates wget \ + && rm -rf /var/lib/apt/lists/* + +RUN corepack enable && corepack prepare pnpm@9.15.4 --activate + +COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ +COPY apps/api/package.json ./apps/api/ +COPY apps/web/package.json ./apps/web/ + +RUN pnpm install --frozen-lockfile + +COPY apps/api ./apps/api + +RUN pnpm --filter api exec prisma generate \ + && pnpm --filter api build + +WORKDIR /app/apps/api + +ENV NODE_ENV=production +ENV PORT=3001 + +EXPOSE 3001 + +CMD ["sh", "-c", "pnpm exec prisma migrate deploy && node dist/main.js"] diff --git a/docker/Dockerfile.web b/docker/Dockerfile.web new file mode 100644 index 0000000..310e689 --- /dev/null +++ b/docker/Dockerfile.web @@ -0,0 +1,50 @@ +FROM node:22-bookworm-slim AS deps + +WORKDIR /app + +RUN apt-get update -y \ + && apt-get install -y --no-install-recommends openssl ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +RUN corepack enable && corepack prepare pnpm@9.15.4 --activate + +COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ +COPY apps/web/package.json ./apps/web/ +COPY apps/api/package.json ./apps/api/ + +RUN pnpm install --frozen-lockfile + +FROM deps AS builder + +WORKDIR /app + +COPY apps/web ./apps/web + +ARG NEXT_PUBLIC_API_URL=http://localhost:3001 +ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} +ENV NEXT_TELEMETRY_DISABLED=1 +ENV NODE_ENV=production + +RUN pnpm --filter web build + +FROM node:22-bookworm-slim AS runner + +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 + +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs + +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static + +USER nextjs + +EXPOSE 3000 + +CMD ["node", "apps/web/server.js"]