Deployment Lifecycle
Keywords
deploy, build, pipeline, lifecycle, build container, deploy process, rolling deployment, zero downtime, readiness check, health check, temporaryShutdown, build timeout, artifact, deploy files, prepareCommands, buildCommands, init commands, start command, container replacement, application version, build cancel, runtime prepare
TL;DR
Zerops build & deploy pipeline: temporary build container runs prepareCommands + buildCommands, uploads artifact via deployFiles, then deploys to runtime containers with optional readiness checks. Default is zero-downtime rolling deployment. Build has a 60-minute timeout. The pipeline emits events trackable via zerops_events.
Build Phase
Build Container Lifecycle
The build container is temporary -- created on demand, destroyed after completion or failure.
Step-by-step execution order:
- Container creation -- base environment from
build.base+build.os(default Alpine) - Source code download -- from GitHub, GitLab, or zcli push to
/var/www - Cache restoration -- cached files moved to
/build/source(no-clobber, source wins) - prepareCommands -- install additional tools/packages (skipped if cache valid)
- buildCommands -- compile, bundle, package your application
- Artifact upload -- files matching
deployFilesstored in internal Zerops storage - Cache preservation -- files matching
cache:moved to/build/cache - Container deletion -- build container destroyed regardless of outcome
Build Limits
- Resources: CPU 1-5 cores, RAM 8 GB fixed, Disk 1-100 GB (auto-scales, not charged separately)
- Timeout: 60 minutes hard limit -- no retry, must trigger new pipeline
- Cancellation: only available before build finishes -- once artifact uploaded, deploy cannot be cancelled
Command Exit Codes
- Exit 0 -- success, next command runs
- Non-zero -- build cancelled, check build log for errors
- YAML list items = separate shells; use
|block scalar for single shell (shared env/cwd)
Runtime Prepare Phase (Optional)
Runs after build, before deploy when run.prepareCommands is defined. Creates a custom runtime image with additional system packages.
Execution order:
- Create prepare container from
run.os+run.base - Copy files from
build.addToRunPrepareto/home/zerops/ - Execute
run.prepareCommandsin order - Snapshot as custom runtime image
- Image cached for future deploys
Cache invalidation triggers:
- Change to
run.os,run.base, orrun.prepareCommands - Change to
build.addToRunPreparefile contents - Manual invalidation via GUI
DO NOT include application code in the runtime prepare image. Deploy files arrive separately.
Deploy Phase
First Deploy
For each new container (count based on auto scaling settings):
- Install runtime -- base image or custom runtime image
- Download artifact -- from internal storage to
/var/www - initCommands -- optional per-container initialization (runs every start/restart)
- start command -- launch application
- Readiness check -- if configured, gates traffic routing
- Container active -- receives incoming requests
Multiple containers deploy in parallel.
Subsequent Deploys (Rolling Deployment)
Default behavior (temporaryShutdown: false):
- New containers started (same count as existing)
- New containers go through steps 1-6 above
- Both old and new versions run simultaneously during transition
- Old containers removed from load balancer (stop receiving new requests)
- Old container processes terminated
- Old containers deleted
temporaryShutdown Behavior
| Setting | Behavior | Downtime |
|---|---|---|
false (default) | New containers start BEFORE old ones stop | Zero downtime |
true | Old containers stop BEFORE new ones start | Temporary downtime |
Use temporaryShutdown: true only when you cannot run two versions simultaneously (e.g., database migrations, singleton locks).
Readiness Check vs Health Check
| Aspect | Readiness Check | Health Check |
|---|---|---|
| When | During deploy only | Continuously after deploy |
| Purpose | Gates traffic to new containers | Detects runtime failures |
| Location | deploy.readinessCheck | run.healthCheck |
| Failure action | Container marked failed after timeout, replaced | Container restarted |
Readiness Check Mechanics
- Application starts via
startcommand - Readiness check runs (httpGet or exec)
- If fails -- wait
retryPeriodseconds (default 5s), retry - If succeeds -- container marked active, receives traffic
- If still failing after
failureTimeout(default 300s / 5 min) -- container deleted, new one created
httpGet: succeeds on HTTP 2xx, follows 3xx redirects, 5-second per-request timeout
exec.command: succeeds on exit code 0, 5-second per-command timeout
Event Timeline (zerops_events)
Typical pipeline events in chronological order:
stack.buildprocess RUNNING -- build container created, pipeline startedstack.buildprocess FINISHED -- build complete, artifact uploadedappVersionbuild event ACTIVE -- deploy started, containers launching- Service status returns to RUNNING -- all containers active, deploy complete
Terminal states:
- Build done:
stack.buildprocess status =FINISHED - Build failed:
stack.buildprocess status =FAILED - Deploy done: service containers all active, new appVersion is
ACTIVE
DO NOT keep polling after stack.build shows FINISHED -- that means the build itself is complete. The ACTIVE status on appVersion means deployed and running.
Build Event Polling Checklist
When monitoring a build/deploy via zerops_events:
- Filter by service: always use
serviceHostnameparameter to avoid stale events from other services or previous iterations - Check
stack.buildprocess: look for statusFINISHED(success) orFAILED(error). OnceFINISHED, the build is done — stop polling build status - Check
appVersionbuild event: statusACTIVEmeans deployed and running. This confirms deploy completion - Do NOT confuse build events:
stack.buildprocessRUNNING= build in progress.appVersionACTIVE= already deployed. These are different events - Timeout guidance: builds have a 60-minute hard limit. If no
FINISHEDafter ~5 minutes for typical apps, check build logs viazerops_logs - Stale events: project-level events may include old builds from previous deploys. Always verify the event timestamp and service match
Application Versions
Zerops keeps 10 most recent versions. Older auto-deleted. Any archived version can be restored -- activates that version, archives current, restores env vars to their state when that version was last active.
Gotchas
- Build and run are SEPARATE containers -- build output does not automatically appear in runtime. You must specify
deployFiles - initCommands run on EVERY container start -- including restarts and horizontal scaling, not just deploys
- initCommands failures do NOT cancel deploy -- app starts regardless of init exit code
- prepareCommands in build vs run --
build.prepareCommandscustomizes build env,run.prepareCommandscreates custom runtime image. Different containers, different purposes - deployFiles land in
/var/www-- tilde syntax (dist/~) extracts contents directly to/var/www/(strips directory). Without tilde,dist→/var/www/dist/(preserved). CRITICAL:run.startpath must match —dist/~+start: bun dist/index.jsBREAKS because the file is at/var/www/index.js, not/var/www/dist/index.js
SSHFS Mount and Deploy Interaction
When using SSHFS (zerops_mount) for dev workflows, deploy replaces the container. This has important consequences:
- After deploy, run container only has
deployFilescontent. All other files (including zerops.yml if not in deployFiles) are gone. UsedeployFiles: [.]for dev services to ensure zerops.yml and source files survive the deploy cycle. - SSHFS mount auto-reconnects after deploy. No explicit remount is needed — the SSHFS reconnect mechanism handles the container replacement transparently. The mount only becomes truly stale during stop (container not running); after start it auto-reconnects again.
- zerops.yml must be in deployFiles for dev self-deploy lifecycle. Without it, subsequent deploys from the container fail because zerops.yml is missing.
Two kinds of "mount" (disambiguation):
zerops_mount-- SSHFS tool, mounts service/var/wwwlocally for development. This is a dev workflow tool.- Shared storage mount -- platform feature, attaches a shared-storage volume at
/mnt/{hostname}viamount:in import.yml + zerops.ymlrun.mount. These are completely unrelated features.
See Also
- zerops://themes/core -- zerops.yml schema and platform rules
- zerops://guides/build-cache -- two-layer cache architecture and invalidation
- zerops://guides/ci-cd -- triggering pipelines from GitHub/GitLab
- zerops://guides/logging -- build and runtime log access