Skip to content

Docker Compose Deployment

Deploy Artifact Keeper using Docker Compose for a complete, containerized setup.

Prerequisites

  • Docker 20.10+ and Docker Compose 2.0+
  • 4 GB RAM minimum (8 GB recommended)
  • 100 GB disk space for artifacts

Quick Start

1. Clone Repository

Terminal window
git clone https://github.com/artifact-keeper/artifact-keeper.git
cd artifact-keeper

2. Create Environment File

Create .env file in the project root:

Terminal window
# Database
DB_PASSWORD=change-me-in-production
# JWT Authentication
JWT_SECRET=generate-secure-secret-here
# Storage
STORAGE_BACKEND=filesystem
STORAGE_PATH=/data/artifacts
# Admin user (first-time setup)
ADMIN_USERNAME=admin
ADMIN_PASSWORD=admin # Change on first login

Generate secure secrets:

Terminal window
# Generate JWT secret
openssl rand -base64 64
# Generate database password
openssl rand -base64 32

3. Start Services

Terminal window
docker-compose up -d

4. Verify Deployment

Terminal window
# Check service status
docker-compose ps
# View logs
docker-compose logs -f
# Access web UI
open http://localhost:3000
# Test API
curl http://localhost:8080/api/v1/health

Production Docker Compose Configuration

Create docker-compose.yml:

version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: artifact-keeper-db
environment:
POSTGRES_DB: artifact_registry
POSTGRES_USER: registry
POSTGRES_PASSWORD: ${DB_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U registry"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
networks:
- artifact-keeper
backend:
image: artifact-keeper/backend:latest
container_name: artifact-keeper-backend
environment:
DATABASE_URL: postgres://registry:${DB_PASSWORD}@postgres:5432/artifact_registry
JWT_SECRET: ${JWT_SECRET}
STORAGE_BACKEND: ${STORAGE_BACKEND:-filesystem}
STORAGE_PATH: /data/artifacts
RUST_LOG: info
PORT: 8080
volumes:
- artifact_data:/data/artifacts
- backup_data:/data/backups
ports:
- "8080:8080"
depends_on:
postgres:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/v1/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
networks:
- artifact-keeper
frontend:
image: artifact-keeper/frontend:latest
container_name: artifact-keeper-frontend
environment:
REACT_APP_API_URL: http://localhost:8080
ports:
- "3000:80"
depends_on:
- backend
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80"]
interval: 30s
timeout: 10s
retries: 3
restart: unless-stopped
networks:
- artifact-keeper
volumes:
postgres_data:
driver: local
artifact_data:
driver: local
backup_data:
driver: local
networks:
artifact-keeper:
driver: bridge

Extended Configuration with Optional Services

With Trivy Security Scanner

Add security scanning capabilities:

services:
# ... existing services ...
trivy:
image: aquasec/trivy:latest
container_name: artifact-keeper-trivy
command: ["server", "--listen", "0.0.0.0:8090"]
ports:
- "8090:8090"
volumes:
- trivy_cache:/root/.cache
restart: unless-stopped
networks:
- artifact-keeper
backend:
# ... existing config ...
environment:
# ... existing env vars ...
TRIVY_ENABLED: "true"
TRIVY_URL: http://trivy:8090
volumes:
# ... existing volumes ...
trivy_cache:
driver: local

With MinIO S3 Storage

Use MinIO for S3-compatible object storage:

services:
# ... existing services ...
minio:
image: minio/minio:latest
container_name: artifact-keeper-minio
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY:-minioadmin}
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY:-minioadmin}
volumes:
- minio_data:/data
ports:
- "9000:9000"
- "9001:9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
restart: unless-stopped
networks:
- artifact-keeper
backend:
# ... existing config ...
environment:
# ... existing env vars ...
STORAGE_BACKEND: s3
S3_ENDPOINT: http://minio:9000
S3_BUCKET: artifacts
S3_REGION: us-east-1
S3_ACCESS_KEY_ID: ${MINIO_ACCESS_KEY:-minioadmin}
S3_SECRET_ACCESS_KEY: ${MINIO_SECRET_KEY:-minioadmin}
S3_FORCE_PATH_STYLE: "true"
depends_on:
- minio
volumes:
# ... existing volumes ...
minio_data:
driver: local

Create MinIO bucket on first startup:

Terminal window
# Wait for MinIO to start
sleep 10
# Create bucket
docker exec artifact-keeper-minio \
mc alias set local http://localhost:9000 minioadmin minioadmin
docker exec artifact-keeper-minio \
mc mb local/artifacts

With Prometheus and Grafana

Add monitoring stack:

