Skip to content

Commit e769ade

Browse files
committed
Clean up service mesh docs and dead prototype
1 parent 3ff63fc commit e769ade

15 files changed

Lines changed: 182 additions & 1155 deletions

File tree

ARCHITECTURE.md

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,10 @@ remote peer over the QUIC link. With the 3-service example
9090
| 8300 | Consul server RPC (server-to-server, client-to-server)| TCP |
9191
| 8301 | Consul serf-LAN gossip | UDP + TCP |
9292

93-
The allowlist is intentionally minimal — mesh-conn knows **peers,
94-
not services**. Apps never dial peer VIPs; only Envoy and Consul-agent
95-
do, and both speak well-known platform ports.
93+
The runtime allowlist is intentionally minimal — mesh-conn knows
94+
**peers, not services**. Apps never dial peer VIPs; only Envoy and
95+
Consul-agent do. Consul uses fixed platform ports; Envoy sidecar ports
96+
are generated from `local.services`.
9697

9798
The allowlist is **platform-generated, not Go-const**: per-service
9899
Connect-sidecar ports come from `local.services` in `cluster.tf`, get
@@ -344,10 +345,10 @@ When a stream opens, the **first 3 bytes** carry a mesh-conn header:
344345
- `tag = 0x33`**streamTCP** — per-connection raw TCP byte stream.
345346

346347
The 16-bit `port` is the **receiver's local port to dial / write
347-
into**. The receiver validates it against the static allowlist
348-
(`{21000, 21001, 8300, 8301}`); anything else is rejected. There is
349-
no per-peer port-list lookup — ports are platform-level constants
350-
the same on every CVM.
348+
into**. The receiver validates it against `MESH_CONN_ALLOWLIST`; any
349+
port absent from that runtime allowlist is rejected. There is no
350+
per-peer port-list lookup — the platform emits the same allowlist on
351+
every CVM from `local.services` plus Consul's infrastructure ports.
351352

352353
UDP-over-stream uses an explicit 2-byte big-endian length prefix per
353354
datagram, since QUIC streams are byte-oriented (like yamux was) and
@@ -440,10 +441,10 @@ instead of a generic TCP connect check.
440441
webdemo, Patroni all think they're on a flat loopback talking to
441442
services by name. Anything that runs against Consul today (Vault,
442443
Nomad, Boundary, custom apps) drops in unchanged.
443-
- **Layer 1 + 2 are a single component (mesh-conn, ~600 LoC Go
444-
including the QUIC adapter) and have zero awareness of services.**
445-
mesh-conn forwards bytes between peer VIPs on a static infra-port
446-
allowlist; it does not know what Consul, Patroni, or Envoy are.
444+
- **Layer 1 + 2 are a single component (`mesh-conn`) and have zero
445+
awareness of services.**
446+
mesh-conn forwards bytes between peer VIPs on the runtime allowlist;
447+
it does not know what Consul, Patroni, or Envoy are.
447448
It would equally well move Postgres replication, Redis Sentinel,
448449
Kafka, etc. — and in fact this example uses it for both Consul
449450
cluster gossip and Patroni-replication-via-Envoy.

ATTESTATION.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ Look for successful node and service admission in worker sidecar logs:
158158

159159
```sh
160160
phala logs --cvm-id <worker-app-id> dstack-sidecar-1 -n 700 |
161-
rg 'admission-client-(node|demo|webdemo).*admission accepted'
161+
rg 'admission-client-.*admission accepted'
162162
```
163163

164164
Look for hard attestation failures:

FAILOVER.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,12 @@ back.
1717

1818
## Recipe
1919

20-
Set up env (cluster IDs from `RESUME.md`):
20+
These recipes require shell access inside the CVMs, so run them on a
21+
dev-image cluster. Production Phala OS images disable SSH; for those,
22+
use Phala logs/API evidence unless a separate debug-access path exists.
23+
24+
Set up env with the gateway domain and current worker IDs from your
25+
Terraform outputs or Phala instance list:
2126

