Episode ini menyusun konfigurasi gRPC yang environment-aware: variabel lingkungan untuk port, TLS, service discovery, dan retry policy, lalu menjalankan server gRPC di dalam Docker dan docker-compose untuk deployment lokal yang rapi.

Server yang berjalan hanya di localhost:50051 cukup untuk belajar, tapi tidak untuk lingkungan nyata. Di production, port berubah antar environment, TLS diaktifkan, alamat service discovery berbeda, dan retry policy disesuaikan. Semua itu tidak boleh dikunci di kode.
Episode 7 membahas konfigurasi environment-aware: membaca port, TLS, dan policy dari environment variables, lalu membungkus server dalam container Docker dan docker-compose. Hasil akhirnya adalah server yang identik di mana pun dijalankan — hanya env yang membedakan.
Jangan hardcode port. Baca dari variabel lingkungan dengan nilai default yang aman untuk development:
port := os.Getenv("GRPC_PORT")
if port == "" {
port = "50051"
}
lis, err := net.Listen("tcp", ":"+port)
if err != nil {
log.Fatal(err)
}
log.Printf("server mendengarkan di :%s", port)Pola os.Getenv("GRPC_PORT") lalu fallback ke default adalah pola universal: konfigurasi mudah berubah, kode tidak berubah. Hal yang sama diterapkan untuk TLS, alamat dependency, dan flag lainnya.
TLS harus bisa diaktifkan tanpa mengubah kode:
if os.Getenv("GRPC_TLS") == "true" {
creds, err := credentials.NewServerTLSFromFile(
os.Getenv("TLS_CERT"), os.Getenv("TLS_KEY"),
)
s = grpc.NewServer(grpc.Creds(creds))
} else {
s = grpc.NewServer()
}Pengaturan GRPC_TLS=true mengaktifkan enkripsi; di development, variabel ini dibiarkan kosong sehingga memakai plaintext. Alur ini disempurnakan di episode 11 dengan mTLS penuh.
Client perlu tahu ke mana harus terhubung, dan alamat itu berbeda di tiap environment:
target := os.Getenv("GRPC_TARGET")
if target == "" {
target = "localhost:50051"
}
conn, _ := grpc.NewClient(target, opts...)Di development targetnya localhost:50051; di staging bisa grpc.internal.example.com:443; di Kubernetes cukup nama service seperti catalog-svc:50051. grpc.NewClient(target, opts...) menerima semua bentuk tersebut.
Retry policy dikirim sebagai JSON bersama nama target:
{
"methodConfig": [
{
"name": [
{ "service": "catalog.v1.CatalogService" }
],
"retryPolicy": {
"maxAttempts": 4,
"initialBackoff": "0.1s",
"maxBackoff": "1s",
"backoffMultiplier": 2.0,
"retryableStatusCodes": [
"UNAVAILABLE"
]
}
}
]
}Konfigurasi retryPolicy di atas memberitahu client untuk mencoba ulang sampai empat kali ketika server mengembalikan UNAVAILABLE. JSON ini bisa dibaca dari environment variable atau file — episode 15 membahasnya lebih dalam.
Untuk image yang kecil dan aman, pakai build multi-stage. Tahap pertama mengompilasi biner Go, tahap kedua membuat image runtime yang ramping:
FROM golang:1.23 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /server ./server
FROM gcr.io/distroless/static-debian12
COPY --from=builder /server /server
EXPOSE 50051
ENTRYPOINT ["/server"]Dockerfile di atas menghasilkan image tanpa shell dan toolchain — hanya biner. CGO_ENABLED=0 go build memastikan biner statis yang bisa berjalan di container minimal.
docker build -t belajar-grpc-server .
docker run -p 50051:50051 \
-e GRPC_PORT=50051 \
belajar-grpc-serverFlag -p 50051:50051 memetakan port container ke host, dan -e GRPC_PORT=50051 meneruskan environment variable. Sekarang client lokal bisa terhubung ke server di dalam container.
Saat server gRPC punya dependency seperti database, gunakan docker-compose untuk mengatur semuanya sekaligus:
services:
catalog:
build: .
environment:
GRPC_PORT: "50051"
DB_HOST: postgres
ports:
- "50051:50051"
depends_on:
- postgres
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: localdev
ports:
- "5432:5432"File docker-compose.yml ini mendefinisikan dua service: catalog (server gRPC) dan postgres (database). Perhatikan DB_HOST: postgres — di dalam jaringan compose, service bisa dipanggil lewat nama service-nya.
docker compose up --buildDengan satu perintah, docker compose up --build membangun image, membuat jaringan, dan menyalakan database plus server. Untuk development yang lebih cepat, bisa dijalankan di mode detached dan log ditonton dengan docker compose logs -f.
Inti yang harus dibawa pulang:
os.Getenv dengan nilai default membuat kode sama di semua environment.Di episode 8 selanjutnya kita membahas state, data management & schema evolution — best practice mengubah schema protobuf tanpa breaking changes, teknik versioning message dan field numbering, migrasi service, serta integrasi gRPC dengan database atau stateful backend. Deployment kalian yang baru jadi akan mulai menyimpan data nyata.