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 ,
})
}
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 )
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.
Handle Discovery Failures
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