A lightweight Python utility that automatically detects and updates Docker Compose services when new image versions are available in the registry!
Warning
Docker socket = root access to your entire Docker environment
This tool can control ALL containers. A compromise means full system access. Review Security Considerations before installing.
- Automatic digest comparison: Detects outdated images by comparing local vs. remote SHA256 digests
- Compose-aware: Works with Docker Compose containers (validates via Compose labels)
- Cron scheduling: Automated updates on your schedule (daily, hourly, custom)
- Flexible update modes: All labeled, single container, or force mode
- Image cleanup: Optionally remove old/dangling images after updates
- State preservation: Respects container running state during updates
- Containerized: Runs as a Docker container with access to host Docker daemon
- Non-interactive mode: Automatic confirmation for CI/CD pipelines
- Security Considerations
- Installation
- Docker Image Tags
- Usage
- Configuration
- Docker Compose Setup Example
- How It Works
- Monitoring and Logs
- Troubleshooting
- Contributing
IMPORTANT: Read this before installing!
- The service needs access to the Docker socket (
/var/run/docker.sock) - Container mode: Runs as root inside container (isolated from host)
- Standalone mode: User must be in the
dockergroup (non-root)
- The autoupdate container has full control over Docker daemon
- Use registry credentials via Docker config for private registries
- Recommend mounting compose directories as read-only (
:ro) - Always test in development before production use
- Don't auto-update critical services: Exclude databases and stateful services from auto-updates
- Use specific tags: Prefer
nginx:1overnginx:latestfor more control - Monitor logs: Regularly check update logs for issues
- Test first: Use
RUN_ON_STARTUP=trueto test immediately - Backup: Always backup before enabling auto-updates on production
Pull the latest stable image from GitHub Container Registry:
# Pull latest stable release
docker pull ghcr.io/buspo/autoupdater:latest
# Or pull development version
docker pull ghcr.io/buspo/autoupdater:devThen create your docker-compose.yml:
services:
autoupdate:
image: ghcr.io/buspo/autoupdater:latest
container_name: autoupdate
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/docker:/opt/docker:ro # Your compose files
environment:
- CRON_SCHEDULE=0 3 * * *
- AUTOUPDATE_LABEL=autoupdate.enable=true
- AUTO_CLEANUP=true
labels:
- autoupdater.self=trueStart the service:
docker compose up -d# Clone the repository
git clone https://github.com/buspo/autoUpdater.git
cd autoUpdater
# Create virtual environment and install dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt# Clone the repository
git clone https://github.com/buspo/autoUpdater.git
cd autoUpdater
# Build the image
docker build -t autoupdate:local .
# Or use docker compose
docker compose build
# Start
docker compose up -dImages are available on GitHub Container Registry:
| Tag | Description | Use Case | Update Frequency |
|---|---|---|---|
latest |
Latest stable release | Production | On each release |
stable |
Alias for latest |
Production | On each release |
dev |
Latest development build | Testing/Staging | On each main branch commit |
X.Y.Z |
Specific version (e.g., 0.1.0) |
Production (pinned) | Never (immutable) |
X.Y |
Latest patch of minor version (e.g., 0.1) |
Production (auto-patch) | On patch releases (0.1.x) |
X |
Latest minor of major version (e.g., 0) |
Staging | On minor/patch releases |
dev-abc1234 |
Specific commit from dev | Debug/Testing | Never (immutable) |
# Production - Latest stable (recommended)
docker pull ghcr.io/buspo/autoupdater:latest
# Production - Specific version (most stable)
docker pull ghcr.io/buspo/autoupdater:0.1.0
# Production - Auto-patch updates
docker pull ghcr.io/buspo/autoupdater:0.1
# Staging/Testing - Latest development
docker pull ghcr.io/buspo/autoupdater:dev
# Debug - Specific commit
docker pull ghcr.io/buspo/autoupdater:dev-a1b2c3d# For production (most stable)
image: ghcr.io/buspo/autoupdater:0.1.0 # Pinned version
# For production (with auto-patch)
image: ghcr.io/buspo/autoupdater:0.1 # Gets 0.1.1, 0.1.2, etc.
# For production (always latest)
image: ghcr.io/buspo/autoupdater:latest # Gets new releases
# For staging/testing
image: ghcr.io/buspo/autoupdater:dev # Latest developmentThe standalone mode requires manual execution or setup with cron/systemd.
# Update all containers with default label
python3 autoupdate.py
# Update a specific container
python3 autoupdate.py --update myapp
# Update and cleanup old images
python3 autoupdate.py --cleanup
# Show all options
python3 autoupdate.py --help| Argument | Short | Default | Description |
|---|---|---|---|
--label LABEL |
- | autoupdate.enable=true |
Label filter to identify containers for update |
--update CONTAINER |
- | None |
Update only the specified container name |
--force |
- | False |
Force update bypassing label and digest checks |
--cleanup |
- | False |
Remove old/dangling images after update |
--yes |
-y |
False |
Automatic yes to prompts (non-interactive mode) |
# Update all labeled containers and cleanup
python3 autoupdate.py --cleanup
# Update only one container
python3 autoupdate.py --update web
# Force update without label check
python3 autoupdate.py --update app --force
# Force update all with automatic confirmation (for scripts/CI)
python3 autoupdate.py --force --yes
# Use custom label
python3 autoupdate.py --label "myapp.autoupdate=enabled"
# Non-interactive mode for cron jobs
python3 autoupdate.py --cleanup --yes# Edit crontab
crontab -e
# Add line (runs daily at 3 AM)
0 3 * * * cd /path/to/autoUpdater && .venv/bin/python3 autoupdate.py --cleanup --yes >> /var/log/autoupdate.log 2>&1The containerized version runs automatically on a cron schedule.
# Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
autoupdate:
image: ghcr.io/buspo/autoupdater:latest
container_name: autoupdate
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/docker:/opt/docker:ro
environment:
- CRON_SCHEDULE=0 3 * * *
- AUTO_CLEANUP=true
labels:
- autoupdater.self=true
EOF
# Start
docker compose up -d
# View logs
docker compose logs -f# Pull latest
docker pull ghcr.io/buspo/autoupdater:latest
# Run with docker run
docker run -d \
--name autoupdate \
--restart unless-stopped \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /opt/docker:/opt/docker:ro \
-e CRON_SCHEDULE="0 3 * * *" \
-e AUTO_CLEANUP=true \
--label autoupdater.self=true \
ghcr.io/buspo/autoupdater:latest
# View logs
docker logs -f autoupdate
# Stop
docker stop autoupdate
# Remove
docker rm autoupdate# Check status
docker ps --filter name=autoupdate
# View configuration
docker exec autoupdate env | grep -E "CRON|LABEL|CLEANUP"
# Run update manually
docker exec autoupdate python3 /app/autoupdate.py
# View cron schedule
docker exec autoupdate crontab -l
# Follow logs
docker logs -f autoupdateEdit docker-compose.yml to customize:
volumes:
# Required
- /var/run/docker.sock:/var/run/docker.sock
# For private registries (optional)
- $HOME/.docker/config.json:/root/.docker/config.json:ro
# Your compose file directories (add all paths)
- /opt/docker:/opt/docker:ro
- /home/user/projects:/projects:ro
- /srv/apps:/apps:roenvironment:
# Cron schedule (when to run updates)
# Format: minute hour day month weekday
- CRON_SCHEDULE=0 3 * * * # Daily at 3 AM
# Examples:
# - CRON_SCHEDULE=0 */6 * * * # Every 6 hours
# - CRON_SCHEDULE=30 2 * * 0 # Sundays at 2:30 AM
# - CRON_SCHEDULE=0 0 1 * * # First day of month
# Label to filter containers
- AUTOUPDATE_LABEL=autoupdate.enable=true
# Auto cleanup old images after update
- AUTO_CLEANUP=true
# Force update all containers (bypass label check)
# WARNING: Use with caution!
- FORCE_UPDATE=false
# Run update immediately on container startup
# Useful for testing
- RUN_ON_STARTUP=false
# Timezone for logs and cron schedule
- TZ=Europe/RomeLabel your services to enable auto-updates:
services:
# Web application - will be auto-updated
web:
image: nginx:latest
labels:
- autoupdate.enable=true # ← Enable auto-update
ports:
- "80:80"
restart: unless-stopped
# Application server - will be auto-updated
app:
image: myapp:latest
labels:
- autoupdate.enable=true # ← Enable auto-update
environment:
- ENV=production
restart: unless-stopped
# Database - NOT auto-updated (no label)
database:
image: postgres:15
# No autoupdate label - this is intentional!
# Databases should be updated manually
volumes:
- db-data:/var/lib/postgresql/data
restart: unless-stopped
# Auto-updater service
autoupdate:
image: ghcr.io/buspo/autoupdater:latest
container_name: autoupdate
restart: unless-stopped
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/docker:/opt/docker:ro
environment:
- CRON_SCHEDULE=0 3 * * *
- AUTO_CLEANUP=true
labels:
# Prevent self-update
- autoupdater.self=true
- autoupdate.enable=false
volumes:
db-data:Then start your stack:
docker compose up -dThe autoupdate service will:
- Run immediately on startup (if
RUN_ON_STARTUP=true) - Run on the configured cron schedule
- Update only services with the label
- Preserve running state of containers
- Optionally cleanup old images
1. Scan Docker containers for Compose metadata labels
2. For each labeled (or specified) container:
├─ Retrieve the local image's RepoDigest (SHA256)
├─ Query the registry for the remote digest
└─ Compare digests to detect if update is available
3. If update needed:
├─ Pull the new image from registry
├─ Run `docker compose up -d --build` (if was running)
│ OR `docker compose up --no-start` (if was stopped)
└─ Optionally cleanup the old image (if AUTO_CLEANUP=true)
4. Log all actions with timestamps
- Running containers: Pulled, rebuilt, and restarted
- Stopped containers: Image updated but container remains stopped
- Labels respected: Only updates containers with the configured label (unless
--force) - Self-protection: Skips containers with
autoupdater.self=truelabel
# Docker Compose
docker compose logs -f autoupdate
# Docker
docker logs -f autoupdate
# Inside container
docker exec autoupdate tail -f /var/log/autoupdate/autoupdate.log# Check health status
docker inspect autoupdate --format='{{.State.Health.Status}}'
# Check if cron is running
docker exec autoupdate ps aux | grep cron# List containers with autoupdate label
docker ps -a --filter "label=autoupdate.enable=true" \
--format "table {{.Names}}\t{{.Image}}\t{{.Status}}"-
Check label: Ensure container has
autoupdate.enable=truedocker inspect <container> --format '{{.Config.Labels}}'
-
Check logs: Look for errors
docker logs autoupdate
-
Test manually: Run update check
docker exec autoupdate python3 /app/autoupdate.py
Mount your Docker config:
volumes:
- $HOME/.docker/config.json:/root/.docker/config.json:roOr login before running:
docker login ghcr.io-
Verify cron is configured:
docker exec autoupdate crontab -l -
Check cron is running:
docker exec autoupdate ps aux | grep cron
-
Test the cron script:
docker exec autoupdate /app/run_cron_update.sh
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request