From edc8e12a599311aa3ca1ca88dc851140639e513d Mon Sep 17 00:00:00 2001 From: feyishola Date: Fri, 20 Feb 2026 11:48:06 +0100 Subject: [PATCH] dockerization of the app --- apps/api/dockerfile | 56 +++++++++++++++ docker-compose.yml | 165 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 apps/api/dockerfile create mode 100644 docker-compose.yml diff --git a/apps/api/dockerfile b/apps/api/dockerfile new file mode 100644 index 0000000..9535277 --- /dev/null +++ b/apps/api/dockerfile @@ -0,0 +1,56 @@ +# Build stage +FROM node:18-alpine AS builder + +WORKDIR /app + +# Copy package files +COPY package*.json ./ +COPY apps/api/package*.json ./apps/api/ +COPY libs/engine/package*.json ./libs/engine/ +COPY packages/rules/package*.json ./packages/rules/ + +# Install dependencies +RUN npm ci + +# Copy source code +COPY . . + +# Build the API +RUN npm run build --workspace=apps/api + +# Production stage +FROM node:18-alpine + +RUN apk add --no-cache tini + +WORKDIR /app + +# Create non-root user +RUN addgroup -g 1001 -S nodejs && \ + adduser -S nodejs -u 1001 + +# Copy package files and installed node_modules +COPY --from=builder --chown=nodejs:nodejs /app/package*.json ./ +COPY --from=builder --chown=nodejs:nodejs /app/apps/api/package*.json ./apps/api/ +COPY --from=builder --chown=nodejs:nodejs /app/libs/engine/package*.json ./libs/engine/ +COPY --from=builder --chown=nodejs:nodejs /app/packages/rules/package*.json ./packages/rules/ +COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules + +# Copy built application +COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist + +# Set environment +ENV NODE_ENV=production +ENV PORT=3000 + +# Expose port +EXPOSE 3000 + +# Switch to non-root user +USER nodejs + +# Use tini as init process +ENTRYPOINT ["/sbin/tini", "--"] + +# Start the API +CMD ["node", "dist/apps/api/main.js"] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..4218efa --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,165 @@ +version: "3.8" + +services: + # PostgreSQL Database + postgres: + image: postgres:15-alpine + container_name: gasguard-postgres + restart: unless-stopped + environment: + POSTGRES_USER: ${DB_USER:-gasguard} + POSTGRES_PASSWORD: ${DB_PASSWORD:-gasguard123} + POSTGRES_DB: ${DB_NAME:-gasguard} + POSTGRES_HOST_AUTH_METHOD: scram-sha-256 + volumes: + - postgres-data:/var/lib/postgresql/data + - ./docker/postgres/init:/docker-entrypoint-initdb.d + ports: + - "5432:5432" + networks: + - gasguard-network + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-gasguard}"] + interval: 10s + timeout: 5s + retries: 5 + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # Redis for BullMQ + redis: + image: redis:7-alpine + container_name: gasguard-redis + restart: unless-stopped + command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD:-redis123} + volumes: + - redis-data:/data + ports: + - "6379:6379" + networks: + - gasguard-network + healthcheck: + test: ["CMD", "redis-cli", "--raw", "incr", "ping"] + interval: 10s + timeout: 5s + retries: 5 + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # Backend API + api: + build: + context: . + dockerfile: apps/api/Dockerfile + container_name: gasguard-api + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + environment: + NODE_ENV: ${NODE_ENV:-production} + PORT: 3000 + DATABASE_URL: postgresql://${DB_USER:-gasguard}:${DB_PASSWORD:-gasguard123}@postgres:5432/${DB_NAME:-gasguard} + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} + RATE_LIMIT_TTL: ${RATE_LIMIT_TTL:-60} + RATE_LIMIT_MAX: ${RATE_LIMIT_MAX:-10} + API_VERSION: v1 + JWT_SECRET: ${JWT_SECRET:-your-secret-key-change-in-production} + ports: + - "3000:3000" + networks: + - gasguard-network + volumes: + - ./logs:/app/logs + healthcheck: + test: + [ + "CMD", + "wget", + "--no-verbose", + "--tries=1", + "--spider", + "http://localhost:3000/health", + ] + interval: 30s + timeout: 10s + retries: 3 + start_period: 20s + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # Worker Service (BullMQ) + worker: + build: + context: . + dockerfile: apps/worker/Dockerfile + container_name: gasguard-worker + restart: unless-stopped + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + environment: + NODE_ENV: ${NODE_ENV:-production} + DATABASE_URL: postgresql://${DB_USER:-gasguard}:${DB_PASSWORD:-gasguard123}@postgres:5432/${DB_NAME:-gasguard} + REDIS_HOST: redis + REDIS_PORT: 6379 + REDIS_PASSWORD: ${REDIS_PASSWORD:-redis123} + WORKER_CONCURRENCY: ${WORKER_CONCURRENCY:-5} + networks: + - gasguard-network + volumes: + - ./logs:/app/logs + deploy: + replicas: ${WORKER_REPLICAS:-2} + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + + # Dashboard (Optional) + dashboard: + build: + context: . + dockerfile: apps/dashboard/Dockerfile + container_name: gasguard-dashboard + restart: unless-stopped + depends_on: + - api + environment: + API_URL: http://api:3000 + ports: + - "8080:80" + networks: + - gasguard-network + logging: + driver: "json-file" + options: + max-size: "10m" + max-file: "3" + +networks: + gasguard-network: + driver: bridge + name: gasguard-network + +volumes: + postgres-data: + name: gasguard-postgres-data + redis-data: + name: gasguard-redis-data