Categories
DevOps

How to automatically update docker containers whenever new image is released

Automatically update docker containers whenever new image is released using watchtower.

This is a great solution, especially when you are using portainer for container management (continuous mode) or jenkins (run-once mode). I will focus on the latter solution.

Display help information.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --help

	Watchtower automatically updates running Docker containers whenever a new image is released.
	More information available at https://github.com/containrrr/watchtower/.

Usage:
  watchtower [flags]

Flags:
  -a, --api-version string                          api version to use by docker client (default "1.25")
  -c, --cleanup                                     Remove previously used images after updating
  -d, --debug                                       Enable debug mode with verbose logging
      --enable-lifecycle-hooks                      Enable the execution of commands triggered by pre- and post-update lifecycle hooks
  -h, --help                                        help for watchtower
  -H, --host string                                 daemon socket to connect to (default "unix:///var/run/docker.sock")
      --http-api-metrics                            Runs Watchtower with the Prometheus metrics API enabled
      --http-api-periodic-polls                     Also run periodic updates (specified with --interval and --schedule) if HTTP API is enabled
      --http-api-token string                       Sets an authentication token to HTTP API requests.
      --http-api-update                             Runs Watchtower in HTTP API mode, so that image updates must to be triggered by a request
      --include-restarting                          Will also include restarting containers
  -S, --include-stopped                             Will also include created and exited containers
  -i, --interval int                                Poll interval (in seconds) (default 86400)
  -e, --label-enable                                Watch containers where the com.centurylinklabs.watchtower.enable label is true
  -m, --monitor-only                                Will only monitor for new images, not update the containers
      --no-color                                    Disable ANSI color escape codes in log output
      --no-pull                                     Do not pull any new images
      --no-restart                                  Do not restart any containers
      --no-startup-message                          Prevents watchtower from sending a startup message
      --notification-email-delay int                Delay before sending notifications, expressed in seconds
      --notification-email-from string              Address to send notification emails from
      --notification-email-server string            SMTP server to send notification emails through
      --notification-email-server-password string   SMTP server password for sending notifications
      --notification-email-server-port int          SMTP server port to send notification emails through (default 25)
      --notification-email-server-tls-skip-verify   Controls whether watchtower verifies the SMTP server's certificate chain and host name.
                                                    Should only be used for testing.
      --notification-email-server-user string       SMTP server user for sending notifications
      --notification-email-subjecttag string        Subject prefix tag for notifications via mail
      --notification-email-to string                Address to send notification emails to
      --notification-gotify-tls-skip-verify         Controls whether watchtower verifies the Gotify server's certificate chain and host name.
                                                    Should only be used for testing.
      --notification-gotify-token string            The Gotify Application required to query the Gotify API
      --notification-gotify-url string              The Gotify URL to send notifications to
      --notification-msteams-data                   The MSTeams notifier will try to extract log entry fields as MSTeams message facts
      --notification-msteams-hook string            The MSTeams WebHook URL to send notifications to
      --notification-report                         Use the session report as the notification template data
      --notification-slack-channel string           A string which overrides the webhook's default channel. Example: #my-custom-channel
      --notification-slack-hook-url string          The Slack Hook URL to send notifications to
      --notification-slack-icon-emoji string        An emoji code string to use in place of the default icon
      --notification-slack-icon-url string          An icon image URL string to use in place of the default icon
      --notification-slack-identifier string        A string which will be used to identify the messages coming from this watchtower instance (default "watchtower")
      --notification-template string                The shoutrrr text/template for the messages
      --notification-url stringArray                The shoutrrr URL to send notifications to
  -n, --notifications strings                        Notification types to send (valid: email, slack, msteams, gotify, shoutrrr)
      --notifications-hostname string               Custom hostname for notification titles
      --notifications-level string                  The log level used for sending notifications. Possible values: panic, fatal, error, warn, info or debug (default "info")
      --remove-volumes                              Remove attached volumes before updating
      --revive-stopped                              Will also start stopped containers that were updated, if include-stopped is active
      --rolling-restart                             Restart containers one at a time
  -R, --run-once                                    Run once now and exit
  -s, --schedule string                             The cron expression which defines when to update
      --scope string                                Defines a monitoring scope for the Watchtower instance.
  -t, --stop-timeout duration                       Timeout before a container is forcefully stopped (default 10s)
  -v, --tlsverify                                   use TLS and verify the remote
      --trace                                       Enable trace mode with very verbose logging - caution, exposes credentials
      --warn-on-head-failure string                 When to warn about HEAD pull requests failing. Possible values: always, auto or never

