Skip to main content
This guide covers deployment strategies, containerization, and best practices for running Kratos services in production.

Deployment Overview

Kratos services can be deployed in various environments:
  • Docker containers - Containerized deployment
  • Kubernetes - Orchestrated container deployment
  • Traditional VMs - Binary deployment on virtual machines
  • Serverless - Function-as-a-Service platforms

Docker Deployment

1
Create Dockerfile
2
Create an optimized multi-stage Dockerfile:
3
# Build stage
FROM golang:1.21-alpine AS builder

WORKDIR /src

# Copy go mod files
COPY go.mod go.sum ./
RUN go mod download

# Copy source code
COPY . .

# Build binary
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo \
    -ldflags '-extldflags "-static" -w -s' \
    -o /app/server ./cmd/server

# Runtime stage
FROM alpine:latest

RUN apk --no-cache add ca-certificates tzdata

WORKDIR /app

# Copy binary from builder
COPY --from=builder /app/server .
COPY --from=builder /src/configs ./configs

# Create non-root user
RUN addgroup -g 1000 app && \
    adduser -D -u 1000 -G app app && \
    chown -R app:app /app

USER app

EXPOSE 8000 9000

ENTRYPOINT ["./server"]
CMD ["-conf", "./configs"]
4
Build Docker Image
5
Build and tag your Docker image:
6
# Build image
docker build -t myservice:latest .

# Tag for registry
docker tag myservice:latest registry.example.com/myservice:v1.0.0

# Push to registry
docker push registry.example.com/myservice:v1.0.0
7
Docker Compose
8
Create a Docker Compose file for local development:
9
version: '3.8'

services:
  app:
    build: .
    ports:
      - "8000:8000"
      - "9000:9000"
    environment:
      - KRATOS_SERVER_HTTP_ADDR=:8000
      - KRATOS_SERVER_GRPC_ADDR=:9000
      - KRATOS_DATA_DATABASE_SOURCE=root:root@tcp(mysql:3306)/mydb
      - KRATOS_DATA_REDIS_ADDR=redis:6379
    depends_on:
      - mysql
      - redis
    networks:
      - app-network

  mysql:
    image: mysql:8.0
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=mydb
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - app-network

  redis:
    image: redis:7-alpine
    networks:
      - app-network

volumes:
  mysql-data:

networks:
  app-network:
    driver: bridge
10
Run with Docker Compose:
11
docker-compose up -d

Kubernetes Deployment

Deployment Manifest

Create a Kubernetes deployment:
k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myservice
  labels:
    app: myservice
    version: v1.0.0
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myservice
  template:
    metadata:
      labels:
        app: myservice
        version: v1.0.0
    spec:
      containers:
      - name: myservice
        image: registry.example.com/myservice:v1.0.0
        imagePullPolicy: Always
        ports:
        - name: http
          containerPort: 8000
          protocol: TCP
        - name: grpc
          containerPort: 9000
          protocol: TCP
        env:
        - name: KRATOS_SERVER_HTTP_ADDR
          value: ":8000"
        - name: KRATOS_SERVER_GRPC_ADDR
          value: ":9000"
        - name: KRATOS_DATA_DATABASE_SOURCE
          valueFrom:
            secretKeyRef:
              name: myservice-secrets
              key: database-url
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 30
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 5
          periodSeconds: 5
      imagePullSecrets:
      - name: registry-credentials

Service Manifest

Expose your deployment:
k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myservice
  labels:
    app: myservice
spec:
  type: ClusterIP
  ports:
  - name: http
    port: 8000
    targetPort: http
    protocol: TCP
  - name: grpc
    port: 9000
    targetPort: grpc
    protocol: TCP
  selector:
    app: myservice

ConfigMap

Store configuration in ConfigMaps:
k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: myservice-config
data:
  config.yaml: |
    server:
      http:
        network: tcp
        addr: 0.0.0.0:8000
        timeout: 1s
      grpc:
        network: tcp
        addr: 0.0.0.0:9000
        timeout: 1s
    data:
      redis:
        addr: redis:6379
        read_timeout: 0.2s
        write_timeout: 0.2s
Mount ConfigMap in deployment:
volumes:
- name: config
  configMap:
    name: myservice-config
containers:
- name: myservice
  volumeMounts:
  - name: config
    mountPath: /app/configs
    readOnly: true

Secrets

Store sensitive data in Secrets:
k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: myservice-secrets
type: Opaque
stringData:
  database-url: "user:password@tcp(mysql:3306)/mydb?parseTime=True"
  redis-password: "redis-secret-password"

Ingress

Expose HTTP service externally:
k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myservice-ingress
  annotations:
    kubernetes.io/ingress.class: nginx
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  tls:
  - hosts:
    - api.example.com
    secretName: myservice-tls
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: myservice
            port:
              number: 8000

Deploy to Kubernetes

Apply manifests:
# Create namespace
kubectl create namespace myservice

# Apply configurations
kubectl apply -f k8s/configmap.yaml -n myservice
kubectl apply -f k8s/secret.yaml -n myservice
kubectl apply -f k8s/deployment.yaml -n myservice
kubectl apply -f k8s/service.yaml -n myservice
kubectl apply -f k8s/ingress.yaml -n myservice

# Check status
kubectl get pods -n myservice
kubectl get svc -n myservice
kubectl logs -f deployment/myservice -n myservice

Helm Charts

Create Helm Chart

Package your deployment as a Helm chart:
helm/myservice/Chart.yaml
apiVersion: v2
name: myservice
description: A Helm chart for myservice
type: application
version: 1.0.0
appVersion: "1.0.0"
helm/myservice/values.yaml
replicaCount: 3

image:
  repository: registry.example.com/myservice
  pullPolicy: Always
  tag: "v1.0.0"

service:
  type: ClusterIP
  httpPort: 8000
  grpcPort: 9000

ingress:
  enabled: true
  className: nginx
  hosts:
    - host: api.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: myservice-tls
      hosts:
        - api.example.com

resources:
  limits:
    cpu: 500m
    memory: 512Mi
  requests:
    cpu: 100m
    memory: 128Mi

autoscaling:
  enabled: true
  minReplicas: 3
  maxReplicas: 10
  targetCPUUtilizationPercentage: 80
Deploy with Helm:
# Install chart
helm install myservice ./helm/myservice -n myservice

# Upgrade deployment
helm upgrade myservice ./helm/myservice -n myservice

# Rollback
helm rollback myservice -n myservice

Auto-Scaling

Horizontal Pod Autoscaler

k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: myservice-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: myservice
  minReplicas: 3
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

Health Checks

Implement Health Endpoints

internal/server/http.go
func NewHTTPServer(c *conf.Server) *http.Server {
	srv := http.NewServer(
		http.Address(c.HTTP.Addr),
	)

	// Liveness probe
	srv.HandleFunc("/health/live", func(ctx http.Context) error {
		return ctx.String(200, "OK")
	})

	// Readiness probe
	srv.HandleFunc("/health/ready", func(ctx http.Context) error {
		// Check dependencies (database, redis, etc.)
		if err := checkDependencies(); err != nil {
			return ctx.String(503, "Not Ready")
		}
		return ctx.String(200, "Ready")
	})

	return srv
}

Monitoring and Observability

Prometheus Metrics

Expose Prometheus metrics:
import (
	"github.com/go-kratos/kratos/v2/middleware/metrics"
	"github.com/prometheus/client_golang/prometheus/promhttp"
)

// Add metrics middleware
srv := http.NewServer(
	http.Middleware(
		metrics.Server(),
	),
)

// Expose metrics endpoint
srv.Handle("/metrics", promhttp.Handler())

ServiceMonitor

k8s/servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: myservice
spec:
  selector:
    matchLabels:
      app: myservice
  endpoints:
  - port: http
    path: /metrics
    interval: 30s

CI/CD Pipeline

GitHub Actions

.github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Go
      uses: actions/setup-go@v4
      with:
        go-version: 1.21
    
    - name: Test
      run: go test -v ./...
    
    - name: Build
      run: go build -v ./cmd/server
    
    - name: Build Docker image
      run: docker build -t myservice:${{ github.sha }} .
    
    - name: Push to registry
      run: |
        echo ${{ secrets.REGISTRY_PASSWORD }} | docker login -u ${{ secrets.REGISTRY_USERNAME }} --password-stdin
        docker tag myservice:${{ github.sha }} registry.example.com/myservice:${{ github.sha }}
        docker push registry.example.com/myservice:${{ github.sha }}
    
    - name: Deploy to Kubernetes
      uses: azure/k8s-deploy@v4
      with:
        manifests: |
          k8s/deployment.yaml
          k8s/service.yaml
        images: registry.example.com/myservice:${{ github.sha }}
        kubectl-version: 'latest'

Best Practices

Immutable Infrastructure

Use immutable container images with version tags

Resource Limits

Always set resource requests and limits

Health Checks

Implement proper liveness and readiness probes

Graceful Shutdown

Handle SIGTERM signals for graceful shutdown

Configuration

Use ConfigMaps and Secrets for configuration

Observability

Add logging, metrics, and tracing

Graceful Shutdown

Implement graceful shutdown:
func main() {
	app := kratos.New(
		kratos.Name("myservice"),
		kratos.Server(httpSrv, grpcSrv),
	)

	// Handle shutdown signals
	if err := app.Run(); err != nil {
		log.Fatal(err)
	}
}
Kratos automatically handles:
  • SIGINT and SIGTERM signals
  • Server graceful shutdown
  • Service deregistration
  • Resource cleanup

Next Steps

Monitoring

Set up monitoring and alerting

Production Checklist

Review production readiness checklist

Build docs developers (and LLMs) love