Useful Scripts for managing multiple Docker containers on a single host
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)
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