Check every container for new image.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --monitor-only --run-once --no-startup-message
time="2022-08-03T18:53:32Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T18:53:32Z" level=info msg="Using no notifications" notify=no
time="2022-08-03T18:53:32Z" level=info msg="Checking all containers (except explicitly disabled with label)" notify=no
time="2022-08-03T18:53:32Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T18:53:38Z" level=info msg="Found new portainer/portainer-ce:latest image (9b512274f720)"
time="2022-08-03T18:53:42Z" level=info msg="Found new vaultwarden/server:latest image (fc5bcff95ea6)"
time="2022-08-03T18:53:45Z" level=info msg="Found new jgraph/drawio:latest image (bc01f6bbc120)"
time="2022-08-03T18:53:47Z" level=info msg="Found new b4bz/homer:latest image (987af447b8a4)"
time="2022-08-03T18:53:49Z" level=info msg="Found new lscr.io/linuxserver/hedgedoc:latest image (0c3e5faf791a)"
time="2022-08-03T18:53:51Z" level=info msg="Found new lscr.io/linuxserver/mariadb:latest image (80297b3a5c68)"
time="2022-08-03T18:53:55Z" level=info msg="Found new dgtlmoon/changedetection.io:latest image (6c5efaea3f4b)"
time="2022-08-03T18:53:58Z" level=info msg="Found new mpepping/cyberchef:latest image (4b4f1b3ee788)"
time="2022-08-03T18:54:01Z" level=info msg="Found new searxng/searxng:latest image (fa2dbd23b296)"
time="2022-08-03T18:54:04Z" level=info msg="Found new tzahi12345/youtubedl-material:latest image (8fd9447216a4)"
time="2022-08-03T18:54:08Z" level=info msg="Found new redis:alpine image (9c5d9fbede14)"
time="2022-08-03T18:54:12Z" level=info msg="Found new binwiederhier/ntfy:latest image (d1f2647f8fc8)"
time="2022-08-03T18:54:15Z" level=info msg="Found new louislam/uptime-kuma:1 image (01d047a5d477)"
time="2022-08-03T18:54:15Z" level=info msg="Session done" Failed=0 Scanned=16 Updated=13 notify=no
time="2022-08-03T18:54:15Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Check specific container for new image.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --monitor-only --run-once --no-startup-message vault_vaultwarden_1
time="2022-08-03T19:06:00Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T19:06:00Z" level=info msg="Using no notifications" notify=no
time="2022-08-03T19:06:00Z" level=info msg="Only checking containers with name \"vault_vaultwarden_1\"" notify=no
time="2022-08-03T19:06:00Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T19:06:03Z" level=info msg="Found new vaultwarden/server:latest image (fc5bcff95ea6)"
time="2022-08-03T19:06:03Z" level=info msg="Session done" Failed=0 Scanned=1 Updated=1 notify=no
time="2022-08-03T19:06:03Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Update specific container.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once --no-startup-message vault_vaultwarden_1
time="2022-08-03T19:07:28Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T19:07:28Z" level=info msg="Using no notifications" notify=no
time="2022-08-03T19:07:28Z" level=info msg="Only checking containers with name \"vault_vaultwarden_1\"" notify=no
time="2022-08-03T19:07:28Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T19:07:32Z" level=info msg="Found new vaultwarden/server:latest image (fc5bcff95ea6)"
time="2022-08-03T19:07:32Z" level=info msg="Stopping /vault_vaultwarden_1 (355f21ac33a2) with SIGTERM"
time="2022-08-03T19:07:34Z" level=info msg="Creating /vault_vaultwarden_1"
time="2022-08-03T19:07:36Z" level=info msg="Session done" Failed=0 Scanned=1 Updated=1 notify=no
time="2022-08-03T19:07:36Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Update specific container and remove old image.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once --no-startup-message --cleanup ytdl_ytdl_material_1
time="2022-08-03T19:10:22Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T19:10:22Z" level=info msg="Using no notifications" notify=no
time="2022-08-03T19:10:22Z" level=info msg="Only checking containers with name \"ytdl_ytdl_material_1\"" notify=no
time="2022-08-03T19:10:22Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T19:10:26Z" level=info msg="Found new tzahi12345/youtubedl-material:latest image (8fd9447216a4)"
time="2022-08-03T19:10:26Z" level=info msg="Stopping /ytdl_ytdl_material_1 (8ca23375b28c) with SIGTERM"
time="2022-08-03T19:10:37Z" level=info msg="Creating /ytdl_ytdl_material_1"
time="2022-08-03T19:10:39Z" level=info msg="Removing image d599d76ad855"
time="2022-08-03T19:11:09Z" level=info msg="Session done" Failed=0 Scanned=1 Updated=1 notify=no
time="2022-08-03T19:11:09Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Update specific container, display debug information and remove old image.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once --no-startup-message --cleanup --debug docs_hedgedoc_1
time="2022-08-03T19:11:45Z" level=debug
time="2022-08-03T19:11:45Z" level=debug msg="Sleeping for a second to ensure the docker api client has been properly initialized."
time="2022-08-03T19:11:46Z" level=debug msg="Making sure everything is sane before starting"
time="2022-08-03T19:11:46Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T19:11:46Z" level=info msg="Using no notifications" notify=no
time="2022-08-03T19:11:46Z" level=info msg="Only checking containers with name \"docs_hedgedoc_1\"" notify=no
time="2022-08-03T19:11:46Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T19:11:46Z" level=debug msg="Checking containers for updated images"
time="2022-08-03T19:11:46Z" level=debug msg="Retrieving running containers"
time="2022-08-03T19:11:46Z" level=debug msg="Trying to load authentication credentials." container=/docs_hedgedoc_1 image="lscr.io/linuxserver/hedgedoc:latest"
time="2022-08-03T19:11:46Z" level=debug msg="No credentials for lscr.io found" config_file=/config.json
time="2022-08-03T19:11:46Z" level=debug msg="Got image name: lscr.io/linuxserver/hedgedoc:latest"
time="2022-08-03T19:11:46Z" level=debug msg="Checking if pull is needed" container=/docs_hedgedoc_1 image="lscr.io/linuxserver/hedgedoc:latest"
time="2022-08-03T19:11:46Z" level=debug msg="Building challenge URL" URL="https://lscr.io/v2/"
time="2022-08-03T19:11:46Z" level=debug msg="Got response to challenge request" header="Bearer realm=\"https://ghcr.io/token\",service=\"ghcr.io\",scope=\"repository:user/image:pull\"" status="401 Unauthorized"
time="2022-08-03T19:11:46Z" level=debug msg="Checking challenge header content" realm="https://ghcr.io/token" service=ghcr.io
time="2022-08-03T19:11:46Z" level=debug msg="Setting scope for auth token" image=lscr.io/linuxserver/hedgedoc scope="repository:lscr.io/linuxserver/hedgedoc:pull"
time="2022-08-03T19:11:46Z" level=debug msg="No credentials found."
time="2022-08-03T19:11:47Z" level=debug msg="Parsing image ref" host=lscr.io image=linuxserver/hedgedoc normalized="lscr.io/linuxserver/hedgedoc:latest" tag=latest
time="2022-08-03T19:11:47Z" level=debug msg="Doing a HEAD request to fetch a digest" url="https://lscr.io/v2/linuxserver/hedgedoc/manifests/latest"
time="2022-08-03T19:11:47Z" level=debug msg="Could not do a head request for \"lscr.io/linuxserver/hedgedoc:latest\", falling back to regular pull." container=/docs_hedgedoc_1 image="lscr.io/linuxserver/hedgedoc:latest"
time="2022-08-03T19:11:47Z" level=debug msg="Reason: registry responded to head request with \"401 Unauthorized\", auth: \"Bearer realm=\\\"https://ghcr.io/token\\\",service=\\\"ghcr.io\\\",scope=\\\"repository:linuxserver/hedgedoc:pull\\\"\"" container=/docs_hedgedoc_1 image="lscr.io/linuxserver/hedgedoc:latest"
time="2022-08-03T19:11:47Z" level=debug msg="Pulling image" container=/docs_hedgedoc_1 image="lscr.io/linuxserver/hedgedoc:latest"
time="2022-08-03T19:11:48Z" level=info msg="Found new lscr.io/linuxserver/hedgedoc:latest image (0c3e5faf791a)"
time="2022-08-03T19:11:48Z" level=info msg="Stopping /docs_hedgedoc_1 (cf864823fb44) with SIGTERM"
time="2022-08-03T19:11:54Z" level=debug msg="Removing container cf864823fb44"
time="2022-08-03T19:11:55Z" level=info msg="Creating /docs_hedgedoc_1"
time="2022-08-03T19:11:55Z" level=debug msg="Starting container /docs_hedgedoc_1 (2589a6687b58)"
time="2022-08-03T19:11:57Z" level=info msg="Removing image 96ed4362fd19"
time="2022-08-03T19:12:29Z" level=info msg="Session done" Failed=0 Scanned=1 Updated=1 notify=no
time="2022-08-03T19:12:29Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Check every container for new image and send notification using ntfy.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --monitor-only --run-once --no-startup-message --notifications shoutrrr --notification-url "generic+https://notify.octocat.cloud/watchtower?title=WatchtowerUpdates"
time="2022-08-03T19:26:42Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T19:26:42Z" level=info msg="Using notifications: generic+https" notify=no
time="2022-08-03T19:26:42Z" level=info msg="Checking all containers (except explicitly disabled with label)" notify=no
time="2022-08-03T19:26:42Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T19:26:54Z" level=info msg="Found new portainer/portainer-ce:latest image (9b512274f720)"
time="2022-08-03T19:26:57Z" level=info msg="Found new jgraph/drawio:latest image (bc01f6bbc120)"
time="2022-08-03T19:27:00Z" level=info msg="Found new b4bz/homer:latest image (987af447b8a4)"
time="2022-08-03T19:27:02Z" level=info msg="Found new lscr.io/linuxserver/mariadb:latest image (80297b3a5c68)"
time="2022-08-03T19:27:05Z" level=info msg="Found new dgtlmoon/changedetection.io:latest image (6c5efaea3f4b)"
time="2022-08-03T19:27:08Z" level=info msg="Found new mpepping/cyberchef:latest image (4b4f1b3ee788)"
time="2022-08-03T19:27:11Z" level=info msg="Found new searxng/searxng:latest image (fa2dbd23b296)"
time="2022-08-03T19:27:14Z" level=info msg="Found new redis:alpine image (9c5d9fbede14)"
time="2022-08-03T19:27:20Z" level=info msg="Found new binwiederhier/ntfy:latest image (d1f2647f8fc8)"
time="2022-08-03T19:27:23Z" level=info msg="Found new louislam/uptime-kuma:1 image (01d047a5d477)"
time="2022-08-03T19:27:23Z" level=info msg="Session done" Failed=0 Scanned=16 Updated=10 notify=no
time="2022-08-03T19:27:23Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Update every running container and remove old images.

