Nov 18, 2021 4 min read

How to Upgrade Docker Containers Automatically When Updating Dockerized Web Apps

Updating WebApps is a regular task for sysadmins. Upgrading the containers that hold them is another extra effort. Automate that & make life easier.
Table of Contents

Imagine this scenario. You host a few web services running in Docker containers. When the web service has a new version release, you fetch the Docker image and update the containers to update the service.

I have discussed updating Docker containers without downtime earlier but this article is not about upgrading the web apps. This one is about updating the operating system containers themselves.

Upgrading the OS running in the container manually can be a daunting task from time to time. You must run the relevant upgrade commands yourself on a running container separately to make that happen.

How about eliminating this extra step and combine the updating of OS along with the updating of the service?

This is an automation trick I use when I update a web service which was deployed with Docker Compose.

We'll use Ghost CMS as a real-world example based on this deployment.

DigitalOcean – The developer cloud
Helping millions of developers easily build, test, manage, and scale applications of any size – faster than ever before.

Upgrading OS containers automatically while updating the web service

You can just read this article to understand what I am doing. But if you want to follow it along, you can do that as well.

I will show two different examples:

  1. For Debian Based Docker Containers
  2. For Alpine Based Docker Containers

Automatically Upgrading Debian Containers

The procedure needs you to take care of two steps:

Step 1: Note The CMD Instruction

Make a note of the CMD instruction that is specified finally inside the WebApp Dockerfile.

To do this you need to check the Dockerfile with which the image was built (Ghost for this example):

Therefore, the actual command here is node current/index.js.

Step 2: Add The "Auto-Upgrade" Setting

Add the upgrade commands and the noted CMD instruction inside the Ghost service section of the Docker Compose file:

command: sh -c "apt update && apt -y upgrade && node current/index.js"

Let's see how that would finally look like. Say, for example, you consider the Docker Compose entries for the Ghost service from the guide cited above. An updated version based on our tutorial would be:

    ghost:
      image: ghost:4.20.4
      volumes:
        - ghost:/var/lib/ghost/content
        - ./config.json:/var/lib/ghost/config.production.json
      command: sh -c "apt update && apt -y upgrade && node current/index.js"
      env_file:
        - ./ghost-mariadb.env
      restart: on-failure
      depends_on: 
        - ghostdb
      networks:
        - net
        - ghost

Here, I've specified the command just after the volumes section.

Automatically Upgrading Alpine Containers

This procedure once again needs you to take care of two similar steps:

Step 1: Note The CMD Instruction

Make a note of the CMD instruction that is specified finally inside the WebApp Dockerfile.

To do this you need to check the Dockerfile (Ghost Alpine for this example):

Very apparently, the command here is the same as seen for the Debian version earlier: node current/index.js.

Step 2: Add The "Auto-Upgrade" Setting

Add the upgrade commands and the noted CMD instruction inside the Ghost service section of the Docker Compose file:

command: sh -c "apk update && apk add --upgrade apk-tools && apk upgrade --available && node current/index.js"

Alpine Upgrade Reference.

Let's see how that would finally look like (note this time that I'll use the alpine image for Ghost). Say, for example, you consider the Docker Compose entries for the Ghost service from the guide cited above. An updated version based on our tutorial would be:

    ghost:
      image: ghost:4.20.4-alpine
      volumes:
        - ghost:/var/lib/ghost/content
        - ./config.json:/var/lib/ghost/config.production.json
      command: sh -c "apk update && apk add --upgrade apk-tools && apk upgrade --available && node current/index.js"
      env_file:
        - ./ghost-mariadb.env
      restart: on-failure
      depends_on: 
        - ghostdb
      networks:
        - net
        - ghost

That's it then. From this point onwards, whenever you update your WebApps without downtime, the container upgrade commands would automatically get invoked and then your web apps would be executed.

Note: When updating any app by changing the version number of the image in the docker compose file, you must temporarily disable the command option that is discussed here with a hashtag. Once the update in done for the web app, re-enable the same line to update the container itself. Both these steps (updating the app and the container) are achievable without any downtime through scaling.

Bonus Tips

Here is a list of commands for other popular apps like Nextcloud and Rocket.Chat. Remember, these are to be added just like how you saw for the Ghost example.

Nextcloud

For Debian:

command: sh -c "apt update && apt -y upgrade && apache2-foreground"

For Alpine:

command: sh -c "apk update && apk add --upgrade apk-tools && apk upgrade --available && apache2-foreground"

Rocket.Chat

command: sh -c "apt update && apt -y upgrade && node main.js"

Hope this article helps you in your day-to-day sysadmin activities. If you have any queries, feedback or suggestions, please leave your thoughts in the comment section below.

Avimanyu Bandyopadhyay
Avimanyu Bandyopadhyay
DevOps Geek at Linux Handbook. Doctoral Researcher on GPU-based Bioinformatics & author of 'Hands-On GPU Computing with Python'. He strongly believes in the significance of Linux and FOSS in Science.

Join the conversation

Great! You’ve successfully signed up.
Welcome back! You've successfully signed in.
You've successfully subscribed to Linux Handbook.
Your link has expired.
Success! Check your email for magic link to sign-in.
Success! Your billing info has been updated.
Your billing was not updated.