Watchtower Automatic Docker Updates
Watchtower automatically updates Docker containers with new images, eliminating manual update procedures and ensuring your applications always run the latest versions. This comprehensive guide covers installation, scheduling, notifications, cleanup policies, label filtering, and operational considerations. Proper automation of container updates reduces maintenance burden while improving security posture through timely vulnerability patching.
Table of Contents
- Understanding Watchtower
- Installing Watchtower
- Basic Configuration
- Scheduling Updates
- Update Notifications
- Filtering and Selection
- Update Strategies
- Monitoring Mode
- Cleanup and Maintenance
- Conclusion
Understanding Watchtower
Watchtower monitors running Docker containers and their images, automatically pulling new images and restarting containers when updates are detected. This ensures your containerized applications always run current versions without manual intervention.
Key features:
- Automatic image update detection
- Scheduled update execution
- Selective container targeting
- Multiple notification channels
- Cleanup of old images
- Pre-update checks and dry-runs
- Include/exclude filtering
- Rollback on failure (optional)
Update workflow:
- Watchtower polls image registry for newer versions
- Compares current running version with latest available
- Pulls new image if update found
- Stops running container
- Starts new container with updated image
- Optionally cleans up old images
- Sends notification about update
Installing Watchtower
Deploy Watchtower as a container service.
Basic Watchtower deployment:
# Run Watchtower
docker run -d \
--name watchtower \
--restart always \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower
# Verify running
docker ps | grep watchtower
# Check logs
docker logs watchtower
Docker Compose deployment:
cat > docker-compose.yml <<'EOF'
version: '3.9'
services:
watchtower:
image: containrrr/watchtower:latest
container_name: watchtower
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
WATCHTOWER_SCHEDULE: "0 0 * * * *"
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_REMOVE_VOLUMES: "false"
WATCHTOWER_INCLUDE_RESTARTING: "true"
app:
image: nginx:latest
container_name: web
restart: always
ports:
- "80:80"
EOF
docker-compose up -d
Watchtower with Docker Swarm:
# Deploy as Swarm service
docker service create \
--name watchtower \
--mode global \
--restart-condition any \
--mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
-e WATCHTOWER_SCHEDULE="0 0 * * * *" \
-e WATCHTOWER_CLEANUP=true \
containrrr/watchtower
# Verify deployment
docker service ls
docker service ps watchtower
Basic Configuration
Configure Watchtower behavior and update policies.
Environment variables configuration:
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_SCHEDULE="0 0 * * * *" \
-e WATCHTOWER_CLEANUP=true \
-e WATCHTOWER_REMOVE_VOLUMES=false \
-e WATCHTOWER_INCLUDE_STOPPED=false \
-e WATCHTOWER_INCLUDE_RESTARTING=false \
-e WATCHTOWER_TIMEOUT=10 \
-e DEBUG=true \
containrrr/watchtower
Common configuration options:
- WATCHTOWER_SCHEDULE: Cron schedule for checks (default: 86400s/24h)
- WATCHTOWER_CLEANUP: Remove old images after update
- WATCHTOWER_REMOVE_VOLUMES: Delete volumes on container removal
- WATCHTOWER_INCLUDE_STOPPED: Update stopped containers
- WATCHTOWER_INCLUDE_RESTARTING: Update restarting containers
- WATCHTOWER_TIMEOUT: Shutdown timeout in seconds
- DEBUG: Enable debug logging
Target specific containers:
# Update specific containers (others ignored)
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
web app database
# Update only containers with label
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_LABEL_ENABLE=true \
containrrr/watchtower
# Label containers for auto-update
docker run -d \
--name myapp \
--label com.centurylinklabs.watchtower=true \
myapp:latest
Scheduling Updates
Configure when Watchtower performs updates.
Cron schedule expressions:
# Common schedules
# Every day at midnight
WATCHTOWER_SCHEDULE="0 0 * * * *"
# Every Sunday at 2 AM
WATCHTOWER_SCHEDULE="0 2 0 * * 0"
# Every 6 hours
WATCHTOWER_SCHEDULE="0 */6 * * * *"
# Every business day at 3 AM
WATCHTOWER_SCHEDULE="0 3 * * 1-5"
# Every 30 minutes
WATCHTOWER_SCHEDULE="0 */30 * * * *"
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e "WATCHTOWER_SCHEDULE=0 0 * * * *" \
containrrr/watchtower
Update timing strategies:
# Low-traffic windows (3 AM daily)
cat > docker-compose.yml <<'EOF'
services:
watchtower:
image: containrrr/watchtower:latest
environment:
# Update during maintenance window
WATCHTOWER_SCHEDULE: "0 3 * * *"
# Give containers 30 seconds to gracefully shutdown
WATCHTOWER_TIMEOUT: 30
# Stagger update checks
WATCHTOWER_CHECK_INTERVAL: 3600
EOF
Dry-run before actual update:
# Dry-run mode (check what would update, don't apply)
docker run -d \
--name watchtower-dryrun \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_DRY_RUN=true \
-e WATCHTOWER_RUN_ONCE=true \
containrrr/watchtower
# Check logs to see what would be updated
docker logs watchtower-dryrun
# Then enable for real updates
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_DRY_RUN=false \
containrrr/watchtower
Update Notifications
Send notifications when Watchtower performs updates.
Email notifications:
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e [email protected] \
-e [email protected] \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.gmail.com \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587 \
-e [email protected] \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=your-app-password \
containrrr/watchtower
Slack notifications:
# Create Slack webhook: https://api.slack.com/apps
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_NOTIFICATIONS=slack \
-e WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL=https://hooks.slack.com/services/YOUR/WEBHOOK/URL \
-e WATCHTOWER_NOTIFICATION_SLACK_IDENTIFIER=watchtower \
containrrr/watchtower
Multiple notification channels:
cat > docker-compose.yml <<'EOF'
version: '3.9'
services:
watchtower:
image: containrrr/watchtower:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
# Email
WATCHTOWER_NOTIFICATIONS: email
WATCHTOWER_NOTIFICATION_EMAIL_FROM: [email protected]
WATCHTOWER_NOTIFICATION_EMAIL_TO: [email protected]
WATCHTOWER_NOTIFICATION_EMAIL_SERVER: smtp.gmail.com
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT: 587
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER: ${GMAIL_USER}
WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD: ${GMAIL_PASSWORD}
# Slack
WATCHTOWER_NOTIFICATION_SLACK_HOOK_URL: ${SLACK_WEBHOOK}
# Schedule
WATCHTOWER_SCHEDULE: "0 0 * * * *"
WATCHTOWER_CLEANUP: "true"
EOF
docker-compose up -d
Filtering and Selection
Selectively update containers with labels and patterns.
Label-based filtering:
# Enable label-based filtering
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_LABEL_ENABLE=true \
containrrr/watchtower
# Deploy containers with update labels
docker run -d \
--name auto-update-app \
--label com.centurylinklabs.watchtower=true \
app:latest
# This container will be updated
docker run -d \
--name manual-app \
--label com.centurylinklabs.watchtower=false \
app:latest
# This container won't be updated
Image-based filtering:
# Update only specific image pattern
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
myregistry.com/myapp
# Update only this image, ignore others
Named container targeting:
# Update specific containers by name
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
web app database
# Updates only: web, app, database
# Ignores: cache, backup, etc.
Update Strategies
Implement different update strategies based on requirements.
Rolling updates:
# Docker Compose with rolling update strategy
cat > docker-compose.yml <<'EOF'
version: '3.9'
services:
watchtower:
image: containrrr/watchtower:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
WATCHTOWER_SCHEDULE: "0 0 * * * *"
WATCHTOWER_CLEANUP: "true"
WATCHTOWER_ROLLING_RESTART: "true"
app:
image: myapp:latest
restart: always
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
EOF
Update with health checks:
# Update only if health check passes
docker run -d \
--name app \
--health-cmd="curl -f http://localhost/ || exit 1" \
--health-interval=10s \
--health-timeout=5s \
--health-retries=3 \
app:latest
# Watchtower respects health status
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_SCHEDULE="0 0 * * * *" \
containrrr/watchtower
Scheduled maintenance windows:
# Update only during specific windows
cat > /usr/local/bin/watchtower-update.sh <<'EOF'
#!/bin/bash
# Check if in maintenance window (2-4 AM)
HOUR=$(date +%H)
if [ "$HOUR" -ge 2 ] && [ "$HOUR" -lt 4 ]; then
docker exec watchtower watchtower --run-once
else
echo "Outside maintenance window"
fi
EOF
chmod +x /usr/local/bin/watchtower-update.sh
# Schedule
0 * * * * /usr/local/bin/watchtower-update.sh
Monitoring Mode
Use Watchtower in monitor-only mode without automatic updates.
Monitor-only configuration:
# Run Watchtower without updating (monitor only)
docker run -d \
--name watchtower-monitor \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_DRY_RUN=true \
-e [email protected] \
-e [email protected] \
-e WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.gmail.com \
-e WATCHTOWER_NOTIFICATIONS=email \
containrrr/watchtower
# Watchtower alerts about available updates without applying them
Report available updates:
# Get list of available updates
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--dry-run
# Output shows what would be updated without applying changes
Cleanup and Maintenance
Manage old images and maintain system health.
Enable automatic cleanup:
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e WATCHTOWER_CLEANUP=true \
-e WATCHTOWER_REMOVE_VOLUMES=false \
-e WATCHTOWER_CLEANUP_PERIOD=86400 \
containrrr/watchtower
# WATCHTOWER_CLEANUP: Remove unused images
# WATCHTOWER_REMOVE_VOLUMES: Remove volumes on update
# WATCHTOWER_CLEANUP_PERIOD: Cleanup interval in seconds (default: 86400/24h)
Monitor Watchtower health:
# Check Watchtower logs
docker logs watchtower | tail -50
# Monitor disk usage
docker system df
# Clean up manually if needed
docker image prune -a --force
# Check Watchtower container status
docker inspect watchtower | grep -A 10 State
Troubleshoot failed updates:
# Enable debug logging
docker run -d \
--name watchtower \
-v /var/run/docker.sock:/var/run/docker.sock \
-e DEBUG=true \
containrrr/watchtower
# Check detailed logs
docker logs watchtower --follow
# Identify failed containers
docker ps -a --filter status=exited
# Check what Watchtower is monitoring
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--list-monitored
Conclusion
Watchtower automates the critical task of keeping containerized applications updated with the latest images, reducing operational overhead while improving security through timely vulnerability patching. By configuring appropriate schedules, filtering rules, and notifications, you create a self-updating infrastructure that requires minimal manual intervention. Start with basic nightly updates for non-critical containers, progress to selective updates using labels for production systems, and eventually integrate with monitoring and notification systems for complete visibility. Whether running a few containers or managing complex microservices deployments, Watchtower simplifies the update management burden. Combine automatic updates with proper health checks, monitoring, and rollback capabilities for a production-grade automated update solution.