$ docker run  -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once --no-startup-message --cleanup
time="2022-08-03T21:22:25Z" level=info msg="Watchtower 1.4.0" notify=no
time="2022-08-03T21:22:25Z" level=info msg="Using no notifications" notify=no
time="2022-08-03T21:22:25Z" level=info msg="Checking all containers (except explicitly disabled with label)" notify=no
time="2022-08-03T21:22:25Z" level=info msg="Running a one time update." notify=no
time="2022-08-03T21:22:37Z" level=info msg="Found new portainer/portainer-ce:latest image (9b512274f720)"
time="2022-08-03T21:22:40Z" level=info msg="Found new jgraph/drawio:latest image (bc01f6bbc120)"
time="2022-08-03T21:22:43Z" level=info msg="Found new b4bz/homer:latest image (987af447b8a4)"
time="2022-08-03T21:22:45Z" level=info msg="Found new lscr.io/linuxserver/mariadb:latest image (80297b3a5c68)"
time="2022-08-03T21:22:48Z" level=info msg="Found new dgtlmoon/changedetection.io:latest image (6c5efaea3f4b)"
time="2022-08-03T21:22:52Z" level=info msg="Found new mpepping/cyberchef:latest image (4b4f1b3ee788)"
time="2022-08-03T21:22:55Z" level=info msg="Found new searxng/searxng:latest image (fa2dbd23b296)"
time="2022-08-03T21:22:58Z" level=info msg="Found new redis:alpine image (9c5d9fbede14)"
time="2022-08-03T21:23:03Z" level=info msg="Found new binwiederhier/ntfy:latest image (d1f2647f8fc8)"
time="2022-08-03T21:23:06Z" level=info msg="Found new louislam/uptime-kuma:1 image (01d047a5d477)"
time="2022-08-03T21:23:06Z" level=info msg="Stopping /uptime_uptime-kuma_1 (8b598f8c9d9f) with SIGTERM"
time="2022-08-03T21:23:11Z" level=info msg="Stopping /notify_ntfy_1 (5fca2dbaf9d6) with SIGTERM"
time="2022-08-03T21:23:12Z" level=info msg="Stopping /search_redis-search_1 (9f0434ef8988) with SIGTERM"
time="2022-08-03T21:23:14Z" level=info msg="Stopping /search_search_1 (00eb06fe2ee1) with SIGTERM"
time="2022-08-03T21:23:25Z" level=info msg="Stopping /toolbox_toolbox_1 (f8d669809c9c) with SIGTERM"
time="2022-08-03T21:23:26Z" level=info msg="Stopping /changedetection_changedetection_1 (ece9f2884be8) with SIGTERM"
time="2022-08-03T21:23:37Z" level=info msg="Stopping /docs_mariadb_1 (0225cbf2d76a) with SIGTERM"
time="2022-08-03T21:23:42Z" level=info msg="Stopping /dashboard_homer_1 (7bd7f4cf0def) with SIGTERM"
time="2022-08-03T21:23:44Z" level=info msg="Stopping /draw_draw_1 (650ecd8cbd02) with SIGTERM"
time="2022-08-03T21:23:47Z" level=info msg="Stopping /portainer (4417ada44347) with SIGTERM"
time="2022-08-03T21:23:48Z" level=info msg="Creating /portainer"
time="2022-08-03T21:23:50Z" level=info msg="Creating /draw_draw_1"
time="2022-08-03T21:23:54Z" level=info msg="Creating /dashboard_homer_1"
time="2022-08-03T21:23:57Z" level=info msg="Creating /docs_mariadb_1"
time="2022-08-03T21:24:00Z" level=info msg="Creating /changedetection_changedetection_1"
time="2022-08-03T21:24:03Z" level=info msg="Creating /toolbox_toolbox_1"
time="2022-08-03T21:24:08Z" level=info msg="Creating /search_search_1"
time="2022-08-03T21:24:12Z" level=info msg="Creating /search_redis-search_1"
time="2022-08-03T21:24:16Z" level=info msg="Creating /notify_ntfy_1"
time="2022-08-03T21:24:20Z" level=info msg="Creating /uptime_uptime-kuma_1"
time="2022-08-03T21:24:24Z" level=info msg="Removing image 0153b5916fa4"
time="2022-08-03T21:24:24Z" level=info msg="Removing image 9dcd83a87127"
time="2022-08-03T21:24:25Z" level=info msg="Removing image 6cc6dadb6baa"
time="2022-08-03T21:24:30Z" level=info msg="Removing image bf7b7ef595d0"
time="2022-08-03T21:25:06Z" level=info msg="Removing image 465a74a8f1d2"
time="2022-08-03T21:25:07Z" level=info msg="Removing image 42020bc23b55"
time="2022-08-03T21:25:07Z" level=info msg="Removing image ee24f59e6e26"
time="2022-08-03T21:25:10Z" level=info msg="Removing image 1de7398797c7"
time="2022-08-03T21:25:10Z" level=info msg="Removing image 3a6672e62038"
time="2022-08-03T21:25:14Z" level=info msg="Removing image e5c6e4452448"
time="2022-08-03T21:25:14Z" level=info msg="Session done" Failed=0 Scanned=16 Updated=10 notify=no
time="2022-08-03T21:25:14Z" level=info msg="Waiting for the notification goroutine to finish" notify=no

Simple as that.