英文:
gRPC service definitions: containerize .proto compilation?
问题
让我们假设我们有一个包含 gRPC 服务定义的 services.proto
文件,例如:
service Foo {
rpc Bar (BarRequest) returns (BarReply) {}
}
message BarRequest {
string test = 1;
}
message BarReply {
string test = 1;
}
我们可以通过以下命令将其编译为 Go 代码:
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
services.proto
然而,我担心运行最后一步可能会产生不一致的输出,这取决于安装的 protobuf 编译器版本和 gRPC 的 Go 插件。例如,两个在同一项目上工作的开发人员可能在本地安装了稍微不同的版本。
我认为通过将 protoc
步骤容器化来解决这个问题是合理的。例如,可以使用以下 Dockerfile
:
FROM golang:1.18
WORKDIR /src
RUN apt-get update && apt-get install -y protobuf-compiler
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
CMD protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative services.proto
然后,在容器中运行 protoc
步骤:
docker run --rm -v $(pwd):/src $(docker build -q .)
将上述命令封装在一个 shell 脚本中后,开发人员可以在本地机器上运行它,从而获得确定性和可重现的输出。它也可以在 CI/CD 流水线中运行。
我的问题是,这种方法是否可行,或者是否有更简单的方法来实现相同的结果?
值得注意的是,我惊讶地发现官方的 grpc/go 镜像没有预安装 protoc
。我是否偏离了常规做法?
英文:
Let's say we have a services.proto
with our gRPC service definitions, for example:
service Foo {
rpc Bar (BarRequest) returns (BarReply) {}
}
message BarRequest {
string test = 1;
}
message BarReply {
string test = 1;
}
We could compile this locally to Go by running something like
$ protoc --go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
services.proto
My concern though is that running this last step might produce inconsistent output depending on the installed version of the protobuf compiler and the Go plugins for gRPC. For example, two developers working on the same project might have slightly different versions installed locally.
It would seem reasonable to me to address this by containerizing the protoc
step. For example, with a Dockerfile
like this...
FROM golang:1.18
WORKDIR /src
RUN apt-get update && apt-get install -y protobuf-compiler
RUN go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.26
RUN go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
CMD protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative services.proto
... we can run the protoc
step inside a container:
docker run --rm -v $(pwd):/src $(docker build -q .)
After wrapping the previous command in a shell script, developers can run it on their local machine, giving them deterministic, reproducible output. It can also run in a CI/CD pipeline.
My question is, is this a sound approach and/or is there an easier way to achieve the same outcome?
NB, I was surprised to find that the official grpc/go image does not come with protoc
preinstalled. Am I off the beaten path here?
答案1
得分: 1
我的问题是,这是一个可行的方法吗?还是有更简单的方法可以实现相同的结果?
这绝对是一个好方法。我也是这样做的。不仅可以在团队中保持一致,还可以确保我们可以在不同的操作系统上产生相同的输出。
不过,还有一种更简单的方法可以实现相同的结果。你可以查看这个仓库:https://github.com/jaegertracing/docker-protobuf
这个镜像在Docker Hub上,但如果你愿意,你也可以创建自己的镜像。
我使用以下命令来生成Go代码:
docker run --rm -u $(id -u) \
-v${PWD}/protos/:/source \
-v${PWD}/v1:/output \
-w/source jaegertracing/protobuf:0.3.1 \
--proto_path=/source \
--go_out=paths=source_relative,plugins=grpc:/output \
-I/usr/include/google/protobuf \
/source/*
英文:
> My question is, is this a sound approach and/or is there an easier way to achieve the same outcome?
It is definitely a good approach. I do the same. Not only to have a consistent across the team, but also to ensure we can produce the same output in different OSs.
There is an easier way to do that, though.
Look at this repo: https://github.com/jaegertracing/docker-protobuf
The image is in Docker hub, but you can create your image if you prefer.
I use this command to generate Go:
docker run --rm -u $(id -u) \
-v${PWD}/protos/:/source \
-v${PWD}/v1:/output \
-w/source jaegertracing/protobuf:0.3.1 \
--proto_path=/source \
--go_out=paths=source_relative,plugins=grpc:/output \
-I/usr/include/google/protobuf \
/source/*
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论