Tines has a familiar architecture:
Our web application handles web requests served by nginx
Background jobs (e.g. those powering Tines Actions) run in a separate process
Data rests in external services like Postgres and Redis
More unusually, we allow customers to self-host Tines on premise, alongside our usual cloud offering. In this configuration, all of the above – the web application, background jobs, and datastores – run on a single machine, in containers orchestrated by docker-compose.

We were faced with an interesting question: how can we safely deploy changes in this configuration without dropping web requests? (Answering this question is key to achieving continuous deployment, which we care deeply about.)
Pare down the problem
First off, we rarely make any changes to the containers running our datastores, so we can eliminate those from our consideration. And we don't need to worry about our background jobs either: those will retry automatically once the deployment finishes, so brief downtime just isn’t an issue.
That leaves our web application. The common advice we heard for achieving what we needed was: