Docker Compose provides a straightforward way to deploy Sentinel with agents as containers. This guide covers local development and small production setups.
Overview
┌──────────────────────────────────────────────────────────────┐
│ docker-compose.yml │
│ ┌─────────────────────────────────────────────────────────┐│
│ │ Network: sentinel ││
│ │ ││
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ││
│ │ │ sentinel │ │ auth │ │ echo │ ││
│ │ │ :8080 │ │ agent │ │ agent │ ││
│ │ │ :9090 │ │ │ │ │ ││
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ ││
│ │ │ │ │ ││
│ │ └─────────────┴─────────────┘ ││
│ │ Unix Sockets ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ┌──────────────────────────────────────────────────────────┐│
│ │ Volume: sockets (for Unix sockets) ││
│ │ Volume: config (configuration files) ││
│ └──────────────────────────────────────────────────────────┘│
└──────────────────────────────────────────────────────────────┘
Quick Start
# docker-compose.yml
version: "3.8"
services:
sentinel:
image: ghcr.io/raskell-io/sentinel:latest
ports:
- "8080:8080" # HTTP
- "9090:9090" # Admin
volumes:
- ./config:/etc/sentinel:ro
- sockets:/var/run/sentinel
depends_on:
- auth-agent
- echo-agent
networks:
- sentinel
auth-agent:
image: ghcr.io/raskell-io/sentinel-auth:latest
platform: linux/amd64 # Currently AMD64 only
environment:
- SOCKET_PATH=/var/run/sentinel/auth.sock
volumes:
- sockets:/var/run/sentinel
networks:
- sentinel
echo-agent:
image: ghcr.io/raskell-io/sentinel-echo:latest
environment:
- SOCKET_PATH=/var/run/sentinel/echo.sock
volumes:
- sockets:/var/run/sentinel
networks:
- sentinel
volumes:
sockets:
networks:
sentinel:
# Start everything
# Check status
# View logs
# Stop
Unix Sockets vs gRPC
Unix Sockets (Shared Volume)
Best for lowest latency when all containers run on the same host:
services:
sentinel:
volumes:
- sockets:/var/run/sentinel
auth-agent:
volumes:
- sockets:/var/run/sentinel
environment:
- SOCKET_PATH=/var/run/sentinel/auth.sock
volumes:
sockets:
Configuration:
agent "auth" type="auth" {
unix-socket "/var/run/sentinel/auth.sock"
}
gRPC (Network)
Best for scaling agents independently or running on different hosts:
Note: The WAF agent (
sentinel-waf) is not yet available. This example shows the planned configuration pattern for future gRPC-based agents.
services:
sentinel:
depends_on:
- custom-agent
custom-agent:
image: your-custom-agent:latest
environment:
- GRPC_ADDRESS=0.0.0.0:50051
networks:
- sentinel
Configuration:
agent "custom" type="custom" {
grpc "http://custom-agent:50051"
}
Complete Example
Project Structure
sentinel-deploy/
├── docker-compose.yml
├── config/
│ └── sentinel.kdl
├── agents/
│ └── auth/
│ └── config.toml
└── certs/
├── cert.pem
└── key.pem
docker-compose.yml
version: "3.8"
services:
# ─────────────────────────────────────────────────────────
# Sentinel Proxy
# ─────────────────────────────────────────────────────────
sentinel:
image: ghcr.io/raskell-io/sentinel:latest
container_name: sentinel
ports:
- "80:8080"
- "443:8443"
- "9090:9090"
volumes:
- ./config:/etc/sentinel:ro
- ./certs:/etc/sentinel/tls:ro
- sockets:/var/run/sentinel
environment:
- RUST_LOG=info
depends_on:
- auth-agent
restart: unless-stopped
networks:
- sentinel
- backend
# ─────────────────────────────────────────────────────────
# Auth Agent (Unix Socket)
# ─────────────────────────────────────────────────────────
auth-agent:
image: ghcr.io/raskell-io/sentinel-auth:latest
platform: linux/amd64 # Currently AMD64 only
container_name: sentinel-auth
volumes:
- sockets:/var/run/sentinel
- ./agents/auth:/etc/auth:ro
environment:
- RUST_LOG=info
- SOCKET_PATH=/var/run/sentinel/auth.sock
- AUTH_SECRET=${AUTH_SECRET}
restart: unless-stopped
networks:
- sentinel
# ─────────────────────────────────────────────────────────
# Echo Agent (for debugging)
# ─────────────────────────────────────────────────────────
echo-agent:
image: ghcr.io/raskell-io/sentinel-echo:latest
container_name: sentinel-echo
volumes:
- sockets:/var/run/sentinel
environment:
- RUST_LOG=debug
- SOCKET_PATH=/var/run/sentinel/echo.sock
restart: unless-stopped
profiles:
- debug
networks:
- sentinel
# ─────────────────────────────────────────────────────────
# Example Backend
# ─────────────────────────────────────────────────────────
backend:
image: nginx:alpine
container_name: backend
volumes:
- ./backend/html:/usr/share/nginx/html:ro
networks:
- backend
volumes:
sockets:
driver: local
networks:
sentinel:
driver: bridge
backend:
driver: bridge
internal: true
config/sentinel.kdl
system {
listen "0.0.0.0:8080"
listen "0.0.0.0:8443" {
tls {
cert "/etc/sentinel/tls/cert.pem"
key "/etc/sentinel/tls/key.pem"
}
}
}
admin {
listen "0.0.0.0:9090"
}
agents {
agent "auth" type="auth" {
unix-socket "/var/run/sentinel/auth.sock"
events "request_headers"
timeout-ms 50
failure-mode "closed"
}
agent "echo" type="custom" {
unix-socket "/var/run/sentinel/echo.sock"
events "request_headers"
timeout-ms 50
failure-mode "open"
}
}
upstreams {
upstream "backend" {
target "backend:80"
}
}
routes {
route "api" {
matches { path-prefix "/api/" }
upstream "backend"
agents "auth"
}
route "default" {
matches { path-prefix "/" }
upstream "backend"
agents "echo"
}
}
Development Setup
Hot Reload with Local Build
# docker-compose.dev.yml
version: "3.8"
services:
sentinel:
build:
context: ../sentinel
dockerfile: Dockerfile
volumes:
- ./config:/etc/sentinel:ro
- sockets:/var/run/sentinel
environment:
- RUST_LOG=debug
ports:
- "8080:8080"
- "9090:9090"
auth-agent:
build:
context: ../sentinel-agent-auth
dockerfile: Dockerfile
volumes:
- sockets:/var/run/sentinel
environment:
- SOCKET_PATH=/var/run/sentinel/auth.sock
volumes:
sockets:
# Build and run in development
Debug Profile
# Start with echo agent for debugging
# Test with echo headers
Scaling
Scale Agents
For gRPC-based agents, you can scale replicas:
# Scale agent replicas (for gRPC-based agents)
With load balancing in config:
agent "custom" type="custom" {
// Docker DNS handles round-robin
grpc "http://custom-agent:50051"
}
Note: Unix socket-based agents cannot be scaled via
--scaleas they bind to a specific socket path.
Multiple Sentinel Instances
services:
sentinel-1:
image: ghcr.io/raskell-io/sentinel:latest
ports:
- "8081:8080"
sentinel-2:
image: ghcr.io/raskell-io/sentinel:latest
ports:
- "8082:8080"
# HAProxy or Traefik in front
lb:
image: haproxy:latest
ports:
- "80:80"
depends_on:
- sentinel-1
- sentinel-2
Resource Limits
services:
sentinel:
deploy:
resources:
limits:
cpus: "2"
memory: 1G
reservations:
cpus: "0.5"
memory: 256M
auth-agent:
deploy:
resources:
limits:
cpus: "0.5"
memory: 128M
Logging
Centralized Logging
services:
sentinel:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
labels: "service"
labels:
service: "sentinel-proxy"
# Or with Loki
sentinel:
logging:
driver: loki
options:
loki-url: "http://loki:3100/loki/api/v1/push"
loki-batch-size: "400"
View Logs
# All services
# Specific service
# With timestamps
# Last 100 lines
Health Checks
Service Dependencies
The default agent images use distroless containers without shell access, so traditional health checks (test -S, curl) are not available. Use one of these approaches:
Option 1: Simple depends_on (recommended for most cases)
services:
sentinel:
depends_on:
- auth-agent
- echo-agent
Option 2: Use the debug image (Alpine-based, has shell)
services:
auth-agent:
image: ghcr.io/raskell-io/sentinel-auth:latest-debug
healthcheck:
test:
interval: 5s
timeout: 3s
retries: 3
start_period: 10s
External Health Check
# Check Sentinel health
# Check if socket exists (from host)
Production Considerations
Security
services:
sentinel:
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
Secrets Management
services:
auth-agent:
secrets:
- auth_secret
environment:
- AUTH_SECRET_FILE=/run/secrets/auth_secret
secrets:
auth_secret:
file: ./secrets/auth.key
# Or from external source
# external: true
TLS Configuration
services:
sentinel:
volumes:
- ./certs:/etc/sentinel/tls:ro
environment:
- SENTINEL_TLS_CERT=/etc/sentinel/tls/cert.pem
- SENTINEL_TLS_KEY=/etc/sentinel/tls/key.pem
Troubleshooting
Container Won’t Start
# Check logs
# Check if socket exists
Note: The default agent images are distroless and don’t have a shell. You cannot use
docker-compose run --rm agent sh. Use the debug images if you need shell access.
Agent Connection Failed
# Check socket exists
# Check agent logs for connection errors
Socket Permission Issues
# Ensure same user in all containers
services:
sentinel:
user: "1000:1000"
auth-agent:
user: "1000:1000"
Memory Issues
# Check memory usage
# Increase limits if needed