fivenines
31/40

Guided Problem

MiniDock Build 26: Resolve Live Names Without Leaking Them

Time
25m
Level
intermediate
Artifacts
not specified
Progress0%
Lesson 31 · Networking

DNS and Service Discovery

Design claim: Service discovery should resolve stable network-scoped names to current endpoints rather than expose container lifetimes.

Starting model

  • You can expose one private service endpoint without changing what the external client sees.
  • The useful vocabulary at this point is deliberately small: embedded DNS, service name, network scope, live endpoint.

Stable intent meets replaceable endpoints

A route worker must reach the current cache instance after replacements without learning or storing its changing address. Connectivity is a set of scoped attachments, routes, and names, not an intrinsic property of a container record.

The tempting shortcut is straightforward: write container IP addresses into application configuration. The shortcut works only while addresses are static and every participant shares one host or trust zone. Container endpoints are allocated and released dynamically, and the same name may resolve differently across isolated networks. Endpoint churn, isolation, or a second host exposes the missing scope and ownership information.

Derive names from live membership

The engine maintains network-scoped name records derived from live endpoint membership and answers queries through an embedded resolver. The mechanism separates membership from packet movement so drivers can implement the same connection contract at different boundaries.

Read the topology by following an endpoint from its sandbox through the selected network boundary, keeping control information separate from packet flow.

Architecture — the embedded resolver's two paths
  flowchart LR
    APP["app in sandbox
resolv.conf → 127.0.0.11"] --> EDNS["embedded DNS
(engine-served)"] EDNS -- "name on a shared network?" --> TBL[("engine's live tables
db → 172.19.0.3")] EDNS -- "unknown name" --> UP["upstream DNS
(host's resolvers)"] TBL --> A1["answer: container IP"] UP --> A2["answer: internet IP"]

It places an embedded resolver between network-scoped names and current endpoints. Its central claim is that name resolution reflects current membership within the caller's network scope; the labels therefore describe authority rather than decorative grouping.

Register on join, forget on leave

Dynamic IPs are only a problem if anything remembers them. The fix: make the engine the authority for names. Each sandbox's /etc/resolv.conf points at 127.0.0.11 — an address the engine intercepts and serves itself, backed by its live container tables. Resolution is scoped: a lookup for db answers only if a container named db (or carrying that network alias) shares a network with the asker — the same segmentation from Lesson 28, extended to names. Anything unknown (like example.com) is forwarded to real upstream DNS. Because answers come from live state, recreating db with a new IP updates the answer instantly; nothing anywhere holds a stale address.

Endpoint join registers names, a sandbox query is answered within its network scope, and leave removes the stale address before reuse. Trace both the forward and cleanup paths; connectivity is correct only when allocation and removal agree about ownership.

The second figure tests the same model in motion: it traces registration, query, replacement, withdrawal, and fresh resolution.

Sequence — internal and external lookups
  sequenceDiagram
    participant A as app (in web's sandbox)
    participant D as embedded DNS (127.0.0.11)
    participant T as engine tables
    participant U as upstream DNS
    A->>D: resolve "db"
    D->>T: container "db" on a network shared with web?
    T-->>D: yes — 172.19.0.3
    D-->>A: 172.19.0.3 (fresh from live state)
    A->>D: resolve "api.stripe.com"
    D->>U: forward
    U-->>D: 54.187.x.x
    D-->>A: 54.187.x.x
      

It traces registration, query, replacement, withdrawal, and fresh resolution. The ordering is valid only when it continues to preserve the stated invariant under retries and interruption.

Freshness and scope are part of the answer

A cache container is replaced, so the old address must stop resolving and the new endpoint must become discoverable without leaking across networks. A stale or conflicting attachment must be refused or withdrawn locally rather than corrupting unrelated network state.

Name resolution reflects current membership within the caller's network scope. The rule binds reachability to explicit, current membership within the correct scope.

Give MiniDock live service names

MiniDock lets ParcelFlow depend on service names while keeping endpoint churn inside the network control plane. MiniDock now needs that connectivity property without being told which component to edit.

What carries forward

  • Name resolution reflects current membership within the caller's network scope.
  • Keep service discovery current and prevent private names from leaking across network boundaries.
  • The rejected shortcut remains a diagnostic: if the design starts depending on it again, the original constraint has probably been lost.
Next step

See what actually stuck.

Take the practice scenarios now.