docs: annotate spec.yml config layering conventions
Compose file owns application defaults. spec.yml config: section is for deployment-specific overrides only (hostnames, IPs, secrets). Start scripts should not have their own defaults — they read what the compose file provides. Annotations added: - CLAUDE.md: config layering table and anti-pattern callout - spec.py: Spec class docstring with good/bad config examples - deployment_create.py: _write_config_file docstring Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>pull/740/head
parent
26dea540e9
commit
d090f2064e
27
CLAUDE.md
27
CLAUDE.md
|
|
@ -114,6 +114,33 @@ One Kind cluster per host by design. Never request or expect separate clusters.
|
|||
- `helpers.py`: `create_cluster()`, etcd cleanup, kind operations
|
||||
- `cluster_info.py`: K8s resource generation (Deployment, Service, Ingress)
|
||||
|
||||
## spec.yml: Config Layering
|
||||
|
||||
**The compose file is the single source of truth for application defaults.**
|
||||
|
||||
The configuration chain is: compose defaults → spec.yml overrides → container env.
|
||||
|
||||
| Layer | Owns | Example |
|
||||
|-------|------|---------|
|
||||
| **compose file** | All env vars and their defaults | `RPC_PORT: ${RPC_PORT:-8899}` |
|
||||
| **spec.yml config:** | Deployment-specific overrides only | `GOSSIP_HOST: 10.0.0.1` |
|
||||
| **start script** | Reads env vars, no defaults of its own | `${RPC_PORT}` |
|
||||
|
||||
**What goes in spec.yml config:**
|
||||
- Values unique to this deployment (hostnames, IPs, endpoints)
|
||||
- Secrets (`$generate:hex:32$`)
|
||||
- Overrides that differ from the compose default for this specific deployment
|
||||
|
||||
**What does NOT go in spec.yml config:**
|
||||
- Application defaults (ports, log levels, intervals, feature flags)
|
||||
- Values that would be the same across all deployments of this stack
|
||||
- Every env var the service accepts — that's the compose file's job
|
||||
|
||||
**Anti-pattern:** Dumping all env vars from the compose file into spec.yml.
|
||||
This creates three sources of truth (compose, spec, start script) that
|
||||
inevitably diverge. If someone changes the default in the compose file,
|
||||
spec.yml still has the old value and silently overrides it.
|
||||
|
||||
## Insights and Observations
|
||||
|
||||
### Design Principles
|
||||
|
|
|
|||
|
|
@ -639,6 +639,18 @@ def create_registry_secret(spec: Spec, deployment_name: str) -> Optional[str]:
|
|||
def _write_config_file(
|
||||
spec_file: Path, config_env_file: Path, deployment_name: Optional[str] = None
|
||||
):
|
||||
"""Write spec.yml config: entries to config.env.
|
||||
|
||||
The config: section in spec.yml should contain only deployment-specific
|
||||
overrides — values that differ between deployments (hostnames, endpoints,
|
||||
credentials, secrets via $generate:...$).
|
||||
|
||||
Application defaults (ports, log levels, feature flags, tuning params)
|
||||
belong in the compose file's environment section. The compose file is
|
||||
the single source of truth for what env vars a service accepts and
|
||||
their default values. spec.yml overrides those defaults for a specific
|
||||
deployment.
|
||||
"""
|
||||
spec_content = get_parsed_deployment_spec(spec_file)
|
||||
config_vars = spec_content.get("config", {}) or {}
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,35 @@ class Resources:
|
|||
|
||||
|
||||
class Spec:
|
||||
"""Deployment spec (spec.yml) — describes WHERE and HOW to deploy a stack.
|
||||
|
||||
A spec.yml contains deployment-specific infrastructure configuration:
|
||||
- stack: path to the stack definition
|
||||
- deploy-to: target platform (k8s-kind, k8s, compose)
|
||||
- network: ports, http-proxy, acme-email
|
||||
- resources: CPU/memory limits and reservations
|
||||
- security: privileged, capabilities, memlock
|
||||
- volumes: host path mappings for persistent data
|
||||
- configmaps: directories mounted as k8s ConfigMaps
|
||||
- config: deployment-specific env var OVERRIDES (see below)
|
||||
|
||||
The config: section is for deployment-specific values only — things
|
||||
that differ between deployments (hostnames, endpoints, secrets).
|
||||
Application defaults belong in the compose file's environment section,
|
||||
not here. If a value would be the same across all deployments of this
|
||||
stack, it belongs in the compose file, not in spec.yml.
|
||||
|
||||
Good config: entries (deployment-specific):
|
||||
VALIDATOR_ENTRYPOINT: my-cluster.example.com:8001
|
||||
PUBLIC_RPC_ADDRESS: my-node.example.com:8899
|
||||
GOSSIP_HOST: 10.0.0.1
|
||||
|
||||
Bad config: entries (these are application defaults):
|
||||
RPC_PORT: '8899' # same everywhere, belongs in compose
|
||||
LIMIT_LEDGER_SIZE: '50000000' # same everywhere, belongs in compose
|
||||
RUST_LOG: info # same everywhere, belongs in compose
|
||||
"""
|
||||
|
||||
obj: typing.Any
|
||||
file_path: Optional[Path]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue