Prerequisites
- Your proxy runs as a Kubernetes Deployment managed by the controller (via
networkTemplate) - Your proxy can make gRPC calls to the controller’s network xDS server
How it works
When a Gateway listener is reconciled, the controller:- Creates a Deployment and Service for your proxy using the image and configuration from
networkTemplate. - Injects environment variables your proxy uses to identify itself to the xDS server.
- Keeps a snapshot of all routes and backends for that listener up to date.
NetworkXDS.GetSnapshot with an infinite timer to retrieve its snapshot, then uses the snapshot to make routing decisions.
Environment variables
The controller injects these environment variables into every network proxy container:| Variable | Description |
|---|---|
NAMESPACE | Kubernetes namespace of the Gateway |
GATEWAY_NAME | Name of the Gateway |
LISTENER_NAME | Name of the listener this proxy serves |
GATEWAY_NETWORK_XDS_HOST | Hostname of the NetworkXDS gRPC server |
GATEWAY_NETWORK_XDS_PORT | Port of the NetworkXDS gRPC server (default: 19000) |
The NetworkXDS API
The API is defined as a single unary RPC:NAMESPACE, GATEWAY_NAME, LISTENER_NAME) as the request fields.
The server returns UNAVAILABLE if no snapshot has been built yet and NOT_FOUND if the gateway/listener combination does not exist.
The Snapshot message
current_generation is an opaque string that changes whenever the snapshot changes. Poll the endpoint periodically and re-apply configuration when the generation changes.
ManagedService
ManagedService represents a Kubernetes Service that was discovered as a backend. servers lists the live endpoints; routes lists the join and fallback rules that point to this service.
ManagedServer
max_players and current_players are populated when the controller can read them from the game server. Use them together with distribution_strategy to implement LEAST_PLAYERS routing.
Route
is_join = true) route a player’s initial connection. Fallback routes (is_fallback = true) activate when a primary backend is unavailable. Evaluate routes in descending priority order.
Routing algorithm
A minimal correct implementation:- On connect: find all join routes across all services whose
rulesmatch the player (domain, permission). Take the highest-priority match. Select a server from that service usingdistribution_strategy. - On failure: if the selected server is unavailable or full, find fallback routes whose
fallback_formatches the failed service’snamespaced_nameand whose other rules match the player. Take the highest-priority match. - Generation polling: re-fetch the snapshot when
current_generationchanges. Apply the new routing table without disconnecting existing players.
Deploying your proxy
UsenetworkTemplate in NetworkInfrastructure to deploy your proxy image:
networkTemplate options such as mounting secrets and setting resource limits.
Using the Java integration-api
If you are writing a JVM-based proxy plugin, theintegration-api library wraps the raw gRPC API and handles polling, diffing, and retries for you. The Velocity built-in integration is implemented using it.
Add the dependency
VERSION with the latest version from Maven Central.
Implement ServerRegistrar
ServerRegistrar is called by the API whenever backend servers appear, update, or disappear in the snapshot. Use server.name() as the stable key in your proxy’s server registry.
ServerRegistrarException to signal a failure for a single server. The library retries failed servers up to retries times (default: 3), once per poll interval.
Implement NetworkPlayer
NetworkPlayer is a per-event wrapper. Create a new instance for each routing call.
connectedServer() must look up the player’s current server through your registrar’s internal map. The fallback routing rules match on parentNamespacedName, which is only available on ManagedServer objects tracked by the registrar — not raw proxy server objects.
Build and start NetworkGateway
Build one NetworkGateway at proxy startup. The builder reads the injected environment variables automatically.
Wire routing events
routeJoin evaluates MinecraftJoinRoute rules in priority order and calls player.connectToServer() on the first match. routeFallback evaluates MinecraftFallbackRoute rules. Both call player.kick() if no matching service is found.
ManagedServer field reference
| Method | Type | Description |
|---|---|---|
name() | String | Stable server name — use as the key in your proxy registry |
ipAddress() | String | IP address to connect to |
port() | int | Port to connect to |
uniqueId() | String | Globally unique identifier for this server instance |
parentNamespacedName() | String | "namespace/service-name" of the Kubernetes Service |
numericalId() | OptionalInt | Optional numerical slot ID |
maxPlayers() | OptionalInt | Configured player capacity |
currentPlayers() | OptionalInt | Current player count (used by least-players distribution strategy) |
NetworkGateway.Builder options
| Method | Default | Description |
|---|---|---|
registrar(ServerRegistrar) | — (required) | Your ServerRegistrar implementation |
intervalSeconds(int) | 5 | How often to poll the xDS server for snapshot updates |
retries(int) | 3 | Retry attempts for failed registerOrUpdate/unregister calls |
context(NetworkSnapshotContext) | from env | Which gateway/listener to subscribe to |
channel(Channel) | from env | gRPC channel to the xDS server |