implement docker
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
backend/node_modules
|
||||
|
||||
# Environment secrets - JANGAN masuk ke image
|
||||
backend/.env
|
||||
.env
|
||||
|
||||
# Log files
|
||||
*.log
|
||||
backend/*.log
|
||||
|
||||
# Git files
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.swp
|
||||
+10
@@ -1,3 +1,13 @@
|
||||
node_modules/
|
||||
backend/node_modules/
|
||||
backend/.env
|
||||
*.log
|
||||
backend/*.log
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Editor
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
# ─── Stage 1: Install dependencies ──────────────────────────────────────────
|
||||
FROM node:22-alpine AS deps
|
||||
WORKDIR /app
|
||||
COPY backend/package*.json ./
|
||||
RUN npm ci --omit=dev
|
||||
|
||||
# ─── Stage 2: Runtime ────────────────────────────────────────────────────────
|
||||
FROM node:22-alpine AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Install dumb-init untuk proper signal handling
|
||||
RUN apk add --no-cache dumb-init
|
||||
|
||||
# Copy dependencies dari stage deps
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
|
||||
# Copy backend source
|
||||
COPY backend/ ./backend/
|
||||
|
||||
# Copy frontend static files
|
||||
COPY frontend/ ./frontend/
|
||||
|
||||
# Set working directory ke backend (karena server.js ada di sini)
|
||||
WORKDIR /app/backend
|
||||
|
||||
# Non-root user untuk keamanan
|
||||
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
||||
USER appuser
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
|
||||
# Health check (dipakai Coolify untuk monitoring)
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
|
||||
CMD wget -qO- http://localhost:3000/health || exit 1
|
||||
|
||||
ENTRYPOINT ["dumb-init", "--"]
|
||||
CMD ["node", "server.js"]
|
||||
@@ -0,0 +1,11 @@
|
||||
# ─── Konfigurasi Database MySQL ─────────────────────────────────────────────
|
||||
# Di Coolify: gunakan nama service MySQL yang dibuat, contoh: "mysql" atau "db"
|
||||
DB_HOST=db
|
||||
DB_PORT=3306
|
||||
DB_USER=webgis_user
|
||||
DB_PASSWORD=ganti_dengan_password_kuat
|
||||
DB_NAME=spbu_pontianak
|
||||
|
||||
# ─── Server ──────────────────────────────────────────────────────────────────
|
||||
PORT=3000
|
||||
NODE_ENV=production
|
||||
@@ -10,9 +10,21 @@ const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
// ─── Middleware ───────────────────────────────────────────────────────────────
|
||||
app.set("trust proxy", 1); // Untuk Coolify reverse proxy (Traefik/Nginx)
|
||||
app.use(cors());
|
||||
app.use(express.json());
|
||||
app.use("/api/poverty", povertyRoutes);
|
||||
|
||||
// ─── Health Check (dibutuhkan Coolify untuk monitoring container) ─────────────────
|
||||
app.get("/health", async (req, res) => {
|
||||
try {
|
||||
await db.execute("SELECT 1");
|
||||
res.json({ status: "ok", db: "connected", timestamp: new Date().toISOString() });
|
||||
} catch (err) {
|
||||
res.status(503).json({ status: "error", db: "disconnected", message: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
// ─── Root: landing page (harus sebelum express.static) ───────────────────────
|
||||
app.get("/", (req, res) => {
|
||||
res.sendFile(path.join(__dirname, "../frontend/landing.html"));
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
# ─── Database MySQL ───────────────────────────────────────────────────────
|
||||
db:
|
||||
image: mysql:8.0
|
||||
container_name: webgis_db
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-rootpassword}
|
||||
MYSQL_DATABASE: ${DB_NAME:-spbu_pontianak}
|
||||
MYSQL_USER: ${DB_USER:-webgis_user}
|
||||
MYSQL_PASSWORD: ${DB_PASSWORD:-webgispassword}
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
- ./schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${MYSQL_ROOT_PASSWORD:-rootpassword}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
networks:
|
||||
- webgis_net
|
||||
|
||||
# ─── Aplikasi Node.js ─────────────────────────────────────────────────────
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: webgis_app
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${APP_PORT:-3000}:3000"
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
PORT: 3000
|
||||
DB_HOST: db
|
||||
DB_PORT: 3306
|
||||
DB_USER: ${DB_USER:-webgis_user}
|
||||
DB_PASSWORD: ${DB_PASSWORD:-webgispassword}
|
||||
DB_NAME: ${DB_NAME:-spbu_pontianak}
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 30s
|
||||
networks:
|
||||
- webgis_net
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
driver: local
|
||||
|
||||
networks:
|
||||
webgis_net:
|
||||
driver: bridge
|
||||
Reference in New Issue
Block a user