Andrew B
Andrew's Blog

Andrew's Blog

Useful Scripts for managing multiple Docker containers on a single host

Andrew B's photo
Andrew B
·Aug 4, 2022·

4 min read

Table of contents

  • Brief overview of Docker Setup
  • Docker service folder
  • Top level scripts

It can be quite tricky to manage multiple services on a single Docker host and may involve a lot of manual intervention for troubleshooting, restarting services and updating images to the latest versions

I've built up a list of scripts over time that I've been using for both Linux and Windows hosts in order to manage servers in both my personal and work experience and will be sharing them below to try to help others

Brief overview of Docker Setup

My current setup has Docker running on a single host (either Windows or Linux depending on requirements). Inside this host I have a single folder that contains all of the scripts and configuration required for services and is version controlled through GIT to enable easy rollbacks

Looking at the top level, each service inside of this folder has it's own folder that is named the same as the docker service name (i.e. plex or coredns) as well as a "template" folder that can be copied for new services (more on this below)

image.png

Docker service folder

Inside each of these folders are a few files that are copied with the template:

compose

This file is used to rebuild and start the service located in this folder

docker stop $(docker ps -aq --filter "label=$(basename "$PWD")")
docker rm $(docker ps -aq --filter "label=$(basename "$PWD")")

docker-compose up --build -d

It will search for any running containers that have the label with the same name as the folder ($PWD), stop and remove running instances and then rebuild with the latest from the docker-compose file

I have used this method as sometimes there are cases where I will need to change some data that is not located in the docker-compose.yml file and this will not trigger a full rebuild of the container (uses the cached version). Examples include changing a configuration file in a copied over data folder

debug

This is used to start an interactive shell session of the current folder's Docker service in order to troubleshoot Bash

docker exec -it $(docker ps --filter "name=$(basename "$PWD")" -lq) /bin/bash

Windows

docker ps -aq --filter  | % { docker exec -it $_ }

There are some cases where you will need to replace the "/bin/bash" with "/bin/sh" at the end of the script depending on the shell environment used by the container

stop

This will completely stop the current folder's Docker service from running and is also used at the start of the compose script

docker stop $(docker ps -aq --filter "label=$(basename "$PWD")")
docker rm $(docker ps -aq --filter "label=$(basename "$PWD")")

docker-compose.yml

This is an example template that has some information pre-filled with some of the data that i will normally set (i.e. labels and networks)

More information of the data used in here can be found on my page about Traefik and certificates

version: '3.3'
services:
  service-name:
    image: image/image
    container_name: template
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Australia/Perth
    labels:
      - template
      - "traefik.enable=true"
      - "traefik.http.routers.template.rule=Host(`template.host.net`)"
      - "traefik.http.routers.template.entrypoints=websecure"
      - "traefik.http.routers.template.tls.certresolver=myresolver"
      - "traefik.http.services.template.loadbalancer.server.port=8080"
      - "traefik.frontend.rule=Host:traefik.host.net"
      - "traefik.http.routers.template.middlewares=middlewares-rate-limit@file,middlewares-ipwhilelist@file" 
    volumes:
      - /dev/null:/path/on/container
    ports:
      - "8085:80"
    restart: unless-stopped
    networks:
      web:

networks:
  web:
    external: true

Top level scripts

These scripts are used to perform bulk changes to the Docker containers and contains the following files:

restart_all

This script will stop all running Docker services, and then start the containers up in a specific order. It can be achieved by adding all of the services needed into a single Docker-compose file but this is useful to separate components out

# Stop all running containers
docker rm -f $(docker ps -a -q)

# List of services to start in order
declare -a arr=("coredns" "pihole" "traefik" "firefly" "plex" "tandoor" "wiki" "nessus" "deluge" "overseerr" "prowlarr" "radarr" "sonarr" "dozzle" "prometheus" "grafana")

# Loop through array
for i in "${arr[@]}"
do
    echo "--------------------------------------------------------------------------------------------------------------------------"
    echo "Starting $i"
    echo "--------------------------------------------------------------------------------------------------------------------------"
    cd $i
    ./compose.sh
    cd ..
done

# List running containers
docker ps

It uses a shell array (arr) to store the list of the folders to cd into and then run the "compose" script described above for each of them. It is also useful for starting services up in a specific order from the array but currently doesn't detect dependencies if required (e.g. pihole needs to have coredns running as it uses it as a forwarder)

stop_all

This is a small script that will stop all running Docker services:

docker rm -f $(docker ps -a -q)

update_images

This script will fetch the latest image from Docker for each of the service names provided in the array (needs to have them manually added for those that aren't pinned to a specific version)

# List of images to pull for update
declare -a arr=("ghcr.io/linuxserver/overseerr" "coredns/coredns:latest" "ghcr.io/linuxserver/deluge" "fireflyiii/core:latest" "yobasystems/alpine-mariadb:latest" "tenableofficial/nessus" "linuxserver/plex" "ghcr.io/linuxserver/prowlarr:develop" "ghcr.io/linuxserver/radarr" "ghcr.io/linuxserver/sonarr" "vabene1111/recipes" "nginx:mainline-alpine" "requarks/wiki:latest" "jc5x/firefly-iii-base-image" "amir20/dozzle" "pihole/pihole")

# Loop through array
for i in "${arr[@]}"
do
    echo "--------------------------------------------------------------------------------------------------------------------------"
    echo "Updating image: $i"
    echo "--------------------------------------------------------------------------------------------------------------------------"
    docker image pull $i
done

It will loop through each item in the array and pull the Docker image. It is useful to run the "restart_all" script after this one in order to apply the new image

 
Share this