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 │ │ waf │ ││
│ │ │ :8080 │ │ :50051 │ │ :50052 │ ││
│ │ │ :9090 │ │ │ │ │ ││
│ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ ││
│ │ │ │ │ ││
│ │ └─────────────┴─────────────┘ ││
│ │ gRPC / UDS ││
│ └─────────────────────────────────────────────────────────┘│
│ │
│ ┌──────────────────────────────────────────────────────────┐│
│ │ 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
command:
volumes:
- sockets:/var/run/sentinel
networks:
- sentinel
echo-agent:
image: ghcr.io/raskell-io/sentinel-echo:latest
command:
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
command:
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:
services:
sentinel:
depends_on:
- waf-agent
waf-agent:
image: ghcr.io/raskell-io/sentinel-waf:latest
command:
networks:
- sentinel
Configuration:
agent "waf" type="waf" {
grpc "http://waf-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:
condition: service_healthy
waf-agent:
condition: service_healthy
healthcheck:
test:
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
networks:
- sentinel
- backend
# ─────────────────────────────────────────────────────────
# Auth Agent (Unix Socket)
# ─────────────────────────────────────────────────────────
auth-agent:
image: ghcr.io/raskell-io/sentinel-auth:latest
container_name: sentinel-auth
command:
- "--socket"
- "/var/run/sentinel/auth.sock"
- "--config"
- "/etc/auth/config.toml"
volumes:
- sockets:/var/run/sentinel
- ./agents/auth:/etc/auth:ro
environment:
- RUST_LOG=info
- AUTH_SECRET=${AUTH_SECRET}
healthcheck:
test:
interval: 5s
timeout: 3s
retries: 3
restart: unless-stopped
networks:
- sentinel
# ─────────────────────────────────────────────────────────
# WAF Agent (gRPC)
# ─────────────────────────────────────────────────────────
waf-agent:
image: ghcr.io/raskell-io/sentinel-waf:latest
container_name: sentinel-waf
command:
- "--grpc"
- "0.0.0.0:50051"
- "--rules"
- "/etc/waf/crs-rules"
volumes:
- ./agents/waf/rules:/etc/waf/crs-rules:ro
environment:
- RUST_LOG=info
healthcheck:
test:
interval: 10s
timeout: 5s
retries: 3
restart: unless-stopped
networks:
- sentinel
# ─────────────────────────────────────────────────────────
# Echo Agent (for debugging)
# ─────────────────────────────────────────────────────────
echo-agent:
image: ghcr.io/raskell-io/sentinel-echo:latest
container_name: sentinel-echo
command:
environment:
- RUST_LOG=debug
healthcheck:
test:
interval: 10s
timeout: 5s
retries: 3
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
server {
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 "waf" type="waf" {
grpc "http://waf-agent:50051"
events "request_headers" "request_body"
timeout-ms 100
failure-mode "open"
max-request-body-bytes 1048576
}
agent "echo" type="custom" {
grpc "http://echo-agent:50052"
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" "waf"
}
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
dockerfile: agents/auth/Dockerfile
volumes:
- sockets:/var/run/sentinel
command:
volumes:
sockets:
# Build and run in development
Debug Profile
# Start with echo agent for debugging
# Test with echo headers
Scaling
Scale Agents
# Scale WAF agent replicas
With load balancing in config:
agent "waf" type="waf" {
// Docker DNS handles round-robin
grpc "http://waf-agent:50051"
}
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
services:
sentinel:
depends_on:
auth-agent:
condition: service_healthy
waf-agent:
condition: service_started
auth-agent:
healthcheck:
test:
interval: 5s
timeout: 3s
retries: 3
start_period: 10s
External Health Check
# Check Sentinel health
# Check agent connectivity
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
# Run interactively
# Check if socket exists
Agent Connection Failed
# Check network connectivity
# Test gRPC connection
# Check socket permissions
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