How to Do Blue/Green Deployments with Envoy EDS and Drain an Upstream Endpoint via API
For a blue/green release behind Envoy, put the blue servers and the green servers in two separate endpoints resources (EDS ClusterLoadAssignments) and point the EDS cluster at one of them through eds_cluster_config.service_name. Elchi's cluster endpoints switch rewrites that one field and pushes every listener that uses the cluster; Envoy builds and warms the changed cluster while the old one keeps serving, then swaps them. To take one upstream server out of rotation instead, the endpoint disable marks that IP or hostname as DRAINING everywhere it is used in the project, so Envoy sends it no new requests. Both are available in the UI and through the public automation API with a project API token.
When you need this
- You release a new version of a backend on new servers and want to move traffic to them at once, with a fast way back.
- A release pipeline should make the switch, check the result and switch back without a person in the UI.
- You need to patch or reboot one upstream server and want Envoy to stop sending it requests first, wherever it is configured.
Steps: blue/green switch
-
Prepare two endpoints resources. Create
backend-blueandbackend-greenas endpoints resources in the same Envoy version. Each resource's owncluster_namemust equal its name. -
Use an EDS cluster. The cluster must be of type
EDSand name the current resource ineds_cluster_config.service_name. STATIC and DNS clusters carry their endpoints themselves and cannot be switched. -
Create an API token. In Settings → Tokens, create a project API token with
clusters:readandclusters:write.GET /api/public/v1/tokenreturns the project ID, andGET /api/public/v1/projects/{project}/versionslists the Envoy versions. -
Preview the switch. Send the switch with
"dry_run": trueto see the endpoints before and after, the listeners that will be pushed, and any warnings:curl -sS -X POST \-H "Authorization: Bearer $ELCHI_TOKEN" -H "Content-Type: application/json" \https://elchi.example.com/api/public/v1/projects/$P/clusters/payments/switch-endpoints \-d '{"version": "v1.40.2", "to": "backend-green", "from": "backend-blue", "dry_run": true}' -
Switch. Send the same request without
dry_run, with anIdempotency-Keyheader and optionallyPrefer: wait=60to wait for the push. Sendingfrommakes the switch fail with409 from_mismatchif the cluster no longer uses the resource you expect, so two releases never overwrite each other. A202answer carries an operation you can follow withGET /api/public/v1/projects/{project}/operations/{operation_id}. -
Switch back if needed. Send the switch again with
toandfromreversed. In the UI, Operations → Cluster Endpoints offers Switch back with the last origin preselected.
A switch is for one Envoy version; switch each version you serve.
Steps: drain one upstream endpoint
- Create a token with
endpoints:readandendpoints:write. - Preview the disable.
POST /api/public/v1/projects/{project}/endpoints/10.0.1.5/disablewith{"dry_run": true}lists every place the address is used, the listeners that will be pushed, andempty_clusters: clusters the disable leaves with no endpoint to balance to. - Disable. Send it without
dry_run, with areasonand optionallyports(no ports means every port of the address). - Enable it again with
POST …/endpoints/10.0.1.5/enableafter the maintenance.
The same operations are on Operations → Endpoint Control in the UI.
How it works
Switch. Only service_name changes in the stored cluster; eds_config and every other field stay as they are, and the listener's publish history records the cluster as changed. To Envoy, a cluster whose service_name changed is a modified cluster: Envoy builds the new one and waits for its endpoints while the old one keeps serving, swaps them, and the old connections finish the requests they carry. Because the new cluster subscribes only to the new name, a target that is missing or holds no endpoint would leave it with zero hosts and answer 503. Elchi therefore refuses such a switch before writing anything (not_eds_cluster, no_service_name, target_name_mismatch, target_has_no_endpoints, or 422 when the target does not exist). In Elchi's end-to-end test suite, switching blue to green and back under 20 requests per second dropped 0 requests.
Disable. The disable is an overlay applied when the control plane builds a snapshot: every matching lb_endpoint, in EDS endpoints resources and in the load_assignment of STATIC, STRICT_DNS and LOGICAL_DNS clusters, is served with health_status: DRAINING. Envoy sends a draining host no new requests, open connections end on their own, and active health checks do not bring it back. The stored resources never change, so editing and publishing them keeps the endpoint disabled. If you disable every endpoint of a cluster, Envoy enters panic mode and keeps sending traffic to them unless the cluster sets common_lb_config.healthy_panic_threshold: 0 or zone_aware_lb_config.fail_traffic_on_panic: true; the preview reports which. A cluster carried in a bootstrap's static_resources is not reached.
Both operations refuse to run with 409 pending_unpublished_changes when the affected listeners have saved but unpublished changes, unless you send allow_pending_changes.
Related docs
- Clusters (blue/green switch) - the switch API, refusals, preview and history.
- Endpoints (disable and enable) - the disable API, matching rules and limits.
- Cluster Endpoints - the switch in the UI.
- Endpoint Control - the disable in the UI.
- Automation API overview - base URL, conventions and long-running operations.
- API tokens - scopes and revocation.
- Errors - every problem+json code.