auth-yes/COMPOSE_CONVENTIONS.md

4.2 KiB

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:
    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:
      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:
    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.