Docker image/container upgrade best practise

I recently created a custom image using the following Dockerfile…

FROM domoticz/domoticz:latest
RUN apt-get update && apt-get upgrade -y && apt-get install etherwake wget curl php-cli php-xml php-soap -y

…from which I created a container (using Docker on Synology btw). What I would like to know is what do I do when one of the packages has an update? Let’s say Domoticz has a new version, what should I do?

I was thinking about running the following command…

docker build -t domoticz-php .

… to create a new image with the same name as the existing image. But how do I “connect” that image to my container? Or do I first have to delete my old container and recreate it? Or can I stop my container, create the updates image, delete the old image and start the container again?

If you have any exposed (non-random) ports, you will need to stop the old container first and start a new one. You can use something like Watchtower if you push your images to a registry. If you do everything locally, I would recommend using Docker Compose to manage the containers. That way you can run an idempotent command and it will always be up to date.

There is no great way to cache bust in Docker Compose that I’m aware of, but I will give you two solutions.


Option 1: Use static versions for all of your dependencies.

Then when there is an update you change the version explicitly in the Dockerfile and everything updates as expected

Dockerfile

FROM domoticz/domoticz:v1.0.0 # I recommend a static version here to help with cache-busting when you update the base image
RUN apt-get update && apt-get upgrade -y && apt-get install etherwake==<etherwake_version> wget==<wget_version> ... -y

And then you have a Docker-compose.yml file like this:

services:
  web:
    build:
      context: .

When you need to update, change your Dockerfile so maybe it says

FROM domoticz/domoticz:v1.0.0 # I recommend a static version here to help with cache-busting when you update the base image
-RUN apt-get update && apt-get upgrade -y && apt-get install ... wget==1.20.0-1ubuntu1 ... -y
+RUN apt-get update && apt-get upgrade -y && apt-get install ... wget==1.20.3-1ubuntu1 ... -y

And you can run docker-compose up -d --build to automatically replace the running container with a newly built image :grinning_face_with_smiling_eyes:

The downside here is that you have to manually look up and manage versions.


Option 2: Use “evergreen” versions and manually cache-bust.

Your Dockerfile would look like this:

FROM domoticz/domoticz:latest
RUN apt-get update && apt-get upgrade -y && apt-get install etherwake wget curl php-cli php-xml php-soap -y

Your docker-compose.yml file will look like this:

services:
  web:
    image: coolness

When you want to update, just run docker build . -t coolness --no-cache --pull && docker-compose up -d.

**The downside here is that no matter if there is a dependency update or not, your resulting image will always change (at least it did in my tests) and thus docker-compose up -d will always replace your container with a new container. **

1 Like

A lot of terms I’m not yet familiar with since I’m still new at Docker. Since it’s only my home network, I’m still in trial and error stage and not afraid to break stuff. Looking at your “Option 2”:

My custom image is called “domoticz-php” and my container is called “domoticz”. If I run the following command, will it update my image and container?

docker build . -t domoticz-php --no-cache --pull && docker-compose up -d

When I currently do, I’m presented the following errors:

Can’t find a suitable configuration file in this directory or any parent. Are you in the right directory?
Supported filenames: docker-compose.yml, docker-compose.yaml

Hehe, sorry! Feel free to check out https://docs.docker.com and ask questions of anything you don’t understand! I can help ya out.

Ah, right. So your command is correct, but you need a docker-compose.yml file in that same directory with the contents of

services:
  web:
    image: coolness

That should fix the error you are getting.

So simply create a file called docker-compose.yml with the following contents in the same folder as my Dockerfile, run the same command and I’m golden?

services:
  web:
    image: domoticz-php

It should update and overwrite my running container, yes? When I do, I’m left with a “domoticz-php” image created “x seconds” ago and an image called “” created 7 days ago (probably when I first fired up Docker). I can’t remove the image “” because it’s in use by a running container which is my current Domoticz container.

Oh btw, my container does have mappings to folders on the host (volumes?) and custom port settings.

Life is easy on Synology:

Create the image using the same image:tag, then open the Synology Docker UI, pick the old container, select the “clear” action. As a result the old container should be replaced with a new container that uses the same configuration, but bases on the new image.

1 Like

Oh, maybe what you want is the UI option that @meyay provided, but I’m not familiar with Synology products–just the Docker part of this.

The caveat I forgot to mention is that it will create a new container. So put all of your configuration in the docker-compose file (volume mounts, ports, etc), and then also set the container_name and it should do what you want

services:
  web:
    image: domoticz-php
    container_name: domoticz
    ports:
      - 8080:8080 # <port_on_host>:<port_in_container>
    volumes:
      - /tmp:/tmp # <volume_on_host>:<volume_in_container>

You can see the compose docs for more information if I left anything out.

Could you point me to where I can find the “clear” option? I seem to only have start, stop, restart, force stop, reset and delete.

Since I’m not a crack (yet) I’ll keep it simple for now. Doing more and more Docker stuff in the CLI, but one stap at a time. Thanks.

I had package version 20.10.3-0552 installed, which had the label “clear” for the action. After updating to 20.10.3-0554 it seem to be relabeled to “reset”.

Btw. Synology’s docker package is far away from beeing a vanila docker engine - the swarm mode is broken by intention. Though, it also brings something good to the table: you can stop containers and change paramenters on an existing container without destroying the container (the container id remains unchanged).

Thanks, I’ll give it a go!

TBH, using the same image tag is an anti-pattern, so use that at your own peril. Why, well, first off docker images are meant to be immutable such that you can rely on the behaviours they exhibit wherever you deploy them. If you update an image and use the same tag you lose that guarantee. My strong recommendation would be to ensure your base image (your FROM) uses an explicitly versioned tag and, your own image should do likewise (use an explicit version tag - following a semantic versioning approach is pretty common or something like your Git repo commit id - you do have your source in a SCM right ?). That way you will easily be able to manage upgrades to your application and move between versions without any confusion or other unexpected side effects.

You might also want to consider whether doing apt update as part of your docker build is what you want in your context. It has the potential advantage of ensuring you are using the latest patched version of packages which can be important from a security perspective, however, you have now introduced the potential of a breaking change along with the possibility of more versioning issues outside of your control. That’s a judgement call for you to make, but as far as security is concerned, you should be scanning your images for vulnerabilities anyway.

HTHs

Fraser.

2 Likes