From 493ff2198aa054db89869b24f1ee35208aceac3f Mon Sep 17 00:00:00 2001 From: Heitor Rosa Date: Fri, 17 Apr 2026 21:39:50 -0300 Subject: [PATCH 1/2] feat: add dockerfile for api container --- .dockerignore | 17 +++++++++++ Dockerfile | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0758b80 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,17 @@ +node_modules +dist +.git +.github +coverage + +docker +docs +test + +.env* +tools +jest.config.ts +Taskfile.yml + +*.md +!README.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..0125a00 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,79 @@ +# syntax=docker/dockerfile:1 + +ARG NODE_IMAGE=node:20-alpine + +# ----------------------------- +# Stage 1 — Install dependencies +# ----------------------------- +FROM ${NODE_IMAGE} AS deps + +RUN corepack enable pnpm + +WORKDIR /app + +COPY package.json pnpm-lock.yaml ./ + +RUN pnpm install --frozen-lockfile + + +# ----------------------------- +# Stage 2 — Build application +# ----------------------------- +FROM ${NODE_IMAGE} AS builder + +RUN corepack enable pnpm + +WORKDIR /app + +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +RUN pnpm build + + +# ----------------------------- +# Stage 3 — Production deps only +# ----------------------------- +FROM ${NODE_IMAGE} AS prod-deps + +RUN corepack enable pnpm + +WORKDIR /app + +COPY package.json pnpm-lock.yaml ./ + +RUN pnpm install --prod --frozen-lockfile + + +# ----------------------------- +# Stage 4 — Production runtime +# ----------------------------- +FROM ${NODE_IMAGE} AS production + +ENV NODE_ENV=production +ENV PORT=3000 + +WORKDIR /app + +# production dependencies +COPY --chown=node:node --from=prod-deps /app/node_modules ./node_modules + +# compiled application +COPY --chown=node:node --from=builder /app/dist ./dist + +# migrations (needed for runtime migrations if used) +COPY --chown=node:node --from=builder /app/migrations ./migrations + +# optional runtime metadata +COPY --chown=node:node package.json ./ + +EXPOSE ${PORT} + +# healthcheck using your /health endpoint +HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \ + CMD wget -qO- http://localhost:${PORT}/health || exit 1 + +# run as non-root user +USER node + +CMD ["node", "dist/main.js"] From aec1f90f9a72283a8e4edb1b68fe1e5a2170ab08 Mon Sep 17 00:00:00 2001 From: Heitor Rosa Date: Fri, 17 Apr 2026 21:40:14 -0300 Subject: [PATCH 2/2] feat: add production docker compose stack --- docker/docker-compose.dev.yml | 1 - docker/docker-compose.prod.yml | 34 +++++++++++++++++++++++++++++++++- docker/docker-compose.test.yml | 1 - 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docker/docker-compose.dev.yml b/docker/docker-compose.dev.yml index 0ae9db4..fce3756 100644 --- a/docker/docker-compose.dev.yml +++ b/docker/docker-compose.dev.yml @@ -1,7 +1,6 @@ services: postgres: image: postgres:16 - container_name: reservation-dev-postgres restart: unless-stopped environment: POSTGRES_DB: reservation_db diff --git a/docker/docker-compose.prod.yml b/docker/docker-compose.prod.yml index b2d5329..7a5757e 100644 --- a/docker/docker-compose.prod.yml +++ b/docker/docker-compose.prod.yml @@ -1,13 +1,45 @@ services: + postgres: image: postgres:16 - container_name: reservation-prod-postgres + restart: unless-stopped environment: POSTGRES_DB: reservation_db POSTGRES_USER: reservation_app POSTGRES_PASSWORD: ${DATABASE_PASSWORD} volumes: - postgres_prod_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U reservation_app -d reservation_db"] + interval: 5s + timeout: 5s + retries: 5 + + migrate: + image: reservation-api + container_name: reservation-prod-migrate + depends_on: + postgres: + condition: service_healthy + environment: + DATABASE_URL: postgres://reservation_app:${DATABASE_PASSWORD}@postgres:5432/reservation_db + command: ["node", "dist/tools/migrate.js"] + restart: "no" + + api: + image: reservation-api + container_name: reservation-prod-api + depends_on: + postgres: + condition: service_healthy + migrate: + condition: service_completed_successfully + environment: + NODE_ENV: production + DATABASE_URL: postgres://reservation_app:${DATABASE_PASSWORD}@postgres:5432/reservation_db + ports: + - "3000:3000" + restart: unless-stopped volumes: postgres_prod_data: diff --git a/docker/docker-compose.test.yml b/docker/docker-compose.test.yml index 913c613..cdd0e2f 100644 --- a/docker/docker-compose.test.yml +++ b/docker/docker-compose.test.yml @@ -1,7 +1,6 @@ services: postgres_test: image: postgres:16 - container_name: barber_test_db restart: no environment: POSTGRES_DB: barber_test