Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
25 Aug 2025 · 6 min read ·Article 78 / 110
Go

78. Deploying a gRPC Service on Docker

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

title: “78. Deploying a gRPC Service on Docker” date: 2024-06-13 author: Software Engineer Senior

Lately, gRPC has been gaining popularity as one of the fast, efficient RPC (Remote Procedure Call) technologies that is particularly well suited for microservices-based architectures. However, simply building a gRPC service isn’t enough without knowing how to package and deploy it properly, especially into a containerized environment like Docker.

In this article, I’ll share my experience and best practices for deploying a gRPC service using Docker, complete with code examples, simulations, tables, and a deployment flow diagram via mermaid. We’ll use Go as the implementation example because of its clear syntax and fast build times, but the concepts apply just as well to any stack (Python, Java, Node.js, and so on).


1. A Quick Introduction to gRPC and Docker

What is gRPC?

gRPC is an open-source framework developed by Google that enables applications to communicate across devices using efficient, interactive, Protobuf-based API definitions. Some of the advantages of gRPC include:

  • Multi-language support (Go, Java, C#, Python, and so on)
  • Fast under-the-hood HTTP/2 (not HTTP/1.1)
  • Support for both bidirectional streaming and unary calls
  • Auto-generated stubs from *.proto files

What is Docker?

Docker is a containerization tool that makes it easy to package an application along with all of its dependencies so it can run consistently anywhere—on your laptop, a server, or in the cloud—without worrying about dependency hell.


2. A Minimal Project Structure

Before we dive into deployment, here is the minimal structure of a Go-based gRPC project that we’ll be using:

plaintext
 1grpc-docker-demo/
 2 3├── proto/
 4│   └── hello.proto
 5├── server/
 6│   └── main.go
 7├── client/
 8│   └── main.go
 9├── Dockerfile
10└── go.mod
Danger

A quick explanation:

  • proto/hello.proto: The Protobuf file that defines the service and messages
  • server/main.go: The service implementation (Go)
  • client/main.go: A simple gRPC client simulation (optional)
  • Dockerfile: The Docker image setup
  • go.mod: Go module dependency management

3. Setting Up a Simple gRPC Service

Step 1: Define the Service in Protobuf

Create the file proto/hello.proto:

proto
 1syntax = "proto3";
 2
 3package helloworld;
 4
 5service Greeter {
 6  rpc SayHello (HelloRequest) returns (HelloReply);
 7}
 8
 9message HelloRequest {
10  string name = 1;
11}
12
13message HelloReply {
14  string message = 1;
15}

Step 2: Generate the Go Code

Install protoc and the Go plugins:

sh
1go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
2go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Generate the code:

sh
1protoc --go_out=. --go-grpc_out=. proto/hello.proto

Step 3: Implement the Server

Create the file server/main.go:

go
 1package main
 2
 3import (
 4  "context"
 5  "log"
 6  "net"
 7
 8  pb "grpc-docker-demo/proto"
 9  "google.golang.org/grpc"
10)
11
12type server struct {
13  pb.UnimplementedGreeterServer
14}
15
16func (s *server) SayHello(ctx context.Context, req *pb.HelloRequest) (*pb.HelloReply, error) {
17  return &pb.HelloReply{Message: "Hello " + req.Name}, nil
18}
19
20func main() {
21  lis, err := net.Listen("tcp", ":50051")
22  if err != nil {
23    log.Fatalf("failed to listen: %v", err)
24  }
25  s := grpc.NewServer()
26  pb.RegisterGreeterServer(s, &server{})
27
28  log.Println("gRPC server listening on :50051")
29  if err := s.Serve(lis); err != nil {
30    log.Fatalf("failed to serve: %v", err)
31  }
32}

4. Creating a Dockerfile for the gRPC Service

To make sure our Go application can run anywhere, we package it using Docker. Here’s a reasonably optimized Dockerfile example:

dockerfile
 1# Stage 1: Build binary
 2FROM golang:1.21-alpine AS builder
 3WORKDIR /app
 4
 5COPY go.mod go.sum ./
 6RUN go mod download
 7
 8COPY . .
 9RUN CGO_ENABLED=0 GOOS=linux go build -o server ./server
10
11# Stage 2: Final image
12FROM scratch
13WORKDIR /root/
14
15COPY --from=builder /app/server .
16COPY proto/ ./proto/
17EXPOSE 50051
18ENTRYPOINT ["./server"]
Danger

Notes:

  • We use a multi-stage build (builder and scratch) so the resulting image is small and contains only the release binary.
  • Only port 50051 (the default gRPC port) is exposed.

5. Building and Simulating a Docker Deploy

Build Simulation

Run the following command from the project root folder:

sh
1docker build -t grpc-docker-demo:latest .

Running the Container

sh
1docker run -p 50051:50051 grpc-docker-demo:latest

The service is now accessible at localhost:50051 (for a gRPC client).


6. Local Testing with a gRPC Client

If you’d like to test it through a simple client:

go
 1package main
 2
 3import (
 4  "context"
 5  "log"
 6  "time"
 7
 8  pb "grpc-docker-demo/proto"
 9  "google.golang.org/grpc"
10)
11
12func main() {
13  conn, err := grpc.Dial("localhost:50051", grpc.WithInsecure())
14  if err != nil {
15    log.Fatalf("did not connect: %v", err)
16  }
17  defer conn.Close()
18  c := pb.NewGreeterClient(conn)
19
20  ctx, cancel := context.WithTimeout(context.Background(), time.Second)
21  defer cancel()
22  r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Dunia"})
23  if err != nil {
24    log.Fatalf("could not greet: %v", err)
25  }
26  log.Printf("Server Response: %s", r.Message)
27}

7. Deployment Flow Diagram

Here is the deployment flow diagram for a gRPC service on Docker:

MERMAID
flowchart TD
    A[dev: Implementasi gRPC Service]
    B[Build Docker Image]
    C[Test Lokal Docker Run]
    D[Push ke Docker Registry]
    E[Deploy ke Server/Cloud (k8s, ECS, dll)]
    A --> B
    B --> C
    C --> D
    D --> E

8. Comparison Table: Docker vs. Native Run

AspectNative RunDockerized Run
DependencyManual installImaged, self-contained
PortabilityOS/machine dependentMulti-platform
IsolationNoneFull (namespace, fs)
Deploy SpeedFaster on a single hostEasier rollout
ManagementHard to scaleOrchestration-friendly

9. Professional Tips for Deploying gRPC on Docker

A few best practices you absolutely should keep in mind:

  • Use a multi-stage build to reduce image size
  • Disable CGO (CGO_ENABLED=0) to make the binary more portable
  • Keep credentials/secrets out of the image; use ENV variables or a secret manager
  • Automate build/test with CI/CD (for example: GitHub Actions, GitLab CI)
  • Monitoring & Health Checks: gRPC doesn’t expose an HTTP endpoint, so use a sidecar or a custom liveness probe

10. Conclusion

Deploying a gRPC service into Docker isn’t just a modern practice—it also ensures our application is ready to scale up to a modern production environment such as Kubernetes or other cloud platforms. The process is fairly straightforward as long as the project is well structured, the dependencies are organized, and we stay disciplined about following best practices.

With the steps above, you can now package, run, and deploy a gRPC service consistently anywhere.

Happy experimenting, and may your service run smoothly without any more dependency drama!


References:


If you’d like to discuss topics around monitoring, observability, or CI/CD for gRPC services on Docker, feel free to request them in the comments!

Related Articles

💬 Comments