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

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:

  1. Watchtower polls image registry for newer versions
  2. Compares current running version with latest available
  3. Pulls new image if update found
  4. Stops running container
  5. Starts new container with updated image
  6. Optionally cleans up old images
  7. 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.