@@ -20,8 +20,9 @@ docker compose
2020 ├─ dstack-vmm # launches real TDX/SNP app CVMs via QEMU
2121 └─ runner
2222 ├─ configures Gateway certbot to use mock CF + Pebble
23- ├─ deploys nginx test app CVM with kms_enabled=true + gateway_enabled=true
24- └─ verifies HTTPS Gateway -> app routing
23+ ├─ deploys legacy and lite TDX nginx CVMs
24+ ├─ verifies KMS key provisioning and HTTPS Gateway -> app routing
25+ └─ snapshots durable KMS/Gateway state for upgrade assertions
2526```
2627
2728It is intended for a ** real TDX/SGX host** (or SEV-SNP host after setting the
@@ -62,8 +63,9 @@ a confidential VM for the app.
6263 $EDITOR .env
6364 ```
6465
65- No Gateway image publishing is needed in this architecture: ` dstack-gateway ` and
66- ` dstack-kms ` are run from the local ` target/release/ ` binaries on the host side.
66+ The normal latest-only run needs no published KMS/Gateway image:
67+ ` dstack-gateway ` and ` dstack-kms ` run from the local ` target/release/ ` binaries.
68+ The upgrade run additionally pulls its old KMS/Gateway images from Docker Hub.
6769
6870## Run
6971
@@ -73,13 +75,64 @@ From this directory, run:
7375DOCKER_BUILDKIT=0 docker compose --env-file .env -f compose.yml up --build --abort-on-container-exit runner
7476```
7577
78+ On TDX this latest-only path deploys two otherwise identical CVMs. Their v3
79+ manifest requirements force ` tdx_measure_acpi_tables=true ` (legacy) and
80+ ` false ` (lite), respectively. Both must reach ` boot_progress=done ` , which is
81+ after the boot-time ` GetAppKey ` request, and both must serve nginx through the
82+ Gateway.
83+
84+ ## Run the upgrade scenario
85+
86+ The host-side driver is required because the runner container cannot replace
87+ its own KMS/Gateway dependencies:
88+
89+ ``` bash
90+ DOCKER_BUILDKIT=0 ./run-upgrade-e2e.sh
91+ ```
92+
93+ Defaults:
94+
95+ - old KMS: ` dstacktee/dstack-kms:0.5.7 ` (pulled from Docker Hub)
96+ - old Gateway: ` dstacktee/dstack-gateway:0.5.8 ` (pulled from Docker Hub)
97+ - latest KMS, Gateway, VMM, guest image: current checkout/build
98+
99+ The driver deliberately fails during the image-pull preflight if the exact old
100+ image is unavailable. Override images only for intentional matrix runs:
101+
102+ ``` bash
103+ DSTACK_E2E_OLD_KMS_IMAGE=dstacktee/dstack-kms:0.5.6 \
104+ DSTACK_E2E_OLD_GATEWAY_IMAGE=dstacktee/dstack-gateway:0.5.8 \
105+ ./run-upgrade-e2e.sh
106+ ```
107+
108+ The upgrade sequence is:
109+
110+ 1 . Boot a forced-legacy CVM against the old KMS and old Gateway.
111+ 2 . Record the KMS CA, root k256 public key, and that app's derived environment
112+ encryption public key.
113+ 3 . Replace only KMS with the current binary while retaining its cert/key dir.
114+ 4 . Require the recorded identities to be byte-for-byte stable; force-reboot the
115+ legacy CVM so it must provision keys from the new KMS; then boot a forced-lite
116+ CVM from scratch against the new KMS.
117+ 5 . Flush and record Gateway WaveKV state: node UUID, CVM registrations/IPs,
118+ certbot config, DNS credential, ZT domain, and wildcard cert fingerprint.
119+ 6 . Start rapid direct HTTP probes to both CVM WireGuard IPs, replace only the
120+ Gateway process, and require ** zero failed probe cycles** .
121+ 7 . Require all recorded Gateway state and the cert fingerprint to survive and
122+ verify both SNI routes through the new Gateway.
123+
124+ The zero-downtime assertion is specifically the CVM WireGuard data plane. The
125+ Gateway process owns the public TLS listener, so a single-node stop/start does
126+ not claim that the external listener itself has zero downtime. External routing
127+ is asserted immediately before and after the upgrade.
128+
76129For iterative debugging, keep the stack running:
77130
78131``` bash
79132DOCKER_BUILDKIT=0 docker compose --env-file .env -f compose.yml up --build
80133```
81134
82- The runner leaves the app VM running by default for inspection. Set
135+ The runner leaves app VMs running by default for inspection. Set
83136` DSTACK_E2E_CLEANUP_AFTER=true ` to remove suite VMs at the end. Stale VMs whose
84137names start with ` DSTACK_E2E_NAME_PREFIX ` are removed at the start when
85138` DSTACK_E2E_CLEAN_START=true ` .
@@ -93,8 +146,16 @@ The runner checks:
931463 . Gateway obtains a wildcard certificate for ` *.DSTACK_E2E_BASE_DOMAIN ` from
94147 Pebble using the mock Cloudflare DNS API.
951484 . VMM API becomes reachable.
96- 5 . A real nginx app CVM boots with ` kms_enabled=true ` and ` gateway_enabled=true ` .
97- 6 . ` curl -k ` through the Gateway SNI route returns the nginx welcome page.
149+ 5 . Real nginx app CVMs boot with ` kms_enabled=true ` and
150+ ` gateway_enabled=true ` .
151+ 6 . On TDX, v3 requirements resolve one CVM to legacy attestation and one to
152+ lite; both complete boot-time KMS key provisioning.
153+ 7 . ` curl -k ` through each Gateway SNI route returns the nginx welcome page.
154+ 8 . KMS and Gateway state can be captured in canonical, diffable artifacts.
155+
156+ ` run-upgrade-e2e.sh ` additionally checks KMS key continuity, Gateway persistence,
157+ old-to-new config/storage compatibility, and zero-failure CVM WireGuard traffic
158+ during the Gateway replacement.
98159
99160Artifacts are written under ` state/work/ ` .
100161
0 commit comments