Canary releases are usually described as a Kubernetes feature, which is a shame, because the idea is older and simpler than Kubernetes: send a small share of real traffic to the new version, watch it, then send the rest. All it needs is two copies of the application and something that splits traffic by percentage. This post follows a release engineer doing exactly that on MassiveGRID PaaS, which is built on Virtuozzo Application Platform, formerly Jelastic, with the Traffic Distributor add-on.
The engineer works on a subscription-box e-commerce site for a company we will call Marigold Crate, a PHP application on a load-balanced environment with a MariaDB cluster. The Traffic Distributor add-on installs two NGINX nodes with a shared entry point that route HTTP and HTTPS traffic between two backend environments according to a percentage you set, with health checks and three routing methods.
The mechanism, in one paragraph
Traffic Distributor is its own small environment: two NGINX load balancer nodes for redundancy, an entry point that is either a public IP or the shared load balancer, and an add-on that writes the NGINX configuration from a form. You give it two backends by hostname, a traffic ratio such as 95 to 5, and a routing method: Round Robin (each request goes to a backend by weight; the backends must serve identical content), Sticky Sessions (each user is pinned to a backend by cookie for their session), or Failover (all traffic to the primary, the secondary only if the primary fails its health check). The health check polls both backends for a 200 response on a configurable interval and drops a failing backend from rotation. Changing the ratio is a form edit and an NGINX reload, live.
Setting it up in front of production without an outage
Marigold's production environment already had a public IP and its domain. The engineer's sequence, following the platform's guide for injecting a distributor in front of a running project: install Traffic Distributor with production as backend one at 100% and, for now, production again as backend two at 0%; give the distributor a public IP; test it on its own platform subdomain; then move the domain's A record to the distributor's IP and let DNS propagate. Production kept serving throughout, first directly and then through the distributor. The Let's Encrypt add-on on the distributor terminates TLS for the domain; the backends are reached over the internal network.
A canary release, step by step
Release day for a redesigned checkout. The engineer clones production; the clone is the canary environment, pointed at the same MariaDB cluster over the internal network because this release has no schema change, and deploys the new build to it. Then:
| Time | Ratio (production : canary) | Routing | What was watched |
|---|---|---|---|
| 10:00 | 100 : 0 | Sticky Sessions | Canary health check green on its own URL |
| 10:05 | 95 : 5 | Sticky Sessions | Canary error rate, checkout conversion, page timing |
| 10:35 | 75 : 25 | Sticky Sessions | Same, plus database load from the new queries |
| 11:15 | 0 : 100 | Sticky Sessions | Everything, with production now idle |
| 11:30 | Production redeployed with the new build | Sequential deploy behind the balancer | |
| 12:00 | 50 : 50 | Round Robin | Two identical environments, doubled capacity |
Sticky Sessions during the canary is not optional: with two different versions live, a shopper who bounced between them mid-checkout would see two different checkouts. Stickiness pins each user to one backend for their session. Once both environments run the same build, the engineer switches to Round Robin and keeps both in rotation, which is the platform's pattern for using the distributor as a permanent high-availability pair across different hardware.
Rollback at any step was the ratio slider back to 100 : 0. The engineer did not need it this time; the previous quarter she had, at the 25% step, when a payment-provider callback misbehaved on the new version, and rolling back took the fifteen seconds it takes to edit a form.
An A/B test, which is the same tool with a different question
The marketing team wanted to test a new product-page layout for a fortnight. The distributor's documentation is explicit about how: two environments serving the two variants, Sticky Sessions so each visitor consistently sees one variant, and a 50 : 50 ratio for a fair sample; Round Robin must not be used, because a visitor would see both layouts across page loads. Conversion is measured by whatever the team already uses, in Marigold's case a tag on the order confirmation that records which variant the session saw. After two weeks the variant with the higher conversion became the production build and the other environment was redeployed to match.
The A/B environment is a clone that lives for a fortnight at production's size, so it costs roughly what production costs for that period. The team decided that a fortnight of doubled hosting was a cheap price for a layout decision worth a measurable share of revenue.
What this replaces, and what it does not
For a team of four with two environments, Traffic Distributor replaces a service mesh, an ingress controller with canary annotations and the operational surface that comes with them. It is free, it is NGINX, and its configuration files can be edited by hand for caching, SNI or TCP mapping if the form is not enough. What it does not do is route by header or user attribute out of the box, split more than two ways, or coordinate database schema changes between versions; those remain the application's problem, and for schema changes the engineer uses the blue-green pattern with a separate database copy described in this blog's WordPress cluster post.
Frequently Asked Questions
Can the two backends be in different regions?
Yes. Backends are addressed by hostname or IP, so one can be in London and one in Frankfurt, or one outside the platform entirely. Latency between the distributor and a remote backend adds to every request, so for canaries keep both backends near the distributor; for cross-region failover, see the companion post on Failover routing.
Does the health check understand my application?
It checks for a 200 response at a path you configure, on an interval and with thresholds you set. Point it at an application health endpoint that checks the database and dependencies, so a backend that is up but broken is removed from rotation rather than one that merely answers.
Is there a cost for the distributor itself?
The add-on is free. You pay for the two NGINX nodes' cloudlets, which are small, and for the public IP if you use one as the entry point rather than the shared load balancer.
Five percent first, then everyone
Install the free Traffic Distributor add-on on MassiveGRID PaaS, clone production as your canary and move a slider. Two NGINX nodes, health checks, sticky sessions and instant rollback, billed per cloudlet-hour. Free 14-day trial.
Traffic Distributor on MassiveGRID PaaS