Automate Docker Container Update with WatchTower

Updating Docker containers can require significant effort. There are of course solutions to automate these updates. Here we look at the solution proposed by the Docker WatchTower image (https://github.com/v2tec/watchtower).

WatchTower is a Docker Container that updates all running containers when there is an update for that container.

The principle is:

  • you run the WatchTower container,
  • you create a Docker image,
  • you push it to Docker Hub,
  • you update this Docker image,
  • you push it to Docker Hub,
  • WatchTower stops the container of the image you have created, updates the image and then restarts the container.

Launch of Watchtower

Create the WatchTower container to monitor running containers:

docker run -d --name watchtower --restart always -v /var/run/docker.sock:/var/run/docker.sock v2tec/watchtower -i 30

It displays the ID of the container:

b4417755c0c4c2d71ce50e48bf2cae0a30b9c133e40791536ac1ecd9d84a5ad8

allows you to specify the frequency of change verification (here, every 30 seconds).

Show the logs of this container at launch:

docker logs watchtower

The log is:

time="2020-11-12T13:33:23Z" level=info msg="First run: 2020-11-12 13:33:53 +0000 UTC"

Connection to Hub Docker

Login to Hub Docker with your credentials ( and ):

docker login -u $HUB_USERNAME -p $HUB_PASSWORD

The output is:

WARNING! Using --password via the CLI is insecure. Use --password-stdin.
Login Succeeded

Creating a first image Docker and launch

Create a first image based on the image. The latter displays a web page via a nginx web server:

cat <<EOF> Dockerfile
FROM devopstestlab/nginx-helloworld
ADD index.html /usr/share/nginx/html/
EOF

Change the default web page to display in the web page:

cat <<EOF> index.html
<html>
<body>
<p>Helloworld v1 !</p>
</body>
</html>
EOF

Create the Docker image:

docker build -t devopstestlab/auto-update .

The output is:

Sending build context to Docker daemon  4.169MB
Step 1/2 : FROM devopstestlab/nginx-helloworld
latest: Pulling from devopstestlab/nginx-helloworld
Digest: sha256:3385ecc3c20a714d257c59c8cbffc7d6e681a6b38c34db6dd43beb48197f3f80
Status: Downloaded newer image for devopstestlab/nginx-helloworld:latest
---> 9468dea24c09
Step 2/2 : ADD index.html /usr/share/nginx/html/
---> Using cache
---> eee8df36d30e
Successfully built eee8df36d30e
Successfully tagged devopstestlab/auto-update:latest

Push it on Hub Docker:

docker push devopstestlab/auto-update

Ths image is pushed:

The push refers to repository [docker.io/devopstestlab/auto-update]e1b56fad: Preparing 
076e3049: Preparing
e5cf1923: Preparing
cf4d16de: Preparing
latest: digest: sha256:6ca819c5e3eca39bbf037995052b103e53253b9efd3dc0dffe4e311d9e15fa79 size: 1360

Launch a Docker container from this image:

docker run -d --rm --name auto-update -p 80:80 devopstestlab/auto-update

This command displays the ID container:

0d538753b84d31a4ae8efbfc8d2476e268b9d7db49e7b79eae17e7486a57cfb4

Check that the Docker container displays a web page and with the message :

curl localhost:80

The website returns:

<html>
<body>
<p>Helloworld v1 !</p>
</body>
</html>

Updating the Docker image

Modify the Docker image web page to display the message :

cat <<EOF> index.html
<html>
<body>
<p>Helloworld v2 !</p>
</body>
</html>
EOF

Create the new image:

docker build -t devopstestlab/auto-update .

The output is:

Sending build context to Docker daemon  4.169MB
Step 1/2 : FROM devopstestlab/nginx-helloworld
---> 9468dea24c09
Step 2/2 : ADD index.html /usr/share/nginx/html/
---> 840abf8ebb48
Successfully built 840abf8ebb48
Successfully tagged devopstestlab/auto-update:latest

Push on Hub Docker the new version of the image:

docker push devopstestlab/auto-update

The output is:

The push refers to repository [docker.io/devopstestlab/auto-update]593359df: Preparing 
076e3049: Preparing
e5cf1923: Preparing
cf4d16de: Preparing
latest: digest: sha256:1514ae398a965c46301c45dd268d1ec2091facabbbe5caf90cd730f6320a4891 size: 1360

Display the contents of the web page of the container:

curl localhost:80

The website returns:

<html>
<body>
<p>Helloworld v1 !</p>
</body>
</html>

It is always the first version that is displayed ().

Wait a few moments and then try again. At some point, the container is stopped:

curl localhost:80

The following error message is displayed:

curl: (7) Failed to connect to localhost port 80: Connection refused

Then it is updated and restarted:

curl localhost:80

The website returns now:

<html>
<body>
<p>Helloworld v2 !</p>
</body>
</html>

The new version is well launched ().

Now we can find these events in the logs of the `watchtower’ container:

docker logs watchtower

The logs are:

time="2020-11-12T13:33:23Z" level=info msg="First run: 2020-11-12 13:33:53 +0000 UTC" 
time="2020-11-12T13:34:24Z" level=info msg="Found new devopstestlab/auto-update:latest image (sha256:840abf8ebb48bc5f589548f5d54277a933ad37da0031ecf69f310ba46e9ca83b)"
time="2020-11-12T13:34:25Z" level=info msg="Stopping /auto-update (0d538753b84d31a4ae8efbfc8d2476e268b9d7db49e7b79eae17e7486a57cfb4) with SIGTERM"
time="2020-11-12T13:34:26Z" level=info msg="Creating /auto-update"

Now, you know how to automate the update of Docker containers from their image on the Hub Docker website.

More articles on my blog http://www.DevOpsTestLab.com.

My DevOpsTestLab Youtube channel.

My LinkedIn profile: https://fr.linkedin.com/in/brunodelb

Written by

Interests in the full lifecycle: design, Agile Coaching, development, testing, DevOps, Cloud, Management 3.0, ITIL. It defines me.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store