Преглед на файлове

feat(docker): update MongoDB connection strings and Dockerfiles for improved configuration
chore(docs): enhance box-mgnt-note with Docker compose commands
chore(docker-compose): streamline services and remove unused configurations
fix(init-repl): refactor replica set initialization logic for better reliability
fix(tsconfig): include mongo directory in TypeScript compilation

Dave преди 3 месеца
родител
ревизия
286d1ad6ed
променени са 10 файла, в които са добавени 227 реда и са изтрити 210 реда
  1. 4 2
      .env.docker
  2. 2 0
      .eslintignore
  3. 5 0
      .gitignore
  4. 47 15
      apps/box-app-api/Dockerfile
  5. 48 15
      apps/box-mgnt-api/Dockerfile
  6. 45 13
      apps/box-stats-api/Dockerfile
  7. 5 0
      box-mgnt-note.md
  8. 35 118
      docker-compose.yml
  9. 35 46
      docker/mongo/init-repl.js
  10. 1 1
      tsconfig.json

+ 4 - 2
.env.docker

@@ -4,8 +4,10 @@ APP_CORS_ORIGIN=*
 
 MYSQL_URL="mysql://root:rootpass@box-mysql:3306/box_admin"
 
-MONGO_URL="mongodb://boxadmin:boxpass@box-mongodb:27017/box_admin?replicaSet=rs0&authSource=admin"
-MONGO_STATS_URL="mongodb://boxadmin:boxpass@box-mongodb:27017/box_stats?replicaSet=rs0&authSource=admin"
+# MONGO_URL="mongodb://boxadmin:boxpass@box-mongodb:27017/box_admin?replicaSet=rs0&authSource=admin"
+# MONGO_STATS_URL="mongodb://boxadmin:boxpass@box-mongodb:27017/box_stats?replicaSet=rs0&authSource=admin"
+MONGO_URL="mongodb://box-mongodb:27017/box_admin?replicaSet=rs0"
+MONGO_STATS_URL="mongodb://box-mongodb:27017/box_stats?replicaSet=rs0"
 
 JWT_SECRET=047df8aaa3d17dc1173c5a9a3052ba66c2b0bd96937147eb643319a0c90d132f
 

+ 2 - 0
.eslintignore

