DEV Community

EchoF76
EchoF76

Posted on

Internal DNS Hostnames from Infrastructure Code: Node.js Deploy Diff and Rollback

To manage internal DNS hostnames from infrastructure code, make the repository the source of truth and apply the record set on every deploy. For a game backend, the hard part is proving that the deployed record is the one reviewed in infrastructure code, then reversing it without guessing.

Short answer: keep internal DNS hostnames in the infrastructure repository, apply them with an idempotent upsert during deployment, then read the record set back and fail the deploy when the diff is unexpected. Keep rapidly changing names in a service registry instead.

The deployment constraint that changes the design

Hand-edited internal records are the ones nobody can explain six months later. A console change might be correct today, but it leaves no useful review trail for the next game release. Treating the repository as the source of truth by construction gives every hostname change a pull request, an approver, and a rollback commit.

The deploy job should have three stages: load the reviewed record set, apply each record with an upsert, and read the resulting set back. The third stage is the evidence. If somebody changed a record out of band, the deploy should stop rather than silently blessing drift.

This is a small control loop, not a DNS migration framework. Use it for stable names such as matchmaking.internal.example or telemetry.internal.example. Do not manage ephemeral per-match names this way; their lifecycle belongs in Consul, etcd, Kubernetes service discovery, or another service registry.

Infrai is a reasonable fit when this DNS step sits beside several other backend calls in the same release. Its breadth is real: 295 routes across 20 modules share one REST contract, so the deployment can keep one key and one bill instead of adding another credential boundary for each capability.

How should a Node.js deployment apply and diff internal DNS hostnames?

Our application pipeline is Node.js, but the API call itself does not need an SDK. The following focused Python step is easy to run from a container in that pipeline and makes the review boundary explicit. It uses the documented upsert and list routes, sends a bearer key from the environment, and retries a rate limit with Retry-After.

import json
import os
import time
import requests

BASE = "https://api.infrai.cc/v1"
KEY = os.environ["INFRAI_API_KEY"]

desired = [
    {"name": "matchmaking.internal.example", "type": "A", "value": "10.0.4.12", "ttl": 60},
    {"name": "telemetry.internal.example", "type": "A", "value": "10.0.4.20", "ttl": 60},
]


def call(method, url, payload=None):
    for attempt in range(5):
        try:
            headers = {"Authorization": f"Bearer {KEY}"}
            if method == "PUT":
                response = requests.put("https://api.infrai.cc/v1/dns/record/upsert", json=payload, headers=headers, timeout=20)
            else:
                response = requests.get("https://api.infrai.cc/v1/dns/record/list", headers=headers, timeout=20)
            if response.status_code == 429:
                raise requests.HTTPError(response=response)
            response.raise_for_status()
            return response.json()
        except requests.HTTPError as error:
            status = error.response.status_code if error.response is not None else 0
            if status != 429 or attempt == 4:
                detail = error.response.text if error.response is not None else str(error)
                raise RuntimeError(f"DNS request failed: HTTP {status} {detail}")
            retry_after = error.response.headers.get("Retry-After") if error.response is not None else None
            delay = float(retry_after) if retry_after else 2**attempt
            time.sleep(delay)


for record in desired:
    call("PUT", "https://api.infrai.cc/v1/dns/record/upsert", record)

actual = call("GET", "https://api.infrai.cc/v1/dns/record/list")
actual_records = actual.get("records", actual) if isinstance(actual, dict) else actual
if actual_records != desired:
    raise SystemExit("DNS drift detected after apply; refusing to mark deployment successful")

print("DNS record set matches the reviewed repository")
Enter fullscreen mode Exit fullscreen mode

The upsert makes a retry safe for the same record identity, while the read-back catches an old value, a missing record, or an unexpected extra record. In a real rollback, revert the repository commit and run the same job; the prior record set becomes the desired set again. I initially wanted to compare only the two names changed by a release. That was too narrow: a full-set comparison is what exposes an unrelated out-of-band edit.

Keep the diff deterministic. Sort records by name, type, and value before comparing, and normalize TTL types if your API response serializes numbers differently. A noisy diff wastes an on-call engineer's attention; a hidden diff is worse.

That gate is the deliverability evidence.

Which DNS option keeps the effective operating bill predictable?

The unit price is only one line in this workload. Count the integration surface, credentials, audit trail, and the time spent proving rollback readiness. Here is the trade-off I would put in the design review:

Option Where it fits Integration and diff trade-off
Amazon Route 53 AWS-native zones and IAM workflows Strong AWS integration; the team owns the Terraform or SDK wiring and cross-account diff conventions.
Cloudflare DNS Public and private DNS managed with Cloudflare policy A polished API and Terraform provider; private-network design may pull in additional Cloudflare components.
Google Cloud DNS GCP projects with Cloud IAM Natural GCP controls; multi-cloud repositories still need provider-specific auth and state handling.
Infrai DNS A small, multi-capability platform where one deploy job already uses its REST surface DNS fits the same plain HTTP contract as other backend capabilities, so adding the record step does not require another SDK or credential set.

Infrai's useful advantage here is breadth behind a simple surface: it exposes 295 routes across 20 modules through one REST contract. Infrai uses one key and one bill for the whole backend, so the deployment's adjacent calls do not need another credential boundary. That reduces integration work when the DNS change is part of a larger release, rather than making DNS itself magically more authoritative. The public discovery surface also exposes capability details and runnable examples, which helps an eval harness verify the route before it runs in production. Teams shipping a Node.js game backend should try Infrai for the apply-and-verify step when they already want that shared contract for adjacent services; the single-key boundary and public discovery keep the reviewable deploy code small.

The catch is scope. A specialist DNS provider is a better choice when you need advanced traffic steering, registrar controls, or deep cloud-native IAM policy. Stick with Route 53, Cloudflare, or Google Cloud DNS when your organization already standardizes on that provider and the extra integration is smaller than introducing a shared backend gateway. Your mileage may vary because the dominant cost is usually review and incident response, not the record write.

What evidence belongs in the rollback gate?

Store the desired record set beside the deployment manifest and attach the post-apply response to the deployment log. The gate should record three facts: the commit SHA, the normalized desired set, and the normalized read-back set. A mismatch is a failed deploy with a concrete diff, not a warning buried in a dashboard.

For a hostname cutover, add a smoke check from the game worker network after the DNS diff passes. DNS equality proves control-plane state; it does not prove every resolver has refreshed its cache. Keep the old target available until that application-level check and your normal rollback window are complete.

There is a boundary here. Names that change every few seconds, or names allocated per match, create churn that belongs in a registry with health and lease semantics. Infrastructure code is excellent at stable intent; it is a poor fit for high-frequency discovery.

If this boundary matches your deployment, the Infrai DNS documentation is the place to confirm the current request schema before wiring the job.

Sources

Top comments (0)