Deploy with Docker
Docker provides a consistent and portable way to package and deploy Bunty applications. This guide covers creating optimized Docker images and running containers in production.
Quick Start
Basic Dockerfile
Create a Dockerfile in your project root:
# Use Bun's official image
FROM oven/bun:1 as base
WORKDIR /app
# Install dependencies
FROM base AS install
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
# Build application (if needed)
FROM install AS build
COPY . .
# RUN bun run build
# Production image
FROM base AS production
COPY --from=install /app/node_modules ./node_modules
COPY --from=build /app .
# Expose port
EXPOSE 3000
# Set environment
ENV NODE_ENV=production
# Run the application
CMD ["bun", "run", "src/main.ts"]
Build and Run
# Build image
docker build -t bunty-app .
# Run container
docker run -p 3000:3000 bunty-app
# Run with environment variables
docker run -p 3000:3000 \
-e DATABASE_URL=postgresql://localhost/mydb \
-e REDIS_URL=redis://localhost:6379 \
bunty-app
Multi-Stage Build (Optimized)
Production-Ready Dockerfile
# syntax=docker/dockerfile:1
# Base stage
FROM oven/bun:1-alpine as base
WORKDIR /app
# Dependencies stage
FROM base AS dependencies
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile --production
# Development dependencies stage
FROM base AS dev-dependencies
COPY package.json bun.lockb ./
RUN bun install --frozen-lockfile
# Build stage
FROM dev-dependencies AS build
COPY . .
# Add build steps if needed
# RUN bun run build
RUN bun test
# Production stage
FROM base AS production
# Create non-root user
RUN addgroup -g 1001 -S bunty && \
adduser -S bunty -u 1001
# Copy dependencies and application
COPY --from=dependencies --chown=bunty:bunty /app/node_modules ./node_modules
COPY --from=build --chown=bunty:bunty /app .
# Switch to non-root user
USER bunty
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD bun run healthcheck.ts || exit 1
# Expose port
EXPOSE 3000
# Set environment
ENV NODE_ENV=production \
PORT=3000
# Run application
CMD ["bun", "run", "src/main.ts"]
Health Check Script
Create healthcheck.ts:
const response = await fetch('http://localhost:3000/health');
if (!response.ok) {
process.exit(1);
}
process.exit(0);
Docker Compose
Single Service
Create docker-compose.yml:
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
restart: unless-stopped
networks:
- bunty-network
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
networks:
- bunty-network
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- bunty-network
volumes:
postgres-data:
redis-data:
networks:
bunty-network:
driver: bridge
Full Stack with Load Balancer
version: '3.8'
services:
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
depends_on:
- app
networks:
- bunty-network
app:
build:
context: .
dockerfile: Dockerfile
deploy:
replicas: 3
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://postgres:password@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
networks:
- bunty-network
worker:
build:
context: .
dockerfile: Dockerfile
command: ["bun", "run", "src/worker.ts"]
deploy:
replicas: 2
environment:
- NODE_ENV=production
- REDIS_URL=redis://redis:6379
depends_on:
- redis
networks:
- bunty-network
db:
image: postgres:16-alpine
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_DB=mydb
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- bunty-network
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
networks:
- bunty-network
volumes:
postgres-data:
redis-data:
networks:
bunty-network:
driver: bridge
Run with Docker Compose
# Start all services
docker-compose up -d
# View logs
docker-compose logs -f
# Scale services
docker-compose up -d --scale app=5
# Stop services
docker-compose down
# Remove volumes
docker-compose down -v
Environment Variables
.env File
Create .env:
NODE_ENV=production
PORT=3000
DATABASE_URL=postgresql://postgres:password@db:5432/mydb
REDIS_URL=redis://redis:6379
JWT_SECRET=your-secret-key
LOG_LEVEL=info
Use in Docker Compose
services:
app:
build: .
env_file:
- .env
# or
environment:
- NODE_ENV=${NODE_ENV}
- PORT=${PORT}
Docker Secrets (Swarm)
version: '3.8'
services:
app:
image: bunty-app:latest
secrets:
- db_password
- jwt_secret
environment:
- DATABASE_PASSWORD_FILE=/run/secrets/db_password
- JWT_SECRET_FILE=/run/secrets/jwt_secret
secrets:
db_password:
external: true
jwt_secret:
external: true
Optimization Tips
1. Use .dockerignore
Create .dockerignore:
node_modules
.git
.github
.vscode
.env
.env.*
*.log
dist
build
coverage
.DS_Store
README.md
docker-compose.yml
Dockerfile
.dockerignore
2. Multi-Architecture Builds
# Build for multiple platforms
docker buildx build --platform linux/amd64,linux/arm64 -t bunty-app:latest .
3. Layer Caching
# Copy package files first (changes less frequently)
COPY package.json bun.lockb ./
RUN bun install
# Copy source code (changes more frequently)
COPY . .
4. Minimize Image Size
# Use alpine base
FROM oven/bun:1-alpine
# Remove unnecessary files
RUN rm -rf /var/cache/apk/* /tmp/*
# Use multi-stage builds
# Copy only production dependencies
Production Best Practices
1. Security
# Don't run as root
USER bunty
# Scan for vulnerabilities
# docker scan bunty-app
2. Resource Limits
services:
app:
deploy:
resources:
limits:
cpus: '2'
memory: 1G
reservations:
cpus: '1'
memory: 512M
3. Health Checks
services:
app:
healthcheck:
test: ["CMD", "bun", "run", "healthcheck.ts"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
4. Logging
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
5. Restart Policy
services:
app:
restart: unless-stopped
# or
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
Registry and Deployment
Push to Docker Hub
# Tag image
docker tag bunty-app:latest yourusername/bunty-app:latest
docker tag bunty-app:latest yourusername/bunty-app:v1.0.0
# Login
docker login
# Push
docker push yourusername/bunty-app:latest
docker push yourusername/bunty-app:v1.0.0
Private Registry
# Tag for private registry
docker tag bunty-app registry.example.com/bunty-app:latest
# Login
docker login registry.example.com
# Push
docker push registry.example.com/bunty-app:latest
Monitoring
Container Stats
# View stats
docker stats
# View logs
docker logs -f container_id
# Inspect container
docker inspect container_id
Integration with Monitoring Tools
services:
app:
labels:
- "prometheus.io/scrape=true"
- "prometheus.io/port=3000"
- "prometheus.io/path=/metrics"
Next Steps
- Deploy to Kubernetes
- Set up CI/CD with Docker
- Configure Docker Swarm
- Add monitoring