The one with the situation

I like https://github.com/casey/just quite a lot. I use it to help manage, monitor, and administer things. Its heavenly integration with https://github.com/junegunn/fzf alone makes it worth a look. Go check it out :)

I tend to use bind-mounts rather than volumes when working with config files for containers. I keep said configs in a dedicated folder at the project root because I like short, relative, bind-mount paths in compose.ymls). The only "real" reason beyond that is to simplify my own mental modelling of containerised projects and their configs: the bind-mounted configs become the only source of configuration truth for a given container/project.

The one with the problem

My containers are generally managed by a user on the host, but this can - and very often does - cause problems with permissions; many images are hard-coded with a specific user or UID/GID combo in mind. Additionally, I use bind mounts, as mentioned. Bind-mounted files/directories are copied into the container when it starts, so they work very well for initialising containers with whatever files you want. Unfortunately, unlike with volumes, changes made to files on the host filesystem won't propagate unless or until the container is restarted. I obviously don't want to stop the container just to add a service to the proxy, or change some headers, so I need a way to force the issue.

The one with the solution

In essence, what needs to happen is this:

  1. Newly-edited config copied into a temp file inside the container (using docker cp).
  2. Temp config file validated (nginx -t -c [file]).
  3. Active config overwritten with the validated new one (from within the container itself).
  4. Nginx reloaded to use new config (nginx -s reload).
  5. Job's a good'un.

Here are the related sections from the project justfile:

set dotenv-filename := ".env"

@_source_env_file:
    . ./.env

NAME := env('CONTAINER_NAME')

[confirm('Update nginx main config?')]
@update-main-config: _source_env_file
    docker compose cp ./nginx.conf nginx_proxy:/tmp/nginx.conf
    cat ./scripts/update-main-config.sh | docker compose exec -iT {{NAME}} bash

Once the new config has been copied into the container (step 1), the line cat ./scripts/update-main-config.sh | docker compose exec -iT {{NAME}} bash does the rest of the work by running the update script from within the container itself.

update-main-config.sh:

#!/bin/sh
set -e 
nginx -t -c /tmp/nginx.conf && \
cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.old && \
cp /tmp/nginx.conf /etc/nginx/nginx.conf && \
nginx -s reload