Files
myos/skills/myos/references/conventions.md
T
Yann Autissier f541ca418b let a stack compute its settings without make
A stack can now ship <name>.env and <name>.sh next to its compose files. The
hook is sourced with the tag helpers available, which is what the computing
.mk files of the catalogue were using make for: 29 of its 44 .mk files only
exist to build variables like the fabio tags.

Converting stack/host/fabio.mk by hand gives byte-identical output for the
route tag, and drops a trailing comma the make version left in the listener
list.

Also: APP_HOST and APP_URI are computed (the tag helpers build on them),
--color controls the escape codes rather than always emitting them, and
make test-portability runs the CLI under busybox ash and dash.
2026-09-03 20:22:52 +02:00

5.1 KiB

Conventions

A stack is a directory of compose files

For stack <name> in environment <env>, myos loads whichever of these exist, in this order. A later file overrides the ones before it.

<name>.yml                 the stack
<name>.<env>.yml           this environment only
<env>/<name>.yml           same, when the stack keeps a directory per environment
<name>.<suffix>.yml        an optional overlay, see below
<name>.<suffix>.<env>.yml
<name>.<version>.yml       when the reference is <name>:<version>

docker-compose.yml is read under the same rules, so a stack can keep an upstream docker-compose.yml untouched and add its own <name>.yml on top.

Then myos appends its own share/compose/networks.yml, and the volumes.<suffix>.<env>.yml of the enabled suffixes.

Overlay suffixes

Every COMPOSE_FILE_<X> variable that is not false enables the suffix <x>.

variable default loads
COMPOSE_FILE_APP true <name>.app.yml
COMPOSE_FILE_LABELS true <name>.labels.yml, the registrator labels
COMPOSE_FILE_NETWORKS true <name>.networks.yml
COMPOSE_FILE_SSH true <name>.ssh.yml
COMPOSE_FILE_VOLUMES true <name>.volumes.yml
COMPOSE_FILE_WWW, _DNS, _HOME, _LOG, _BACKUP false the matching overlay, and the framework bind mount

A value that is neither true nor false also enables <suffix>.<value>: COMPOSE_FILE_WWW=nginx loads <name>.www.yml and <name>.www.nginx.yml.

Project names

scope project why
host/* $HOSTNAME a singleton of the machine: one consul, one fabio on 80/443
User/* the user identity derived from the mail address one per user
cluster/* the stack name one namespace per swarm
anything else <user>-<env>-<app> one per user, environment and app

MYOS_PROJECT_FORMAT=user-app-env restores the older order. Any deployment created before the rename must set it, in its .env or in /etc/conf.d/myos; otherwise the containers and volumes of the old project are orphaned and the stack comes back up empty.

Networks

network name scope
default _<project> the project. The leading underscore keeps it first alphabetically, so it is the first interface attached and service names never resolve across stacks.
private <user>-<env> external, shared between the stacks of one user and environment
public <hostname> external, where the load balancer reaches the services

myos up creates the external ones when they are missing.

Routing: registrator, consul, fabio

A service is published by labels, which registrator copies into consul, and on which fabio routes:

labels:
  - SERVICE_8000_NAME=${COMPOSE_SERVICE_NAME}-kong-8000
  - SERVICE_8000_TAGS=${SUPABASE_KONG_SERVICE_8000_TAGS:-urlprefix-supabase.localhost/*}
  - SERVICE_8000_CHECK_TCP=true
  - SERVICE_8001_IGNORE=true

Registrator only sees ports that are exposed, and consul only routes a service whose check passes.

Tag variables follow <STACK>_SERVICE_<port>_<KEY>, with PATH, OPTS, URIS, NAME, and the fabio options allow, auth, deny, prepend, proto, register, strip:

HOST_NGINX_SERVICE_443_PROTO='https tlsskipverify=true'
DUNITER_V2S_SERVICE_9944_STRIP=/ws

Configuration

Layers, the last one wins:

defaults < /etc/conf.d/myos, /etc/default/myos < ~/.config/myos/config
        < <workdir>/.env < <workdir>/.env.<env> < environment < VAR=value on the command line

All of them are dotenv: KEY=value, # comments, optional quotes. They are parsed, never sourced, so a value may contain a # or a $(...) without breaking anything or being executed. The make engine included .env as a makefile, where both broke.

Per-stack settings

A stack keeps its own settings next to its compose files:

file for
<name>.env plain values: versions, defaults
<name>.env.<env> the same, for one environment
<name>.sh values that have to be computed
<name>.mk the legacy make snippet; still read for its groups

A .sh hook is sourced with the myos helpers available, and sets variables directly. This is what lets a stack work on a machine that has no make:

# stack/host/fabio.sh
HOST_FABIO_VERSION=${HOST_FABIO_VERSION:-1.6.3}
HOST_FABIO_SERVICE_9998_NAME=${HOST_FABIO_SERVICE_9998_NAME:-fabio}
HOST_FABIO_SERVICE_9998_AUTH=${HOST_FABIO_SERVICE_9998_AUTH:-default}
HOST_FABIO_SERVICE_9998_TAGS=${HOST_FABIO_SERVICE_9998_TAGS:-$(myos_tagprefix HOST_FABIO 9998)}

Always write ${VAR:-default} so the environment and the .env still win. Helpers available in a hook: myos_tagprefix, myos_urlprefix, myos_uri, myos_url, myos_envprefix, myos_servicenvs, myos_var, myos_lower, myos_upper.

Groups

A group is a lowercase name whose value lists stacks. It can live in a .env, in the environment, in <path>/<group>.env, or in a legacy <group>.mk:

host=host/consul host/fabio host/registrator
testing=drone/drone drone/gc

Groups expand recursively. Only lowercase names are considered, so an environment variable can never be mistaken for a group.