The variable declared an intent and changed nothing: it fed the report and
never the binding, so it could say public while the file published on the
loopback, or the reverse. A declaration that cannot be wrong is better than one
that has to be kept in step.
The scope is now which binding the file asks for, read from the compose files
as written: ${MYOS_BIND_PUBLIC} is public, a hand-written address is pinned,
and a bare '- 80' or '9000:9000' is unbound, meaning docker opens it on every
address and nobody chose that. --strict fails on those.
Reading the resolved configuration instead would lose the distinction: every
form ends up as a plain address, and an unbound port looks exactly like a
deliberate public one.
What is left to configure per host is the address of each scope, which is the
part that belongs to the host rather than to the stack.
myos - Make Your Own Stack
myos runs docker compose stacks: on a server, in a project directory, for a user.
It is a thin layer over docker compose that resolves which compose files to load,
under which project name, with which environment variables.
The framework itself ships no stack. Ready-to-use stacks (consul, fabio, registrator, postgres, supabase, drone, …) live in a separate catalogue, myos-stacks.
Disclaimer
This is beta software, use it at your own risks.
Requirements
docker (with the docker compose plugin >= 2.24.4, or a docker-compose binary),
git and make.
Install
As a command
sudo git clone https://github.com/aya/myos /usr/local/lib/myos
sudo ln -s /usr/local/lib/myos/myos /usr/local/bin/myos
Optionally pin per-machine settings in /etc/conf.d/myos (or /etc/default/myos),
one VAR=value per line, no comments:
DOMAIN=example.org
ENV=master
myos runs from the current directory: it passes it as WORKDIR, so stacks and
.env are looked up there. A WORKDIR set in the config file wins over the current
directory, which pins a machine to its deployment directory.
As a make include
Add to your project Makefile:
MYOS ?= /usr/local/lib/myos
-include $(MYOS)/make/include.mk
Then make help lists the available targets.
Stack catalogue
myos looks for stacks in ./stack, ../stack, ~/.local/share/myos/stack,
/usr/local/share/myos/stack and /usr/share/myos/stack:
sudo git clone https://github.com/aya/myos-stacks /usr/local/share/myos
Usage
myos doctor # check the installation first
myos ls # what stacks are reachable
myos -n up host # print what it would run
myos up # the stack of the current directory
myos up STACK=host # a group of stacks, see stack/host/host.mk
myos up STACK=host/fabio # a single stack
myos up STACK=postgres:9.6 # a versioned stack
myos ps
myos logs
myos config # rendered compose file
myos down
myos shutdown # every stack: app, host and user
How a stack is resolved
A stack is a directory of compose files. For STACK=<name> in environment ENV,
myos loads, in order, whichever of these exist:
<name>.yml <name>.<ENV>.yml <ENV>/<name>.yml
<name>.<suffix>.yml <name>.<suffix>.<ENV>.yml <name>.<version>.yml
<suffix> comes from the COMPOSE_FILE_* variables that are not false
(app, labels, networks, ssh, volumes by default; add e.g.
COMPOSE_FILE_WWW=true to also load <name>.www.yml). The framework always
appends its own share/compose/networks.yml.
Project names and networks
| stack | compose project | meaning |
|---|---|---|
host/* |
$(HOSTNAME) |
one instance per machine: ports 80/443, consul, certbot |
User/* |
user identity | one instance per user |
| anything else | <user>-<app>-<env> |
many instances per machine |
Networks: default = _<project> (private to the project), private =
<user>-<env> and public = <hostname>, both external and created on demand.
Variables
| variable | effect |
|---|---|
DEBUG=true |
show executed commands |
DRYRUN=true |
print commands instead of running them |
VERBOSE=true |
show called functions |
ENV=<env> |
environment: selects .env.<env> and the <name>.<env>.yml overlays |
STACK=<refs> |
stacks to act on |
SERVICE=<name> |
target one compose service (exec, run, logs, scale) |
MYOS_PROJECT_FORMAT |
user-env-app (default) or user-app-env for deployments made before myos 2.0 |
myos env COMPOSE_FILE # show a variable
myos env COMPOSE_PROJECT_NAME
myos config <stack> # the rendered compose file
The make targets keep working: print-VAR, stack-<stack>-<command>,
<command>@<env>, and a project Makefile that includes make/include.mk.
SETUP_UFW=true enables the ufw/ufw-docker integration (myos setup-ufw).
With make
A project that would rather drive make can include the shim, which turns every myos command into a make target while leaving its own targets alone:
MYOS ?= /usr/local/lib/myos
include $(MYOS)/share/make/shim.mk
make up STACK=host then runs exactly what myos up host runs: the shim only
forwards. make is not needed otherwise, and the CLI never calls it.
For agents
skills/myos/SKILL.md is a skill describing how to drive myos, with
references on the conventions, the commands and the failure modes.
AGENTS.md covers changing myos itself.
Tests
make test # shellspec: unit + golden (a mocked docker, no daemon needed)
make test-golden # golden only
make golden-record # re-record the golden expectations
make lint # shellcheck
License
GPL-3.0, see LICENSE.