Skip to content
NebulaCtrldocs
Concepts

Deployments

How a release becomes active in an environment. The deployment states, what ends a deployment, and how supersede, rollback, promotion and deploy order work.

A release is an immutable image digest plus the configuration frozen when it was created, numbered per service per environment (r-1, r-2). A deployment is one attempt to make a release active in an environment. It moves through a visible state machine instead of stalling silently, and it always ends in one of five final states.

A deployment has a kind: deploy, rollback or promote.

The state machine

stateDiagram-v2
state "awaiting-approval" as awaiting
[*] --> awaiting: protected environment
[*] --> pending: any other environment
awaiting --> pending: approved
awaiting --> rejected: rejected
awaiting --> cancelled: cancelled or expired
pending --> admitted
admitted --> releasing: release has a release command
admitted --> starting
releasing --> starting
starting --> qualifying
qualifying --> activating
activating --> draining
draining --> healthy
healthy --> [*]

A deployment waits for an approval only in a protected environment. After that it walks eight stages in order, and releasing appears only when the release has a release command. From any stage before healthy it can also end as failed, cancelled or superseded.

StateMeaning
awaiting-approvalA deployment in a protected environment, waiting for someone to decide its approval. Nothing reaches the cluster. The console reads Waiting for approval.
pendingCreated and waiting to be admitted, or held behind a dependency that is still deploying.
admittedAdmitted onto the environment's cluster.
releasingThe release command runs with the new release's image, before any process starts. The console calls this stage Release command.
startingThe release's processes are starting.
qualifyingThe agent checks the new processes from inside the cluster before they take traffic.
activatingThe environment's stable entry point switches traffic to the new release.
drainingThe previous release stops taking traffic and shuts down.
healthyFinal. The release is active.
failedFinal. The deployment stopped on a blocker.
rejectedFinal. Its approval was rejected.
cancelledFinal. Someone cancelled it, or its approval expired.
supersededFinal. A newer deployment of the same service in the same environment took over first.

What each stage checks

  • Qualifying. Every replica of the primary process must stay Ready for the process's stabilization period. For an http process the agent also sends a GET to the readiness path, / by default, through the release's own service, and the response must be below 500. For a worker with a port it opens a TCP connection. A release with no long-running process, such as cron or job only, qualifies at once. A process that isn't ready within 5 minutes fails with the blocker readiness.
  • Releasing. A failing or timed-out release command fails the deployment with the blocker release-command. The previous release keeps serving.
  • Activating. Traffic switches only when the agent can repoint the stable service. If the Kubernetes API keeps refusing the change for 2 minutes, the deployment fails with route-activation, and the previous release keeps serving.
  • Draining. A release that touches a volume and has the downtime acknowledged drains the previous release before starting, because the old pod must release the volume first.

When a deployment fails

A failed deployment names a blocker: the reason it stopped, such as image-pull, capacity, readiness or release-command. The previous release keeps serving, because traffic only moves at activating. The control plane also sets a blocker on a deployment that's still open and clears it when the cause is gone: configuration when the service can't be compiled, delivery when the cluster's agent is offline, and stalled when a stage ran past its normal time. The deployment states reference lists every blocker with its fix, and Troubleshooting deployments starts from the message you see.

A newer deployment replaces the one in flight

Deploying, redeploying, rolling back or promoting while an earlier deployment of the same service is still in progress replaces it. What happens depends on how far the earlier one got:

  • It has not taken traffic yet (pending through qualifying). It ends as superseded with a message such as Superseded by r-7. Its pods are removed, and the response to the new request lists what it ended. You don't need to cancel it first. The release that was serving keeps serving until the new one is healthy.
  • It is taking over traffic (activating or draining). It finishes, because stopping it halfway could leave nothing serving. The new deployment starts right behind it and shows Waiting for r-6 to finish taking over traffic.

A deployment waiting for approval stops nothing until it's approved. Approving it supersedes what's in flight at that moment. Rolling back or promoting also ends the service's queued and running builds in that environment, and a build that finished before the rollback doesn't create its release afterwards.

Rollback, promotion and redeploy

  • A rollback makes a previously active release active again. It's a deployment like any other and passes through the same approval, unless the organization's Rollbacks skip approval policy is on. The 3 most recent retired releases of a service stay available for rollback.
  • A promotion creates a new release in another environment from an existing release's image, then deploys it there.
  • A redeploy creates a new release from the image that's active now. It needs an environment that has had a healthy release.

What waits for what

A deployment waits for the services it depends on. A service depends on another service or database in the project when:

  • It references it. A variable that reads ${{ api.KEY }} or ${{ db.DATABASE_URL }}, or a database connection. A ${{ host(api) }} is only an address and doesn't order deploys.
  • It says so. The service's Deploy after list, set in its settings in the console or with [deploy] depends_on in its nebula.toml. The file wins and shows read-only in the console. A cycle, an unknown slug or the service itself is refused when the list is set.

While a dependency has a deployment in flight in the same environment that started first, the dependent deployment stays pending with the blocker waiting and the message Waiting for db to finish deploying (r-4). Nothing reaches the cluster for it, and its current release keeps serving. It starts as soon as the dependency is healthy. A dependency that isn't being deployed costs nothing, so most deploys never wait.

If the dependency ends failed, cancelled or rejected, the held deployment ends failed: Not deployed: db failed to deploy (r-4). api keeps running r-7. Deploy api again once db is healthy. Nothing that went healthy is rolled back, and services that don't depend on the failed one carry on.

A change set applies in dependency order: databases first, then along the same edges. See Deploy order.

Concurrency

A project can cap how many deployments run at once with Deploy concurrency in the project's settings. It's unlimited by default. A deployment past the limit is refused, not queued, with an error that says the project is already running its maximum number of concurrent deployments. A deployment held behind a dependency still counts toward the limit.

On this page