discovery

package
v0.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2026 License: Apache-2.0 Imports: 19 Imported by: 0

README

Service Discovery Providers

AIBrix was originally built on Kubernetes, and service discovery was tightly coupled to K8s informers. This made it impossible to run the gateway in non-K8s environments (bare metal, Docker Compose, VM-based deployments). This package defines the Provider interface for pluggable service discovery in the AIBrix gateway. It decouples the routing layer from any specific infrastructure — Kubernetes, Consul, etcd, or static configuration can all serve as backends.

Interface

type EventHandler func(event WatchEvent)

type Provider interface {
    Watch(handler EventHandler, stopCh <-chan struct{}) error
    Type() string
}
Watch(handler EventHandler, stopCh <-chan struct{}) error

Registers a callback for resource changes and starts watching. The provider calls handler directly — there is no intermediate channel or buffer. This design allows K8s informers to invoke the handler on the informer goroutine without backpressure concerns.

  • StaticProvider: reads config, delivers all endpoints as EventAdd via the handler, returns. No ongoing changes.
  • KubernetesProvider: wires the handler directly into informer callbacks. Events (including the initial list phase) flow to the handler immediately. After WaitForCacheSync, does a post-sync reconcile to fix ordering, then returns. Informer callbacks continue invoking the handler for ongoing changes.
  • Consul/etcd providers: starts a watch/poll loop in a goroutine, calls handler from that goroutine.

Watch should return once the provider has reached a consistent ready state (e.g., initial sync complete, config loaded). This ensures the cache is warm before the gateway starts accepting traffic.

Type() string

Returns a string identifier for logging: "static", "kubernetes", "etcd", etc.

Existing Providers

StaticProvider (static.go)

Loads endpoints from a YAML config file. No dynamic updates.

Non-disaggregated config:

models:
  - name: "Qwen/Qwen2.5-1.5B-Instruct"
    endpoints:
      - "vllm-0:8000"
      - "vllm-1:8000"

Disaggregated (P/D) config:

models:
  - name: "Qwen/Qwen2.5-72B"
    engine: vllm
    rolesets:
      - name: default
        prefill:
          - "prefill-0:8000"
          - "prefill-1:8000"
        decode:
          - "decode-0:8000"

The rolesets structure expresses the pairing between prefill and decode workers. The PD routing algorithm selects the roleset first and then chooses the best prefill+decode pair within the same roleset. endpoints and rolesets are mutually exclusive per model.

KubernetesProvider (kubernetes.go)

Watches Pods and ModelAdapters via K8s informers. This is the default when no DiscoveryProvider is set in InitOptions.

The handler is wired directly into K8s informer callbacks — events flow from the start, including during the initial list phase. No intermediate channel, no buffer, no snapshot replay.

  1. Registers handler on Pod and ModelAdapter informers.
  2. Starts informers — initial objects arrive via AddFunc as part of the informer's list+watch.
  3. Waits for cache sync (WaitForCacheSync).
  4. Post-sync reconcile: re-emits all ModelAdapters as EventAdd to fix ordering (Pod and ModelAdapter informers list concurrently, so an adapter may arrive before its pods).
  5. Returns — informer callbacks continue delivering ongoing changes.

Architecture

                    ┌──────────────────┐
                    │  Provider        │
                    │  Interface       │
                    └────────┬─────────┘
                             │
              ┌──────────────┼──────────────┐
              │              │              │
    ┌─────────▼──┐  ┌───────▼────┐  ┌──────▼───────┐
    │ Static     │  │ Kubernetes │  │ Consul/etcd  │
    │ Provider   │  │ Provider   │  │ Provider     │
    │            │  │            │  │              │
    │ YAML file  │  │ Informers  │  │ Blocking     │
    │ → Load()   │  │ → Watch()  │  │ query / poll │
    └─────┬──────┘  └─────┬──────┘  └──────┬───────┘
          │               │                │
          │  synthetic *v1.Pod objects      │
          └───────────────┼────────────────┘
                          │
                          ▼
                ┌─────────────────┐
                │  Cache Store    │
                │  (metaPods,     │
                │   metaModels)   │
                └────────┬────────┘
                         │
                         ▼
                ┌─────────────────┐
                │  Routing        │
                │  Algorithms     │
                │  (unchanged)    │
                └─────────────────┘

All providers produce synthetic *v1.Pod objects. The cache store and routing algorithms are completely unaware of which discovery backend is in use.

Future Work

  • Consul/etcd providers — first-class support for non-K8s service discovery.
  • Platform-agnostic Endpoint type — replace *v1.Pod as the internal representation to remove the K8s dependency from routing algorithms.

Documentation

Overview

Package discovery provides service discovery backends for the gateway.

Available providers:

  • StaticProvider: loads endpoints from a YAML config file (for standalone/Docker mode)
  • KubernetesProvider: watches Pods and ModelAdapters via K8s informers

