74. Integrasi gRPC dengan Envoy Proxy
gRPC telah menjadi salah satu pilihan utama dalam membangun layanan microservices yang cepat, efisien, dan mudah dikembangkan. Namun, pada skala produksi, kebutuhan seperti load balancing, service discovery, observability, hingga mTLS sering kali menuntut adanya proxy canggih—dan di sinilah Envoy Proxy hadir sebagai solusi. Dalam artikel ini, saya akan membahas secara praktis bagaimana mengintegrasikan gRPC dengan Envoy Proxy, mulai dari konsep, benefit, hingga contoh implementasi yang bisa langsung kamu coba.
Mengapa Harus Menggunakan Envoy untuk gRPC?
Sebelum masuk ke kode dan simulasi, mari kita telaah alasan di balik keputusan untuk meletakkan Envoy di depan gRPC server:
- gRPC memiliki protocol berbasis HTTP/2 yang tidak selalu kompatibel dengan proxy HTTP konvensional.
- Load balancing cerdas: Envoy mendukung load balancing level aplikasi dan aware terhadap state koneksi HTTP2.
- Observability: Integrasi logging, metrics (Prometheus), dan tracing (Jaeger, Zipkin) menjadi jauh lebih mudah.
- Security: Envoy dapat mengenakan mTLS tanpa perlu memodifikasi aplikasi.
- Network resilience: Dapat mengatur retry, timeouts, circuit breaking, dsb.
Komponen yang Akan Kita Bangun
Skenario sederhana yang akan kita simulasikan:
- Service A: Client aplikasi (gRPC client)
- Envoy Proxy: Sebagai reverse proxy dan load balancer
- Service B: gRPC server (hello world)
- Semua layanan berjalan secara lokal, bisa dengan Docker atau langsung run binary.
Arsitektur High-Level
flowchart LR
subgraph Client Side
A[gRPC Client]
end
subgraph Proxy
B[Envoy Proxy]
end
subgraph Backend
C[gRPC Server]
end
A -- gRPC/HTTP2 --> B
B -- gRPC/HTTP2 --> C
1. Membuat gRPC Service Sederhana
Kita mulai dengan mendefinisikan service sederhana dengan Protocol Buffers:
helloworld.proto
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
Generate kode stub-nya menggunakan protoc. Untuk Go, contohnya:
protoc --go_out=. --go-grpc_out=. helloworld.proto
Implementasi sederhana untuk server (Go):
// server.go
package main
import (
"context"
"log"
"net"
pb "yourmod/helloworld"
"google.golang.org/grpc"
)
type server struct {
pb.UnimplementedGreeterServer
}
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
return &pb.HelloReply{Message: "Hello, " + in.Name}, nil
}
func main() {
lis, err := net.Listen("tcp", ":50051")
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
log.Println("gRPC server listening on :50051")
s.Serve(lis)
}
2. Konfigurasi Envoy Proxy untuk gRPC
Envoy harus diatur untuk memahami protokol HTTP/2. Kita setup sebagai reverse proxy dari port 9901 ke backend gRPC server di 50051.
envoy.yaml:
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains: ["*"]
routes:
- match: { prefix: "/" }
route: { cluster: greeter_service }
http_filters:
- name: envoy.filters.http.router
# Envoy will use HTTP/2 to proxy the gRPC calls.
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
lb_policy: round_robin
http2_protocol_options: {} # Enables HTTP2 for this cluster
load_assignment:
cluster_name: greeter_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 50051
admin:
access_log_path: "/tmp/admin_access.log"
address:
socket_address:
address: 0.0.0.0
port_value: 9900
Poin Penting:
- http2_protocol_options: {} menginstruksikan Envoy untuk menggunakan HTTP/2 ketika berbicara ke backend cluster.
- Pastikan cluster mengarah ke port di mana gRPC server berjalan.
- Envoy proxy expose port 9901 (frontend).
3. Membuat Client untuk Terhubung ke Envoy
Implementasi client Go, spesifik konek ke Envoy, buka channel ke localhost:9901:
// client.go
package main
import (
"context"
"log"
"time"
pb "yourmod/helloworld"
"google.golang.org/grpc"
)
func main() {
conn, err := grpc.Dial("localhost:9901", grpc.WithInsecure())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Envoy"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.Message)
}
Jalankan server, Envoy, lalu client:
go run server.go
envoy -c envoy.yaml
go run client.go
4. Simulasi Request Flow
Mari visualisasikan alur request-nya:
sequenceDiagram
participant Client
participant Envoy
participant Server
Client->>Envoy: gRPC Request (SayHello)
Envoy->>Server: gRPC Request (forward)
Server-->>Envoy: gRPC Response
Envoy-->>Client: gRPC Response (relay)
Benefit-nya:
- Client tidak perlu tahu IP/host server gRPC backend
- Bisa scaling server gRPC dan update konfigurasi cluster Envoy secara dinamis
- Observabilitas, circuit breaker, dll bisa langsung kita manfaatkan
5. Studi Kasus: Load Balancing dan Health Checking
Bayangkan kita menambah dua node server di belakang Envoy (misal di port 50051 dan 50052). Cukup ubah bagian load_assignment:
load_assignment:
cluster_name: greeter_service
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 50051
- endpoint:
address:
socket_address:
address: 127.0.0.1
port_value: 50052
Kita juga bisa menambahkan health check:
health_checks:
- timeout: 1s
interval: 2s
unhealthy_threshold: 2
healthy_threshold: 2
grpc_health_check: {} # Sesuai standard gRPC health check
Tabel ringkas fitur utama Envoy pada integrasi gRPC:
| Fitur | Deskripsi | Konfigurasi |
|---|---|---|
| Load Balancing | Round robin, least request, dll | lb_policy |
| Observability | Metrics Prometheus, tracing | Metrics, Tracing config |
| Security | mTLS, AuthZ, Rate Limiting | tls_context, Filter HTTP |
| Health Checking | Cek status backend, auto-remove instance | health_checks |
| Retry/Timeout | Menjamin resilience | retry_policy, timeout |
6. Kesimpulan, Tantangan, dan Best Practices
Dengan integrasi gRPC dan Envoy Proxy, aplikasi microservices Anda mendapatkan bonus skala, observability, dan security tanpa perlu banyak perubahan di level aplikasi. Namun, ada beberapa catatan penting:
- Selalu menggunakan health check pada cluster backend
- Monitor Envoy metrics untuk understanding traffic dan latency
- Konfigurasikan rate limiting dan circuit breaking secukupnya
- Untuk production, pastikan Envoy berjalan dengan mTLS
- Deployment sebaiknya dilakukan via container orchestration (Kubernetes, Nomad, dsb) untuk hasil optimal
Integrasi ini bukan solusi “one size fits all”, tetapi menawarkan fondasi kokoh untuk service mesh dan scalable platform microservices Anda. Cobalah simulasi sederhana ini di lingkungan lokal Anda, dan eksplorasi lebih lanjut seluruh potensi Envoy di production!
Referensi
Selamat bereksperimen! Jangan ragu share insight dan pertanyaan di kolom komentar.