2227
```bash
2328
GW=dstack-pha-prod5.phala.network

PUBLISHING.md

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,16 @@ tag (or, better, by digest) and verify provenance with
77
`gh attestation verify`.
88

99
`mesh-sidecar` is the consolidated platform-plumbing image — a single
10-
container that runs bootstrap-secrets, mesh-conn, consul, and (on
11-
workers) envoy. It's the heaviest by a wide margin because it
12-
inherits from envoyproxy/envoy and bundles three more binaries on top.
10+
container that runs bootstrap-secrets, mesh-conn, attestation
11+
admission helpers, consul, and (on workers) envoy. It's the heaviest
12+
by a wide margin because it inherits from envoyproxy/envoy and bundles
13+
several more binaries on top.
1314

1415
This doc covers the three paths you'll actually use:
1516

1617
1. **CI publish** (the steady-state)
1718
2. **Manual one-off publish** (dev iteration / breaking glass)
18-
3. **Hot-patch on a live cluster** (debugging without a redeploy)
19+
3. **Hot-patch on a dev cluster** (debugging without a redeploy)
1920

2021
## 1. CI publish — the steady-state
2122

@@ -25,9 +26,10 @@ change, and on PRs touching the same paths. Each run:
2526

2627
- Builds all four images via a matrix job. The `mesh-sidecar` build
2728
uses `consul-postgres-ha/` as its docker context (instead of
28-
`consul-postgres-ha/mesh-sidecar/`) so its Dockerfile can pull
29-
`bootstrap-secrets/` and `mesh-conn/` Go sources from sibling
30-
directories.
29+
`consul-postgres-ha/mesh-sidecar/`) so its Dockerfile can pull the
30+
embedded Go components from sibling directories:
31+
`bootstrap-secrets/`, `mesh-conn/`, `admission-broker/`, and
32+
`admission-client/`.
3133
- On `main`, pushes to `ghcr.io/dstack-tee/dstack-examples/consul-postgres-ha-<name>` with two tags: the long-form commit SHA (`sha-<40-hex>`) and `latest`.
3234
- Generates a GitHub Build Provenance attestation per image via
3335
`actions/attest-build-provenance@v2`. The attestation is signed by
@@ -78,9 +80,11 @@ docker build -t $TAG -f consul-postgres-ha/mesh-sidecar/Dockerfile consul-postgr
7880
docker push $TAG
7981
```
8082

81-
Then point the running cluster at it via `terraform.tfvars`'s
82-
`mesh_sidecar_image = ...` (and `terraform apply`), or hot-patch the
83-
running CVM (see §3). `ttl.sh` images expire 24h after push.
83+
Then use it in `terraform.tfvars` for a fresh dev cluster, or
84+
hot-patch one SSH-enabled dev CVM (see §3). Existing provider-0.3
85+
named-slot clusters cannot roll measured image changes in place until
86+
the revision-redeploy provider path lands. `ttl.sh` images expire 24h
87+
after push.
8488

8589
### b) Personal GHCR namespace (persistent, requires PAT)
8690

@@ -97,16 +101,13 @@ These manual builds do **not** carry a build-provenance attestation —
97101
that comes from CI's OIDC identity. For anything user-facing, run the
98102
real CI workflow.
99103

100-
## 3. Hot-patch on a live cluster — debugging without a redeploy
104+
## 3. Hot-patch on a dev cluster — debugging without a redeploy
101105

102-
Sometimes you need to swap a binary on a running CVM right now —
103-
faster than re-running `terraform apply` (which propagates env updates
104-
correctly as of provider `0.2.0-beta.3`, but still goes per-CVM and
105-
takes a minute), useful for testing a fix on one CVM before rolling it
106-
cluster-wide, and the only option on clusters running the older
107-
`0.2.0-beta.2` provider where in-place env updates silently no-op'd
108-
(Phala-Network/phala-cloud#246; fixed by
109-
Phala-Network/terraform-provider-phala#8).
106+
Sometimes you need to swap a binary on one running CVM right now to
107+
debug a fix before building a proper image. This is a dev-only path.
108+
It requires SSH, so it works only on dev OS images; production Phala
109+
OS images disable SSH. It also bypasses dstack compose measurements,
110+
so do not use it for attestation or production validation.
110111

111112
```bash
112113
GW=dstack-pha-prod5.phala.network
@@ -133,16 +134,18 @@ your tfstate.
133134

134135
## What to bump after a CI publish
135136

136-
When CI publishes a new `latest` and you want to roll it to a running
137-
cluster:
137+
When CI publishes new images:
138138

139139
1. Decide whether you're pinning to `:latest` (drifts) or to the
140140
`:sha-...` tag from the new run (recommended). Find the new SHA by
141141
inspecting the workflow run's output or `gh run view`.
142-
2. Edit `consul-postgres-ha/cluster-example/terraform.tfvars`
143-
to that pin.
144-
3. `terraform apply`. Per-CVM compose re-renders and the dstack agent
145-
recreates each service. (Or hot-patch per §3 if you want to verify
146-
on one CVM first.)
142+
2. For a new cluster, edit
143+
`consul-postgres-ha/cluster-example/terraform.tfvars` to that pin
144+
before `terraform apply`.
145+
3. For an existing provider-0.3 named-slot cluster, app-level image
146+
and compose changes are blocked until the Cloud revision-redeploy
147+
endpoint is wired into the provider. Today, use a new cluster or an
148+
explicit destroy/recreate for measured changes; use the hot-patch
149+
path only for dev smoke testing on a single SSH-enabled CVM.
147150
4. Verify with `gh attestation verify oci://...@<digest>` if you want
148151
to be sure the image you're pinning was built by this repo.

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,7 @@ consul-postgres-ha/
127127
├── mesh-conn/ Go source — QUIC-over-pion/ICE overlay (built into sidecar)
128128
├── patroni/ Patroni + Postgres image
129129
├── webdemo/ example workload sitting on the mesh
130-
├── signaling/ HTTP /publish + /poll broker for ICE auth/candidate exchange
131-
└── quic-on-ice/ standalone smoke test for the QUIC-over-ICE transport
130+
└── signaling/ HTTP /publish + /poll broker for ICE auth/candidate exchange
132131
```
133132

134133
## Adapting to your own workload
@@ -164,8 +163,8 @@ Say you want a billing service on port 9090 that the existing
164163
and add a `billing` service to `compose/worker.yaml` (modelled on
165164
`webdemo` — it just binds `127.0.0.1:9090` and serves).
166165

167-
3. **`terraform apply`**. The provider's in-place env update pushes
168-
the new `SERVICES_JSON` to every CVM:
166+
3. **Deploy the new revision**. For a fresh cluster, `terraform apply`
167+
creates CVMs with the new `SERVICES_JSON`:
169168

170169
- `mesh-conn`'s allowlist extends to `{21000, 21001, 21002,
171170
8300, 8301}` automatically — `MESH_CONN_ALLOWLIST` is computed
@@ -176,6 +175,13 @@ Say you want a billing service on port 9090 that the existing
176175
- Coordinator-0 writes a default-allow intention for `billing`
177176
and any subset/redirect resolvers implied by the declaration.
178177

178+
On an existing provider-0.3 named-slot cluster, app-level
179+
`docker_compose`, `env`, and `image` mutations are intentionally
180+
blocked until the Cloud revision-redeploy endpoint is wired into
181+
the Terraform provider. Today that means this kind of service-shape
182+
change is a new-cluster or destroy/recreate operation, not an
183+
in-place roll.
184+
179185
4. **From any container on any peer**, `curl http://billing:9090/...`
180186
load-balances across all peers' `billing` instances over Connect
181187
mTLS. No application-side service-discovery code.

ROBUSTNESS.md

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ do we do about it?", and lands on a prioritised punch list.
1313
```
1414
Layer 3 apps Consul + Envoy + webdemo + Patroni
1515
(HashiCorp / Lyft / Zalando code, well-trodden)
16-
Layer 2 forwarder mesh-conn ~600 LoC: peer VIPs (127.50.0.0/24),
17-
static infra-port allowlist {21000, 21001,
18-
8300, 8301}, 3-byte stream header
16+
Layer 2 forwarder mesh-conn: peer VIPs (127.50.0.0/24),
17+
runtime allowlist from SERVICES_JSON plus
18+
Consul infra ports, 3-byte stream header
1919
Layer 1 transport pion/ice + QUIC: punched UDP path,
2020
stream multiplex, flow control, keepalive
2121
Layer 0 rendezvous coturn + signalling broker on a public box;
@@ -79,7 +79,7 @@ whose direct path goes down can't fail over to TURN until it's back".
7979

8080
### What's there
8181

82-
- one ICE connection per peer-pair (6 in our 4-CVM cluster),
82+
- one ICE connection per peer-pair (15 in the default 6-CVM cluster),
8383
established via signalling broker + coturn
8484
- one `QUIC.Session` per ICE conn, with `EnableKeepAlive=true`
8585
- the streams flowing inside (one long-lived UDP-per-port,
@@ -201,8 +201,9 @@ whose direct path goes down can't fail over to TURN until it's back".
201201
### What's there
202202

203203
- peer VIPs `127.50.0.<vip>` (one per peer, in PEERS_JSON)
204-
- the static infra-port allowlist `{21000, 21001, 8300, 8301}`
205-
(in `mesh-conn/main.go`, deliberately small — see ARCHITECTURE.md)
204+
- the runtime port allowlist from `MESH_CONN_ALLOWLIST`
205+
(generated by `mesh-sidecar/entrypoint.sh`, deliberately small —
206+
see ARCHITECTURE.md)
206207
- the 3-byte stream header (tag, port-uint16-BE)
207208
- the per-stream pumps (UDP length-prefix, TCP raw splice)
208209
- one accept-loop per peer pair to demux incoming streams
@@ -259,17 +260,20 @@ The mitigations are mostly testing discipline:
259260
out-of-range VIPs. A canonicalised `peersDigest()` is logged at
260261
startup so `grep` across all peers' logs immediately surfaces
261262
config drift. Unit tests in `validate_test.go` cover the cases
262-
plus an `allowedPort` check pinning the static allowlist.
263+
plus an `allowedPort` check pinning membership in the configured
264+
allowlist.
263265

264266
## Layer 3 — Consul + Envoy + apps
265267

266268
### What's there
267269

268270
- three Consul servers (Raft quorum) on the coordinator CVMs, three
269271
clients on the worker CVMs
270-
- Connect enabled, default CA, allow intention webdemo→webdemo
272+
- Connect enabled, default CA, generated default-allow intentions per
273+
parent service
271274
- Envoy sidecars front-running each webdemo and Patroni
272-
- gossip key NOT set; RPC TLS NOT set
275+
- gossip key set from Terraform-generated cluster material; RPC TLS
276+
not set
273277

274278
### What can break
275279

@@ -426,8 +430,8 @@ Honest answer: not really. Each layer earns its place.
426430
- **Per-peer loopback VIPs** are the *one* clever-and-ours
427431
technique, and they exist because Consul's own protocol assumes
428432
every peer can be reached at a stable address. The peer-VIP plane
429-
gives us that stable address without modifying Consul; the static
430-
infra-port allowlist on top keeps mesh-conn workload-agnostic.
433+
gives us that stable address without modifying Consul; the runtime
434+
allowlist on top keeps mesh-conn workload-agnostic.
431435

432436
The risk concentration isn't in the count of layers; it's in the
433437
**single piece of code we wrote ourselves** (mesh-conn). That's

cluster-example/cluster.tf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,8 @@ locals {
188188
# Peer VIPs: 127.50.0.<vip>/32. Allocated as ordinal+1 (so vip=1
189189
# for the first coordinator, never 0 — the validate_test in
190190
# mesh-conn rejects vip=0). PEERS_JSON shape: [{id, vip}], same
191-
# on every CVM. mesh-conn binds the static infra-port allowlist
192-
# ({21000, 21001, 8300, 8301}) on every other peer's VIP.
191+
# on every CVM. mesh-conn binds the runtime allowlist emitted by
192+
# mesh-sidecar/entrypoint.sh on every other peer's VIP.
193193
peers = concat(
194194
[
195195
for i in range(var.coordinator_replicas) : {

design/README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Design docs — open work, intentionally separate from the user-facing docs
22

3-
This directory holds design briefs for **planned but not-yet-implemented**
4-
work on `consul-postgres-ha`. Each doc is structured so an agent (or a
5-
person) can pick it up cold and start implementing.
3+
This directory holds design briefs and handoff notes for open or
4+
partially landed work on `consul-postgres-ha`. Each doc is structured
5+
so an agent (or a person) can pick it up cold and continue.
66

77
The user-facing docs (`README.md`, `ARCHITECTURE.md`, `FAILOVER.md`,
88
`PUBLISHING.md`, `ROBUSTNESS.md`) describe what's *shipping today*.
@@ -12,8 +12,8 @@ in their face.
1212

1313
| Doc | What |
1414
|---|---|
15-
| [`attestation-admission.md`](attestation-admission.md) | Use dstack TEE attestation as the mesh-conn admission credential, replacing/augmenting the shared TURN HMAC. Phased plan: per-app-id first, Consul-KV-rooted policy later. |
16-
| [`terraform-slot-api.md`](terraform-slot-api.md) | Integrate the Phala Cloud slot API into Terraform so mesh members have stable logical identities across CVM replacement and future attestation policy binding. |
15+
| [`attestation-admission.md`](attestation-admission.md) | Phase 1 admission is implemented. Remaining work: token lifecycle, non-NAT secret distribution, upgrade policy, and rendezvous hardening. |
16+
| [`terraform-slot-api.md`](terraform-slot-api.md) | Provider slot resources are implemented and validated. Remaining work: slot-preserving revision rollout through the Cloud redeploy endpoint. |
1717

1818
Each doc includes:
1919

@@ -25,5 +25,5 @@ Each doc includes:
2525
- Success criteria
2626
- Hand-off instructions
2727

28-
When a doc's work lands, delete the doc (the implementation + the
29-
user-facing docs are the surviving artifacts).
28+
When all open work in a doc lands, delete the doc; the implementation
29+
and user-facing docs are the surviving artifacts.

0 commit comments

Comments
 (0)