Skip to main content

Serve a project from two data planes

Enterprise Tier

From 0.7.0 two data planes in one organization can declare the same hostname, and a platform administrator can label both with the same project. Each data plane then serves the project's configuration on that name, and customer-managed DNS or a global server load balancer moves callers between them. Agent Router ships no traffic steering: the DNS name, the health checks, and the failover policy stay the operator's.


Persona: Platform operator working in the Admin Console, the data planes' Helm values, and the organization's DNS provider (the examples use AWS Route 53).

Estimated time: 30 to 45 minutes for one pair, plus certificate issuance and DNS propagation.

Outcomes​

By the end of this guide:

  • Two data planes declare one client-facing hostname and each declares its own hostname for health checks.
  • Both data planes carry the project's project label and report it verified.
  • DNS fails callers over between the two data planes on the readiness probe, and developers are shown the client-facing name.

Prerequisites​

  • Two data planes on 0.7.0 or later, deployed and connected, typically in different regions or clusters. A data plane before 0.7.0 cannot declare hostnames.
  • The project created, with its models granted.
  • Control of the DNS zone that callers resolve, with health-checked failover or weighted records (Route 53 or an equivalent), and of the certificate each data plane's load balancer presents.

The running example uses project payments-assist, client-facing name ai.payments.examplebank.com, and two data planes:

Data planeOwn hostnameRegion
dp-prod-use1ai-use1.payments.examplebank.comus-east-1
dp-prod-usw2ai-usw2.payments.examplebank.comus-west-2

Step 1: declare both names on each data plane​

On each data plane, list the client-facing name first and the data plane's own name second. The console prints the first name wherever it shows a single address.

# dp-prod-use1 serve-helm values
global:
gateway:
hostnames:
- ai.payments.examplebank.com
- ai-use1.payments.examplebank.com
# dp-prod-usw2 serve-helm values
global:
gateway:
hostnames:
- ai.payments.examplebank.com
- ai-usw2.payments.examplebank.com

With tare, pass the same names as repeated --gateway-hostname flags to tare upgrade. The management plane records the shared name for both data planes, and the Admin Console lists both under it. Another organization cannot claim the same name.

Each data plane's own name gives the health checks in Step 4 a target that reaches that data plane and no other. The full rules for the list are in Declare the hostnames a data plane serves.

Step 2: cover both names with each certificate​

Callers dial the client-facing name and land on either data plane, and the health checks dial each data plane's own name. The certificate each load balancer presents must therefore cover two names:

Load balancerNames the certificate must cover
In front of dp-prod-use1ai.payments.examplebank.com, ai-use1.payments.examplebank.com
In front of dp-prod-usw2ai.payments.examplebank.com, ai-usw2.payments.examplebank.com

A wildcard on *.payments.examplebank.com covers both. Otherwise request one certificate per region with both names as subject alternative names. Where the load balancer routes by host, add a rule for each name on each side, or a failed-over caller gets no route.

Route 53 health checks do not validate the certificate, and in steady state callers only reach the primary. A secondary missing the client-facing name looks healthy until the first failover. Check both sides before relying on the pair:

tare doctor /path/to/dp-prod-usw2-credentials.json --only gateway

tare doctor warns for a declared name the certificate does not cover. The Admin Console shows the same reading beside each name on the data plane's page.

Step 3: label both data planes with the project​

  1. In the Admin Console, open Directory → Data Planes and select dp-prod-use1.
  2. In Project labels, add payments-assist.
  3. Repeat for dp-prod-usw2.

Each label shows three steps: label applied, config pulled (the revision the data plane holds and the one it picks up next), and verified (when the data plane first answered a request for that project). A data plane is a safe failover target once its label reads verified. The project's Data Planes tab shows the same progress per data plane.

The same labels can be applied with AddDataplaneProject (POST /admin/v1/customers/{customer_id}/dataplanes/{dataplane_id}/projects). Both data planes receive the identical project configuration: API keys, model access, MCP access, and guardrails behave the same on either side once both hold the current revision.

Step 4: health-check each data plane​

Create one HTTPS health check per data plane, on its own name:

  1. In Route 53, create an HTTPS health check with domain ai-use1.payments.examplebank.com, port 443, and path /healthz/membership.
  2. Require a 2xx status, and turn on string matching for "status":"ready".
  3. Use the fast interval (10 seconds) and a failure threshold of 3. Expect roughly 30 seconds to mark a data plane unhealthy, plus the record TTL for callers to move.
  4. Repeat for ai-usw2.payments.examplebank.com.

/healthz/membership carries the readiness answer on every deployment. Bare /healthz carries the same answer only once global.publishHealthzContract is set on the data plane; before that it answers a host-blind liveness 200 with {"status":"ok"}, which the string match rejects. A green answer is:

curl -s https://ai-use1.payments.examplebank.com/healthz/membership
{"status":"ready","dataplane":"dp-prod-use1"}

Never health-check the client-facing name: the check would follow the failover itself and observe nothing about either data plane. The probe answers on port 443 only.

Step 5: create the failover records​

  1. Create a record ai.payments.examplebank.com pointing at dp-prod-use1's load balancer, routing policy Failover, type Primary, associated with the ai-use1 health check.
  2. Create a second record ai.payments.examplebank.com pointing at dp-prod-usw2's load balancer, routing policy Failover, type Secondary, associated with the ai-usw2 health check.
  3. Keep the TTL short, 30 to 60 seconds. The TTL usually decides how fast callers move.

Active/active is the same shape with Weighted records, one per data plane, each with its health check.

Step 6: show developers the client-facing name​

The Developer Console lists every endpoint serving the project, so it lists ai.payments.examplebank.com and each data plane's own name. An application that hardcodes one data plane's own name does not fail over. Point developers at the shared name in one of two ways:

  • A project owner stars ai.payments.examplebank.com on the project's Data Planes tab. The console then prints it as the Base URL on the getting-started card, beside a new key, and on the model catalog bar. This is the preferred endpoint.
  • A platform administrator sets the project endpoint URL to https://ai.payments.examplebank.com through the admin API (public_endpoint_url on PATCH /admin/v1/customers/{customer_id}/projects/{project_id}). The console prints it in place of any star and offers no star while it is set. Agent Router displays this URL and never routes on it.

What the probe tells DNS on 0.7.0​

On a data plane on 0.7.0 or later the readiness probe answers for the whole data plane on every hostname it declares, not for one project on it:

Data plane stateProbe
Declaring the name, carrying no projects200 green
Carrying one or more projects200 green
One project's label removed, others still served200 green
Declaring an empty list404 red
Gateway or listener downRed (connection failure)
Partitioned from the management plane but reachable by callers200 green

Removing the project's label from a data plane therefore does not take its address out of DNS. Drain first:

  1. Remove the data plane's record from the failover set, or set its weight to zero, and wait out the TTL.
  2. Check request logs filtered by that data plane until its count for the project falls to zero.
  3. Remove the label in Project labels. Removing the last label serving a project is refused unless the removal acknowledges that the project will be served nowhere.

To take a data plane out of rotation for every project at once, declare an empty list on it, which turns its probe red on the next reconcile.

Rate limits are per data plane​

Each data plane counts only the traffic it sees. A project served from two data planes admits up to twice its configured token ceiling across the pair, and a caller that fails over meets a counter that has never seen it. Size per-key limits with the number of data planes in mind, and tell application teams that a failover resets their rate-limit window. Budgets are different: the management plane evaluates them against spend from every data plane.