Sử dụng Docker để xây dựng grpc-gateway

AJ Pham
ZaloPay Engineering
7 min readJun 12, 2019

--

1. Mở đầu

Hiện nay việc sử dụng framework gRPC của Google để xây dựng các service không còn quá xa lạ với giới lập trình nữa. Nhưng các service được xây dựng trên nền tảng gRPC sẽ không thể giao tiếp trực tiếp với các RESTful JSON API mà phía frontend hay sử dụng.

Vấn đề đặt ra là chúng ta cần phải chuyển đổi các yêu cầu RESTful API thành các yêu cầu gRPC để hệ thống các service gRPC có thể hiểu được.

Google đã nêu ra hướng giải quyết bài toán trên bằng cách sử dụng grpc-gateway. Nhưng để có thể xây dựng grpc-gateway nhiều bạn developer đã gặp khá nhiều khó khăn từ việc cài đặt môi trường Golang, protobuf, các lệnh generate, cách xây dựng, …

Ở bài viết này mình xin giới thiệu một cách đơn giản để có thể xây dựng được grpc-gatewayhơn đó là sử dụng Docker xây dựng grpc-gateway.

2. Xây dựng grpc-gateway

Ở phần 2 này mình sẽ giới thiệu giải pháp thực hiện xây dựng grpc-gateway bằng Docker và cách cài đặt như thế nào.

Giải pháp

Chúng ta sẽ sử dụng open source namely/docker-protoc đễ xây dựng grpc-gateway bằng docker. Ngoài việc hỗ trợ docker grpc-gateway, open source namely cũng cung cấp nhiều tính năng tiện lợi như Uber’s Prototool với namely/prototool hay grpc_cli với namely/grpc-cli.

Cài đặt namely/docker-protoc

Trước khi bắt đầu vào xây dựng demo grpc-gateway mình sẽ giới thiệu cách sử dụng namely/docker-protoc. Điều kiện đầu tiên là các bạn phải cài đặt docker cho máy tính của mình. Sau khi cài đặt thành công docker, các bạn hãy pull container namely/docker-protoc về bằng lệnh sau:

$ docker pull namely/protoc-all

Việc pull container về thành công là bạn có thể bắt tay ngay vào việc xây dựng grpc-gateway rồi, không cần phải cài đặt gì thêm nữa.

3. Demo xây dựng grpc-gateway với một service

Mô hình gRPC-gateway với một service

Tạo grpc-gateway

Ở phần này mình sẽ demo một service grpc đơn giản với API ping, sau đó mình sẽ xây dựng grpc-gateway để có thể chuyển đổi các yêu cầu http-json thành grpc-protobuf.

Đầu tiên mình định nghĩa các file proto như sau:

File common.proto
File serviceA.proto

Bước tiếp theo mình sẽ generate grpc-gateway từ các file proto bằng container namely/docker-protoc. Các bạn đi tới thư mục chứa các file proto và chạy lệnh sau:

$ docker run -v `pwd`:/defs namely/gen-grpc-gateway -f . -s ServiceA

Sau khi run thành công sẽ tạo cho chúng ta một project hoàn chỉnh để xây dựng grpc-gateway ngay trong thư mục mà ta đang đứng.

Folder chứa các đoạn code được generate

Cấu hình grpc-gateway

Tiếp theo mình sẽ cấu hình grpc-gateway trong file config.yaml.

File config.yaml sau khi sửa đổi

Mình sẽ giải thích qua các option quan trọng:

- backend: host của grpc serviceA nơi mà grpc-gateway sẽ chuyển yêu cầu tới.
- cors: cấu hình sercurity
- proxy: port của grpc-gateway

Mình cũng sẽ sửa Dockerfile như sau:
- Chắc đây là lỗi của namely/docker-protoc khi gen file nên đường dẫn không đúng ở dòng:

COPY — from=build /app/src/gen/pb-go/..swagger.json /app/

Chúng ta sẽ phải sửa lại đường dẫn thành:

COPY — from=build /app/src/gen/pb-go/serviceA.swagger.json /app/

Vì mình config port của grpc-gateway là 9000 nên trong Dockerfile phần EXPOSE mình cũng sửa lại thành port 9000.

Bước tiếp theo chúng ta sẽ build image bằng cách chạy lệnh sau:

#docker build -t grpc-gateway directory_contains_dockerfile
$ docker build -t grpc-gateway gen/grpc-gateway/

Bước cuối cùng chúng ta sẽ start grpc-gateway bằng lệnh:

$ docker run -p 9000:9000 --rm --link service-a grpc-gateway

Test grpc-gateway

Để test grpc-gateway trước hết mình sẽ xây dựng grpc ServiceA như sau:

