Docker Deployment Guide
This guide explains how to deploy Mangrullo using Docker containers.
Quick Start
The official images are published on GitHub Container Registry:
ghcr.io/ralsina/mangrullo:latest (multi-architecture: amd64 + arm64).
The image ships an entrypoint that understands the commands daemon (default), web, check, dry-run and help.
Option 1: One-shot Mode
Run a single update check:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/ralsina/mangrullo:latest check
Option 2: Daemon Mode
Run Mangrullo as a background daemon that periodically checks for updates:
docker run -d \
--name mangrullo \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/ralsina/mangrullo:latest
The daemon checks every MANGRULLO_INTERVAL seconds (entrypoint default: 3600).
Option 3: Dry Run Mode
See what would be updated without making changes:
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/ralsina/mangrullo:latest dry-run
Option 4: Check Specific Containers
The entrypoint commands don't take container names; bypass the entrypoint to filter by name:
docker run --rm \
--entrypoint mangrullo \
-v /var/run/docker.sock:/var/run/docker.sock \
ghcr.io/ralsina/mangrullo:latest \
--once flatnotes atuin
Docker Compose
Use the provided docker-compose.yml for easier deployment:
Start Mangrullo
docker-compose up -d
Stop Mangrullo
docker-compose down
View Logs
docker-compose logs -f
Configuration
Environment Variables
All configuration options can be set via environment variables with the MANGRULLO_ prefix:
| Variable | Description | Default |
|---|---|---|
MANGRULLO_INTERVAL |
Check interval in seconds | 3600 (entrypoint) |
MANGRULLO_ALLOW_MAJOR |
Allow major version upgrades | false |
MANGRULLO_SOCKET |
Docker socket path | /var/run/docker.sock |
MANGRULLO_LOG_LEVEL |
Log level (debug, info, warn, error) | info |
MANGRULLO_RUN_ONCE |
Run once and exit | false |
MANGRULLO_DRY_RUN |
Show what would be updated without changes | false |
Web mode honors these additional variables (set them for the web service):
| Variable | Description | Default |
|---|---|---|
MANGRULLO_WEB_PORT |
Web interface port | 3000 |
MANGRULLO_WEB_HOST |
Web interface bind address | 0.0.0.0 |
MANGRULLO_WEB_USER |
HTTP Basic auth user (optional) | unset |
MANGRULLO_WEB_PASSWORD |
HTTP Basic auth password (optional) | unset |
Note: Setting both MANGRULLO_WEB_USER and MANGRULLO_WEB_PASSWORD enables
HTTP Basic authentication on every route except /health (so Docker health
checks keep working). With either unset the UI is open.
Note: The old environment variable MANGRULLO_DOCKER_SOCKET has been renamed to MANGRULLO_SOCKET for consistency.
Configuration File
YAML configuration file support is not currently enabled: the plumbing
exists (via docopt-config) but no CLI flag passes a config file path, and
--config=/config.yml is not a valid option. Use environment variables
instead.
Example with Custom Configuration
docker run -d \
--name mangrullo \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-e MANGRULLO_LOG_LEVEL=debug \
-e MANGRULLO_INTERVAL=1800 \
-e MANGRULLO_ALLOW_MAJOR=true \
ghcr.io/ralsina/mangrullo:latest daemon
Building the Image
Build the Docker image from source:
docker build -t mangrullo .
Build for a specific platform:
docker build -t mangrullo --platform linux/amd64 .
docker build -t mangrullo --platform linux/arm64 .
Security Considerations
Docker Socket Access
Mangrullo needs access to the Docker socket to manage containers. This is done with:
-v /var/run/docker.sock:/var/run/docker.sock
Note: Mangrullo needs write access to the Docker socket to recreate containers. The :ro flag cannot be used as it would prevent container operations. If you want to restrict access further, consider:
- Using a Docker socket proxy that filters allowed operations
- Running Mangrullo in a separate Docker network with limited access
- Using Docker's socket activation with proper permissions
Non-root User
The Docker image runs Mangrullo as a non-root user (UID 1000) for improved security.
Monitoring
Logs
View container logs:
docker logs mangrullo
docker logs -f mangrullo # Follow logs
Health Checks
The image defines a Docker HEALTHCHECK (backed by docker-healthcheck.sh)
that probes the endpoint matching the container's mode:
- Daemon mode (default): the daemon serves
GET /healthon port${MANGRULLO_HEALTH_PORT:-3001}and the healthcheck reportshealthywhile the endpoint answers. - Web mode (
command: web): the healthcheck curlshttp://localhost:${MANGRULLO_WEB_PORT:-3000}/health, which stays reachable even when HTTP Basic authentication is enabled.
The daemon health endpoint returns 200 with a JSON body while the update
loop is progressing:
{
"status": "ok",
"uptime_seconds": 86300,
"interval_seconds": 3600,
"last_successful_check": "2026-09-12T18:00:00Z",
"seconds_since_successful_check": 123,
"last_error": null
}
It reports 503 with "status": "degraded" when no update cycle has
succeeded within twice the check interval, so a stuck daemon or an
unreachable Docker socket becomes visible to orchestrators.
Check the reported status at any time with:
docker inspect mangrullo --format='{{.State.Health.Status}}'
docker inspect mangrullo --format='{{json .State.Health}}'
docker logs -f mangrullo
The daemon health endpoint is enabled inside containers by default
(MANGRULLO_HEALTH_PORT=3001); set it to 0 to disable, or run the binary
outside Docker with --health-port=<port> to opt in.
Production Deployment
Using Docker Swarm
version: '3.8'
services:
mangrullo:
image: mangrullo:latest
deploy:
mode: replicated
replicas: 1
restart_policy:
condition: on-failure
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
environment:
- MANGRULLO_LOG_LEVEL=info
- MANGRULLO_INTERVAL=3600
- MANGRULLO_HEALTH_PORT=3001
healthcheck:
test: ["CMD", "curl", "-fsS", "http://127.0.0.1:3001/health"]
interval: 30s
timeout: 5s
retries: 3
start_period: 30s
networks:
- mangrullo-network
networks:
mangrullo-network:
driver: overlay
Using Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: mangrullo
spec:
replicas: 1
selector:
matchLabels:
app: mangrullo
template:
metadata:
labels:
app: mangrullo
spec:
containers:
- name: mangrullo
image: mangrullo:latest
env:
- name: MANGRULLO_LOG_LEVEL
value: "info"
- name: MANGRULLO_INTERVAL
value: "3600"
- name: MANGRULLO_HEALTH_PORT
value: "3001"
ports:
- containerPort: 3001
name: health
livenessProbe:
httpGet:
path: /health
port: health
initialDelaySeconds: 30
periodSeconds: 30
readinessProbe:
httpGet:
path: /health
port: health
initialDelaySeconds: 5
periodSeconds: 30
volumeMounts:
- name: docker-socket
mountPath: /var/run/docker.sock
readOnly: true
volumes:
- name: docker-socket
hostPath:
path: /var/run/docker.sock
Troubleshooting
Permission Denied
If you get permission denied errors:
# Add user to docker group on host
sudo usermod -aG docker $USER
# Or run with elevated privileges
docker run --privileged ...
Connection Issues
If Mangrullo can't connect to Docker:
- Verify Docker is running:
docker ps - Check socket permissions:
ls -la /var/run/docker.sock - Ensure the socket is mounted correctly
Advanced Usage
Custom Dockerfile
For custom builds, create a .dockerignore file:
.git
.github
.spec
lib/
bin/
*.log
.DS_Store
Multi-architecture Builds
Build for multiple architectures:
docker buildx build --platform linux/amd64,linux/arm64 -t mangrullo:latest .
Private Registry
Push to a private registry:
docker tag mangrullo:latest my-registry.com/mangrullo:latest
docker push my-registry.com/mangrullo:latest