Files
computer-playbook/docs/contributing/artefact/files/compose.yml.md
kevinveenbirkenbachandClaude Opus 5.5 d2b33a3b2a fix(compose): keep dynamic addresses off the stack's static IPs
compose/cache.shared.override.yml attaches every worktree stack's
infinito service to the primary's network (infinito-nexus-core_default,
172.30.0.0/24) without an ipv4_address. The default network declared
no ip_range, so Docker IPAM handed out the lowest free address and the
worktree stacks took 172.30.0.2, .3, .8, .9 and, whenever the primary
container was down, .10, the primary's INFINITO_IP4. The primary's
`make compose-up` then failed with "Address already in use", and with
it `make quality-high` on main.

The default network now declares ip_range: ${INFINITO_IP_RANGE}, the
upper half of INFINITO_SUBNET. Every static address of the stack (.1,
.4 to .6, .10, .53) sits in the lower half, so a container without a
static address can no longer take one.

INFINITO_IP_RANGE is derived from the final INFINITO_SUBNET after
custom.env is applied, because a worktree pins its subnet there and
`make dotenv-force` regenerates without it in the environment. Existing
worktrees therefore get their own slot's range without a new pin.

A lint checks that every static IP in default.env and every
172.30.${slot}.N pin in scripts/system/worktree/up.sh lies below the
pool.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 21:44:16 +02:00

8.0 KiB
Raw Permalink Blame History

compose.yml 🐳

This page documents the rules that govern the top-level compose.yml and the environment variables it consumes. For general documentation rules (links, writing, RFC 2119 keywords), see documentation.md. For CI debugging workflows that use these variables, see ci.md.

Purpose 🎯

The top-level compose.yml is scoped to local development and CI testing only. It MUST NOT be used to deploy or run a live Infinito.Nexus stack. Production deployments MUST go through the Ansible roles and their own rendered compose files under roles/<role>/templates/.

Within its scope, compose.yml MUST stay a thin orchestration surface for the infinito runner container and its CoreDNS sidecar. It MUST NOT host application roles, fixtures, or test harnesses.

Structure 📐

  • You MUST consume tunable runtime parameters via strict substitution ${VAR:?Run 'make dotenv' to generate the .env single source of truth}; the default lives in default.env. Inline ${VAR:-default} forms are forbidden and enforced by test_no_default_substitutions.py.
  • You MUST NOT hardcode values that differ between operators (paths, image tags, CPU or memory caps).
  • You SHOULD annotate non-obvious keys with a short inline comment that explains why they exist, not what they do.
  • You MUST document every new env var by adding the row below AND committing a one-line # ... comment above its key in default.env.

Environment Variables 📋

All variables consumed by compose.yml. The per-variable default + comment lives next to the key in default.env; the tables below stay scoped to "what role does this variable play in compose.yml" and stop duplicating the default.

Image and Runtime

Variable Purpose
INFINITO_IMAGE Image reference used by the infinito service. Composed at runtime by the env generator on GHA, empty locally so the build: block builds from source.
INFINITO_PULL_POLICY Compose pull_policy. Defaults to never for local builds, generator overrides to always on GHA.
INFINITO_CONTAINER Used directly as container_name. Derived from INFINITO_DISTRO by container.py.
NIX_CONFIG Build-arg forwarded to the Dockerfile for Nix configuration. Pass-through if set in the calling shell.

Resource Caps (OOM Reproduction)

These variables cap the infinito container so local runs can reproduce GitHub-hosted runner pressure. Each default is 0, which Docker interprets as "unlimited" and is identical to omitting the key. See ci.md for runner specs and reproduction profiles.

Variable Compose key Example override
INFINITO_MEM_LIMIT mem_limit 16g
INFINITO_MEMSWAP_LIMIT memswap_limit 16g
INFINITO_CPUS cpus 4

You SHOULD set INFINITO_MEMSWAP_LIMIT to the same value as INFINITO_MEM_LIMIT to disable swap inflation. Allowing swap masks OOM conditions that the real runner would hit.

Storage

Variable Purpose
INFINITO_DOCKER_VOLUME Named volume (or host path) backing the nested Docker directory. Generator overrides to /mnt/docker on GHA.
INFINITO_DOCKER_MOUNT Mount point inside the container for the nested Docker data.

Caches

For activation, coverage, and operations of the registry-cache, package-cache, and package-cache-frontend services, see cache.md.