services:
# ... existing services ...
prometheus:
image: prom/prometheus:latest
container_name: artifact-keeper-prometheus
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
ports:
- "9090:9090"
restart: unless-stopped
networks:
- artifact-keeper
grafana:
image: grafana/grafana:latest
container_name: artifact-keeper-grafana
environment:
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
volumes:
- grafana_data:/var/lib/grafana
- ./grafana/dashboards:/etc/grafana/provisioning/dashboards
ports:
- "3001:3000"
depends_on:
- prometheus
restart: unless-stopped
networks:
- artifact-keeper
volumes:
# ... existing volumes ...
prometheus_data:
driver: local
grafana_data:
driver: local

Create prometheus.yml:

global:
scrape_interval: 15s
scrape_configs:
- job_name: 'artifact-keeper'
static_configs:
- targets: ['backend:8080']

Building Images

Build from Source

Terminal window
# Build backend
docker build -t artifact-keeper/backend:latest -f docker/Dockerfile.backend .
# Build frontend
docker build -t artifact-keeper/frontend:latest -f docker/Dockerfile.frontend .

Use Pre-built Images

Terminal window
# Pull from Docker Hub (when available)
docker pull artifact-keeper/backend:latest
docker pull artifact-keeper/frontend:latest

Managing Services

Start Services

Terminal window
# Start all services
docker-compose up -d
# Start specific service
docker-compose up -d backend

Stop Services

Terminal window
# Stop all services
docker-compose down
# Stop and remove volumes (WARNING: deletes data)
docker-compose down -v

View Logs

Terminal window
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f backend
# Last 100 lines
docker-compose logs --tail=100 backend

Restart Services

Terminal window
# Restart all
docker-compose restart
# Restart specific service
docker-compose restart backend

Update Services

Terminal window
# Pull latest images
docker-compose pull
# Restart with new images
docker-compose up -d

Data Persistence

Volume Management

Terminal window
# List volumes
docker volume ls
# Inspect volume
docker volume inspect artifact-keeper_artifact_data
# Backup volume
docker run --rm \
-v artifact-keeper_artifact_data:/data \
-v $(pwd):/backup \
alpine tar czf /backup/artifacts-backup.tar.gz /data
# Restore volume
docker run --rm \
-v artifact-keeper_artifact_data:/data \
-v $(pwd):/backup \
alpine tar xzf /backup/artifacts-backup.tar.gz -C /

Database Backup

Terminal window
# Backup database
docker-compose exec postgres pg_dump -U registry artifact_registry | gzip > backup.sql.gz
# Restore database
gunzip < backup.sql.gz | docker-compose exec -T postgres psql -U registry artifact_registry

Resource Limits

Configure resource constraints:

services:
backend:
# ... existing config ...
deploy:
resources:
limits:
cpus: '2'
memory: 4G
reservations:
cpus: '1'
memory: 2G
postgres:
# ... existing config ...
deploy:
resources:
limits:
cpus: '1'
memory: 2G
reservations:
cpus: '0.5'
memory: 1G

Reverse Proxy with Nginx

Add Nginx for SSL termination and routing:

services:
nginx:
image: nginx:alpine
container_name: artifact-keeper-nginx
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./ssl:/etc/nginx/ssl:ro
ports:
- "80:80"
- "443:443"
depends_on:
- frontend
- backend
restart: unless-stopped
networks:
- artifact-keeper

Create nginx.conf:

upstream backend {
server backend:8080;
}
upstream frontend {
server frontend:80;
}
server {
listen 80;
server_name registry.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name registry.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
client_max_body_size 10G;
location /api/ {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location / {
proxy_pass http://frontend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}

Health Checks

Monitor service health:

Terminal window
# Check all services
docker-compose ps
# Backend health
curl http://localhost:8080/api/v1/health
# Database health
docker-compose exec postgres pg_isready -U registry
# Frontend health
curl http://localhost:3000

Troubleshooting

Services Won’t Start

Terminal window
# Check logs
docker-compose logs
# Verify environment variables
docker-compose config
# Check port conflicts
netstat -tulpn | grep -E ':(3000|8080|5432)'

Database Connection Errors

Terminal window
# Verify database is running
docker-compose ps postgres
# Check database logs
docker-compose logs postgres
# Test connection
docker-compose exec postgres psql -U registry -d artifact_registry -c '\conninfo'

Out of Disk Space

Terminal window
# Check disk usage
df -h
# Clean up Docker
docker system prune -a --volumes
# Check volume sizes
docker system df -v

Production Checklist

  • Change default passwords (database, admin user)
  • Generate secure JWT secret
  • Configure SSL/TLS certificates
  • Set up automated backups
  • Configure log rotation
  • Set resource limits
  • Enable monitoring
  • Configure firewall rules
  • Set up log aggregation
  • Test disaster recovery