Browse Source

feat: container registry friendly docker images and all-in-one container (#3193)

Co-authored-by: Balu Babu <balub997@gmail.com>
Andrew Bastin 1 year ago
parent
commit
efa40cf6ea

+ 2 - 1
.dockerignore

@@ -1 +1,2 @@
-*/**/node_modules
+node_modules
+**/*/node_modules

+ 11 - 0
aio.Caddyfile

@@ -0,0 +1,11 @@
+:3000 {
+  try_files {path} /
+  root * /site/selfhost-web
+  file_server
+}
+
+:3100 {
+  try_files {path} /
+  root * /site/sh-admin
+  file_server
+}

+ 72 - 0
aio_run.mjs

@@ -0,0 +1,72 @@
+#!/usr/local/bin/node
+// @ts-check
+
+import { execSync, spawn } from "child_process"
+import fs from "fs"
+import process from "process"
+
+function runChildProcessWithPrefix(command, args, prefix) {
+  const childProcess = spawn(command, args);
+
+  childProcess.stdout.on('data', (data) => {
+    const output = data.toString().trim().split('\n');
+    output.forEach((line) => {
+      console.log(`${prefix} | ${line}`);
+    });
+  });
+
+  childProcess.stderr.on('data', (data) => {
+    const error = data.toString().trim().split('\n');
+    error.forEach((line) => {
+      console.error(`${prefix} | ${line}`);
+    });
+  });
+
+  childProcess.on('close', (code) => {
+    console.log(`${prefix} Child process exited with code ${code}`);
+  });
+
+  childProcess.on('error', (stuff) => {
+    console.log("error")
+    console.log(stuff)
+  })
+
+  return childProcess
+}
+
+const envFileContent = Object.entries(process.env)
+  .filter(([env]) => env.startsWith("VITE_"))
+  .map(([env, val]) => `${env}=${
+    (val.startsWith("\"") && val.endsWith("\""))
+      ? val
+      : `"${val}"`
+  }`)
+  .join("\n")
+
+fs.writeFileSync("build.env", envFileContent)
+
+execSync(`npx import-meta-env -x build.env -e build.env -p "/site/**/*"`)
+
+fs.rmSync("build.env")
+
+const caddyProcess = runChildProcessWithPrefix("caddy", ["run", "--config", "/etc/caddy/Caddyfile", "--adapter", "caddyfile"], "App/Admin Dashboard Caddy")
+const backendProcess = runChildProcessWithPrefix("pnpm", ["run", "start:prod"], "Backend Server")
+
+caddyProcess.on("exit", (code) => {
+  console.log(`Exiting process because Caddy Server exited with code ${code}`)
+  process.exit(code)
+})
+
+backendProcess.on("exit", (code) => {
+  console.log(`Exiting process because Backend Server exited with code ${code}`)
+  process.exit(code)
+})
+
+process.on('SIGINT', () => {
+  console.log("SIGINT received, exiting...")
+
+  caddyProcess.kill("SIGINT")
+  backendProcess.kill("SIGINT")
+
+  process.exit(0)
+})

+ 76 - 7
docker-compose.yml

@@ -8,16 +8,16 @@ services:
   hoppscotch-backend:
     container_name: hoppscotch-backend
     build:
-      dockerfile: packages/hoppscotch-backend/Dockerfile
+      dockerfile: prod.Dockerfile
       context: .
-      target: prod
+      target: backend
     env_file:
       - ./.env
     restart: always
     environment:
       # Edit the below line to match your PostgresDB URL if you have an outside DB (make sure to update the .env file as well)
       - DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch?connect_timeout=300
-      - PORT=3000
+      - PORT=3170
     volumes:
       # Uncomment the line below when modifying code. Only applicable when using the "dev" target.
       # - ./packages/hoppscotch-backend/:/usr/src/app
@@ -26,7 +26,7 @@ services:
       hoppscotch-db:
         condition: service_healthy
     ports:
-      - "3170:3000"
+      - "3170:3170"
 
   # The main hoppscotch app. This will be hosted at port 3000
   # NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for
@@ -34,8 +34,9 @@ services:
   hoppscotch-app:
     container_name: hoppscotch-app
     build:
-      dockerfile: packages/hoppscotch-selfhost-web/Dockerfile
+      dockerfile: prod.Dockerfile
       context: .
+      target: app
     env_file:
       - ./.env
     depends_on:
@@ -49,8 +50,9 @@ services:
   hoppscotch-sh-admin:
     container_name: hoppscotch-sh-admin
     build:
-      dockerfile: packages/hoppscotch-sh-admin/Dockerfile
+      dockerfile: prod.Dockerfile
       context: .
+      target: sh_admin
     env_file:
       - ./.env
     depends_on:
@@ -58,6 +60,23 @@ services:
     ports:
       - "3100:8080"
 
+  # The service that spins up all 3 services at once in one container
+  hoppscotch-aio:
+    container_name: hoppscotch-aio
+    build:
+      dockerfile: prod.Dockerfile
+      context: .
+      target: aio
+    env_file:
+      - ./.env
+    depends_on:
+      hoppscotch-db:
+        condition: service_healthy
+    ports:
+      - "3000:3000"
+      - "3100:3100"
+      - "3170:3170"
+
   # The preset DB service, you can delete/comment the below lines if
   # you are using an external postgres instance
   # This will be exposed at port 5432
@@ -73,9 +92,59 @@ services:
       POSTGRES_PASSWORD: testpass
       POSTGRES_DB: hoppscotch
     healthcheck:
-      test: ["CMD-SHELL", "sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'"]
+      test:
+        [
+          "CMD-SHELL",
+          "sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'"
+        ]
       interval: 5s
       timeout: 5s
       retries: 10
 
+  # All the services listed below are deprececated
+  hoppscotch-old-backend:
+    container_name: hoppscotch-old-backend
+    build:
+      dockerfile: packages/hoppscotch-backend/Dockerfile
+      context: .
+      target: prod
+    env_file:
+      - ./.env
+    restart: always
+    environment:
+      # Edit the below line to match your PostgresDB URL if you have an outside DB (make sure to update the .env file as well)
+      - DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch?connect_timeout=300
+      - PORT=3000
+    volumes:
+      # Uncomment the line below when modifying code. Only applicable when using the "dev" target.
+      # - ./packages/hoppscotch-backend/:/usr/src/app
+      - /usr/src/app/node_modules/
+    depends_on:
+      hoppscotch-db:
+        condition: service_healthy
+    ports:
+      - "3170:3000"
+
+  hoppscotch-old-app:
+    container_name: hoppscotch-old-app
+    build:
+      dockerfile: packages/hoppscotch-selfhost-web/Dockerfile
+      context: .
+    env_file:
+      - ./.env
+    depends_on:
+      - hoppscotch-old-backend
+    ports:
+      - "3000:8080"
 
+  hoppscotch-old-sh-admin:
+    container_name: hoppscotch-old-sh-admin
+    build:
+      dockerfile: packages/hoppscotch-sh-admin/Dockerfile
+      context: .
+    env_file:
+      - ./.env
+    depends_on:
+      - hoppscotch-old-backend
+    ports:
+      - "3100:8080"

+ 14 - 0
healthcheck.sh

@@ -0,0 +1,14 @@
+#!/bin/bash
+
+curlCheck() {
+  if ! curl -s --head "$1" | head -n 1 | grep -q "HTTP/1.[01] [23].."; then
+    echo "URL request failed!"
+    exit 1
+  else
+    echo "URL request succeeded!"
+  fi
+}
+
+curlCheck "http://localhost:3000"
+curlCheck "http://localhost:3100"
+curlCheck "http://localhost:3170/ping"

+ 2 - 2
packages/hoppscotch-backend/package.json

@@ -33,7 +33,7 @@
     "@nestjs/passport": "^9.0.0",
     "@nestjs/platform-express": "^9.2.1",
     "@nestjs/throttler": "^4.0.0",
-    "@prisma/client": "^4.7.1",
+    "@prisma/client": "^4.16.2",
     "apollo-server-express": "^3.11.1",
     "apollo-server-plugin-base": "^3.7.1",
     "argon2": "^0.30.3",
@@ -57,7 +57,7 @@
     "passport-jwt": "^4.0.1",
     "passport-local": "^1.0.0",
     "passport-microsoft": "^1.0.0",
-    "prisma": "^4.7.1",
+    "prisma": "^4.16.2",
     "reflect-metadata": "^0.1.13",
     "rimraf": "^3.0.2",
     "rxjs": "^7.6.0"

+ 1 - 1
packages/hoppscotch-backend/prisma/schema.prisma

@@ -5,7 +5,7 @@ datasource db {
 
 generator client {
   provider      = "prisma-client-js"
-  binaryTargets = ["native", "debian-openssl-1.1.x"]
+  binaryTargets = ["native", "debian-openssl-1.1.x", "debian-openssl-3.0.x"]
 }
 
 model Team {

+ 9 - 0
packages/hoppscotch-backend/src/app.controller.ts

@@ -0,0 +1,9 @@
+import { Controller, Get } from '@nestjs/common';
+
+@Controller('ping')
+export class AppController {
+  @Get()
+  ping(): string {
+    return 'Success';
+  }
+}

+ 2 - 0
packages/hoppscotch-backend/src/app.module.ts

@@ -19,6 +19,7 @@ import { UserCollectionModule } from './user-collection/user-collection.module';
 import { ShortcodeModule } from './shortcode/shortcode.module';
 import { COOKIES_NOT_FOUND } from './errors';
 import { ThrottlerModule } from '@nestjs/throttler';
+import { AppController } from './app.controller';
 
 @Module({
   imports: [
@@ -81,5 +82,6 @@ import { ThrottlerModule } from '@nestjs/throttler';
     ShortcodeModule,
   ],
   providers: [GQLComplexityPlugin],
+  controllers: [AppController],
 })
 export class AppModule {}

+ 4 - 2
packages/hoppscotch-backend/src/user-history/user-history.service.spec.ts

@@ -24,6 +24,8 @@ beforeEach(() => {
   mockPubSub.publish.mockClear();
 });
 
+const date = new Date();
+
 describe('UserHistoryService', () => {
   describe('fetchUserHistory', () => {
     test('Should return a list of users REST history if exists', async () => {
@@ -400,7 +402,7 @@ describe('UserHistoryService', () => {
         request: [{}],
         responseMetadata: [{}],
         reqType: ReqType.REST,
-        executedOn: new Date(),
+        executedOn: date,
         isStarred: false,
       });
 
@@ -410,7 +412,7 @@ describe('UserHistoryService', () => {
         request: JSON.stringify([{}]),
         responseMetadata: JSON.stringify([{}]),
         reqType: ReqType.REST,
-        executedOn: new Date(),
+        executedOn: date,
         isStarred: false,
       };
 

Some files were not shown because too many files changed in this diff