Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 31 additions & 23 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,34 +1,42 @@
# Use a slim Node.js image as base
FROM node:20-alpine
# ------------------------
# Stage 1: Build Stage
# ------------------------
FROM node:20-alpine AS builder

# Install docker CLI to execute docker command (for accessing host Docker)
# Also install bash for better scripting capabilities inside the container if needed
RUN apk add --no-cache docker-cli bash

# Set working directory inside the container
# Set working directory
WORKDIR /app

# Copy only package.json and package-lock.json to leverage Docker layer caching
# This ensures npm install is re-run only if dependencies change
# Copy only package files to install dependencies first (cache-friendly)
COPY package*.json ./

# Install project dependencies
RUN npm install
# Install dependencies
RUN npm ci --omit=dev

# Copy the rest of your application source code
# Copy the rest of the app source code
COPY . .

# Set environment variables
ENV PORT=9091
# ------------------------
# Stage 2: Production Image
# ------------------------
FROM node:20-alpine AS production

# Set working directory
WORKDIR /app

# Copy only the necessary files from builder
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/temp ./temp
COPY --from=builder /app/public ./public
COPY --from=builder /app/*.js ./

# Create a temporary directory that will be used for mounting (if it doesn't exist on host)
# This command ensures the directory exists within the image,
# but the volume mount `./temp:/app/temp` will override it with the host's `./temp`
# if `./temp` exists on the host. If `./temp` doesn't exist on the host, Docker will create it.
RUN mkdir -p /app/temp
# Set environment variables
ENV NODE_ENV=production
ENV PORT=5000

# Expose the port your Node.js application listens on
EXPOSE 9091
# Expose app port
EXPOSE 5000

# Command to run your application when the container starts
CMD ["npm", "start"]
# Start the application
CMD ["node", "index.js"]
157 changes: 115 additions & 42 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -1,79 +1,152 @@
services:
app:
profiles:
- prod
- dev
build:
context: .
dockerfile: Dockerfile
image: ${DOCKER_USERNAME}/${PACKAGE_NAME}:${PACKAGE_VERSION}
container_name: ${PACKAGE_NAME}_api
environment:
- PORT=${PORT}
- NODE_ENV=${NODE_ENV}
- EMAIL=${EMAIL}
- BASE_URL=${BASE_URL}
- HOST_PROJECT_ROOT=${PWD}
ports:
- "5000:${PORT}"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./temp:/app/temp
networks:
- default
restart: unless-stopped

healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:${PORT}/"]
interval: 30s # Check every 15 seconds (more frequent)
timeout: 15s # 10 second timeout
retries: 3 # 3 retries before marking unhealthy
start_period: 30s # Wait 30 seconds before starting health checks

# Add logging configuration
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Add labels for better container management
labels:
- "app.name=${PACKAGE_NAME}"
- "app.version=${PACKAGE_VERSION}"
- "deployment.type=zero-downtime"

nginx:
profiles:
- prod
image: nginx:alpine
container_name: ${PACKAGE_NAME}_nginx
depends_on:
- app
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/certbot/www:/var/www/certbot
- ./nginx/certbot/conf:/etc/letsencrypt
- ./nginx/selfsigned:/etc/nginx/selfsigned

ports:
- "80:80"
- "443:443"
networks:
- default
restart: always

certbot:
profiles:
- prod
image: certbot/certbot
container_name: ${PACKAGE_NAME}_certbot
volumes:
- ./nginx/certbot/www:/var/www/certbot
- ./nginx/certbot/conf:/etc/letsencrypt
environment:
- EMAIL=${EMAIL}
- BASE_URL=${BASE_URL}
entrypoint: >
certbot certonly --webroot --webroot-path=/var/www/certbot
--email ${EMAIL} --agree-tos --no-eff-email
-d ${BASE_URL}
depends_on:
- nginx
networks:
- default
restart: "no"

certbot-renew:
profiles:
- prod
image: certbot/certbot
container_name: ${PACKAGE_NAME}_certbot_renew
volumes:
- ./nginx/certbot/www:/var/www/certbot
- ./nginx/certbot/conf:/etc/letsencrypt
entrypoint: >
sh -c "trap exit TERM;
while :; do
echo '🔄 Checking for SSL renewal...';
certbot renew --webroot --webroot-path=/var/www/certbot --quiet --deploy-hook 'nginx -s reload';
sleep 12h;
done"
depends_on:
- nginx
networks:
- default
restart: unless-stopped

# ====================== language image ====================== #
nodejs-image:
profile:
profiles:
- prod
build:
context: .
dockerfile: docker/Dockerfile.nodejs
image: executor-nodejs:latest

deno-image:
profile:
profiles:
- prod
build:
context: .
dockerfile: docker/Dockerfile.deno
image: executor-deno:latest

python-image:
profile:
profiles:
- prod
build:
context: .
dockerfile: docker/Dockerfile.python
image: executor-python:latest

java-image:
profile:
profiles:
- prod
build:
context: .
dockerfile: docker/Dockerfile.jvm
image: executor-java:latest

kotlin-image:
profile:
profiles:
- prod
build:
context: .
dockerfile: docker/Dockerfile.kotlin
image: executor-kotlin:latest

nodejs-server-image:
profile:
- prod
- dev
build:
context: .
dockerfile: Dockerfile
image: nodejs-server-image:latest
environment:
- PORT=9091
- HOST_PROJECT_ROOT=${PWD}
ports:
- "9091:9091"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./temp:/app/temp
networks:
- app-network
restart: unless-stopped

executeme-nginx:
profile:
- prod
image: nginx:alpine
ports:
- "9292:9292"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs:ro
depends_on:
- nodejs-server-image
networks:
- app-network
restart: unless-stopped

networks:
app-network:
driver: bridge
default:
name: ${PACKAGE_NAME}_network
labels:
- "project=${PACKAGE_NAME}"
Loading