This is for a cheap VPS I use for personal projects. I like having a message of the day displaying system info on login; I wanted to add the status of my docker containers to it, to see if all are running and whatnot.
The scripts I found online for this displayed all the containers, but since I run mailcow for my email and it has 10+ containers in that single docker-compose project, the MOTD was much too long for my liking. So I decided to write my own although I've never written anything in Bash before this.
My script lists Docker containers and their status, but containers that are part of a docker-compose project are condensed into one as if they were a single container with the name of the compose project. If a container of a docker-compose project isn't running then the status of the "condensed container" is changed to "partial", and the container that isn't running is listed with its full name.
Screenshot (highlighted with a box is the output of the script)
My concerns about this are:
- I don't want to miss out on relevant info (other than the amount of time a container has been up for; I don't care about that), I'm not too familiar with docker and possible status a container could have and whether my way of doing
...!= "Up"
to check the status is good enough. - When a compose project has all its containers stopped/exited (any status that isn't "Up") I'd like to "condense" it again, since at the moment if that's the case then it will display partial, even though all its containers are not running, then it also list all of its containers. I don't know how I'd achieve this without running multiple chained
docker ps
commands that would slow down the script considerably. For now I'm content that a compose project having all its containers being down isn't something frequent. - I'm not too happy with the way I order the containers. I use two arrays put what I want near the top in one, and then what I want near the bottom in the second. I then concat the arrays. Not sure if this matters or if there's a cleaner way of doing it.
- Any unforeseen effects, or any way this doesn't work how I intended (outlined above) that is caused by my relative unfamiliarity with Docker or complete unfamiliarity with Bash scripts. And lastly and super minor, almost not worth mentioning: my choice of wording for saying "partial" when not all compose project's containers are running. Couldn't think of any better word, not sure if there is one.
#!/bin/bash
COLUMNS=2
# colors
green="\e[1;32m"
yellow="\e[1;33m"
red="\e[1;31m"
blue="\e[36;1m"
undim="\e[0m"
mapfile -t containers \
< <(docker ps -a --format='{{.Label "com.docker.compose.project"}},{{.Names}},{{.Status}}' \
| sort -r -k3 -t "," \
| awk -F '[ ,]' -v OFS=',' '{ print $1,$2,$3 }')
declare -A upper_containers # To later concat with the ones I want to display first at the top
declare -A lower_containers
for i in "${!containers[@]}"; do
IFS="," read proj_name name status <<< ${containers[i]}
if [[ -n $proj_name ]]; then # is docker-compose
color=$green;
if [[ "$status" != "Up" ]]; then
lower_containers[$name]="${name}:,${red}${status,,}${undim},";
color=$yellow;
status="partial";
fi
upper_containers[$proj_name]="${blue}${proj_name}:,${color}${status,,}${undim},"
else # not docker-compose
if [[ "$status" != "Up" ]]; then
lower_containers[$name]="${name}:,${red}${status,,}${undim},";
else
upper_containers[$name]="${name}:,${green}${status,,}${undim},";
fi
fi
done;
i=1
out=""
containers=("${upper_containers[@]}" "${lower_containers[@]}")
for el in "${containers[@]}"; do
out+=$el
if [ $(($i % $COLUMNS)) -eq 0 ]; then
out+="\n"
fi
i=$(($i+1))
done;
out+="\n"
printf "\ndocker status:\n"
printf "$out" | column -ts $',' | sed -e 's/^/ /'
printf "\n\n"