refactor: new dev/prod containers
- Use a single Dockerfile for all Zeppelin services - Add a Dockerfile in project root that can be used by app hosting services - Provide a standalone and lightweight prod setup - Standalone is the same as the old setup, with mysql+nginx - Lightweight only runs bot+backend+dash, no mysql/nginx - Remove mounted mysql data folders for dev and prod - This resolves permission issues caused by the mount - The mysql service uses a regular named volume now - Simplify .env options and clearly separate different prod setups - Remove update.sh - Different setups require different update procedures, so a common update.sh no longer works
This commit is contained in:
parent
730b8c1d6b
commit
509d96ce83
30 changed files with 948 additions and 274 deletions
|
@ -4,28 +4,28 @@
|
|||
"description": "",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"watch": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node start-dev.js\"",
|
||||
"watch-yaml-parse-test": "cross-env NODE_ENV=development tsc-watch --onSuccess \"node dist/backend/src/yamlParseTest.js\"",
|
||||
"watch": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"node start-dev.js\"",
|
||||
"watch-yaml-parse-test": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"node dist/backend/src/yamlParseTest.js\"",
|
||||
"build": "tsc --build",
|
||||
"start-bot-dev": "cross-env NODE_ENV=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
|
||||
"start-bot-dev": "NODE_ENV=development HOST_MODE=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
|
||||
"start-bot-dev-debug": "NODE_ENV=development DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9229 dist/backend/src/index.js",
|
||||
"start-bot-prod": "cross-env NODE_ENV=production node --enable-source-maps --stack-trace-limit=30 dist/backend/src/index.js",
|
||||
"start-bot-prod-debug": "NODE_ENV=production DEBUG=true clinic heapprofiler --collect-only --dest .clinic-bot -- node --enable-source-maps --stack-trace-limit=30 dist/backend/src/index.js",
|
||||
"watch-bot": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-bot-dev\"",
|
||||
"start-api-dev": "cross-env NODE_ENV=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
|
||||
"watch-bot": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"npm run start-bot-dev\"",
|
||||
"start-api-dev": "NODE_ENV=development HOST_MODE=development node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
|
||||
"start-api-dev-debug": "NODE_ENV=development DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node --enable-source-maps --stack-trace-limit=30 --inspect=0.0.0.0:9239 dist/backend/src/api/index.js",
|
||||
"start-api-prod": "cross-env NODE_ENV=production node --enable-source-maps --stack-trace-limit=30 dist/backend/src/api/index.js",
|
||||
"start-api-prod-debug": "NODE_ENV=production DEBUG=true clinic heapprofiler --collect-only --dest .clinic-api -- node --enable-source-maps --stack-trace-limit=30 dist/backend/src/api/index.js",
|
||||
"watch-api": "cross-env NODE_ENV=development tsc-watch --onSuccess \"npm run start-api-dev\"",
|
||||
"watch-api": "NODE_ENV=development HOST_MODE=development tsc-watch --onSuccess \"npm run start-api-dev\"",
|
||||
"typeorm": "node ./node_modules/typeorm/cli.js",
|
||||
"migrate": "npm run typeorm -- migration:run -d dist/backend/src/data/dataSource.js",
|
||||
"migrate-prod": "cross-env NODE_ENV=production npm run migrate",
|
||||
"migrate-dev": "cross-env NODE_ENV=development npm run build && npm run migrate",
|
||||
"migrate-dev": "NODE_ENV=development HOST_MODE=development npm run build && npm run migrate",
|
||||
"migrate-rollback": "npm run typeorm -- migration:revert -d dist/backend/src/data/dataSource.js",
|
||||
"migrate-rollback-prod": "cross-env NODE_ENV=production npm run migrate",
|
||||
"migrate-rollback-dev": "cross-env NODE_ENV=development npm run build && npm run migrate",
|
||||
"validate-active-configs": "cross-env NODE_ENV=development node --enable-source-maps dist/backend/src/validateActiveConfigs.js > ../config-errors.txt",
|
||||
"export-config-json-schema": "cross-env NODE_ENV=development node --enable-source-maps dist/backend/src/exportSchemas.js > ../config-schema.json",
|
||||
"migrate-rollback-dev": "NODE_ENV=development HOST_MODE=development npm run build && npm run migrate",
|
||||
"validate-active-configs": "NODE_ENV=development HOST_MODE=development node --enable-source-maps dist/backend/src/validateActiveConfigs.js > ../config-errors.txt",
|
||||
"export-config-json-schema": "NODE_ENV=development HOST_MODE=development node --enable-source-maps dist/backend/src/exportSchemas.js > ../config-schema.json",
|
||||
"test": "npm run build && npm run run-tests",
|
||||
"run-tests": "ava",
|
||||
"test-watch": "tsc-watch --onSuccess \"npx ava\""
|
||||
|
|
|
@ -51,7 +51,7 @@ app.use((req, res, next) => {
|
|||
return notFound(res);
|
||||
});
|
||||
|
||||
const port = env.API_PORT;
|
||||
const port = 3001;
|
||||
app.listen(port, "0.0.0.0", () => console.log(`API server listening on port ${port}`)); // tslint:disable-line
|
||||
|
||||
startBackgroundTasks();
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import moment from "moment-timezone";
|
||||
import path from "path";
|
||||
import { DataSource } from "typeorm";
|
||||
import { MysqlConnectionOptions } from "typeorm/driver/mysql/MysqlConnectionOptions.js";
|
||||
import { env } from "../env";
|
||||
import { backendDir } from "../paths";
|
||||
|
||||
|
@ -9,13 +10,39 @@ moment.tz.setDefault("UTC");
|
|||
const entities = path.relative(process.cwd(), path.resolve(backendDir, "dist/backend/src/data/entities/*.js"));
|
||||
const migrations = path.relative(process.cwd(), path.resolve(backendDir, "dist/backend/src/migrations/*.js"));
|
||||
|
||||
type DbOpts = Pick<MysqlConnectionOptions, "host" | "port" | "username" | "password" | "database">;
|
||||
let dbOpts: DbOpts;
|
||||
if (env.HOST_MODE === "development") {
|
||||
dbOpts = {
|
||||
host: "mysql",
|
||||
port: 3306,
|
||||
username: "zeppelin",
|
||||
password: env.DEVELOPMENT_MYSQL_PASSWORD,
|
||||
database: "zeppelin",
|
||||
};
|
||||
} else if (env.HOST_MODE === "standalone") {
|
||||
dbOpts = {
|
||||
host: "mysql",
|
||||
port: 3306,
|
||||
username: "zeppelin",
|
||||
password: env.STANDALONE_MYSQL_PASSWORD,
|
||||
database: "zeppelin",
|
||||
};
|
||||
} else if (env.HOST_MODE === "lightweight") {
|
||||
dbOpts = {
|
||||
host: env.LIGHTWEIGHT_DB_HOST,
|
||||
port: env.LIGHTWEIGHT_DB_PORT,
|
||||
username: env.LIGHTWEIGHT_DB_USER,
|
||||
password: env.LIGHTWEIGHT_DB_PASSWORD,
|
||||
database: env.LIGHTWEIGHT_DB_DATABASE,
|
||||
};
|
||||
} else {
|
||||
throw new Error(`Unknown host mode: ${env.HOST_MODE}`);
|
||||
}
|
||||
|
||||
export const dataSource = new DataSource({
|
||||
type: "mysql",
|
||||
host: env.DB_HOST,
|
||||
port: env.DB_PORT,
|
||||
username: env.DB_USER,
|
||||
password: env.DB_PASSWORD,
|
||||
database: env.DB_DATABASE,
|
||||
...dbOpts,
|
||||
charset: "utf8mb4",
|
||||
supportBigNumbers: true,
|
||||
bigNumberStrings: true,
|
||||
|
|
|
@ -13,7 +13,6 @@ const envType = z.object({
|
|||
|
||||
DASHBOARD_URL: z.string().url(),
|
||||
API_URL: z.string().url(),
|
||||
API_PORT: z.preprocess((v) => Number(v), z.number().min(1).max(65535)).default(3000),
|
||||
|
||||
STAFF: z
|
||||
.preprocess(
|
||||
|
@ -39,18 +38,16 @@ const envType = z.object({
|
|||
|
||||
PHISHERMAN_API_KEY: z.string().optional(),
|
||||
|
||||
DOCKER_DEV_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development
|
||||
DOCKER_PROD_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in production
|
||||
DEVELOPMENT_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in development
|
||||
STANDALONE_MYSQL_PASSWORD: z.string().optional(), // Included here for the DB_PASSWORD default in production
|
||||
|
||||
DB_HOST: z.string().optional().default("mysql"),
|
||||
DB_PORT: z
|
||||
.preprocess((v) => Number(v), z.number())
|
||||
.optional()
|
||||
.default(3306),
|
||||
DB_USER: z.string().optional().default("zeppelin"),
|
||||
DB_PASSWORD: z.string().optional(), // Default is set to DOCKER_MYSQL_PASSWORD further below
|
||||
DB_DATABASE: z.string().optional().default("zeppelin"),
|
||||
LIGHTWEIGHT_DB_HOST: z.string().optional(),
|
||||
LIGHTWEIGHT_DB_PORT: z.preprocess((v) => Number(v), z.number()).optional(),
|
||||
LIGHTWEIGHT_DB_USER: z.string().optional(),
|
||||
LIGHTWEIGHT_DB_PASSWORD: z.string().optional(),
|
||||
LIGHTWEIGHT_DB_DATABASE: z.string().optional(),
|
||||
|
||||
HOST_MODE: z.enum(["development", "standalone", "lightweight"]).optional().default("lightweight"),
|
||||
DEBUG: z
|
||||
.string()
|
||||
.optional()
|
||||
|
@ -65,11 +62,3 @@ if (fs.existsSync(envPath)) {
|
|||
}
|
||||
|
||||
export const env = envType.parse(toValidate);
|
||||
|
||||
if (!env.DB_PASSWORD) {
|
||||
if (process.env.NODE_ENV === "production" && env.DOCKER_PROD_MYSQL_PASSWORD) {
|
||||
env.DB_PASSWORD = env.DOCKER_PROD_MYSQL_PASSWORD;
|
||||
} else if (env.DOCKER_DEV_MYSQL_PASSWORD) {
|
||||
env.DB_PASSWORD = env.DOCKER_DEV_MYSQL_PASSWORD;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ if (process.env.NODE_ENV === "production") {
|
|||
}
|
||||
|
||||
// Verify required Node.js version
|
||||
const REQUIRED_NODE_VERSION = "14.0.0";
|
||||
const REQUIRED_NODE_VERSION = "16.9.0";
|
||||
const requiredParts = REQUIRED_NODE_VERSION.split(".").map((v) => parseInt(v, 10));
|
||||
const actualVersionParts = process.versions.node.split(".").map((v) => parseInt(v, 10));
|
||||
for (const [i, part] of actualVersionParts.entries()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue