From c2920e4534ffc8e822453df5f16b2fed8a99c251 Mon Sep 17 00:00:00 2001 From: qwan30 Date: Wed, 8 Jul 2026 21:01:58 +0700 Subject: [PATCH] feat: dockerize SAG application (#6) - Add multi-stage Dockerfile - Add docker-entrypoint.sh for migrations - Update docker-compose.yml to orchestrate app and postgres --- .dockerignore | 9 +++++++++ Dockerfile | 32 ++++++++++++++++++++++++++++++++ docker-compose.yml | 17 +++++++++++++++++ docker-entrypoint.sh | 8 ++++++++ 4 files changed, 66 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 docker-entrypoint.sh diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..a73269b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +node_modules +dist +web/dist +.git +.env +.env.* +!.env.example +docker-compose.yml +Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..7b00c5b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,32 @@ +# Stage 1: Build +FROM node:22-alpine AS builder +WORKDIR /app +COPY package*.json ./ +RUN npm ci +COPY . . +RUN npm run build + +# Stage 2: Runner +FROM node:22-alpine AS runner +ENV NODE_ENV=production +WORKDIR /app + +# Install production dependencies only +COPY package*.json ./ +RUN npm ci --omit=dev && npm cache clean --force + +# Copy compiled assets and change ownership to the 'node' user +COPY --from=builder --chown=node:node /app/dist ./dist +COPY --from=builder --chown=node:node /app/web/dist ./web/dist +COPY --from=builder --chown=node:node /app/migrations ./dist/migrations + +# Copy the entrypoint script +COPY --chown=node:node docker-entrypoint.sh ./ +RUN sed -i 's/\r$//' docker-entrypoint.sh && chmod +x docker-entrypoint.sh + +# Drop privileges to non-root user for security +USER node + +# The application listens on port 4173 by default +EXPOSE 4173 +CMD ["./docker-entrypoint.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index eee0db1..1dabb3b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,7 @@ services: postgres: image: pgvector/pgvector:pg16 container_name: sag_lite_postgres + restart: unless-stopped environment: POSTGRES_DB: sag_lite POSTGRES_USER: sag_lite @@ -16,5 +17,21 @@ services: timeout: 5s retries: 20 + app: + build: + context: . + dockerfile: Dockerfile + container_name: sag_lite_app + restart: unless-stopped + ports: + - "4173:4173" + environment: + - DATABASE_URL=postgres://sag_lite:sag_lite_pass@postgres:5432/sag_lite + - HTTP_HOST=0.0.0.0 + - HTTP_PORT=4173 + depends_on: + postgres: + condition: service_healthy + volumes: sag_lite_pgdata: diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh new file mode 100644 index 0000000..c303638 --- /dev/null +++ b/docker-entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +echo "Running migrations..." +node dist/src/db/migrate.js + +echo "Starting app..." +exec node dist/src/index.js