Docker Compose

gw plays very well with docker, especially docker compose. You can use gw to build the Docker image and then stop and recreate the container. It can be done with docker, but it is recommended to do it with docker compose as it will handle the whole lifecycle of build, stop and restart.

Project configuration #

Make sure to have a docker-compose.yaml file in the root directory. It can start existing containers or build images from the local files.

Note: if you build docker images locally, you save the storage and transfer costs of the docker image repository.

Since it is also a file in your git repository, it basically doubles as an infrastructure-as-a-code. You can modify the docker compose setup (e.g. add another dependency, for example cache), commit and have the changes reflected in your infrastructure immediately.

gw configuration #

Just simply point to your repository and run docker compose up. It will restart your containers and apply any new changes.

gw /path/to/repo -s 'docker compose up -d'

If you are building your containers, add --build:

gw /path/to/repo -s 'docker compose up -d --build'

Systemd unit #

One neat way to use docker-compose is to use it together with systemd units. They play very nicely together because docker-compose is hard to be containerized, but this way it can run in the background on the host and update automatically.

To create a systemd unit, you can use the systemd usage guide, but add this to the unit file (e.g. /etc/systemd/system/gw.service):

# /etc/systemd/system/gw.service
[Unit]
Description = Autorestartable docker-compose for application
After = NetworkManager-wait-online.service network.target docker.service
PartOf = docker.service

[Service]
Type = simple
ExecStart = /usr/local/bin/gw /path/to/repo -v -p '/usr/bin/docker compose -f /path/to/repo/docker-compose.yml up --build'

[Install]
WantedBy = default.target

This will rebuild your containers in the directory, every time there is a change.

Template systemd unit #

If you have many applications that you want to autorestart with docker-compose, it might make sense to use a template systemd unit. These are units that have a pattern (%I) in their unit files, which you can call multiple times with multiple configurations.

For example if you have a /path/to/repos/app1 and /path/to/repos/app2, you can create a generic systemd unit such as this (make sure that the filename ends with @):

# /etc/systemd/system/gw@.service
[Unit]
Description = Autorestartable docker-compose for %I
After = NetworkManager-wait-online.service network.target docker.service
PartOf = docker.service

[Service]
Type = simple
WorkingDirectory = /path/to/repos/%I
ExecStart = /usr/local/bin/gw /path/to/repos/%I -vv -p '/usr/bin/docker compose -f /path/to/repos/%I/docker-compose.yml -p %I up --build'

[Install]
WantedBy = default.target

You can call it using the app name after a @, like gw@app1 and gw@app2, and the %I will be automatically replaced with app1 and app2. So in this case systemctl start gw@app1 will start a docker-compose in /path/to/repos/app1 using the /path/to/repos/app1/docker-compose.yml file with the project name app1.

You can extend these further by simply adding new directories and starting an automaticly deploying process with one line of code.