Implement serviceA

Mình cũng đã tạo Dockerfile cho grpc ServiceA, các bạn có thể xem tại đây. Chúng ta cũng build image cho ServiceA và run image như sau:

#build image service-a
$ docker build -t service-a .

#run image
$ docker run --name service-a --rm service-a

Có nhiều cách test API, mình có thể dùng postman, curl hay swagger. Ở đây mình sẽ tận dụng luôn file swagger.json đã gen được ở trên. Các bạn vào đường dẫn https://editor.swagger.io/, sau đó copy nội dung file serviceA.swagger.json và paste vào vùng editor của trang web. Các bạn nhớ thêm dòng host: localhost:9000 vào nữa nhé. Sau đó các bạn nhập timestamp và Exeute API. Đây là kết quả trả về:

Kết quả test API ping của service A qua grpc-gateway

Như vậy chúng ta đã xây dựng thành công grpc-gateway bằng Docker rồi.

4. Grpc-gateway với nhiều service

Mô hình gRPC-gateway với nhiều service

Giải pháp

Ở phần demo trên mình chỉ xây dựng hệ thống có một ServiceA và đã chạy thành công grpc-gateway. Vậy trong trường hợp hệ thống chúng ta có nhiều grpc service thì liệu rằng namely/docker-protoc có hỗ trợ cho chúng ta không. Câu trả lời là không nhé các bạn. Mình có tạo issue trên github của namely/docker-protoc. Nhưng các bạn đừng lo, mình đã tìm ra cách rất đơn giản để giải quyết vấn đề này.

Trước hết mình tạo thêm file proto cho serviceB tương tự như file proto của serviceA:

File serviceB.proto

Sau đó mình vẫn dùng lệnh docker để generate:

$ docker run -v `pwd`:/defs namely/gen-grpc-gateway -f . -s ServiceA

Chú ý ở đây dù mình có 2 service nhưng vẫn để name service là tên của một trong hai service nhé. Sau khi generate thành công cũng sẽ tạo ra các file như lần demo ở mục 2. Chúng ta cũng cấu hình file config và sửa file Dockerfile như ở mục 2.

Bước tiếp theo chúng ta sẽ sửa file main.go một chút. Vì chúng ta có hai service nên cần phải đăng kí cả hai service đó với gateway. Cách làm như sau:

File main.go

Bình thường ở func SetupMux(…) chỉ có đăng kí ServiceA (vì lúc chạy docker run mình để tên là ServiceA), chúng ta sẽ thêm phần đăng kí ServiceB vào func SetupMux(..). Đến đây chúng ta đã xong phần sửa đổi grpc-gateway cho nhiều service.

Chúng ta cũng build image và run image grpc-gateway:

#docker build -t grpc-gateway directory_contains_dockerfile
$ docker build -t grpc-gateway gen/grpc-gateway/

#run image
$ docker run -p 9000:9000 --link service-ping --rm grpc-gateway

Test grpc-gateway

Chúng ta cũng sẽ xây dựng grpc ServiceB như ở mục 2. Và mình cũng tạo Dockerfile để chạy, các bạn có thể xem tại đây.

Tiếp theo mình sẽ build image và run docker image cho service-ping (hệ thống gồm ServiceA và ServiceB):

#build image
$ docker build -t service-ping .

#run image
$ docker run --name service-ping --rm service-ping

Mình vẫn dùng swagger để test API như trên. Trước hết mình sẽ gọi qua ServiceA, và đây là kết quả:

Kết quả test API ping của serviceA qua grpc-gateway

Lần này mình sẽ gọi qua ServiceB để test, và đây là kết quả:

Kết quả test API ping của serviceB qua grpc-gateway

Cả hai lần test API ping đều thành công, vậy grpc-gateway của chúng ta đã hoạt động tốt.

5. Kết luận

Bài viết trên đây mình đã giới thiệu các bạn open source namely/docker-protoc để tạo grpc-gateway bằng docker. Mình đã thực hiện demo xây dựng grpc-gateway với một service, đồng thời hướng dẫn cách xây dựng grpc-gateway với nhiều service. Qua các bước hướng dẫn của mình, các bạn có thể thấy để xây dựng một grpc-gateway bằng docker rất đơn giản, giúp chúng ta tiết kiệm được nhiều thời gian và đặc biệt không cần phải cài đặt môi trường gì cả. Các bạn có thể xem toàn bộ source code tại đây. Hẹn các bạn ở bài blog tiếp theo nhé.

--

--

AJ Pham
ZaloPay Engineering

I am a Senior Software Engineer at VNG. I often write blogs to share experiences as well as read more blog posts. linkedin.com/in/aj-pham-abc27011997