Update #6 Old fashioned bash scripting

Due to holidays (a week in the sun & the snow!) and busy return at work, my study progress has been disappointing. But I was able to work on another technical topic that had some urgency: updating the software on my NUC that runs this blog. For the technical nurds some more information on my setup:

  1. An intel NUC with 16G memory and a fast 500GB SSD
  2. The NUC runs Proxmox virtualization software
  3. In Proxmox I have a so called LXC container running, which you could compare with a virtual machine
  4. The LXC container runs Nginx as reverse proxy for my domains and docker to run my containers
  5. On the LXC container, 4 docker containers are running:
  • 1 WordPress container for this blog
  • 1 WordPress container for my band: https://thomandthejerrys.nl
  • 1 MySQL container for WordPress
  • 1 Portainer container, to have a nice frontend for the containers

Portainer is great: you visually see the status of your containers and you can stop, start or rebuild them from the GUI. You can even go directly into a container terminal from Portainer. But there is one problem, you cannot update portainer from within portainer. It is not too difficult to do this from the command line, but I always forget the exact commands. The solution: A bash script that took me almost a day to make.

Continue if you are curious…

The tricky part of scripting the update of the portainer container, is that you need the ID’s for the running container and the image the container is based on. It took me ages to figure our how to do this with really old fashioned linux/Bash commands. Using Regex to find the id’s in the docker command output was my idea from the start, but it took a lot of searching and trial and error to get it right. I ended up code below. Not perfect, but it works for me.

#!/bin/bash

# ----------------------------------------------------------
# AKN - updated April 2, 2022
# Script to update the portainer container to latest version
# ----------------------------------------------------------

# ---- Get the id of the running portainer container
psline=$(docker ps | grep portainer)
containernmbr=$(echo "$psline" | grep -E -o '^.{12}')

# ---- Get the id of the current portainer image 
lsline=$(docker image ls | grep portainer)
imagenmbr=$(echo "$lsline" | grep -E -o '[0-9a-fA-F]{12}')

# ---- Stop the container, remove the container, remove the image and recreate the container with latest image
docker stop $containernmbr
docker rm $containernmbr
docker image rm $imagenmbr --force
docker run -d -p 9000:9000 -p 8000:8000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest

In the code above I first retrieve the container ID. The container ID is always a hexadecimal number at the first 12 positions in a row in the list generated by docker ps. So I first get the line containing the portainer container with docker ps | grep container. As a second step I use the regex ^.{12} to get the first 12 characters.

In second part I retrieve the portainer image ID, this is needed to remove it later on. This is harder, as docker image ls command shows the container ID as 3rd column. Now I use regex [0-9a-fA-F]{12}. In other words: select the first 12 consecutive character that are either 0-9 or A-F, the characters of the hexadecimal number. This code is not perfect: if at another place in the output there are by coincidence 12 consecutive characters with just 0-9 or A-F, these would be selected. But in my case, where content of the first 2 colums in the output is known, this script will work fine.

I can’t remember the days I was doing this kind of stuff, but it was fun to do it again and frustrating that is takes sooo looong. And also very satisfying when it works in the end. Next time I maybe better do this kind of thing in Java 🙂