Global Discovery Service Registration Storage
Experimental. The Global Discovery Service keeps the registrations that Pool Relays
send with POST /pools, with every --pool-discovery value. With registrations, it lists the
registered pools. With karmada or mcs, it joins them with the EndpointSlices that Multi-Cluster
Services imports. The registration store decides where those registrations live, and each store works
in every mode. This page explains when to use each store, how to set up DynamoDB, and how to run and
verify the service. For every flag and endpoint, see
Global Discovery Service Configuration.
Choose a store
Use memory for a single-replica development or lab deployment. Use dynamodb when the service must
survive restarts without a gap in the pool list, run more than one replica, or span AWS regions.
Create the table
The table has a string partition key pk and a string sort key sk, on-demand billing, and a TTL
attribute named expires_at. Create it once per account and region:
TTL removes registrations that nobody has renewed for seven days. It is garbage collection only; it never decides whether a pool is live. Point-in-time recovery is optional but recommended.
Add regions with a Global Table
To serve several regions, add a replica of the table in each one. Run this after the table is active:
Repeat with another RegionName for each region. Enable point-in-time recovery in each region
separately. Replicas in each region point at their regional endpoint with --dynamodb-region. A Global
Table resolves concurrent writes to one item by last writer wins on the whole item, which matches how
the service treats registrations: whichever copy wins is a complete registration.
DynamoDB copies each write to the other regions in the background, usually within a second, but the
copying can fall behind. A service replica would then see an old renewal for a pool that still
heartbeats in another region, and drop it as expired. So each item records the region it was written
through, and a pool written through another region stays listed for --dynamodb-replication-grace-secs
(default 60) after its lease, with complete: false in GET /pools meanwhile. Raise it if replication
in your setup can fall behind further than that; the cost is that a pool that really stopped in another
region stays listed that much longer.
Grant access
The service needs three actions on the table ARN, and the same in every replica region:
Add dynamodb:CreateTable, dynamodb:DescribeTimeToLive, and dynamodb:UpdateTimeToLive only for a
development deployment that uses --dynamodb-ensure-table.
The service reads credentials from the AWS SDK default chain. On EKS, attach the policy to an IAM role and give the Pod’s ServiceAccount access to it.
With IAM Roles for Service Accounts (IRSA), annotate the ServiceAccount with the role ARN:
With EKS Pod Identity, create an association instead and leave the ServiceAccount unannotated:
Run the service
Add the DynamoDB flags to the container arguments. Two replicas share one table:
POST /pools takes a registration from any caller that can reach the service, and any caller may
overwrite any pool. Keep the service on a trusted network. A ClusterIP Service limits reachability
to inside the cluster but does not authenticate callers. --tls-cert-path and
--tls-key-path encrypt the traffic (see
Global Discovery Service Configuration).
With Karmada, the DynamoDB flags stay the same. The router Service’s flags replace --router, and the
service joins the registrations with the pools that Karmada imports:
Start from container/global-discovery-service.yaml,
which grants the EndpointSlice access this mode needs, and give its ServiceAccount the IAM role above.
With --pool-discovery mcs, only that flag changes.
At startup, the service checks that the table exists (DescribeTable), that it can read the table (a
Query of one item), and that it can write it (an UpdateItem whose condition never holds, so nothing
is written). While a check fails, for example during a DynamoDB outage, before the table is created, or
while the role lacks one of the three actions, the service logs why, names the table, and tries again
after a backoff of up to 30 seconds. It serves nothing until every check passes, so the Pod stays unready
rather than restarting. A missing AWS region stops the service at once.
Each replica then reads the table every --dynamodb-poll-interval-secs (default 2) and answers
GET /pools from what it read, so a request costs no read of its own, and a pool registered through
another replica shows within that interval. The poll interval plus --heartbeat-interval-secs must be
less than --lease-duration-secs plus --lease-skew-secs, so that every renewal shows before its lease
runs out, or the service refuses to start.
Local development
For development, run DynamoDB Local and let the service create the table:
With Karmada, keep these DynamoDB flags and use the Karmada flags from the example above in place of
--pool-discovery=registrations.
--dynamodb-ensure-table creates the table if it is missing and turns on TTL if it is off, on every
start, without point-in-time recovery or replicas. Without the TTL permissions, it logs a warning and
starts anyway. Do not use it in production.
How leases and expiry work
A registration is stored with the time it was renewed and the lease the accepting replica granted.
Replicas decide whether a pool is live when they read it, not when it is written: a pool is live while
renewed_at + lease + skew has not passed on the reading replica’s clock. Nothing in the table is
removed when a lease lapses, so a pool that resumes heartbeating reappears without any repair.
--lease-skew-secs (default 2) adds slack for clock differences between replicas. Raise it if your
nodes’ clocks drift further than that. Without it, a replica with a fast clock hides a pool slightly
early. The effect is only a pool appearing or disappearing a moment sooner or later on one replica.
Each item stores the lease its writer granted, so replicas configured with different
--lease-duration-secs values still judge each pool by the lease it was given.
With a Global Table, a pool written through another region’s replica stays listed for
--dynamodb-replication-grace-secs past its lease, as described in
Add regions with a Global Table.
Verify
Port-forward to a replica and list the pools:
With a registered Pool Relay, the response lists the pool, even right after a restart. complete is
false for one lease after the Pod starts, and true after that:
Query another replica, or delete a Pod, and the same pools appear. With --pool-discovery registrations,
relay_identities is empty because registrations do not carry relay identities. With karmada or
mcs, MCS supplies them, and a pool is listed only while MCS also imports a Ready Pool Relay for it.
GET /healthz is for readiness. Until the startup check has passed, nothing listens, so the probe
fails and the Pod stays out of the Service. After that, GET /healthz returns 200 without calling
DynamoDB. A DynamoDB outage then shows in the answers to requests instead, so it does not take every
replica out of the Service at once:
POST /poolsreturns 503, and Pool Relays register again on their next heartbeat.GET /poolskeeps answering from the last read of the table, withcomplete: false, and drops each pool whose lease lapses, since no Pool Relay can renew meanwhile.- After the table is back,
completestaysfalsefor one more lease, until every Pool Relay has registered again.
Operate
- Replicas. Put any number of replicas behind one Kubernetes Service. Any replica accepts
POST /poolsand any replica answersGET /pools. A pool registered through one replica shows on the others at their next read of the table, within--dynamodb-poll-interval-secs. - Rolling restarts. Nothing special is needed. A new replica lists every live pool at once, with
complete: falsefor one lease, and Pool Relays keep heartbeating through the Service. - Moving to DynamoDB, or to another table. During a rolling update, old and new replicas keep
different registrations, and each Pool Relay keeps registering with the replica it is connected to. A
new replica reports
complete: falsefor only one lease, so replace all replicas at once (strategy: Recreate). Every Pool Relay then registers with the new table within one heartbeat. - Throttling and outages. A failed DynamoDB call returns 503 from the endpoint that made it, and
GET /poolsreportscomplete: falseuntil a lease after the table answers again (see Verify). A Pool Relay registers again on its next heartbeat. On-demand capacity absorbs the expected write rate, roughlypools x relay replicas / heartbeat interval, for example 80 writes per second for 200 pools with two relay replicas at a 5 second heartbeat. - Several Pool Relays for one pool. They must send the same registration: model, capabilities, capacity, location, and frontends, in any order. The last write wins, so if they differ, the pool’s listing switches between their versions at every heartbeat. The service logs a warning that names such a pool.
- Corrupt items. An item that cannot be decoded is logged and skipped. The rest of the list is served.
- Scale limit. All items share one partition key. That is sized for tens to hundreds of pools.