fix, feat, doc: massive build system refactorion, bug fixes and apex documentation (#19)

This commit is contained in:
deytenit authored and GitHub committed 2026-07-12 01:57:40 +03:00
1 parent e8b42c60c2
commit 91f5245823
165 files changed
+8598 -1205

No files matched your search

@@ -0,0 +1,101 @@
---
title: Add a service composition
description: "Wire a new project into a node: anchor IP, networks, tiers, and lint."
weight: 23
---
**Context:** a project joins a [node](/apex/glossary#node) as one directory under `compositions/` containing a hand-authored compose file. The framework's contract for that file is small: a static [anchor IP](/apex/glossary#anchor-ip) on the `direct` network, external network references by key, and tier-relative data paths.
{{% steps %}}
### Allocate the anchor address
Pick the next free address at `.20` or above in the node's /24 and record it in `compositions/ADDRESSING.md`. Addresses `.10`–`.19` are reserved for the [core composition](/apex/glossary#core-composition) (see [Concept: Fleet addressing scheme](/apex/concepts/addressing)).
### Author the compose file
```yaml {filename="compositions/<project>/docker-compose.yml"}
name: <project>
services:
<anchor>:
image: ...
container_name: <project>-<anchor>
user: "${APEX_UID?error}:${APEX_GID?error}"
group_add:
- "${APEX_SHARED_GID?error}"
volumes:
- ./@tier1/<anchor>/config:/config
- ./@tier2/<anchor>/data:/data
networks:
direct:
ipv4_address: 198.18.16.20
enclave: {}
labels:
- "traefik.enable=true"
- "traefik.http.routers.<project>.rule=Host(`...`)"
- "traefik.http.services.<project>.loadbalancer.server.port=8080"
# backup intent (resticontainer, discovered from restic.* labels)
- "restic.enable=true"
- "restic.backup.paths=/config"
restart: unless-stopped
<sidecar>:
image: ...
network_mode: "service:<anchor>"
networks:
direct:
external: true
enclave:
external: true
```
Conventions at work:
- **One anchor per project** holds the static `ipv4_address` on `direct`; sidecars share its network namespace via `network_mode: service:<anchor>`.
- **Networks are referenced by key** (`direct`, `enclave`, `socket`) with `external: true` — the core composition owns their definitions.
- **`enclave` membership plus traefik labels** publishes the service through the edge proxy; the proxy discovers it via the socket proxy, never via published ports.
- **Data paths are tier-relative** (`./@tierN/...`) and resolve through the symlinks created by `tiers/link`.
- **Backup is opt-in via `restic.*` labels.** `apex backup/run` drives [resticontainer](https://github.com/deytenit/resticontainer), which discovers what to snapshot from compose labels: `restic.enable=true` marks the service, `restic.backup.paths=<container-path>` names the mounts to back up (resticontainer resolves them to host paths). A service with no `restic.*` labels is simply not backed up. Back up config only where the data is regenerable.
- The `${APEX_UID...}` trio comes from the project `.env` maintained by `tiers/useradd`.
### Provision storage and identity
```bash
apex tiers/link <tier1> <tier2> <tier3>
apex tiers/useradd
apex tiers/chown
```
Re-running the trio is idempotent; it picks up the new project, creates its tier directories and `.env`, provisions its `noroot-<project>` user, and applies the ownership matrix.
### Lint
```bash
apex utils/lint-docker-compose
```
Validates every anchor IP (well-formed, unique, inside the node subnet) and runs the compose linter over the repository. The pre-commit hook enforces the same lint on staged compose files.
### Deploy
```bash
apex compose up
```
The core composition is already up; the new project starts in its alphabetical slot. Verify with `docker ps` and, if the service is proxied, through its route on the edge.
{{% /steps %}}
## Notes
- Service-internal secrets (for example a database password) live in the project's own `.env` in tier-1 storage, alongside the auto-injected UID block.
- Never define `direct`/`enclave`/`socket` inside a project file — a second definition would race the core composition for network ownership.
---
**See also:**
- [Concept: Compositions and the shared core](/apex/concepts/compositions)
- [Concept: Tiered storage and privilege isolation](/apex/concepts/tiered-storage)
- [Concept: Fleet addressing scheme](/apex/concepts/addressing)