gRPC on Kubernetes — Deploying, Scaling, and Managing gRPC Services in Containers
In this tutorial, you will learn about grpc on kubernetes. We cover key concepts, practical examples, and best practices to help you master this topic.
Deploying gRPC on Kubernetes requires specific configuration for HTTP/2 transport, gRPC-specific load balancing, health checks, and service discovery to ensure reliable communication between gRPC microservices.
What You'll Learn
- Containerizing gRPC services for Kubernetes
- gRPC load balancing with headless services
- Kubernetes liveness and readiness probes
- Ingress controllers for gRPC
- Autoscaling gRPC services
- gRPC-Web with Kubernetes ingress
Why It Matters
gRPC's HTTP/2 multiplexing and long-lived connections behave differently from REST under Kubernetes load balancing. Without proper configuration, gRPC connections can fail, traffic can be unbalanced, and deployments can break. DodaTech's Durga Antivirus Pro runs 50+ gRPC microservices on Kubernetes with automatic scaling, rolling deployments, and 99.99% uptime.
Real-World Use
A gRPC threat analysis service is deployed with 10 replicas. When traffic spikes, Kubernetes autoscales to 50 replicas. The gRPC clients use headless service DNS to discover all replicas and distribute connections using round-robin or least-loaded client-side load balancing.
flowchart TB
A["Client Pod"] --> B["Headless Service\n(no cluster IP)"]
B --> C["Pod 1\n(10.0.0.1:50051)"]
B --> D["Pod 2\n(10.0.0.2:50051)"]
B --> E["Pod 3\n(10.0.0.3:50051)"]
A -->|Client-side LB| C
A -->|Client-side LB| D
A -->|Client-side LB| E
F["HPA"] --> G["Scale Pods"]
style B fill:#fef3c7,stroke:#d97706
Code Examples
Example 1: Kubernetes Deployment for gRPC
apiVersion: apps/v1
kind: Deployment
metadata:
name: threat-service
spec:
replicas: 3
selector:
matchLabels:
app: threat-service
template:
metadata:
labels:
app: threat-service
spec:
containers:
- name: threat-service
image: dodatech/threat-service:latest
ports:
- containerPort: 50051
name: grpc
- containerPort: 8080
name: health
env:
- name: GRPC_GO_LOG_SEVERITY_LEVEL
value: "info"
- name: GRPC_GO_LOG_VERBOSITY_LEVEL
value: "2"
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
livenessProbe:
grpc:
port: 50051
service: threat-service
initialDelaySeconds: 10
periodSeconds: 15
readinessProbe:
grpc:
port: 50051
service: threat-service
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: threat-service
spec:
clusterIP: None # Headless for gRPC
ports:
- port: 50051
targetPort: 50051
name: grpc
selector:
app: threat-service
Example 2: Client-Side Load Balancing with Headless Service
package main
import (
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/resolver"
)
func main() {
// Register Kubernetes DNS resolver
resolver.SetDefaultScheme("dns")
// Use headless service DNS name
conn, _ := grpc.Dial(
"dns:///threat-service.default.svc.cluster.local:50051",
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithDefaultServiceConfig(`{
"loadBalancingConfig": [
{ "round_robin": {} }
]
}`),
)
client := pb.NewThreatServiceClient(conn)
// gRPC automatically distributes calls across all
// pods resolved from the headless service DNS
}
Example 3: gRPC Ingress with Contour
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
name: grpc-ingress
spec:
virtualhost:
fqdn: api.dodatech.com
routes:
- conditions:
- prefix: /threat.v1.ThreatService
services:
- name: threat-service
port: 50051
permitInsecure: true
- conditions:
- prefix: /scan.v1.ScanService
services:
- name: scan-service
port: 50051
permitInsecure: true
---
# Alternative: Envoy-based ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: grpc-ingress
annotations:
kubernetes.io/ingress.class: "contour"
ingress.kubernetes.io/protocol: "h2c"
spec:
rules:
- host: api.dodatech.com
http:
paths:
- path: /threat.v1.ThreatService
pathType: Prefix
backend:
service:
name: threat-service
port:
number: 50051
Common Mistakes
- Using ClusterIP service for gRPC — ClusterIP uses kube-proxy which doesn't support HTTP/2 load balancing correctly. Use headless services with client-side load balancing.
- Not setting HTTP/2 in ingress controllers — default ingress controllers (nginx) proxy HTTP/1.1. Configure HTTP/2 support or use Envoy/Contour for gRPC ingress.
- Using default kube-proxy mode — iptables mode load-balances per connection, not per request, causing imbalance with gRPC's long-lived connections.
- Not configuring readiness probes correctly — without gRPC health probes, Kubernetes may route traffic to pods that aren't ready to serve.
- Setting CPU limits too low — gRPC's HTTP/2 framing and protobuf serialization need CPU. Under-provisioned pods can cause latency spikes and timeouts.
Practice Questions
- Why does gRPC need headless services on Kubernetes?
- How does client-side load balancing work with DNS resolution?
- What ingress controllers support gRPC natively?
- How do you configure autoscaling for gRPC services?
- Why might gRPC connections become unbalanced across pods?
Challenge: Design a Kubernetes deployment Strategy for a gRPC microservice architecture with 10 services. Include headless services, client-side load balancing with round-robin, gRPC health probes, HPA based on CPU and request rate, and rolling update strategy with zero downtime.
Mini Project
Deploy a complete gRPC microservice on Kubernetes with: Docker container with gRPC health checks, headless service for client-side load balancing, HPA autoscaling, Contour ingress with HTTP/2 support, Prometheus monitoring, and Grafana dashboard for gRPC metrics.
FAQ
What's Next
Learn about Dockerizing gRPC services
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro