Docker Folder Setup on Homelab (with Scripts)
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:
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:
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