Kubernetes can do rolling deployments. So can a much smaller setup. For many applications, a managed load balancer in front of two or more app instances covers the need with less operational work.

The basic pattern

  1. Build a new version of the app as an image or release artifact.
  2. Start a new instance with the new version.
  3. Wait until its health check passes.
  4. Add it to the load balancer.
  5. Drain one old instance: stop sending it new requests, let current requests finish, then shut it down.
  6. Repeat until every instance runs the new version.

Managed platforms such as AWS Elastic Beanstalk, ECS, Google Cloud Run, Fly.io and Render do this for you. On plain virtual machines, a deploy script and the load balancer's API do the same job.

Health checks that mean something

A health check that returns 200 as soon as the web server starts will send traffic to an app that can't reach its database. Our health endpoint checks the things a request needs: a database query, the cache connection and any required config. It runs in under a few hundred milliseconds so the load balancer can call it often.

We keep a separate "liveness" check that only confirms the process is running. Mixing the two causes restarts when the database has a short blip.

Database migrations are the hard part

During a rolling deploy, old and new code run at the same time against the same database. A migration that renames a column breaks the old code the moment it runs.

Our rule: every migration must work with both the current and the previous version of the code. In practice that means splitting changes:

It takes more releases. It never takes the site down.

Draining and long requests

Uploads, reports and websockets hold connections open. When we drain an instance we give it a timeout long enough for normal requests to finish, usually 30 to 60 seconds. Background jobs get a shutdown signal so they finish the current task and stop picking up new ones.

Rolling back

Because the old version keeps running until the new one is healthy, a failed deploy stops before it reaches users. If a bug slips through, rolling back is a redeploy of the previous artifact. We keep the last several releases available and test the rollback path, not only the deploy path.

When Kubernetes makes sense

If you run many services, need fine control over scheduling or already have people who operate clusters, Kubernetes earns its keep. For a single product with a web app, a worker and a database, the pattern above gives you zero-downtime releases at a much lower running cost and with less for your team to learn.

← More in Cloud & DevOps