Migrating to docker-compose
When I first setup my Docker VM on my Proxmox machine I did it on Ubuntu Server 18.04 LTS with a desktop environment installed because I was still very new to using command line. A desktop environment to manage everything with just seemed easier at the time. I also just installed everything with 'docker run' commands and managed the images with Portainer. After completing a hardware overhaul and moving my Proxmox instance from 1 2U server to 3 Intel NUCs in a cluster I decided it was time to finally migrate all my various containers(minus NGINX) to 1 Docker VM. And since I'm much more comfortable working off a command line now compared to 2018 I could do this in the regular Ubuntu Server environment.
The Docker VM was upgraded to 20.04 TLS at some point without much issue so first attempt was to create a backup of the image in Proxmox and update it to 22.04 LTS...which did not go as planned. Trying different methods either caused the install to fail or when it did complete I ran into an error many encountered in upgrading to 22.04 LTS that involves a conflict between network-manager and netplan. 22.04 seems to default to netplan even if your install was using network-manager before the upgrade and while I WAS eventually able to address it(using DHCP in netplan but static addresses were still not working) I opted to just start on a fresh 22.04 image in a different one and migrate everything over for a fresh start.
What are the benefits of docker-compose?
While not necessary it makes deploying multiple images a lot easier and helps in managing apps that depend on others to run properly. Let's look at bookstack for example since it was initially one of the apps I was running. If I wanted to run it as a docker image according to the documentation on its Docker Hub page it would look like this in the terminal
docker run -d \
--name=bookstack \
-e PUID=1000 \
-e PGID=1000 \
-e TZ=Etc/UTC \
-e APP_URL=<yourbaseurl> \
-e DB_HOST=<yourdbhost> \
-e DB_PORT=<yourdbport> \
-e DB_USER=<yourdbuser> \
-e DB_PASS=<yourdbpass> \
-e DB_DATABASE=bookstackapp \
-p 6875:80 \
-v /path/to/data:/config \
--restart unless-stopped \
lscr.io/linuxserver/bookstack:latest
This will pull the image for the first run and sets up access to a database, but this is a command that will be hard to reference later unless you copy it somewhere else or have easy access to the terminal history of this server. Also this assumes you have the database access already and doesn't automatically check to make sure the database is up before starting the image in the future to avoid errors. Let's compare this to the suggested docker-compose yaml file excerpt from the same documentation
---
version: "2"
services:
bookstack:
image: lscr.io/linuxserver/bookstack
container_name: bookstack
environment:
- PUID=1000
- PGID=1000
- APP_URL=https://bookstack.example.com
- DB_HOST=bookstack_db
- DB_PORT=3306
- DB_USER=bookstack
- DB_PASS=<yourdbpass>
- DB_DATABASE=bookstackapp
volumes:
- ./bookstack_app_data:/config
ports:
- 6875:80
restart: unless-stopped
depends_on:
- bookstack_db
bookstack_db:
image: lscr.io/linuxserver/mariadb
container_name: bookstack_db
environment:
- PUID=1000
- PGID=1000
- MYSQL_ROOT_PASSWORD=<yourdbpass>
- TZ=Europe/London
- MYSQL_DATABASE=bookstackapp
- MYSQL_USER=bookstack
- MYSQL_PASSWORD=<yourdbpass>
volumes:
- ./bookstack_db_data:/config
restart: unless-stopped
In this proposed docker-compose file that contains nothing else we see some similarities to the docker run command they provide but notice 2 things immediately.
- This is easier to read in the yaml file compared to the docker run command. Since the docker-compose.yaml file will exist on the filesystem as long as you don't remove it, being able to see where a mistake was possibly made when deploying it is much easier to parse in this format or reference in the future if you want to add additional services to this docker-compose file.
- The depends_on key in the file allows you to reference another container. If you don't have an external database and are going to be hosting 1 in a container specifically for bookstack you can include this command and it will make sure to wait for this container to start before starting the bookstack container.
You can have multiple services in a docker-compose.yaml file too. Mine currently has this Ghost blog(and a mysql database it depends on), Gitea and Bookstack(plus a mariadb database it depends on). As long as there isn't any port conflicts it shouldn't cause any issues. After creating the docker-compose.yaml file running the following command in the directory pulled images and started everything
docker-compose up
If I want to have the containers running in the background to free up the terminal can use this instead(preferred for me)
docker-compose up -d
Its the same as the --detach option. If I want to bring all the images down I can run the following
docker-compose down
Do note that if you don't specify any volumes on the filesystem in the docker-compose file, doing this means you lose any data tied to that container. The bookstack + bookstack database specified above have mapped volumes so this is avoided. And updating images is as easy as either running
docker-compose pull
to update everything or if you wish to only update specific images(maybe you want to keep databases on specific versions) you can specify what image to pull by referencing the container name in the docker-compose.yaml file as seen below
docker-compose pull bookstack
This will only pull and update the bookstack service using the image reference in the compose file. You can find references to these commands and other docker-compose commands at the official docker documentation here.
One final thing to note is that all these commands have to be run in the same directory the docker-compose.yaml file is located. One way I approached this is to just have my default directory when I log into this server be the location where the docker-compose file is located. You can achieve this by running the following command to append a line to your bashrc file
echo "cd /location/of/docker-compose" >> ~/.bashrc
This automatically puts me in the directory of the docker-compose.yaml file when I log in to save some time. And incase I ever want to use a different docker-compose file for testing in another directory I could edit this to change it to that directory, this way my permanent containers don't get effected by any commands I might be running for managing temporary container deployments.
Using docker-compose has allowed me to neatly consolidate 2 servers running desktop environments down to 1 barebones Ubuntu server for most of my permanent containers, using less resources and making it much easier to manage via CLI which I'm more comfortable doing now than I was when I first started deploying these in 2018.