Graphic showing the logo of the Watchtower container update tool

Watchtower solves the common problem of how to update running Docker containers when a new image releases. Watchtower automatically “watches” your containers, periodically polls for new versions of their images, and restarts them so they’re running the new release.

In this article we’ll show how to use Watchtower to simplify your container fleet administration. We’ll also look at the advanced options you can use to customize Watchtower’s behavior.

Deploying Watchtower

The first step is to start a Watchtower instance inside its own Docker container. Run the following command to download the Watchtower image and create a container:

$ docker run -d --name watchtower \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

Your host’s Docker socket is mounted into the Watchtower container with the -v flag. This allows Watchtower to interact with your host’s Docker daemon instance. It’s required so Watchtower can enumerate and start containers.

It’s possible to use Watchtower with a remote Docker host. Expose that host’s Docker daemon on a TCP port, then start Watchtower with a DOCKER_HOST environment variable instead of a socket bind:

$ docker run -d --name watchtower \
    -e DOCKER_HOST="tcp://192.168.0.1:2375" \
    containrrr/watchtower

If your Docker host is protected with TLS, use Watchtower’s --tlsverify flag and mount your certificates into the container’s /etc/ssl/docker directory:

$ docker run -d --name watchtower \
    -e DOCKER_HOST="tcp://192.168.0.1:2375" \
    -e DOCKER_CERT_PATH=/etc/ssl/docker
    -v ./certs:/etc/ssl/docker
    containrrr/watchtower --tlsverify

Watchtower is designed to run once per Docker host. When a new Watchtower instance starts, it’ll clean up any other Watchtower containers already exist. You can run multiple instances by assigning them each unique scopes but this isn’t usually necessary in most deployments.

Using Watchtower

Your Watchtower container immediately starts monitoring the other containers on your Docker host. It’ll poll for image updates once every 24 hours and restart your containers when changes occur.

New container retain the same options as the original that they’re created from. Port binds, volume mounts, environment variables, and any other settings will all be intact on the replacement.

Watchtower is also dependency-aware: when containers are linked together, Watchtower will stop and start them in a logical order. Services that depend on a particular container will be stopped before that container’s updated, then brought back up after the replacement’s available. This ensures your applications don’t encounter errors while their dependencies are updating.

Watchtower sends a SIGTERM signal to containers when it needs them to stop for an update. You can change this signal by setting a label on your containers. Here’s how to switch to SIGHUP instead of SIGTERM:

$ docker run -d --label=com.centurylinklabs.watchtower.stop-signal=SIGHUP my-image

Excluding and Including Containers

You can customize which containers are monitored using a combination of Watchtower command arguments and Docker labels on your individual containers. Here’s an example of starting a container which is opted-out of Watchtower updates using a label:

$ docker run -d --label=com.centurylinklabs.watchtower.enable=false my-image

It’s also possible to whitelist the containers that should be updated, instead of opting out the ones that shouldn’t. Start Watchtower with the --label-enable flag to activate this behavior:

$ docker run -d --name watchtower \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower --label-enable

Now use the label to designate some containers as eligible to receive updates:

$ docker run -d --label=com.centurylinklabs.watchtower.enable=true my-image

Lifecycle Hooks

Watchtower can optionally run scripts inside your containers when specific events occur. Four hooks are available:

  • pre-check – Before Watchtower checks whether an update is available for the container.
  • pre-update – After an update has been found but before the container’s restarted.
  • post-update – After an update has been completed.
  • post-check – After a container’s check for updates has been completed.

Hooks are configured using container labels. The value of the label needs to be the path to an executable inside the container image. This will be called each time the hook fires.

Here’s an example of using the pre-update hook:

$ docker run -d --label=com.centurylinklabs.watchtower.lifecycle.pre-update="/backup.sh --create" my-image

The other hooks are configured similarly by substituting their name into the label.

Notifications and Monitoring

