(skip to content)

Executable compose files

Executable compose files

Systemd polyglot

A while ago I came up with an interesting polyglot file; a systemd unit definition file which is also an executable Node.js script and can execute itself:

#!/usr/bin/env node
;console.log(process.argv[2]==="+"?"foo":"bar")
;process.exit(0);
;/*
[Unit]
Description="Polyglot"
[Service]
Type=oneshot
ExecStart=/usr/bin/env node /etc/systemd/system/polyglot.service +
[Install]
WantedBy="default.target"
;*/

It can be placed at /etc/systemd/system/polyglot.service and if executed as a script will print bar. If started as a systemd unit, it will print foo:

Starting "Polyglot"...
foo
polyglot.service: Deactivated successfully.
Finished "Polyglot".

The executable bit doesn’t have to be set for it to be executed like that. While kind of cool, I couldn’t come up with a real use case for this. Also, in my day job, I lately tend to edit and use docker compose files more often than systemd unit files.

Compose polyglot

So I asked myself, can we make docker compose files executable too? Well…, while also quite cursed, of course we can! Here a basic example:

#!/usr/bin/env bash
x-exec(){ :;}; x-exec : | #
  echo "foo" && exit 0

services:
  web:
    image: nginx

Make sure to keep the space in x-exec : on the second line so that bash doesn’t complain. Formatters tend to remove such things.

This file, when made executable, is simultaneously a valid bash script, a valid yaml file and a valid docker compose file. The reason why it works as a compose file is because of compose files’ extensions:

Extensions can be used to make your Compose file more efficient and easier to maintain.

Use the prefix x- as a top-level element to modularize configurations that you want to reuse. Compose ignores any fields that start with x-, this is the sole exception where Compose silently ignores unrecognized fields.

In order for this to be a bit nicer, I wanted the script to be located below the compose keys. I was able to do this with a heredoc:

#!/usr/bin/env bash
x-exec(){ :;}; x-exec : | #
  :; : <<'x-script: |'

services:
  web:
    image: nginx

x-script: |
  echo "hello world" && exit 0

The heredoc is just used as a way to comment out the yaml from the “bash perspective” without having to prepend lines with #. Of course, any arbitrary command can be executed in the script section. Combined with uv and cut, we can make it a python script:

#!/usr/bin/env bash
x-exec(){ :;}; x-exec : | #
  :; : <<'x-script: |'

services:
  web:
    image: nginx
    ports:
      - 127.0.0.1:8989:80

x-script: |
  cut -c 3- <<'x-eof:' | uv run -
  # /// script
  # dependencies = ["docker-composer"]
  # ///
  from docker_composer import DockerCompose

  base = DockerCompose(file="compose.yml")
  base.up().call()

x-eof:

The above script brings up itself as a compose project when executed as ./compose.yml.

Yes, this is weird and totally cursed.