docs: add root COMPOSE_CONVENTIONS.md documenting compose, storage, and smart image standards
This commit is contained in:
parent
1f03cfc85f
commit
c07f2d1135
112
COMPOSE_CONVENTIONS.md
Normal file
112
COMPOSE_CONVENTIONS.md
Normal file
@ -0,0 +1,112 @@
|
||||
# Compose & Infrastructure Conventions
|
||||
|
||||
This document outlines the standard conventions and best practices for Docker
|
||||
and Podman Compose files, volume layouts, networking, and smart image packaging
|
||||
across our infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## 1. Storage & Host Volume Conventions
|
||||
|
||||
- **Root Project Directory:** All project state lives under
|
||||
`/volume1/docker/<stack-name>/` (e.g., `/volume1/docker/auth-yes/`,
|
||||
`/volume1/docker/spire/`).
|
||||
- **Standard Folder Naming:** Always use **`data`** for persistent application
|
||||
and database storage (never `db` or fragmented subfolders when a single root
|
||||
directory suffices).
|
||||
- **Local Bind Mount Syntax:** Always use the standard `driver_opts` local bind
|
||||
definition:
|
||||
```yaml
|
||||
volumes:
|
||||
<service>-data:
|
||||
driver: local
|
||||
driver_opts:
|
||||
type: none
|
||||
device: ${<STACK>_DATA_PATH}
|
||||
o: bind
|
||||
```
|
||||
- **Zero-Trust Inter-Process Sockets:**
|
||||
- Sockets shared across stacks (e.g., the SPIFFE Workload API `agent.sock`)
|
||||
MUST use a **named volume** (`spire-socket`).
|
||||
- Application containers mount this volume read-only (`:ro`), ensuring zero
|
||||
access to sensitive server CA keys, SQLite databases, or internal host
|
||||
state.
|
||||
- Client stacks declare `spire-socket` as `external: true`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Smart Container Images & Scripting Guidelines
|
||||
|
||||
- **Pragmatic Scripting in Compose:**
|
||||
- Short one-line commands, flags, or glue checks in `command:` or
|
||||
`entrypoint:` are fine.
|
||||
- Complex configuration generation, heredoc templating (`cat << 'EOF'`), and
|
||||
heavy lifecycle bootstrapping MUST NOT be embedded in Compose files.
|
||||
- **Smart Image Packaging & Repository Segregation:**
|
||||
- Self-seeding configuration and container lifecycle scripts belong in the
|
||||
container image.
|
||||
- All smart image logic, Dockerfiles, entrypoint scripts (`entrypoint.sh`),
|
||||
and configuration templates (`templates/`) must be cleanly segregated in
|
||||
dedicated directories in the codebase (e.g., `spire/`).
|
||||
- **Persistence & User Modification:**
|
||||
- Smart image entrypoints must follow the self-seeding pattern: check if the
|
||||
target configuration exists on the host mount.
|
||||
- If missing on first boot $\rightarrow$ atomically write the master template
|
||||
with guiding comments.
|
||||
- If already present $\rightarrow$ leave it untouched, preserving all user
|
||||
modifications across restarts and image updates.
|
||||
|
||||
---
|
||||
|
||||
## 3. Environment Variables & Clean YAML
|
||||
|
||||
- **No Inline Variable Fallbacks in Compose:**
|
||||
- Always write clean variable references: `${REG}`, `${GHCR_REG}`,
|
||||
`${SYSTEM_DOMAIN}`, `${SPIRE_DATA_PATH}`.
|
||||
- Do NOT use inline defaults (e.g., `${REG:-quay.atyg.org}`) inside the
|
||||
Compose file.
|
||||
- All default values belong strictly in `.env` or the interactive setup wizard
|
||||
(`infra/setup.ts`).
|
||||
- **Parameterize Registry Endpoints:**
|
||||
- Always prefix images with `${REG}/library/<image>:<tag>` or
|
||||
`${GHCR_REG}/<org>/<image>:<tag>`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Networking & Traefik Routing
|
||||
|
||||
- **Ingress Network:**
|
||||
- Web-facing containers connect to the pre-existing external network
|
||||
`traefik-net` (`external: true`).
|
||||
- **Network Routing Ambiguity Guard:**
|
||||
- Whenever a service connects to more than one network (e.g., internal
|
||||
bridge + `traefik-net`), always specify:
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.docker.network=traefik-net"
|
||||
```
|
||||
- **Internal Service Mesh:**
|
||||
- Backends, databases, Valkey, and internal daemons communicate over a project
|
||||
bridge network (e.g., `auth-internal-net`) without exposing ports directly
|
||||
to the host.
|
||||
- **Standard Websecure Labels:**
|
||||
```yaml
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik-net"
|
||||
- "traefik.http.routers.<app>.rule=Host(`${SYSTEM_DOMAIN}`)"
|
||||
- "traefik.http.routers.<app>.entrypoints=websecure"
|
||||
- "traefik.http.routers.<app>.tls=true"
|
||||
- "traefik.http.services.<app>.loadbalancer.server.port=<port>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Stack Independence & Decoupling
|
||||
|
||||
- **Standalone Infrastructure Stacks:**
|
||||
- General-purpose infrastructure components (e.g., SPIRE, Auth-Yes, Registry
|
||||
Caches) are standalone stacks with their own dedicated project directories
|
||||
(`/volume1/docker/spire`, `/volume1/docker/auth-yes`).
|
||||
- Never nest one stack's storage or lifecycle under another stack's directory
|
||||
structure.
|
||||
Loading…
x
Reference in New Issue
Block a user