On this page
Every small team I meet is stuck between two bad options: FTP era deploys, where someone SSHes in and pulls and prays, or a Kubernetes setup so elaborate that deploys require the one person who understands it, who is on holiday. There is a middle path, it fits in an afternoon, and it gives you the two properties that actually matter: every commit deployable, every deploy reversible.
I have set this up across AWS and Azure for product teams with no dedicated DevOps engineer. Here is the shape, principle by principle, with the pipeline spelled out.
Principle 1: Build once, promote everywhere
The single most important rule: the image you tested is the image you ship. CI builds one Docker image per commit, tags it with the git SHA, pushes it to a registry, and then staging and production both run that exact artifact with different environment variables.
The anti pattern is rebuilding per environment. "It worked in staging" while production got a different dependency resolution is a mystery you never need to debug again once artifacts are facts and rebuilds are forbidden.

Principle 2: Multi stage builds keep images honest
FROM node:20-alpine AS deps # install dependencies
FROM node:20-alpine AS builder # compile the app
FROM node:20-alpine AS runner # copy only what runtime needs
USER nonroot
CMD ["node", "server.js"]Dependencies cached, build tools excluded from the final image, a small attack surface and fast pulls. The runtime image should contain your app and nothing that can compile anything. This is also most of your container security posture, for free.
Principle 3: The pipeline is boring on purpose
On every push to main, four stages:
- Verify. Lint, typecheck, tests. Fail fast, before any image exists.
- Build. One image, tagged with the commit SHA, pushed to the registry.
- Stage. Deploy to staging automatically, run smoke checks against the health endpoint.
- Promote. Deploy the same image to production, automatically or behind a one click approval depending on the team's appetite.
In GitHub Actions this is one workflow file with four jobs and about eighty lines. The whole point is that nobody thinks about it after week one. Deploys stop being events and become side effects of merging good code.
Principle 4: Health checks are the contract with your infrastructure
Every service exposes a health endpoint that checks itself and its critical dependencies: database reachable, queue reachable. The deploy script, orchestrator or load balancer refuses to switch traffic until it passes.
This single convention prevents the most common outage class I see: the deploy succeeded but the app cannot reach the database, and now the whole site is an error page that "deployed successfully". With the health gate, that scenario ends as a failed deploy and a Slack message instead of an incident.
Principle 5: Rollback is a pointer move, not a war room
Because every image is tagged by commit, rolling back is redeploying the previous tag. Seconds. Practice it once on a calm Tuesday: deploy, roll back, confirm, so the first real rollback is muscle memory instead of improvisation. Teams that have rehearsed rollback ship more bravely, which compounds into shipping more often.
Principle 6: Configuration lives in the environment
Images are identical everywhere; behavior comes from environment variables. Secrets live in the platform's secret store, never in the repo and never baked into images. The test: if you cannot rotate a credential without rebuilding, it is stored in the wrong place.
What about zero downtime and scaling?
For most small products: two containers behind a load balancer, or your cloud's container service, or even a modest VPS with Docker Compose and a reverse proxy. Start the new container, health check it, drain the old one. That is zero downtime deployment without a single YAML file about pod affinity.
Kubernetes earns its complexity at a scale most products have not reached and may never need. Adopting it early does not make you ready for scale; it makes you slow before scale arrives.
The payoff
Consistency is not glamorous. It is just the difference between shipping calmly on a Friday afternoon and having a "never deploy on Fridays" rule, which is really a confession about your pipeline. Every commit deployable, every deploy reversible, every environment identical. Everything else is optional.
Want this pipeline set up for your product? It is a one week engagement. Contact me.
Need this built?
These services can turn the ideas in this article into production software.

