How to Integrate Kratos Services with Modern Service Mesh Platforms Like Istio and Linkerd

Integrate Kratos services with Istio or Linkerd by deploying the Kubernetes registry to annotate pods with protocol metadata, enabling OpenTelemetry tracing middleware for distributed context propagation, and exposing Prometheus metrics, which allows the mesh sidecar to automatically handle traffic routing, mTLS, and observability.

The go-kratos/kratos framework provides transport-agnostic servers and pluggable middleware that align perfectly with service mesh architectures. By leveraging the contrib/registry/kubernetes package to patch pod annotations and using first-class observability middleware, your Kratos applications become native citizens in Istio or Linkerd environments without invasive code changes.

Core Components for Mesh Integration

Service meshes rely on sidecar proxies (Envoy for Istio, Linkerd-proxy for Linkerd) intercepting network traffic based on Kubernetes metadata. Kratos provides specific components that satisfy these requirements.

Kubernetes Registry for Metadata Enrichment

The contrib/registry/kubernetes/registry.go implementation automatically patches the running pod with labels and annotations that service meshes use for protocol detection and service discovery. When you instantiate registryk8s.NewRegistry(), it updates the pod with:

  • kratos-service-protocols: A JSON annotation mapping container ports to protocols (e.g., {"8080":"http","9090":"grpc"})
  • Labels: kratos-service-id, kratos-service-app, and kratos-service-version for identity

This metadata allows Istio and Linkerd to distinguish HTTP from gRPC traffic without additional configuration.

Observability Middleware

Service meshes aggregate telemetry from application workloads. Kratos exposes this data through:

Both middlewares integrate with the HTTP and gRPC server implementations found in transport/http/server.go and transport/grpc/server.go.

Step-by-Step Integration Guide

Configure the Kubernetes Registry

Initialize the registry inside your main function to enable automatic pod annotation. The registry uses in-cluster configuration to patch the current pod.

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

func main() {
    // Create in-cluster Kubernetes client
    cfg, err := rest.InClusterConfig()
    if err != nil {
        log.Fatal(err)
    }
    clientSet, err := kubernetes.NewForConfig(cfg)
    if err != nil {
        log.Fatal(err)
    }
    
    // Instantiate registry (empty string for current pod)
    reg := registryk8s.NewRegistry(clientSet, "")
    
    // Continue with app construction...
}

Instrument Servers with Tracing and Metrics

Apply the OpenTelemetry and Prometheus middleware to both HTTP and gRPC transports. This ensures the mesh can collect consistent telemetry regardless of protocol.

import (
    "github.com/go-kratos/kratos/v2/middleware/metrics"
    "github.com/go-kratos/kratos/v2/middleware/tracing"
    "github.com/go-kratos/kratos/v2/transport/grpc"
    "github.com/go-kratos/kratos/v2/transport/http"
)

app := kratos.New(
    kratos.Name("ordersvc"),
    kratos.Version("v1.0.0"),
    kratos.Registry(reg),
    kratos.Server(
        http.NewServer(
            http.Address(":8080"),
            http.Middleware(
                tracing.Server(), // OpenTelemetry
                metrics.Server(), // Prometheus
            ),
        ),
        grpc.NewServer(
            grpc.Address(":9090"),
            grpc.Middleware(
                tracing.Server(),
                metrics.Server(),
            ),
        ),
    ),
)

Deploy with Mesh-Ready Annotations

Your Kubernetes Deployment must expose the ports and allow the registry to annotate the pod template. The kratos-service-protocols annotation is automatically populated by the registry, but you can pre-declare it for clarity.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ordersvc
spec:
  replicas: 2
  selector:
    matchLabels:
      app: ordersvc
  template:
    metadata:
      labels:
        app: ordersvc
        kratos-service-version: "v1.0.0"
      annotations:
        kratos-service-protocols: |
          {"8080":"http","9090":"grpc"}
        kratos-service-metadata: |
          {"team":"payment"}
    spec:
      containers:
      - name: ordersvc
        image: myrepo/ordersvc:latest
        ports:
        - containerPort: 8080
        - containerPort: 9090

Inject the Mesh Sidecar

For Istio, enable injection at the namespace or deployment level:

kubectl label namespace default istio-injection=enabled

# Or annotate specific deployment

kubectl annotate deployment ordersvc sidecar.istio.io/inject="true"

For Linkerd, use the CLI to patch the deployment:

linkerd inject deployment/ordersvc | kubectl apply -f -

Verifying Mesh Integration

Check Protocol Detection

Once deployed, verify the mesh recognizes the protocols correctly. For Istio, check the proxy configuration:

istioctl dashboard proxy-config pod ordersvc-<hash>

Look for listener entries on ports 8080 (HTTP) and 9090 (gRPC) based on the kratos-service-protocols annotation.

Validate Telemetry Export

Confirm that Prometheus metrics are accessible on the /metrics endpoint:

kubectl port-forward pod/ordersvc-<hash> 8080:8080
curl localhost:8080/metrics

For distributed tracing, ensure your OpenTelemetry Collector or Jaeger instance receives traces by checking the Kratos middleware configuration:

tp := sdktrace.NewTracerProvider(
    sdktrace.WithSampler(sdktrace.TraceIDRatioBased(1.0)),
)
// Pass tp to tracing.Server(tracing.WithTracerProvider(tp))

Complete Working Example

Here is a minimal, production-ready main.go that combines all integration points:

package main

import (
    "log"

    "github.com/go-kratos/kratos/v2"
    "github.com/go-kratos/kratos/v2/middleware/metrics"
    "github.com/go-kratos/kratos/v2/middleware/tracing"
    "github.com/go-kratos/kratos/v2/transport/grpc"
    "github.com/go-kratos/kratos/v2/transport/http"
    
    registryk8s "github.com/go-kratos/kratos/contrib/registry/kubernetes/v2"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
)

func main() {
    // Kubernetes client configuration
    cfg, err := rest.InClusterConfig()
    if err != nil {
        log.Fatalf("failed to create k8s config: %v", err)
    }
    cs, err := kubernetes.NewForConfig(cfg)
    if err != nil {
        log.Fatalf("failed to create k8s client: %v", err)
    }
    
    // Mesh-aware registry
    reg := registryk8s.NewRegistry(cs, "")
    
    // Build application with observability middleware
    app := kratos.New(
        kratos.Name("ordersvc"),
        kratos.Version("v1.0.0"),
        kratos.Metadata(map[string]string{"team": "payment"}),
        kratos.Registry(reg),
        kratos.Server(
            http.NewServer(
                http.Address(":8080"),
                http.Middleware(
                    tracing.Server(),
                    metrics.Server(),
                ),
            ),
            grpc.NewServer(
                grpc.Address(":9090"),
                grpc.Middleware(
                    tracing.Server(),
                    metrics.Server(),
                ),
            ),
        ),
    )
    
    if err := app.Run(); err != nil {
        log.Fatalf("app exited: %v", err)
    }
}

Summary

  • Use the Kubernetes registry (contrib/registry/kubernetes/registry.go) to automatically annotate pods with protocol metadata and service identities required by Istio and Linkerd.
  • Enable OpenTelemetry tracing via middleware/tracing to ensure distributed trace context propagates through the mesh sidecar to downstream services.
  • Expose Prometheus metrics using middleware/metrics so the mesh control plane can scrape standard metrics from the /metrics endpoint.
  • Deploy standard HTTP/gRPC servers from transport/http and transport/grpc without TLS inside the pod; the mesh sidecar terminates mTLS automatically.
  • Inject sidecars using native Istio annotations or Linkerd CLI commands; no application code changes are required for traffic management or security.

Frequently Asked Questions

Does Kratos require code modifications to work with Istio?

No. According to the source code in transport/http/server.go and transport/grpc/server.go, Kratos servers work transparently with Istio once you configure the Kubernetes registry and inject the sidecar. The mesh handles traffic routing, retries, and mTLS termination externally.

How does the Kubernetes registry help with service mesh integration?

The registry implementation in contrib/registry/kubernetes/registry.go patches the running pod with the kratos-service-protocols annotation and standardized labels. This metadata tells Istio and Linkerd which ports serve HTTP versus gRPC traffic, enabling proper protocol selection and telemetry collection.

Can I use Linkerd instead of Istio with Kratos?

Yes. Both service meshes consume the same Kubernetes metadata and OpenTelemetry/Prometheus standards that Kratos produces. Use linkerd inject on your deployments instead of Istio's injection labels, while keeping the same Kratos application code and registry configuration.

Should Kratos handle TLS when running inside a service mesh?

Typically no. When running in a mesh, configure Kratos servers to use plain text (HTTP) or server-only TLS if required by your security policy. The mesh's sidecar proxy (Envoy or Linkerd-proxy) automatically upgrades connections to mutual TLS (mTLS) between services, handling certificate management and encryption at the infrastructure layer.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →