There is no point in explaining in details how to install docker on your machine as the documentation would be deprecated the moment I finish this sentence.
However you can find how to install Docker on Ubuntu right here.
Now that you have installed Docker, you can install
docker-compose, a magnificent tool to configure your container with a simple text file !
The instructions can be found on docker’s official documentation.
Setting up the docker network
We want each of our docker container to have statics MAC and IP addresses. To do so, we use the
macvlan network mode.
To be able to use this mode, we first need to create the actual macvlan.
Let’s create a script called
host-macvlan-net.sh containing the command and its explanation :
Here is the script content:
#!/bin/zsh # This script creates the network host-macvlan-net used by the docker containers on this server # Every container has an address in 10.0.6.x # Note that it is impossible for the current server to ping these containers # However an external computer, or another docker container will be able to do so docker network create -d macvlan --subnet=10.0.0.0/20 --gateway=10.0.0.1 --ip-range=10.0.6.0/24 -o parent=eno1 host-macvlan-net # Use `docker network ls` to list the docker networks # Use `docker network inspect host-macvlan-net` to print the network details # User `docker network rm host-macvlan-net` to remove the network
The command is
docker network create -d macvlan --subnet=10.0.0.0/20 --gateway=10.0.0.1 --ip-range=10.0.6.0/24 -o parent=eno1 host-macvlan-net
-d macvlan: uses the network mode
--subnet=10.0.0.0/20: defines the subnet for the network
--gateway=10.0.0.1: defines the gateway for the network
--ip-range=10.0.6.0/24: defines the ip-range for the network (useful only if you don’t want to set static IPs in the docker-compose file)
-o parent=eno1: defines the parent interface (here it is my ethernet interface)
host-macvlan-net: the name I gave to the network.
We can now use
docker network ls to list the docker networks to verify that it was properly created.
Setting up an application
Since most applications will be set up the same way, I decided I would show in details how a simple one is done here to save some effort for the next ones.
In this sample application setup we install pyload.
I like to organize my applications in folders :
braincoke@nuc$ ls -1 Firefly Gitlab Jdownloader2 MayanEdms Monica OpenHab Organizr Portainer Pyload Rancher Torrent
Each folder here will contain :
- the docker-compose.yml file describing the application
- the directories that will be mounted in the container
Since I decided at the beginning of my project that each container will have its own reserved IP address, I will have to manually reserve the IP address in my router configuration panel.
If I decide that the IP address of the container should be
10.0.6.11, I know that the MAC address will be
With that information I can set my DHCP to reserve the IP
10.0.6.11 to the MAC address
Docker MAC addresses are predictable for static IPs. It will follow the format :
02:42:<IPv4 address in hexa>. For instance
10 in hexadecimal is
The docker-compose file
Once we have our folder (that was hard), we have to create our docker-compose.yml file.
cd Pyload touch docker-compose.yml
Our docker-compose will look like this :
version: '2.2' services: web: container_name: 'pyload' image: 'writl/pyload:latest' hostname: 'pyload' restart: unless-stopped environment: - PUID=1000 - PGID=1004 ports: - '80:80' - '443:443' volumes: - '../NAS/Downloads:/opt/pyload/Downloads' - './config:/opt/pyload/pyload-config' networks: host-macvlan-net: ipv4_address: 10.0.6.11 networks: host-macvlan-net: external: name: host-macvlan-net
As you can see from the line
image: 'writl/pyload:latest', we are downloading a container named
pyload with the tag
latest from user
writl from hub.docker.io.
Be very careful what container you download from hub.docker.io. It is as dangerous as downloading an unkwnown binary and executing it on your system. Take 10 minutes to overview the Dockerfile and see if there is something shady going on when the image is being built.
Here is a brief explanation of most of the configuration lines :
version: '2.2': the docker-compose file version used (expands or reduces the scope of options that can be used in the file)
services: we tell the file that we are about to describe containers
web: this is our first service, we call it “web”
container_name: the name we want our container to have. Used by the docker daemon.
hostname: the name our container will give itself on the network.
restart: define when to restart the container
environment: define environment variables
ports: define ports you want to export
volumes: define volume you want to mount from the system to the container
networks: tell the file we are about to define the network configuration for the container
host-macvlan-net: tell the file we are about to define the configuration for the network named
ipv4_address: the IP address we want our container to have
networks: describe the networks we will use for our container
When using the
volumes option, remember that the syntax is
To summarize all of this, our docker file is saying that :
- our container comes from the docker hub
- our container will be named
- the hostname of the container will also be
- its IP address will be
GUIDenvironment variables will be set to our predefined values in the container
- some volumes will be mounted as described in the file
Creating the directories
As we have seen from our docker-compose file, we have specified that :
- the directory
../NAS/Downloadsshould be mounted to
/opt/pyload/Downloadsinside the container
- the directory
./configshould be mounted to
/opt/pyload/pyload-configinside the container
We don’t have to create the directories inside the containers, docker will handle that (if they don’t already exist). However we do need to create them on our system. So be sure that
~/Pyload/config exist before starting the container !
You will often see a mount point
./config. This is a really usefull way to save the application config. Docker containers are stateless, when a container is removed, all the data it contained is destroyed… unless it was stored in a mounted directory !
By mounting the application config folder, you can save the state of your docker container and back it up regularly if you ever have a hardware issue with your homelab server.
You can also obtain data persistence by creating docker volumes which is the recommended way to mount volumes.
This creates a data blob that you can reuse in other containers and is managed by docker. It adds a layer of security since the container does not have direct access to the host filesystem.
Using a NAS
In my setup I mostly use a NAS to store :
- the backups of the configuration directories
- the container downloads
To do so I mount the NAS directory directly on the host.
For instance if I need to mount the NAS directory
//nas/Downloads to the host
~/mounted/Downloads/ I will need to :
- Create a user
downloaduserwith the correct rights on the NAS.
- Create a read-only file
- Add the following line to
//nas/Download /home/braincoke/mounted/Downloads cifs user,rw,credentials=/etc/nas-downloaduser-credentials,dir_mode=0777,file_mode=0777,iocharset=utf8,x-systemd.automount,vers=3.0 0 0
/etc/nas-downloaduser-credentials looks like this :
We change its permission to read-only to the user with
chmod 400 /etc/nas-downloaduser-credentials.
Since the credentials are not protected on the host, it is important to reduce its privileges on the NAS to the strict minimum.
Managing your containers
Once you have your
docker-compose.yml file, you can start the container with :
docker-compose up -d
-d starts the process as a daemon. Also, you must do it in the directory
containing the file or use the appropriate option to specify which docker-compose
file should be used.
If you ever need to see the container logs, just run :
docker-compose logs -f
To stop all the containers started by the file:
restart to restart the containers.
rm to delete the containers.
You can list the running containers with
docker ps and all the containers (including the stopped ones) wit
docker ps -a.
I always end up my configurations by creating a backup script and testing my backup.
If you have never tested your backup, consider you have none.
I store my backup scripts in
~/scripts/backup and the backup themselves in
~/backup which is a mounted volume from my NAS.
That way, my backup are stored on another device.
The purpose of the backup script is to back up the state of the container. To do so, I copy and tar every volume the container mounts.
This post exposed the basics of how I manage my docker-compose files, volumes, and backups. The next posts will explain briefly how to install specific applications and how to configure them.