From e6bc36bf9a188b91eeb161041fbf430f47fb384b Mon Sep 17 00:00:00 2001 From: finxol Date: Fri, 13 Dec 2024 16:50:09 +0100 Subject: [PATCH] feat(deploy): get Docker container working Initial Docker setup, with only API + Postgres + Caddy reverse proxy --- .dockerignore | 10 +++++++ apps/api/.dockerignore | 17 +++++++++++ apps/api/Dockerfile | 28 ++++++++++++++++++ apps/api/deno.json | 2 +- apps/api/src/db/local_dev_init.ts | 2 +- apps/api/src/db/users.ts | 2 +- apps/api/src/lib/db_conn.ts | 2 +- apps/api/src/lib/db_init.ts | 2 +- apps/api/src/lib/helpers.ts | 2 +- apps/api/src/main.ts | 9 +++--- apps/api/src/routes/account.ts | 2 +- apps/api/src/routes/trip.ts | 2 +- apps/api/src/server.ts | 2 +- compose.yml | 47 +++++++++++++++++++++++++++++++ packages/config/src/config.ts | 2 +- packages/util/src/logger.ts | 2 +- 16 files changed, 118 insertions(+), 15 deletions(-) create mode 100644 .dockerignore create mode 100644 apps/api/.dockerignore create mode 100644 apps/api/Dockerfile create mode 100644 compose.yml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..f2f008f --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +# Ignore everything, except... +* + +# Pakcages +!deno.json +!deno.lock + +# Source +!apps/ +!packages/ diff --git a/apps/api/.dockerignore b/apps/api/.dockerignore new file mode 100644 index 0000000..8ad3035 --- /dev/null +++ b/apps/api/.dockerignore @@ -0,0 +1,17 @@ +# Ignore everything, except... +* + +# Pakcages +!deno.json +!deno.lock + +# Source +!src/ +!drizzle.config.ts +!init.sh + +# ...but always include these files... +README.md +routes.md +.zed +.*ignore diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile new file mode 100644 index 0000000..247dce0 --- /dev/null +++ b/apps/api/Dockerfile @@ -0,0 +1,28 @@ +FROM denoland/deno:alpine-2.1.4 + +WORKDIR /app +# make /app belong to deno user +RUN chown -R deno:deno /app + +# Prefer not to run as root. +USER deno + +# Cache the dependencies as a layer (the following two steps are re-run only when deps.ts is modified). +# Ideally cache deps.ts will download and compile _all_ external files used in main.ts. +COPY --chown=deno:deno deno.json deno.lock ./ + +# These steps will be re-run upon each file change in your working directory: +COPY --chown=deno:deno packages packages +COPY --chown=deno:deno apps/api apps/api +COPY --chown=deno:deno apps/auth/deno.json ./apps/auth/deno.json + +WORKDIR /app/apps/api + +# The port that your application listens to. +EXPOSE 1993 +ENV PORT=1993 + +# Compile the main app so that it doesn't need to be compiled each startup/entry. +RUN deno cache ./src/main.ts + +CMD ["task", "start"] diff --git a/apps/api/deno.json b/apps/api/deno.json index 8076677..8d38542 100644 --- a/apps/api/deno.json +++ b/apps/api/deno.json @@ -1,7 +1,7 @@ { "tasks": { "dev": "LOG_LEVEL=trace deno run --watch --allow-env --allow-net --allow-sys ./src/main.ts", - "start": "LOG_LEVEL=info deno run --allow-env --allow-net --allow-sys ./src/main.ts", + "start": "deno run --allow-env --allow-net --allow-sys ./src/main.ts", "check-types": "deno check ." }, "imports": { diff --git a/apps/api/src/db/local_dev_init.ts b/apps/api/src/db/local_dev_init.ts index 320a6a5..dc521f3 100644 --- a/apps/api/src/db/local_dev_init.ts +++ b/apps/api/src/db/local_dev_init.ts @@ -3,7 +3,7 @@ import { usersTable } from "./users.sql.ts" import { userPrefsTable } from "./userprefs.sql.ts" import db from "../lib/db_conn.ts" import { eq } from "drizzle-orm" -import logger from "@util/logger.ts" +import { logger } from "@util" const initUsersTable = async () => { // check if test user already exists diff --git a/apps/api/src/db/users.ts b/apps/api/src/db/users.ts index 5bbf292..c5fd7e7 100644 --- a/apps/api/src/db/users.ts +++ b/apps/api/src/db/users.ts @@ -4,7 +4,7 @@ import { eq } from "drizzle-orm" import { userPrefsTable } from "./userprefs.sql.ts" import type { UserPublicProfile, UserWithPrefsAndStatus } from "../lib/types.d.ts" import { specialStatusTable } from "./specialstatus.sql.ts" -import logger from "@util/logger.ts" +import { logger } from "@util" /** * Select a user by their ID diff --git a/apps/api/src/lib/db_conn.ts b/apps/api/src/lib/db_conn.ts index 28633bc..2c2a4ab 100644 --- a/apps/api/src/lib/db_conn.ts +++ b/apps/api/src/lib/db_conn.ts @@ -1,5 +1,5 @@ import { DB_CONFIG } from "@config" -import logger from "@util/logger.ts" +import { logger } from "@util" import { drizzle } from "drizzle-orm/postgres-js" diff --git a/apps/api/src/lib/db_init.ts b/apps/api/src/lib/db_init.ts index 62f1c39..d301aa5 100644 --- a/apps/api/src/lib/db_init.ts +++ b/apps/api/src/lib/db_init.ts @@ -4,7 +4,7 @@ import postgres from "postgres" import sql, { connection } from "../lib/db_conn.ts" -import logger from "@util/logger.ts" +import { logger } from "@util" /** * Check if the database is initialised diff --git a/apps/api/src/lib/helpers.ts b/apps/api/src/lib/helpers.ts index 4e942f7..d8a99c1 100644 --- a/apps/api/src/lib/helpers.ts +++ b/apps/api/src/lib/helpers.ts @@ -1,4 +1,4 @@ -import logger from "@util/logger.ts" +import { logger } from "@util" import { ADMIN_EMAIL } from "@config" import type { Context } from "hono" diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 8d36dcc..305f4ac 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,5 +1,5 @@ import { build } from "./server.ts" -import logger from "@util/logger.ts" +import { logger } from "@util" import { LOG_LEVEL, logLevels, PORT, PRODUCTION } from "@config" import type { Hono } from "hono" @@ -20,13 +20,14 @@ logger.info(`Timezone: ${Temporal.Now.timeZoneId()}`) try { const app: Hono = build() - const host = "localhost" Deno.serve({ - hostname: host, port: PORT, + onListen(info: { hostname: string; port: number; transport: string }) { + logger.info(`Server listening on ${info.hostname}:${info.port}`) + }, }, app.fetch) - logger.info(`Server listening on ${host}:${PORT}`) + //logger.info(`Server listening on ${host}:${PORT}`) } catch (err) { logger.error(err) Deno.exit(1) diff --git a/apps/api/src/routes/account.ts b/apps/api/src/routes/account.ts index 7f59880..1d52665 100644 --- a/apps/api/src/routes/account.ts +++ b/apps/api/src/routes/account.ts @@ -1,5 +1,5 @@ import type { AccountVerified, DataResponse } from "../lib/types.d.ts" -import logger from "@util/logger.ts" +import { logger } from "@util" import { Hono } from "hono" import { isVerified, updateEmail } from "../db/accounts.ts" import { handleRequest, responseErrorObject } from "../lib/helpers.ts" diff --git a/apps/api/src/routes/trip.ts b/apps/api/src/routes/trip.ts index c8ec74f..2ad4e6d 100644 --- a/apps/api/src/routes/trip.ts +++ b/apps/api/src/routes/trip.ts @@ -1,5 +1,5 @@ import type { DataResponse } from "../lib/types.d.ts" -import logger from "@util/logger.ts" +import { logger } from "@util" import { Hono } from "hono" import { streamSSE } from "hono/streaming" diff --git a/apps/api/src/server.ts b/apps/api/src/server.ts index 053ee04..9631556 100644 --- a/apps/api/src/server.ts +++ b/apps/api/src/server.ts @@ -9,7 +9,7 @@ import system from "./routes/system.ts" import user from "./routes/user.ts" import account from "./routes/account.ts" import trip from "./routes/trip.ts" -import logger from "@util/logger.ts" +import { logger } from "@util" /** * Setup the Hono app with all the routes and plugins diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..553a23d --- /dev/null +++ b/compose.yml @@ -0,0 +1,47 @@ +services: + api: + build: + context: . + dockerfile: ./apps/api/Dockerfile + environment: + - LOG_LEVEL=debug + - DB_HOST=db + ports: + - 1993:1993 + depends_on: + db: + condition: service_healthy + + db: + image: postgres:17-alpine + ports: + - 5432:5432 + environment: + - POSTGRES_PASSWORD=password + - POSTGRES_USER=postgres + - POSTGRES_DB=karr + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + caddy: + image: caddy:2-alpine + restart: unless-stopped + ports: + - "8080:8080" + #- "443:443" + #- "443:443/udp" + environment: + - TZ=Europe/Paris + - HOST=localhost:8080 + - API_PORT=1993 + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - caddy_data:/data + - caddy_config:/config + +volumes: + caddy_data: + caddy_config: diff --git a/packages/config/src/config.ts b/packages/config/src/config.ts index 7be6225..9e755df 100644 --- a/packages/config/src/config.ts +++ b/packages/config/src/config.ts @@ -39,7 +39,7 @@ export const DB_CONFIG = Object.freeze({ host: Deno.env.get("DB_HOST") || "localhost", port: toInt(Deno.env.get("DB_PORT") || 5432), ssl: (Deno.env.get("DB_SSL") || "false") === "true", - name: Deno.env.get("DB_NAME") || "carpool", + name: Deno.env.get("DB_NAME") || "karr", user: Deno.env.get("DB_USER") || (PRODUCTION ? "carpool" : "postgres"), password: Deno.env.get("DB_PASS") || "password", diff --git a/packages/util/src/logger.ts b/packages/util/src/logger.ts index 6508d70..0aafe06 100644 --- a/packages/util/src/logger.ts +++ b/packages/util/src/logger.ts @@ -68,7 +68,7 @@ const formatArg = (arg: unknown): string => { * The logger also logs timestamps, which can be disabled using the LOG_TIMESTAMP environment variable. * @example * ```ts - * import logger from "@util/logger.ts" + * import { logger } from "@util" * logger.info("Hello, world!") * logger.error("Major error", error, 123) * ```