Docker deploy: give apps a writable /data, and stop reissuing ports after a restart - #575
Open
lmo-selected wants to merge 1 commit into
Open
Docker deploy: give apps a writable /data, and stop reissuing ports after a restart#575lmo-selected wants to merge 1 commit into
lmo-selected wants to merge 1 commit into
Conversation
…tart Two defects that together make a locally deployed app that stores anything fail on first run and then fail differently after a restart. The container mounts the snapshot read-only at /app and nothing writable anywhere, so an app that opens a database or writes a file dies on startup. The platform already has a contract for this: aws-deploy-provider sets DATA_DIR to /data, and wiring warns that a deployment without a data bucket has "NO durable /data". The Docker provider never implemented its half, so an app written against that contract works on AWS and crashes locally. It now gets a per-deployment host directory mounted at /data, DATA_DIR in its environment, and the same path advertised on the provider profile. The directory lives outside the container, so data survives a redeploy. Host ports were handed out from a counter held in process memory. Every restart reset it to the base, so the next deployment was handed a port an existing container already held, and the second one to start failed to bind. The allocation is already durable — it is on the deployment record as endpoint.port — so apply now prefers the recorded port and advances the counter past it, rather than keeping a parallel copy in RAM that a restart silently invalidates. Tests cover the mount, the environment variable, the read-only snapshot, and a restart modelled as a fresh provider instance: a redeploy keeps its port, and a new deployment does not collide with it.
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.
Two defects in the Docker deploy provider. Together they make a locally deployed app that stores anything fail on first run, and then fail differently after a restart. Both are invisible from the outside: the deployment record says
runningwhile the container has already exited.1. No writable storage
The container gets the snapshot mounted read-only at
/appand nothing writable anywhere:So an app that opens a database or writes a file dies on startup.
mkdirSync('/app/data')fails, and with{ recursive: true }it fails the same way, just withEROFSinstead ofENOENT.The platform already has a contract for this.
aws-deploy-provider.tsdefinesDATA_DIR = "/data"andDATA_DB = "/data/app.db", andwiring.tswarns that an AWS deployment without a data bucket has "NO durable /data".DeployProfileeven carries adataDirfield. The Docker provider never implemented its half — so an app written correctly against that contract works on AWS and crashes locally, which is the wrong way round for the environment people develop in.Now: a per-deployment directory on the host, mounted read-write at
/data,DATA_DIRin the app's environment, and the path advertised onprofile.dataDir. The directory lives outside the container, so data survives a redeploy.2. Host ports are allocated in memory
Every process restart resets the counter to the base. The next
applythen hands out a port an existing container already holds, and the second container to start fails to bind — after several restarts a set of deployments can all carry the same recorded port.The allocation is already durable: it is on the deployment record as
endpoint.port, andapplyreceives theDeployment. So this keeps no new state —applyprefers the recorded port and advances the counter past it, instead of maintaining a parallel copy in RAM that a restart silently invalidates.Tests
dataRootandmkdirare injectable alongside the existingdockerExec, so both paths are covered without touching a real filesystem or daemon:/data, andDATA_DIRis set, while the snapshot stays:rotest/docker-deploy-provider.test.ts7/7,test/aws-deploy-provider.test.ts46/46 unaffected,tsc --noEmitclean.Not fixed here
Nothing reconciles a deployment's recorded
statusagainst the container's actual state, so a crashed app reportsrunningindefinitely and the UI shows it as starting up. That is what made both defects above hard to see, but it needs a reconcile loop rather than a change to this file, so it is left for a separate change.Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.