Docker Folder Setup on Homelab (with Scripts)

·

4 min read

Why Docker?

Docker is currently the best tool that I've found for the job of hosting linux containers. It creates a repeatable system that is easy to deploy.
These are the steps that the system uses to deploy the software:

  • A "Dockerfile"
    • Instructions to run on the system(such as installing packages or manipulating files)
    • Ports to expose
    • Variables and labels to apply to the container image

When you build a Dockerfile it will execute all of the steps and save them as "image layers" that are saved to the host server. If you need to change a single step of the Dockerfile then it will only need to rebuild the layers from that point onwards

There are a large number of tutorials and posts on the actual setting up of Docker or the images, but this post will go more into how I am managing multiple containers on a single host as part of a homelab

Requirements

I am using the following software on the host:

  • Docker
  • Docker-compose
  • Traefik (used as a web proxy for Docker services)
  • Git (tracks changes to the code base and Docker images)

Template folder

Inside of my main Docker folder I have a single folder for each service: Folder_Structure.png This is done because each service has a single docker-compose.yml file that would overwrite each other, and also for simplicity of separating files belonging to each image

When I am setting up a new service, I have a template folder that is copied from the main Docker folder with 4 files inside: Template_Folder_Structure.png

Compose.sh

By keeping each image in a folder that is named the same as the image name, you can use the $PWD command to fetch the image name based on the folder that you are currently in. This script will stop all instances of only the current image and then restart it

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

docker-compose up --build -d

Debug.sh

This script will allow you to enter the terminal of the image (based on the current folder) in order to troubleshoot

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

Stop.sh

This script will stop all instances of only the current image (avoiding disrupting other services)

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

Docker-compose.yml

This is the template for Docker images, and contains some labels that are used for the Traefik proxy. Most of these values will be replaced with what the image requires

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.domain`)"
      - "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.domain"
      - "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

Scripts

I also regularly use the following scripts to tear down, update and rebuild the Docker images as required:

Stop_all.sh

This script will stop all running containers

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

Update_images.sh

This script will pull the latest image for each of the images specified in the array (useful for containers that are pinned to the :latest tag)

# List of images to pull for update
declare -a arr=("coredns/coredns:latest" "ghcr.io/linuxserver/deluge" "linuxserver/plex" "pihole/pihole")

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

Restart_all.sh

This script will start up all required containers in a specific order: (useful for a new host or if you have stopped all containers) It will cd into each folder and run the compose.sh script

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

# List of services to start in order
declare -a arr=("coredns" "pihole" "traefik" "plex" "deluge")

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

# List containers
docker ps

Final Thoughts

The way that this is setup with all of the code backed up to a GIT repository makes it very easy to tear down this setup and rebuild on a new host (useful for data recovery). I have quite a few of the images dependent on each other (e.g. all services behind Traefik) so it's been much easier to manage multiple images this way