TODO: Add ConsulProvider, EtcdProvider.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type EventHandler added in v0.7.0

type EventHandler func(event WatchEvent)

EventHandler is a callback invoked by a provider when a resource changes.

type EventType added in v0.7.0

type EventType int

EventType represents the type of a watch event.

const (
	EventAdd EventType = iota
	EventUpdate
	EventDelete
)

type KubernetesProvider added in v0.7.0

type KubernetesProvider struct {
	// contains filtered or unexported fields
}

KubernetesProvider implements Provider using Kubernetes informers.

func NewKubernetesProvider added in v0.7.0

func NewKubernetesProvider(config *rest.Config) *KubernetesProvider

NewKubernetesProvider creates a new Kubernetes discovery provider.

func (*KubernetesProvider) Type added in v0.7.0

func (p *KubernetesProvider) Type() string

Type returns the provider type identifier.

func (*KubernetesProvider) Watch added in v0.7.0

func (p *KubernetesProvider) Watch(handler EventHandler, stopCh <-chan struct{}) error

Watch starts K8s informers with the handler wired directly into informer callbacks. Watch returns once the initial sync and reconcile are complete. After return, informer callbacks continue delivering ongoing changes asynchronously.

type Provider

type Provider interface {
	// Watch registers a handler for resource change events and starts watching.
	// The provider calls handler for each change (add/update/delete).
	//
	// Watch should return once the provider has reached a consistent ready state
	// (e.g., initial sync complete, config loaded). After return, dynamic providers
	// continue delivering ongoing changes via the handler asynchronously.
	//
	// Static providers deliver initial state and return (no ongoing changes).
	// K8s provider lets informers deliver events directly via the handler from
	// the start, then does a post-sync reconcile before returning.
	// Consul/etcd providers may deliver initial state, then start a background
	// watch/poll loop.
	Watch(handler EventHandler, stopCh <-chan struct{}) error

	// Type returns a string identifier for the provider type (e.g., "static", "consul").
	Type() string
}

Provider defines the interface for service discovery backends.

All initial state and ongoing changes are delivered through Watch() via the EventHandler callback.

type RoleSetConfig added in v0.7.0

type RoleSetConfig struct {
	// Name identifies this roleset (used as pairing key in PD routing).
	Name string `json:"name"`
	// Prefill lists prefill worker addresses in "host:port" format.
	Prefill []string `json:"prefill"`
	// Decode lists decode worker addresses in "host:port" format.
	Decode []string `json:"decode"`
}

RoleSetConfig defines a group of prefill and decode workers that can be paired together. The PD routing algorithm scores prefill and decode pods within the same roleset to find the optimal pair (e.g., Single node P/D etc).

type StaticConfig added in v0.7.0

type StaticConfig struct {
	// Models is the list of models and their workers.
	Models []StaticModelConfig `json:"models"`
}

StaticConfig represents the complete static endpoints configuration.

type StaticModelConfig added in v0.7.0

type StaticModelConfig struct {
	// Name is the model name (e.g., "Qwen/Qwen2.5-72B").
	Name string `json:"name"`
	// Engine is the inference engine type (e.g., "vllm", "sglang", "trtllm"). Optional.
	Engine string `json:"engine,omitempty"`
	// Endpoints lists worker addresses for non-disaggregated serving.
	// Each entry is a "host:port" string. Mutually exclusive with RoleSets.
	Endpoints []string `json:"endpoints,omitempty"`
	// RoleSets defines prefill/decode worker groups for disaggregated serving.
	// Mutually exclusive with Endpoints.
	RoleSets []RoleSetConfig `json:"rolesets,omitempty"`
}

StaticModelConfig represents a model and its backend workers.

type StaticProvider added in v0.7.0

type StaticProvider struct {
	// contains filtered or unexported fields
}

StaticProvider implements Provider by loading a static YAML configuration file. The configuration is loaded once at startup; no dynamic updates are supported.

func NewStaticProvider added in v0.7.0

func NewStaticProvider(configPath string) *StaticProvider

NewStaticProvider creates a new static discovery provider.

func (*StaticProvider) Type added in v0.7.0

func (p *StaticProvider) Type() string

Type returns the provider type identifier.

func (*StaticProvider) Watch added in v0.7.0

func (p *StaticProvider) Watch(handler EventHandler, _ <-chan struct{}) error

Watch reads the config file, delivers all endpoints as EventAdd via the handler, and returns. Static provider has no ongoing dynamic updates.

type WatchEvent added in v0.7.0

type WatchEvent struct {
	// Type is the kind of change: add, update, or delete.
	Type EventType
	// Object is the current state of the resource (for add/update) or
	// the last known state (for delete). Currently *v1.Pod.
	Object any
	// OldObject is the previous state, only set for EventUpdate. Nil otherwise.
	OldObject any
}

WatchEvent represents a change detected by a discovery provider.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL