feat(proxy): rename container identity to dash and migrate hosts across - #130
Merged
Conversation
Stage 3c part 2 of the server-artifact rename (#124), gem side. The proxy image moved first in zoolutions/dash-proxy#122, released as v1.1.0.0. Renamed: the proxy container and its port holder, the docker network every app, accessory and proxy joins, the config volumes, the image title the prune filters key on, and the in-image paths the gem mounts and execs. Three migrations run once per proxy host, before the normal boot, wired through a new Dash::Cli::Proxy::LegacyRename: - The network is bridged rather than renamed, because docker cannot rename one. App containers would be replaced by the next deploy anyway; accessories are not, and without the bridge a renamed proxy cannot reach db or redis. - The config volume is copied before anything starts. It holds the routing table and the ACME account and certificate cache, so losing it means re-issuing every certificate and spending Let's Encrypt rate limits to get back to where we were. - The legacy container is stopped and removed so the renamed one can claim ports 80/443. No port-holder handoff spans two container names, so this stage costs a brief outage per host. Deliberate, and settled in the issue. Each is idempotent and guarded on its destination not existing, so a second deploy is a no-op. The volume copy's guard is negated and leads its chain: shell && and || share precedence and associate left, so the obvious `exists || legacy && create && copy` parses as `((exists || legacy) && create) && copy` and would re-copy the legacy volume over live state on every deploy. Verified against a shell rather than reasoned about. Prune filters now match the pre-rename image title as well as the current one, or `dash proxy remove` would silently leave the old container and image on a host that has not yet migrated. Docker ANDs multiple `--filter label=` values, so that is two chained commands. Nothing removes the legacy network or volume: an operator who wants them gone removes them by hand, and stage 3d deletes this whole path. MINIMUM_VERSION is NOT bumped here - that lands with the docs, once v1.1.0.0 is pullable. Refs #124
MINIMUM_VERSION moves to v1.1.0.0, the first image with the renamed binary, user, data directory and image title. Verified before pinning: the published tag carries /usr/local/bin/dash-proxy, runs as uid 1001, is multi-arch, and its org.opencontainers.image.title is dash-proxy — which the prune filters key on. bin/sync-proxy-flags invoked `kamal-proxy` to read Cobra's help, so it broke the moment the binary moved. Fixed and the manifest regenerated; the flag surface is unchanged, this release being a rename. The docs claimed three things this stage falsifies: that the container keeps the kamal-proxy name, that dash manages the one kamal booted, and that an upgrade leaves it untouched. Replaced with what actually happens, including the part operators need to plan for — replacing the container costs a short outage on that host, because the old one has to release ports 80/443 before the new one can bind them. Refs #124
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part 2 of stage 3c (#124), the gem side. The proxy image moved first in zoolutions/dash-proxy#122, released as v1.1.0.0, which this pins.
kamal-proxydash-proxykamal-proxy-netdash-proxy-netkamaldashkamal-proxy-config,kamal-loadbalancer-configdash-proxy-config,dash-loadbalancer-configkamal-proxydash-proxy/home/kamal-proxy/…/home/dash-proxy/…Replacing the container means the old one must release ports 80/443 before the new one can bind them, and no port-holder handoff spans two container names. Accepted deliberately — settled in #124.
The three migrations
Wired through a new
Dash::Cli::Proxy::LegacyRename, run once per proxy host before the normal boot. All idempotent, all guarded on the destination not existing.dashis created alongsidekamaland everything still attached joins the new one. App containers get replaced by the next deploy anyway; accessories do not, which is the whole point — without this a renamed proxy cannot reachdborredis.Nothing removes the legacy network or volume. An operator who wants them gone runs
docker network rm kamalby hand; stage 3d deletes this whole path.A data-loss bug worth reading
I first wrote the volume-copy guard the way the issue phrases it:
Shell
&&and||share precedence and associate left, so that parses as((exists || legacy_exists) && create) && copy. Once the new volume existed,existsshort-circuited the||to true and the copy ran anyway — re-copying the legacy volume over live state on every deploy.Restructured to lead with a negated guard so the whole chain is one left-associative AND:
Verified against a real shell rather than reasoned about twice:
Test plan
bin/testincl. integration — 1572 runs, 2 failures, 0 errors; integration added 19 runs and zero failures, so the migrations ran against real Docker-in-Docker hosts without breaking a deploybundle exec rubocop --parallel— 223 files, no offensescd docs && bundle exec rspec— 64 examples, 0 failures/usr/local/bin/dash-proxy, uid 1001, multi-arch, andorg.opencontainers.image.title=dash-proxy— which the prune filters key onDeviations & judgment calls
A second bug, caught by tests. Making the prune filters dual-match meant changing
label, which is also used for--labelondocker run— so containers were briefly created with--label dash-proxyinstead of the fullkey=value. Split intolabel(full pair, for creation) andimage_title/legacy_image_title(bare, for pruning).Prune filters match both titles. Docker ANDs multiple
--filter label=values, so this is two chained commands, not one filter with two values. Without the legacy pass,dash proxy removeon a host that has not yet migrated silently leaves the old container and image behind.The issue's file list was incomplete. It missed
Dash::Configuration::Proxy::CONTAINER_NAME/LOADBALANCER_CONTAINER_NAME,commands/app/execution.rb, andcommands/proxy/cert_transfer.rb. All found by grepping for the identifiers rather than following the list.bin/sync-proxy-flagswas broken by part 1 — it shelled out tokamal-proxy --helpto read Cobra's flag list, so it failed the moment the binary moved. Fixed here. The flag surface itself is unchanged, this release being a rename.Legacy names live as
LEGACY_*constants onDash::Configuration::Proxyrather than inline strings, so stage 3d has one place to delete andgrep LEGACY_shows the entire compatibility surface.otel_shipper.rbstill reportsservice.name: "kamal". Left alone deliberately — that is telemetry identity, and renaming it breaks existing operator dashboards, the same reasoning #124 uses to defer the proxy's Prometheus namespace. Worth its own decision.Docs claimed things this falsifies.
from_kamal.rbsaid the container keeps its name and "dash manages the one kamal booted";overview.rbsaid an upgrade leaves it untouched. Both corrected, including the outage operators must plan for.The manual upgrade rehearsal from #124 has not been run: deploy a host on the pre-rename gem, upgrade, then confirm the ACME certificate was not re-issued (compare
notBefore), the accessory is attached to both networks,dash-proxy listreturns the same services, and a second deploy replaces nothing.Integration proves the commands work against real Docker. It does not prove the certificate store survives, because the dind fixtures have no real ACME certificate. Given this is 4.0.0 and a botched volume copy means re-issuing certificates against Let's Encrypt rate limits, I would not merge this without that rehearsal.
Closes #124
Summary by cubic
Renames the proxy container from
kamal-proxytodash-proxy(including network, config volumes, and in-image paths) and adds a one‑time migration that runs on each proxy host before boot. Replacing the container costs a short outage per host because ports 80/443 must be released, which is accepted per #124.Migration
dashnetwork, copies the config volume (routing table + ACME cache) intodash-proxy-config, and swaps the legacy container.dbandredis.Other changes
dash proxy removedoesn’t leave old containers behind.bin/sync-proxy-flagswas broken by the binary rename and now callsdash-proxy; the flag surface is unchanged.Written for commit c3844eb. Summary will update on new commits.