Update tech_docs/docker_compose_guide.md

This commit is contained in:
2025-08-06 05:50:46 -05:00
parent 62125ab35a
commit b822bba5d1

View File

@@ -32,7 +32,7 @@ serendipity/
### 2. The Royal Charter (`kingdom.yml`) ### 2. The Royal Charter (`kingdom.yml`)
```yaml
kingdom: kingdom:
# determinism knobs # determinism knobs
seed: 42 seed: 42
@@ -53,7 +53,7 @@ kingdom:
to: stdout to: stdout
- format: yaml - format: yaml
to: out/kingdom_rendered.yaml to: out/kingdom_rendered.yaml
```
Nothing outside this file ever changes the deterministic output except the **seed**. Nothing outside this file ever changes the deterministic output except the **seed**.
@@ -63,12 +63,12 @@ Nothing outside this file ever changes the deterministic output except the **see
Every object **MUST** be valid YAML and **MAY** include Jinja2 expressions inside **quoted** scalars only. Every object **MUST** be valid YAML and **MAY** include Jinja2 expressions inside **quoted** scalars only.
```yaml
# objects/unicorn.yaml # objects/unicorn.yaml
id: unicorn id: unicorn
color: "{{ rng.choice(['silver','iridescent']) }}" color: "{{ rng.choice(['silver','iridescent']) }}"
blessing: "{{ magic.uuid4() }}" blessing: "{{ magic.uuid4() }}"
```
Important: Important:
- Expressions are **strings** → safe for YAML parsers. - Expressions are **strings** → safe for YAML parsers.
@@ -78,7 +78,7 @@ Important:
### 4. The Single Rulebook (`rules/resolve.j2`) ### 4. The Single Rulebook (`rules/resolve.j2`)
```jinja2
{#- 1. Bootstrap deterministic engines -#} {#- 1. Bootstrap deterministic engines -#}
{% set rng = load_rng(kingdom.rng) %} {% set rng = load_rng(kingdom.rng) %}
{% set magic = load_magic(kingdom.magic) %} {% set magic = load_magic(kingdom.magic) %}
@@ -93,7 +93,7 @@ Important:
{#- 3. Emit final deterministic YAML -#} {#- 3. Emit final deterministic YAML -#}
{{ court | to_yaml }} {{ court | to_yaml }}
```
Helper filters (`load_rng`, `load_magic`, `glob`, `read_file`, `render_str`) are registered once at startup; **they never change** and are **not serialisable**, so they cannot leak into objects. Helper filters (`load_rng`, `load_magic`, `glob`, `read_file`, `render_str`) are registered once at startup; **they never change** and are **not serialisable**, so they cannot leak into objects.
@@ -101,7 +101,7 @@ Helper filters (`load_rng`, `load_magic`, `glob`, `read_file`, `render_str`) are
### 5. Bootstrap Script (one-time, never edited) ### 5. Bootstrap Script (one-time, never edited)
```python
#!/usr/bin/env python3 #!/usr/bin/env python3
# bootstrap.py (kept outside kingdom/) # bootstrap.py (kept outside kingdom/)
import os, yaml, jinja2, glob, hashlib, random import os, yaml, jinja2, glob, hashlib, random
@@ -128,7 +128,7 @@ env.globals.update({
template = env.get_template('resolve.j2') template = env.get_template('resolve.j2')
print(env.from_string(template.render(kingdom=meta['kingdom'])).render()) print(env.from_string(template.render(kingdom=meta['kingdom'])).render())
```
Run once → deterministic stream of bytes. Run once → deterministic stream of bytes.
Commit the stream if you need reproducibility without Python. Commit the stream if you need reproducibility without Python.
@@ -169,11 +169,11 @@ Commit the stream if you need reproducibility without Python.
### 9. Single-Command Invocation (CI / Makefile) ### 9. Single-Command Invocation (CI / Makefile)
```makefile
render: render:
@python bootstrap.py > kingdom_rendered.yaml @python bootstrap.py > kingdom_rendered.yaml
@echo "SHA256: $$(sha256sum kingdom_rendered.yaml)" @echo "SHA256: $$(sha256sum kingdom_rendered.yaml)"
```
--- ---
@@ -187,7 +187,7 @@ render:
Here is a **drop-in Jinja2 template skeleton** that turns the entire service stanza into variables you can override at render-time (`docker compose -f <(jinja2 compose.yml.j2 env.yml)` or `docker compose config`). Here is a **drop-in Jinja2 template skeleton** that turns the entire service stanza into variables you can override at render-time (`docker compose -f <(jinja2 compose.yml.j2 env.yml)` or `docker compose config`).
You only need to set the variables you care about; everything else falls back to safe blanks or defaults. You only need to set the variables you care about; everything else falls back to safe blanks or defaults.
```jinja2
# compose.yml.j2 # compose.yml.j2
services: services:
{{ service_name | default("app") }}: {{ service_name | default("app") }}:
@@ -316,11 +316,11 @@ services:
{{ k }}: {{ v }} {{ k }}: {{ v }}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
```
Usage example with a tiny `env.yml`: Usage example with a tiny `env.yml`:
```yaml
# env.yml # env.yml
service_name: api service_name: api
image: mycorp/api:1.4.2 image: mycorp/api:1.4.2
@@ -334,13 +334,13 @@ volumes:
depends_on: depends_on:
- db - db
restart: always restart: always
```
Render and validate: Render and validate:
```bash
jinja2 compose.yml.j2 env.yml | docker compose -f - config # dry-run jinja2 compose.yml.j2 env.yml | docker compose -f - config # dry-run
```
All other knobs (secrets, configs, devices, ulimits, etc.) can be added the same way—only when you need them. All other knobs (secrets, configs, devices, ulimits, etc.) can be added the same way—only when you need them.