The env-var contracts each service expects strictly via ${VAR:?…} (consumed in compose.yml and compose/cache.override.yml):

Variable Purpose
INFINITO_CACHE_REGISTRY_HOST_PATH Host path bind-mounted into registry-cache for blob/manifest persistence.
INFINITO_CACHE_REGISTRY_CA_HOST_PATH Host path holding the proxy MITM CA bundle. Mounted writable into registry-cache, read-only into infinito.
INFINITO_CACHE_REGISTRY_MAX_SIZE Maximum on-disk size. Computed by registry_cache_max_size.py as half the free disk at the cache path, floor 1g, fallback 2g.
INFINITO_CACHE_REGISTRY_PROXY_CONF Bind source for the systemd drop-in inside infinito. Set by the dev tooling to the real proxy.conf under the cache profile. Driver-injected; not produced by make dotenv.
INFINITO_CACHE_PACKAGE_HOST_PATH Host path bind-mounted at /nexus-data.
INFINITO_CACHE_PACKAGE_HEAP JVM heap (-Xms/-Xmx). Computed as half free RAM, capped 2g, floor 1g.
INFINITO_CACHE_PACKAGE_DIRECT_MEM MaxDirectMemorySize. Mirrors INFINITO_CACHE_PACKAGE_HEAP.
INFINITO_CACHE_PACKAGE_BLOBSTORE_MAX Soft quota for the default blobstore. Computed as half free disk at the cache path, floor 2g.
INFINITO_CACHE_PACKAGE_MAX_AGE_MIN Cache freshness window in minutes, applied to every Nexus proxy repo (contentMaxAge/metadataMaxAge/negative-cache TTL). Stays strictly below the 7-day Valid-Until window Debian / Ubuntu generate in their apt Release files, so apt-get update never aborts with "Release file ... is expired".
INFINITO_CACHE_PACKAGE_ADMIN_PASSWORD Target value for the rotated Nexus admin password. Default is a stable per-host hash.
INFINITO_CACHE_PACKAGE_PORT Host-side port mapped to Nexus REST/UI. Bound to ${INFINITO_BIND_IP} only.
INFINITO_CACHE_PACKAGE_PIP_CONF Bind source for /etc/pip.conf. Driver-injected by make compose-up under the cache profile.
INFINITO_CACHE_PACKAGE_NPMRC Bind source for /root/.npmrc. Driver-injected.
INFINITO_CACHE_PACKAGE_FRONTEND_CA_DIR Host directory for the frontend CA.
INFINITO_CACHE_PACKAGE_FRONTEND_CERTS_DIR Host directory for per-hostname leaf certs.
INFINITO_CACHE_PACKAGE_FRONTEND_IP Static IPv4 address for the frontend on the compose default network.
INFINITO_CACHE_PACKAGE_FRONTEND_CA_FILE Bind source for /opt/package-frontend-ca.crt inside the runner. Driver-injected.

Networking

Variable Purpose
INFINITO_DNS_IP Static IP assigned to the CoreDNS sidecar and used as the DNS server. Default lives in default.env.
INFINITO_IP4 Static IPv4 address assigned to the infinito container. Default in default.env.
INFINITO_DOMAIN Base domain exported into the container environment. Default in default.env.
INFINITO_BIND_IP Host address that all published ports bind to.
INFINITO_SUBNET IPAM subnet for the default bridge network.
INFINITO_IP_RANGE IPAM pool for containers that join the default bridge without a static address, such as worktree stacks on the primary's cache network. It is the upper half of INFINITO_SUBNET, derived after custom.env by ip_range.py; every static address stays below it.
INFINITO_GATEWAY IPAM gateway for the default bridge network.
INFINITO_OUTER_NETWORK_MTU MTU for the bridge network. Lower when the host network is tunneled.

Adding a Variable ➕

When you introduce a new env var in compose.yml, you MUST:

  1. Add the default + one-line # ... comment to default.env; defaults never live in compose.yml.
  2. Consume the variable strictly via ${VAR:?Run 'make dotenv' to generate the .env single source of truth}; bare ${VAR} is acceptable only when the value is optional (e.g. NIX_CONFIG).
  3. Add a row to the matching table above with its compose-side purpose.
  4. Cross-link the variable from the relevant workflow page when it exists only to drive a specific workflow (e.g. resource caps link to ci.md).