@@ -0,0 +1,2 @@
+docker/mongo/**
+scripts/**

+ 5 - 0
.gitignore

@@ -62,3 +62,8 @@ src/tmp/*
 # .env.app.dev
 # .env.mgnt
 # .env.mgnt.dev
+scripts/cleanup-docker.sh
+scripts/smoke.sh
+scripts/start-db.sh
+scripts/stop-db.sh
+docker/mongo/mongo-keyfile

+ 47 - 15
apps/box-app-api/Dockerfile

@@ -1,12 +1,28 @@
 # syntax=docker/dockerfile:1
-FROM node:20-alpine AS deps
+
+# ----------------------------
+# deps: install full deps once
+# ----------------------------
+FROM node:20-slim AS deps
 WORKDIR /workspace
+
+# Build tools needed for native modules (bcrypt) during install in this stage
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends python3 make g++ \
+  && rm -rf /var/lib/apt/lists/*
+
 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
 COPY tsconfig.json tsconfig.base.json tsconfig.seed.json nest-cli.json ./
-RUN corepack enable && corepack pnpm install --frozen-lockfile
 
-FROM node:20-alpine AS builder
+RUN corepack enable \
+  && corepack pnpm install --frozen-lockfile
+
+# ----------------------------
+# builder: generate prisma + build
+# ----------------------------
+FROM node:20-slim AS builder
 WORKDIR /workspace
+
 COPY --from=deps /workspace/node_modules ./node_modules
 COPY --from=deps /workspace/package.json ./package.json
 COPY --from=deps /workspace/pnpm-lock.yaml ./pnpm-lock.yaml
@@ -15,25 +31,41 @@ COPY --from=deps /workspace/tsconfig.json ./tsconfig.json
 COPY --from=deps /workspace/tsconfig.base.json ./tsconfig.base.json
 COPY --from=deps /workspace/tsconfig.seed.json ./tsconfig.seed.json
 COPY --from=deps /workspace/nest-cli.json ./nest-cli.json
+
 COPY apps ./apps
 COPY libs ./libs
 COPY prisma ./prisma
-COPY .env.docker .env.docker
-RUN set -a \
-  && . .env.docker \
-  && corepack enable \
-  && corepack pnpm prisma generate --schema=prisma/mysql/schema/main.prisma \
-  && corepack pnpm prisma generate --schema=prisma/mongo/schema/main.prisma \
-  && corepack pnpm prisma generate --schema=prisma/mongo-stats/schema/main.prisma \
-  && set +a \
-  && corepack pnpm build:app
-
-FROM node:20-alpine AS runner
+
+# No build-time env sourcing; keep build deterministic
+RUN corepack enable \
+  && corepack pnpm prisma:generate:mysql \
+  && corepack pnpm prisma:generate:mongo \
+  && corepack pnpm prisma:generate:mongostats \
+  && corepack pnpm build:stats
+
+# ----------------------------
+# runner: prod deps + bcrypt rebuild + runtime files
+# ----------------------------
+FROM node:20-slim AS runner
 WORKDIR /workspace
+
+# Only what's needed to rebuild native module in runtime image
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends python3 make g++ \
+  && rm -rf /var/lib/apt/lists/*
+
 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
-RUN corepack enable && corepack pnpm install --frozen-lockfile --prod
+
+RUN corepack enable \
+  && corepack pnpm install --frozen-lockfile --prod \
+  && npm rebuild bcrypt
+
 COPY --from=builder /workspace/dist ./dist
+
+# Prisma runtime artifacts
 COPY --from=builder /workspace/node_modules/@prisma ./node_modules/@prisma
+COPY --from=builder /workspace/node_modules/.prisma ./node_modules/.prisma
+
 ENV NODE_ENV=production
 EXPOSE 3301
 CMD ["node", "dist/apps/box-app-api/src/main.js"]

+ 48 - 15
apps/box-mgnt-api/Dockerfile

@@ -1,12 +1,29 @@
+
 # syntax=docker/dockerfile:1
-FROM node:20-alpine AS deps
+
+# ----------------------------
+# deps: install full deps once
+# ----------------------------
+FROM node:20-slim AS deps
 WORKDIR /workspace
+
+# Build tools needed for native modules (bcrypt) during install in this stage
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends python3 make g++ \
+  && rm -rf /var/lib/apt/lists/*
+
 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
 COPY tsconfig.json tsconfig.base.json tsconfig.seed.json nest-cli.json ./
-RUN corepack enable && corepack pnpm install --frozen-lockfile
 
-FROM node:20-alpine AS builder
+RUN corepack enable \
+  && corepack pnpm install --frozen-lockfile
+
+# ----------------------------
+# builder: generate prisma + build
+# ----------------------------
+FROM node:20-slim AS builder
 WORKDIR /workspace
+
 COPY --from=deps /workspace/node_modules ./node_modules
 COPY --from=deps /workspace/package.json ./package.json
 COPY --from=deps /workspace/pnpm-lock.yaml ./pnpm-lock.yaml
@@ -15,25 +32,41 @@ COPY --from=deps /workspace/tsconfig.json ./tsconfig.json
 COPY --from=deps /workspace/tsconfig.base.json ./tsconfig.base.json
 COPY --from=deps /workspace/tsconfig.seed.json ./tsconfig.seed.json
 COPY --from=deps /workspace/nest-cli.json ./nest-cli.json
+
 COPY apps ./apps
 COPY libs ./libs
 COPY prisma ./prisma
-COPY .env.docker .env.docker
-RUN set -a \
-  && . .env.docker \
-  && corepack enable \
-  && corepack pnpm prisma generate --schema=prisma/mysql/schema/main.prisma \
-  && corepack pnpm prisma generate --schema=prisma/mongo/schema/main.prisma \
-  && corepack pnpm prisma generate --schema=prisma/mongo-stats/schema/main.prisma \
-  && set +a \
-  && corepack pnpm build:mgnt
-
-FROM node:20-alpine AS runner
+
+# No build-time env sourcing; keep build deterministic
+RUN corepack enable \
+  && corepack pnpm prisma:generate:mysql \
+  && corepack pnpm prisma:generate:mongo \
+  && corepack pnpm prisma:generate:mongostats \
+  && corepack pnpm build:stats
+
+# ----------------------------
+# runner: prod deps + bcrypt rebuild + runtime files
+# ----------------------------
+FROM node:20-slim AS runner
 WORKDIR /workspace
+
+# Only what's needed to rebuild native module in runtime image
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends python3 make g++ \
+  && rm -rf /var/lib/apt/lists/*
+
 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
-RUN corepack enable && corepack pnpm install --frozen-lockfile --prod
+
+RUN corepack enable \
+  && corepack pnpm install --frozen-lockfile --prod \
+  && npm rebuild bcrypt
+
 COPY --from=builder /workspace/dist ./dist
+
+# Prisma runtime artifacts
 COPY --from=builder /workspace/node_modules/@prisma ./node_modules/@prisma
+COPY --from=builder /workspace/node_modules/.prisma ./node_modules/.prisma
+
 ENV NODE_ENV=production
 EXPOSE 3300
 CMD ["node", "dist/apps/box-mgnt-api/src/main.js"]

+ 45 - 13
apps/box-stats-api/Dockerfile

@@ -1,12 +1,28 @@
 # syntax=docker/dockerfile:1
-FROM node:20-alpine AS deps
+
+# ----------------------------
+# deps: install full deps once
+# ----------------------------
+FROM node:20-slim AS deps
 WORKDIR /workspace
+
+# Build tools needed for native modules (bcrypt) during install in this stage
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends python3 make g++ \
+  && rm -rf /var/lib/apt/lists/*
+
 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
 COPY tsconfig.json tsconfig.base.json tsconfig.seed.json nest-cli.json ./
-RUN corepack enable && corepack pnpm install --frozen-lockfile
 
-FROM node:20-alpine AS builder
+RUN corepack enable \
+  && corepack pnpm install --frozen-lockfile
+
+# ----------------------------
+# builder: generate prisma + build
+# ----------------------------
+FROM node:20-slim AS builder
 WORKDIR /workspace
+
 COPY --from=deps /workspace/node_modules ./node_modules
 COPY --from=deps /workspace/package.json ./package.json
 COPY --from=deps /workspace/pnpm-lock.yaml ./pnpm-lock.yaml
@@ -15,25 +31,41 @@ COPY --from=deps /workspace/tsconfig.json ./tsconfig.json
 COPY --from=deps /workspace/tsconfig.base.json ./tsconfig.base.json
 COPY --from=deps /workspace/tsconfig.seed.json ./tsconfig.seed.json
 COPY --from=deps /workspace/nest-cli.json ./nest-cli.json
+
 COPY apps ./apps
 COPY libs ./libs
 COPY prisma ./prisma
-COPY .env.docker .env.docker
-RUN set -a \
-  && . .env.docker \
-  && corepack enable \
-  && corepack pnpm prisma generate --schema=prisma/mysql/schema/main.prisma \
-  && corepack pnpm prisma generate --schema=prisma/mongo/schema/main.prisma \
-  && corepack pnpm prisma generate --schema=prisma/mongo-stats/schema/main.prisma \
-  && set +a \
+
+# No build-time env sourcing; keep build deterministic
+RUN corepack enable \
+  && corepack pnpm prisma:generate:mysql \
+  && corepack pnpm prisma:generate:mongo \
+  && corepack pnpm prisma:generate:mongostats \
   && corepack pnpm build:stats
 
-FROM node:20-alpine AS runner
+# ----------------------------
+# runner: prod deps + bcrypt rebuild + runtime files
+# ----------------------------
+FROM node:20-slim AS runner
 WORKDIR /workspace
+
+# Only what's needed to rebuild native module in runtime image
+RUN apt-get update \
+  && apt-get install -y --no-install-recommends python3 make g++ \
+  && rm -rf /var/lib/apt/lists/*
+
 COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./
-RUN corepack enable && corepack pnpm install --frozen-lockfile --prod
+
+RUN corepack enable \
+  && corepack pnpm install --frozen-lockfile --prod \
+  && npm rebuild bcrypt
+
 COPY --from=builder /workspace/dist ./dist
+
+# Prisma runtime artifacts
 COPY --from=builder /workspace/node_modules/@prisma ./node_modules/@prisma
+COPY --from=builder /workspace/node_modules/.prisma ./node_modules/.prisma
+
 ENV NODE_ENV=production
 EXPOSE 3302
 CMD ["node", "dist/apps/box-stats-api/src/main.js"]

+ 5 - 0
box-mgnt-note.md

@@ -20,6 +20,11 @@ pnpm prisma:generate
 ## to install redis server locally
 docker run -d --name box-redis -p 6379:6379 redis:7
 
+docker compose down -v
+docker compose --env-file .env.docker up -d
+docker compose --env-file .env.docker up -d box-mongodb-init
+docker compose ps
+
 ## to start redis server
 docker start box-redis
 

+ 35 - 118
docker-compose.yml

@@ -1,104 +1,26 @@
-version: '3.9'
-
 services:
-  box-redis:
-    image: redis:7
-    restart: unless-stopped
-    ports:
-      - '6379:6379'
-    healthcheck:
-      test: ["CMD", "redis-cli", "-h", "127.0.0.1", "ping"]
-      interval: 10s
-      timeout: 5s
-      retries: 5
-    volumes:
-      - redis_data:/data
-    networks:
-      - box-network
-
-  box-rabbitmq:
-    image: rabbitmq:3.12-management
-    restart: unless-stopped
-    ports:
-      - '5672:5672'
-      - '15672:15672'
-    environment:
-      RABBITMQ_DEFAULT_USER: boxrabbit
-      RABBITMQ_DEFAULT_PASS: BoxRabbit2025
-      RABBITMQ_DEFAULT_VHOST: /
-    healthcheck:
-      test: ["CMD", "rabbitmq-diagnostics", "status"]
-      interval: 10s
-      timeout: 5s
-      retries: 5
-    volumes:
-      - rabbitmq_data:/var/lib/rabbitmq
-    networks:
-      - box-network
-
-  box-mongodb:
-    image: mongo:7
-    restart: unless-stopped
-    command: ["mongod", "--replSet", "rs0", "--bind_ip_all"]
-    ports:
-      - '27017:27017'
-    environment:
-      MONGO_INITDB_ROOT_USERNAME: boxadmin
-      MONGO_INITDB_ROOT_PASSWORD: boxpass
-      MONGO_INITDB_DATABASE: box_admin
-    healthcheck:
-      test: ["CMD", "mongo", "--quiet", "--eval", "db.adminCommand('ping')", "-u", "boxadmin", "-p", "boxpass", "--authenticationDatabase", "admin"]
-      interval: 10s
-      timeout: 5s
-      retries: 5
-    volumes:
-      - mongo_data:/data/db
-      - ./docker/mongo/init-repl.js:/docker-entrypoint-initdb.d/init-repl.js:ro
-    networks:
-      - box-network
-
-  box-mysql:
-    image: mysql:8
-    restart: unless-stopped
-    profiles:
-      - migration
-    ports:
-      - '3306:3306'
-    environment:
-      MYSQL_ROOT_PASSWORD: rootpass
-      MYSQL_DATABASE: box_admin
-    healthcheck:
-      test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1"]
-      interval: 10s
-      timeout: 5s
-      retries: 5
-    volumes:
-      - mysql_data:/var/lib/mysql
-    networks:
-      - box-network
-
   box-mgnt-api:
     build:
       context: .
       dockerfile: apps/box-mgnt-api/Dockerfile
+    container_name: box-mgnt-api
+    restart: unless-stopped
     ports:
-      - '3300:3300'
+      - "3300:3300"
     env_file:
       - .env.docker
     environment:
       NODE_ENV: development
       APP_HOST: 0.0.0.0
       APP_PORT: 3300
-      APP_CORS_ORIGIN: '*'
-      REDIS_DB: 0
-      REDIS_TLS: 'false'
-    depends_on:
-      box-redis:
-        condition: service_healthy
-      box-rabbitmq:
-        condition: service_healthy
-      box-mongodb:
-        condition: service_healthy
+      APP_CORS_ORIGIN: "*"
+      REDIS_HOST: box-redis
+      REDIS_PORT: "6379"
+      REDIS_DB: "0"
+      REDIS_TLS: "false"
+      RABBITMQ_HOST: box-rabbitmq
+      MONGO_HOST: box-mongodb
+      MYSQL_HOST: box-mysql
     networks:
       - box-network
 
@@ -106,24 +28,24 @@ services:
     build:
       context: .
       dockerfile: apps/box-app-api/Dockerfile
+    container_name: box-app-api
+    restart: unless-stopped
     ports:
-      - '3301:3301'
+      - "3301:3301"
     env_file:
       - .env.docker
     environment:
       NODE_ENV: development
       APP_HOST: 0.0.0.0
       APP_PORT: 3301
-      APP_CORS_ORIGIN: '*'
-      REDIS_DB: 1
-      REDIS_TLS: 'false'
-    depends_on:
-      box-redis:
-        condition: service_healthy
-      box-rabbitmq:
-        condition: service_healthy
-      box-mongodb:
-        condition: service_healthy
+      APP_CORS_ORIGIN: "*"
+      REDIS_HOST: box-redis
+      REDIS_PORT: "6379"
+      REDIS_DB: "1"
+      REDIS_TLS: "false"
+      RABBITMQ_HOST: box-rabbitmq
+      MONGO_HOST: box-mongodb
+      MYSQL_HOST: box-mysql
     networks:
       - box-network
 
@@ -131,33 +53,28 @@ services:
     build:
       context: .
       dockerfile: apps/box-stats-api/Dockerfile
+    container_name: box-stats-api
+    restart: unless-stopped
     ports:
-      - '3302:3302'
+      - "3302:3302"
     env_file:
       - .env.docker
     environment:
       NODE_ENV: development
       APP_HOST: 0.0.0.0
       APP_PORT: 3302
-      APP_CORS_ORIGIN: '*'
-      REDIS_DB: 2
-      REDIS_TLS: 'false'
-    depends_on:
-      box-redis:
-        condition: service_healthy
-      box-rabbitmq:
-        condition: service_healthy
-      box-mongodb:
-        condition: service_healthy
+      APP_CORS_ORIGIN: "*"
+      REDIS_HOST: box-redis
+      REDIS_PORT: "6379"
+      REDIS_DB: "2"
+      REDIS_TLS: "false"
+      RABBITMQ_HOST: box-rabbitmq
+      MONGO_HOST: box-mongodb
+      MYSQL_HOST: box-mysql
     networks:
       - box-network
 
-volumes:
-  redis_data:
-  rabbitmq_data:
-  mongo_data:
-  mysql_data:
-
 networks:
   box-network:
-    driver: bridge
+    external: true
+    name: box-network

+ 35 - 46
docker/mongo/init-repl.js

@@ -1,57 +1,46 @@
 (function () {
-  const replSetName = 'rs0';
-  const replSetHost = 'box-mongodb:27017';
-  const config = {
-    _id: replSetName,
-    members: [
-      {
-        _id: 0,
-        host: replSetHost,
-      },
-    ],
-  };
+  const rsName = 'rs0';
+  const host = 'box-mongodb:27017';
 
-  function replicaSetIsReady() {
+  const j = (x) => {
     try {
-      const status = rs.status();
-      return status && status.ok === 1;
-    } catch (error) {
-      print('Replica set status unavailable:', error.message);
-      return false;
+      return JSON.stringify(x);
+    } catch (e) {
+      return String(x);
     }
+  };
+
+  try {
+    const st = rs.status();
+    if (st && st.ok === 1) {
+      print('[init-rs] Replica set already initialized. ok=1');
+      quit(0);
+    }
+  } catch (e) {
+    // not initialized yet => continue
   }
 
-  if (!replicaSetIsReady()) {
-    print('Initializing replica set', JSON.stringify(config));
-    rs.initiate(config);
-    let attempts = 0;
-    while (attempts < 20) {
-      let status;
-      try {
-        status = rs.status();
-      } catch (error) {
-        print('Replica set not ready yet:', error.message);
-        sleep(1000);
-        attempts += 1;
-        continue;
-      }
+  const cfg = { _id: rsName, members: [{ _id: 0, host }] };
 
-      if (status && status.ok === 1 && status.myState === 1) {
-        print('Replica set is PRIMARY');
-        break;
-      }
+  try {
+    const res = rs.initiate(cfg);
+    print('[init-rs] rs.initiate:', j(res));
+  } catch (e) {
+    print('[init-rs] rs.initiate error:', String(e));
+  }
 
-      print('Waiting for PRIMARY (attempt', attempts + 1, ')');
-      sleep(1000);
-      attempts += 1;
-    }
-  } else {
-    print('Replica set already initialized');
+  // wait for ok
+  for (let i = 0; i < 60; i++) {
+    try {
+      const st2 = rs.status();
+      if (st2 && st2.ok === 1) {
+        print('[init-rs] Replica set OK. status:', j(st2));
+        quit(0);
+      }
+    } catch (e) {}
+    sleep(1000);
   }
 
-  ['box_admin', 'box_stats'].forEach((dbName) => {
-    const targetDb = db.getSiblingDB(dbName);
-    const result = targetDb.runCommand({ ping: 1 });
-    print('Ensured database ' + dbName + ':', tojson(result));
-  });
+  print('[init-rs] Replica set NOT OK after timeout');
+  quit(1);
 })();

+ 1 - 1
tsconfig.json

@@ -11,6 +11,6 @@
       "@prisma/mongo/client": ["node_modules/@prisma/mongo/client/index.d.ts"]
     }
   },
-  "include": ["apps/**/*", "libs/**/*", "prisma/**/*"],
+  "include": ["apps/**/*", "libs/**/*", "prisma/**/*", "mongo/**/*"],
   "exclude": ["node_modules", "dist", "**/*.spec.ts", "**/*.test.ts"]
 }