Watchtower can send you notifications over email, Slack, Microsoft Teams, Gotify and Shoutrrr when container updates become available. Each of these delivery mechanisms needs to be configured separately by setting environment variables in your Watchtower container.

Here’s a basic example that uses Gmail:

$ docker run -d --name watchtower \
    -e WATCHTOWER_NOTIFICATIONS=email
    -e WATCHTOWER_NOTIFICATION_EMAIL_FROM=you@gmail.com
    -e WATCHTOWER_NOTIFICATION_EMAIL_TO=you@gmail.com
    -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.gmail.com
    -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587
    -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=you@gmail.com
    -e WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=your_gmail_app_password
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

Watchtower also supports an operating mode where it checks for container updates without applying them. You can use this to be notified when updates are available, then restart your containers yourself at a convenient time.

Activate this mode with the --monitor-only flag:

$ docker run -d --name watchtower \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower --monitor-only

There’s also a label that can be set on individual containers to opt them into the monitoring mode:

$ docker run -d --label=com.centurylinklabs.watchtower.monitor-only=true my-image

Changing the Update Polling Interval

Watchtower checks for new images every 24 hours. This interval can be changed with the --interval flag or WATCHTOWER_POLL_INTERVAL environment variable. It accepts a value in seconds.

# Update every hour
$ docker run -d --name watchtower \
    -e WATCHTOWER_POLL_INTERVAL=3600
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

Alternatively you can define a fixed polling schedule using cron syntax. This is accepted as the --schedule flag or WATCHTOWER_SCHEDULE environment variable.

# Update every five minutes
$ docker run -d --name watchtower \
    -e WATCHTOWER_SCHEDULE="*/5 * * * *"
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

Cleaning Up Old Images

Watchtower leaves the old version of container images on your host after a new one is pulled. Setting the --cleanup flag or WATCHTOWER_CLEANUP environment variable will delete old images after an update. This can significantly free up disk space over time.

$ docker run -d --name watchtower \
    -e WATCHTOWER_CLEANUP=true
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

Running On-Demand

Watchtower is designed to run as a long-lived daemon that continually monitors containers for updates. Sometimes you might want to manually check for new images on-demand. You can do this with the --run-once command flag:

$ docker run --rm \
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower --run-once

This will perform a single update attempt for all your running containers. The Watchtower container will then stop and be removed.

Using Private Registries

Watchtower needs authentication details to check for updates to images in private registries. One way to supply them is by mounting your Docker config.json file to /config.json in your Watchtower container:

$ docker run -d --name watchtower \
    -v $HOME:/.docker/config.json:/config.json
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

There’s a caveat with this approach: updates to config.json on your host won’t necessarily be reflected inside the container. Commands like docker login actually replace the file, instead of directly editing it. This creates a new inode, breaking the Docker bind mount.

Another way to provide registry credentials to Watchtower is its REPO_USER and REPO_PASS variables. It’ll login as the defined user before trying to pull your images.

$ docker run -d --name watchtower \
    -e REPO_USER=demo-user
    -e REPO_PASS=users-password
    -v /var/run/docker.sock:/var/run/docker.sock \
    containrrr/watchtower

Conclusion

Watchtower lets you automate Docker container updates when new images are pushed to a registry. It’s a highly customizable system that supports container blacklists and whitelists, advanced scheduling with cron syntax, and notifications delivered to several popular providers.

Optional configuration parameters expose further functionality, such as rolling restarts, updates of restarting and stopped containers, and support for exposing metrics that give you another way to visualize update activity. This makes Watchtower a good choice for managing a busy set of production Docker containers.

Profile Photo for James Walker James Walker
James Walker is a contributor to How-To Geek DevOps. He is the founder of Heron Web, a UK-based digital agency providing bespoke software development services to SMEs. He has experience managing complete end-to-end web development workflows, using technologies including Linux, GitLab, Docker, and Kubernetes.
Read Full Bio »