also looking at this
feat(fleet): move a deployed site to another server (#167 operation 2)
#176
4 files
+951
-0
| @@ -155,6 +155,7 @@ See [Preview environments](/features/preview-environments) for policy, source li | ||
| 155 | 155 | | `cloud server:ssh <name>` / `server:logs <name>` / `server:monitoring <name>` | Connect / logs / metrics. | |
| 156 | 156 | | `cloud server:deploy <name>` / `server:reboot` / `server:resize <name> <type>` | Deploy / reboot / resize. | |
| 157 | 157 | | `cloud server:rename <name> <new-name> [--apply]` | Rename a server in place. Prints the plan; `--apply` performs it. | |
| 158 | | `cloud site:move <name> --to <server> [--apply]` | Move a deployed site to another server, DNS cutover included. | | |
| 158 | 159 | | `cloud server:recipe <name> <recipe>` | Run a reusable script across servers. | |
| 159 | 160 | | `cloud server:worker:add/list/restart/remove` | Queue workers (Supervisor). | |
| 160 | 161 | | `cloud server:cron:add/list/remove` | Scheduled jobs / cron. | |
| @@ -165,6 +166,53 @@ See [Preview environments](/features/preview-environments) for policy, source li | ||
| 165 | 166 | |
| 166 | 167 | See [Laravel / Forge-style](/features/laravel) for the `infrastructure.compute` + `sites` config. |
| 167 | 168 | |
| 169 | ### Moving a site to another server | |
| 170 | ||
| 171 | Consolidation's second operation: three boxes with one app each becoming one box | |
| 172 | with three sites. | |
| 173 | ||
| 174 | ```bash | |
| 175 | cloud site:move bughq --to statushq-box # plan only | |
| 176 | cloud site:move bughq --to statushq-box --apply # perform it | |
| 177 | ``` | |
| 178 | ||
| 179 | It moves the site's on-box footprint wholesale — the whole | |
| 180 | `/var/www/<slug>-<site>` tree (every release, `shared/`, the `current` symlink) | |
| 181 | plus the systemd units that run it. Those units are not regenerated, they are | |
| 182 | moved: rebuilding from the repo on the target would not be a move but a fresh | |
| 183 | deploy that happens to be preceded by a data copy, picking up whatever the repo | |
| 184 | says today rather than what is actually running. | |
| 185 | ||
| 186 | The order is chosen so that **every prefix of the plan is a working system**, | |
| 187 | on the old box or the new one: | |
| 188 | ||
| 189 | | Step | Why there | | |
| 190 | |---|---| | |
| 191 | | Stop background work on the source | A queue worker writing mid-`tar` produces a torn snapshot. The web service keeps serving — the source is still live. | | |
| 192 | | Archive, carry, unpack, start | The target comes up but nothing routes to it yet. | | |
| 193 | | Health gate on the target's loopback | The public name still points at the source, so asking it would wave a broken target through. | | |
| 194 | | Route the site on the target | Same gateway builder the deploy uses, so a moved site is routed byte-identically to a deployed one. | | |
| 195 | | Cut DNS over | Only after the target has proved itself. A provider warning stops the run here rather than continuing to the drain. | | |
| 196 | | Drain the source | Units stopped and disabled, gateway fragment removed. **Files left in place.** | | |
| 197 | ||
| 198 | Nothing in the operation deletes anything, so a bad cutover is undone by starting | |
| 199 | the source's units again and pointing DNS back. That reversibility lasts until | |
| 200 | the source *server* is destroyed, which is a separate and deliberately separate | |
| 201 | command. Background units are enabled but not started on the target until the | |
| 202 | source is drained, so the two boxes can never both run a scheduler against one | |
| 203 | dataset. | |
| 204 | ||
| 205 | The archive travels through the machine running the command rather than directly | |
| 206 | between the boxes: a direct hop would need the target to hold a credential for | |
| 207 | the source, which is the same credential-radius problem consolidation already | |
| 208 | has. Both boxes must be enrolled with pinned host keys (`cloud server:validate`). | |
| 209 | ||
| 210 | Resuming works the same way as `server:rename` — re-run the identical command and | |
| 211 | the finished steps skip themselves. Two steps deliberately never skip: the | |
| 212 | snapshot (an archive from an earlier attempt predates whatever the source has | |
| 213 | served since) and the health gate (a gate that remembers a previous pass is not a | |
| 214 | gate). | |
| 215 | ||
| 168 | 216 | ### Renaming a server |
| 169 | 217 | |
| 170 | 218 | A name is spelled in four places, and a rename is only done when all four agree: |