149 lines
5.8 KiB
Markdown
149 lines
5.8 KiB
Markdown
# 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. Container Registries, Mirrors & Image Distribution
|
|
|
|
Our infrastructure uses a tiered registry architecture to balance local caching,
|
|
private custom image hosting, and universal build portability:
|
|
|
|
### 3.1 Registry Tier Classification
|
|
|
|
1. **Primary Custom Image Registry (`${REG}` $\rightarrow$ `quay.atyg.org`):**
|
|
- Hosts all internally built, project-specific custom images
|
|
(`${REG}/library/<image>:<tag>`).
|
|
- Examples: `${REG}/library/auth-yes-api:latest`,
|
|
`${REG}/library/spire-server:latest`, `${REG}/library/spire-agent:latest`.
|
|
- Retention policy is set for **indefinite storage** (auto-pruning disabled).
|
|
2. **Docker Hub Pull-Through Cache (`acr.atyg.org`):**
|
|
- Proxies and indefinitely caches upstream Docker Hub images on the local
|
|
network.
|
|
- Examples: `acr.atyg.org/library/postgres:18-alpine`,
|
|
`acr.atyg.org/valkey/valkey:8-alpine`, `acr.atyg.org/library/alpine:3.20`.
|
|
3. **GHCR Pull-Through Mirror (`${GHCR_REG}` $\rightarrow$ `ghcr.atyg.org`):**
|
|
- Proxies and caches GitHub Container Registry packages.
|
|
- Examples: `${GHCR_REG}/spiffe/spire-server:1.9.3`,
|
|
`${GHCR_REG}/spiffe/spire-agent:1.9.3`.
|
|
|
|
### 3.2 Universal Dockerfile Portability (Jules & External CI)
|
|
|
|
- **Public Upstream Defaults:** Dockerfiles must declare public upstream
|
|
registries by default so external agents (like Jules) and cloud CI runners can
|
|
build without private `.atyg.org` DNS:
|
|
```dockerfile
|
|
ARG SPIRE_UPSTREAM=ghcr.io/spiffe/spire-server:1.9.3
|
|
ARG BASE_IMAGE=alpine:3.20
|
|
|
|
FROM ${SPIRE_UPSTREAM} AS upstream
|
|
FROM ${BASE_IMAGE}
|
|
```
|
|
- **Local Build Acceleration:** Local builds and CLI scripts (`infra/setup.ts`)
|
|
can optionally pass `--build-arg` to pull through local mirrors
|
|
(`ghcr.atyg.org`, `acr.atyg.org`).
|
|
- **Push Destination:** Custom built images are tagged and pushed to the local
|
|
authority `${REG}/library/...` (`quay.atyg.org`).
|
|
|
|
### 3.3 Compose Variable Cleanliness
|
|
|
|
- **No Inline Defaults:** Always write clean variable references in Compose
|
|
files (`image: ${REG}/library/spire-server:latest`,
|
|
`image: ${GHCR_REG}/spiffe/spire-server:1.9.3`).
|
|
- **Centralized Values:** Default registry variables belong strictly in `.env`
|
|
and `infra/setup.ts`.
|
|
|
|
---
|
|
|
|
## 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.
|