Operations
Docker runtime
Run app instances as containers under the zero-downtime proxy, while one host stays one server on the dashboard.
One host, one agent
The docker runtime keeps a single Phelix agent on the host, exactly as on a bare VPS - one agent_id, one apps.json - but instead of executing each app as a host process, it builds an image per app and runs each instance as a container. One host therefore stays one server on the dashboard no matter how many app containers it runs.
The proxy still owns the single public port and routes to each container's published loopback port; a version rollback restarts the recorded image (myapp:v11) instead of a binary.
┌─ VPS — ONE Phelix agent = ONE server on the dashboard ─────────────┐│ phelix monitor (host process, systemd — as today) ││ phelix proxy :8080 ─┐ ││ ├─→ 127.0.0.1:49215 ← docker: billing:v3 ││ ├─→ 127.0.0.1:49216 ← docker: auth:v7 ││ └─→ 127.0.0.1:49217 ← docker: user:v2 │└────────────────────────────────────────────────────────────────────┘Requirements
- Phelix runs on the host (the normal systemd install) with a reachable Docker daemon. Do not run Phelix itself inside a container for this model unless you deliberately mount the Docker socket (see Security).
- Each app must read
PORT- the same PORT contract as native apps. Phelix injectsPORTinto the container and publishes it to an ephemeral host port bound to127.0.0.1. - The docker runtime rides the zero-downtime topology, so the app needs a zero-downtime strategy -
blue-green,rolling,canary, orprogressive. Theclassicstop-start path is native-only.
Enable the docker runtime
Set the runtime in the app's project configuration:
name: billingport: 8080deploy: runtime: docker # run instances as containers instead of host processes strategy: blue-green # required: classic is native-onlyhealth: endpoints: - name: default path: /health interval: 10s retries: 3 mode: autophelix init writes this for you when you pick the docker runtime (or pass --runtime docker); it defaults strategy to blue-green so the file is valid. Flip a single command to docker without editing the file:
PHELIX_RUNTIME=docker phelix rebuild billingPrecedence is PHELIX_RUNTIME env → phelix.yaml deploy.runtime → native.
Deploy and roll back
# One-time on the hostphelix proxy # zero-downtime proxy (auto-started by rebuild too) # Build an image (myapp:vN) and roll it out with zero downtimephelix rebuild billing --blue-green # Roll back to the previous image, zero downtimephelix rollback billingPhelix generates a multi-stage Dockerfile if the project has none (the same generator phelix dockerize uses; a user-provided Dockerfile is always respected), builds billing:v<N>, records it in versions.json, then runs it with the phelix.managed, phelix.app, and phelix.slot labels.
Step by step
- Initialise and choose the docker runtimephelix init --name billing --port 8080 --runtime docker --yes writes deploy.runtime: docker with deploy.strategy: blue-green. The port here is the public port the proxy binds.
- Make the app read PORTThe one hard requirement: Phelix runs the container with PORT set and maps it to a private host port the proxy dials. Run phelix doctor to check.
- Provide a Dockerfile - or let Phelix generate oneNo Dockerfile: Phelix generates a multi-stage one on the first deploy and never overwrites it. Your own Dockerfile is used as-is. It only needs to start the app as ENTRYPOINT/CMD and bind the PORT variable - no EXPOSE or hardcoded port.
- Create the app with phelix buildphelix build billing creates the app and goes straight through the container path: build billing:v1, run it on a private loopback port, health-check it, then point the proxy at it. Only Docker is required on the host.
- Ship a change with phelix rebuildphelix rebuild billing builds billing:v2, health-checks it, and switches over. The old container keeps serving until the new one is healthy.
- Roll back if neededphelix rollback billing returns to the previous image with zero downtime; --to v1 targets a specific version.
Instance identity & cleanup
- Every container Phelix starts carries a
phelix.managed=truelabel plus the app and slot. Liveness and shutdown verify the container id + label (never a recycled host PID), so a live container is never mistaken for dead and Phelix never signals a container it did not create. - Secrets reach the container through a
0600--env-file, never as-eon the command line, so decrypted values never appear indocker inspector the host process table. - If a deploy crashes after
docker runbut before recording the instance, the orphaned container is reclaimed the next timephelix monitorstarts - onlyphelix.managedcontainers that no deploy state references are removed.