Skip to main content
Kratos provides a service registry and discovery system that enables microservices to find and communicate with each other dynamically. The system is transport-agnostic and works with various registry backends.

Core Interfaces

Registrar

Register and deregister services:
registry/registry.go:10-15
type Registrar interface {
    // Register the registration
    Register(ctx context.Context, service *ServiceInstance) error
    
    // Deregister the registration
    Deregister(ctx context.Context, service *ServiceInstance) error
}

Discovery

Discover services:
registry/registry.go:18-23
type Discovery interface {
    // GetService return the service instances in memory according to the service name
    GetService(ctx context.Context, serviceName string) ([]*ServiceInstance, error)
    
    // Watch creates a watcher according to the service name
    Watch(ctx context.Context, serviceName string) (Watcher, error)
}

Watcher

Watch for service changes:
registry/registry.go:26-34
type Watcher interface {
    // Next returns services in the following two cases:
    // 1. the first time to watch and the service instance list is not empty
    // 2. any service instance changes found
    // if the above two conditions are not met, it will block until context deadline exceeded or canceled
    Next() ([]*ServiceInstance, error)
    
    // Stop close the watcher
    Stop() error
}

Service Instance

registry/registry.go:37-51
type ServiceInstance struct {
    // ID is the unique instance ID as registered
    ID string `json:"id"`
    
    // Name is the service name as registered
    Name string `json:"name"`
    
    // Version is the version of the compiled
    Version string `json:"version"`
    
    // Metadata is the kv pair metadata associated with the service instance
    Metadata map[string]string `json:"metadata"`
    
    // Endpoints are endpoint addresses of the service instance
    // Examples:
    //   http://127.0.0.1:8000?isSecure=false
    //   grpc://127.0.0.1:9000?isSecure=false
    Endpoints []string `json:"endpoints"`
}

Registering Services

HTTP Server Registration

import (
    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/registry"
    "github.com/go-kratos/kratos/v2/transport/http"
    "github.com/go-kratos/kratos/contrib/registry/consul/v2"
)

func main() {
    // Create registry client
    consulClient, _ := api.NewClient(api.DefaultConfig())
    r := consul.New(consulClient)
    
    // Create HTTP server
    httpSrv := http.NewServer(
        http.Address(":8000"),
    )
    
    // Create Kratos app with registry
    app := kratos.New(
        kratos.Name("user-service"),
        kratos.Version("v1.0.0"),
        kratos.Metadata(map[string]string{
            "region": "us-west",
            "env":    "production",
        }),
        kratos.Server(httpSrv),
        kratos.Registrar(r),
    )
    
    // Service automatically registers on start
    if err := app.Run(); err != nil {
        log.Fatal(err)
    }
    // Service automatically deregisters on stop
}

gRPC Server Registration

import (
    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/registry"
    "github.com/go-kratos/kratos/v2/transport/grpc"
)

func main() {
    // Create registry
    r := consul.New(consulClient)
    
    // Create gRPC server
    grpcSrv := grpc.NewServer(
        grpc.Address(":9000"),
    )
    
    // Register with Kratos
    app := kratos.New(
        kratos.Name("order-service"),
        kratos.Version("v2.0.0"),
        kratos.Server(grpcSrv),
        kratos.Registrar(r),
    )
    
    app.Run()
}

Multiple Transports

Register a service with both HTTP and gRPC:
func main() {
    r := consul.New(consulClient)
    
    httpSrv := http.NewServer(http.Address(":8000"))
    grpcSrv := grpc.NewServer(grpc.Address(":9000"))
    
    app := kratos.New(
        kratos.Name("api-gateway"),
        kratos.Server(httpSrv, grpcSrv),
        kratos.Registrar(r),
    )
    
    app.Run()
    // Both endpoints registered:
    // http://127.0.0.1:8000
    // grpc://127.0.0.1:9000
}

Discovering Services

HTTP Client with Discovery

import (
    "github.com/go-kratos/kratos/v2/transport/http"
    "github.com/go-kratos/kratos/contrib/registry/consul/v2"
)

func main() {
    // Create discovery client
    consulClient, _ := api.NewClient(api.DefaultConfig())
    dis := consul.New(consulClient)
    
    // Create HTTP client with discovery
    client, err := http.NewClient(
        context.Background(),
        http.WithEndpoint("discovery:///user-service"),
        http.WithDiscovery(dis),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()
    
    // Make request - automatically routes to available instance
    var reply UserResponse
    err = client.Invoke(
        ctx,
        http.MethodGet,
        "/api/users/123",
        nil,
        &reply,
    )
}

gRPC Client with Discovery

import (
    "github.com/go-kratos/kratos/v2/transport/grpc"
    "github.com/go-kratos/kratos/contrib/registry/consul/v2"
)

func main() {
    // Create discovery client
    dis := consul.New(consulClient)
    
    // Create gRPC client with discovery
    conn, err := grpc.DialInsecure(
        context.Background(),
        grpc.WithEndpoint("discovery:///order-service"),
        grpc.WithDiscovery(dis),
    )
    if err != nil {
        log.Fatal(err)
    }
    defer conn.Close()
    
    // Create service client
    client := pb.NewOrderServiceClient(conn)
    
    // Make request - automatically load balanced
    reply, err := client.CreateOrder(ctx, &pb.CreateOrderRequest{
        UserID: 123,
    })
}

Endpoint Format

When using service discovery, use the discovery:// scheme:
discovery:///service-name
The three slashes are required. This distinguishes discovery endpoints from direct addresses.

Registry Implementations

Kratos contrib provides several registry implementations:

Consul

import (
    consulapi "github.com/hashicorp/consul/api"
    "github.com/go-kratos/kratos/contrib/registry/consul/v2"
)

client, _ := consulapi.NewClient(consulapi.DefaultConfig())
r := consul.New(client)

Etcd

import (
    clientv3 "go.etcd.io/etcd/client/v3"
    "github.com/go-kratos/kratos/contrib/registry/etcd/v2"
)

client, _ := clientv3.New(clientv3.Config{
    Endpoints: []string{"127.0.0.1:2379"},
})
r := etcd.New(client)

Nacos

import (
    "github.com/nacos-group/nacos-sdk-go/clients"
    "github.com/go-kratos/kratos/contrib/registry/nacos/v2"
)

sc := []constant.ServerConfig{
    *constant.NewServerConfig("127.0.0.1", 8848),
}
cc := constant.ClientConfig{
    NamespaceId: "public",
}
client, _ := clients.NewNamingClient(
    vo.NacosClientParam{
        ClientConfig:  &cc,
        ServerConfigs: sc,
    },
)
r := nacos.New(client)

Kubernetes

import (
    "k8s.io/client-go/kubernetes"
    "github.com/go-kratos/kratos/contrib/registry/kubernetes/v2"
)

config, _ := rest.InClusterConfig()
clientset, _ := kubernetes.NewForConfig(config)
r := kubernetes.New(clientset)

Service Metadata

Add metadata to service instances:
app := kratos.New(
    kratos.Name("user-service"),
    kratos.Metadata(map[string]string{
        "region":      "us-west-1",
        "zone":        "us-west-1a",
        "environment": "production",
        "version":     "v1.2.3",
        "weight":      "100",
    }),
    kratos.Server(httpSrv),
    kratos.Registrar(r),
)
Metadata can be used for:
  • Load balancing decisions
  • Service filtering
  • Traffic routing
  • Feature flags

Service Versioning

app := kratos.New(
    kratos.Name("api-service"),
    kratos.Version("v2.0.0"),
    kratos.Server(httpSrv),
    kratos.Registrar(r),
)

// Client can filter by version
import "github.com/go-kratos/kratos/v2/selector/filter"

client, _ := http.NewClient(
    ctx,
    http.WithEndpoint("discovery:///api-service"),
    http.WithDiscovery(dis),
    http.WithNodeFilter(
        filter.Version("v2.0.0"),
    ),
)

Health Checks

Most registries support health checking:

Consul Health Checks

import "github.com/go-kratos/kratos/contrib/registry/consul/v2"

// Consul automatically creates health checks:
// - TTL check (default)
// - HTTP check (if HTTP endpoint available)
// - gRPC check (if gRPC endpoint available)

r := consul.New(client,
    consul.WithHealthCheck(true),
    consul.WithHealthCheckInterval(10*time.Second),
)

Custom Health Check

import "google.golang.org/grpc/health/grpc_health_v1"

// Implement custom health check
type HealthChecker struct {
    grpc_health_v1.UnimplementedHealthServer
}

func (h *HealthChecker) Check(ctx context.Context, req *grpc_health_v1.HealthCheckRequest) (*grpc_health_v1.HealthCheckResponse, error) {
    // Custom health check logic
    return &grpc_health_v1.HealthCheckResponse{
        Status: grpc_health_v1.HealthCheckResponse_SERVING,
    }, nil
}

grpcSrv := grpc.NewServer(
    grpc.CustomHealth(),
)
grpc_health_v1.RegisterHealthServer(grpcSrv, &HealthChecker{})

Direct Service Access

Query registry directly:
import "github.com/go-kratos/kratos/v2/registry"

// Get service instances
instances, err := dis.GetService(ctx, "user-service")
if err != nil {
    log.Fatal(err)
}

for _, inst := range instances {
    log.Infof("Instance: %s, Endpoints: %v", inst.ID, inst.Endpoints)
}

// Watch for changes
watcher, err := dis.Watch(ctx, "user-service")
if err != nil {
    log.Fatal(err)
}
defer watcher.Stop()

for {
    instances, err := watcher.Next()
    if err != nil {
        break
    }
    log.Infof("Service updated, instance count: %d", len(instances))
}

Best Practices

Use consistent, meaningful service names across your infrastructure.
Include region, zone, version, and other routing metadata with service instances.
Always enable health checks to ensure only healthy instances receive traffic.
Implement fallback mechanisms when service discovery is unavailable.
Use semantic versioning for services to enable gradual rollouts.
Monitor service registration/deregistration events for operational insights.

Complete Example

package main

import (
    "context"
    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/registry"
    "github.com/go-kratos/kratos/v2/transport/http"
    "github.com/go-kratos/kratos/v2/transport/grpc"
    consulapi "github.com/hashicorp/consul/api"
    "github.com/go-kratos/kratos/contrib/registry/consul/v2"
)

// Server
func runServer() {
    // Create Consul client
    consulClient, _ := consulapi.NewClient(consulapi.DefaultConfig())
    r := consul.New(consulClient)
    
    // Create servers
    httpSrv := http.NewServer(http.Address(":8000"))
    grpcSrv := grpc.NewServer(grpc.Address(":9000"))
    
    // Register services...
    
    // Create app with registry
    app := kratos.New(
        kratos.Name("user-service"),
        kratos.Version("v1.0.0"),
        kratos.Metadata(map[string]string{
            "region": "us-west",
            "weight": "100",
        }),
        kratos.Server(httpSrv, grpcSrv),
        kratos.Registrar(r),
    )
    
    app.Run()
}

// Client
func runClient() {
    // Create Consul discovery
    consulClient, _ := consulapi.NewClient(consulapi.DefaultConfig())
    dis := consul.New(consulClient)
    
    // Create HTTP client
    client, _ := http.NewClient(
        context.Background(),
        http.WithEndpoint("discovery:///user-service"),
        http.WithDiscovery(dis),
    )
    defer client.Close()
    
    // Make requests
    var reply Response
    client.Invoke(ctx, "GET", "/api/users/1", nil, &reply)
}

Selector

Load balancing and node selection

HTTP Client

HTTP client with discovery

gRPC Client

gRPC client with discovery

Metadata

Service metadata handling

Build docs developers (and LLMs) love