11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

protobufのコード生成をDockerでやりたい

Last updated at Posted at 2025-12-10

概要

Protocol Buffers(gRPC)のコード生成を行う際、チームメンバー間で protoc やプラグイン(protoc-gen-go 等)のバージョンが異なり、生成されるコードに意図しない差分が発生します。これを防ぐため、コード生成環境を Docker 化し、ローカルへのツールインストール不要&バージョン管理の手間をなくすようにしました。

実装

公式から protoc を取得し、Go 製のプラグインをインストールして軽量な Distroless イメージにまとめています。

FROM golang:bookworm AS golang
ARG PROTOBUF_GO_VERSION=1.36.10
ARG GRPC_GO_VERSION=1.6.0
ARG PROTOBUF_VERSION=33.1

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go install google.golang.org/protobuf/cmd/protoc-gen-go@v${PROTOBUF_GO_VERSION}

RUN --mount=type=cache,target=/go/pkg/mod \
    --mount=type=cache,target=/root/.cache/go-build \
    go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v${GRPC_GO_VERSION}

RUN apt-get update && \
    apt-get install -y --no-install-recommends curl unzip && \
    [[ $(uname -m) == "aarch64" ]] && ARCH="aarch_64" || ARCH="x86_64" && \
    curl -L https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOBUF_VERSION}/protoc-${PROTOBUF_VERSION}-linux-${ARCH}.zip -o protoc.zip && \
    unzip protoc.zip -d /usr/local/

FROM gcr.io/distroless/static-debian12:nonroot AS builder
WORKDIR /tmp/work

COPY --from=golang --chown=nonroot:nonroot /go/bin/protoc-gen-go /usr/local/bin/protoc-gen-go
COPY --from=golang --chown=nonroot:nonroot /go/bin/protoc-gen-go-grpc /usr/local/bin/protoc-gen-go-grpc
COPY --from=golang --chown=nonroot:nonroot /usr/local/bin/protoc /usr/local/bin/protoc
COPY --from=golang --chown=nonroot:nonroot /usr/local/include /usr/local/include

ENTRYPOINT [ "protoc" ]

image 作成

docker buildx build . -t protoc

gRPC 生成してみた

ディレクトリ構造

検証用のディレクトリ構成は以下になります。

.
├── proto/
│   ├── common/      # 共通メッセージ定義
│   └── helloworld/  # 個別のgRPCサービス定義
├── gen/             # 生成コードの出力先
└── go.mod

user_type.proto

syntax = "proto3";

package common;

option go_package = "project/gen/proto/common";

message UserInfo {
  string user_id = 1;
  string name = 2;
  int32 age = 3;
  UserStatus status = 4;
}

message UserStatus {
  bool is_active = 1;
  string last_login = 2;
}

helloworld.proto

syntax = "proto3";

package helloworld;

option go_package = "project/gen/proto/helloworld";

import "google/protobuf/timestamp.proto";
import "proto/common/user_type.proto";

// The greeting service definition.
service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
  common.UserInfo user = 2;
  google.protobuf.Timestamp date = 3;
}

※ go_package は実際のプロジェクトに合わせて変更してください。

生成コマンド

zsh の場合

docker run --rm -u $UID:$GID -v $PWD:/tmp/work protoc --go_out=./gen --go_opt=paths=source_relative --go-grpc_out=./gen --go-grpc_opt=paths=source_relative **/*.proto

bash の場合

# shopt -s globstar を利用するかパスを直接指定してください
docker run --rm -u $UID:$GID -v $PWD:/tmp/work protoc --go_out=./gen --go_opt=paths=source_relative --go-grpc_out=./gen --go-grpc_opt=paths=source_relative proto/*/*.proto

※ -u オプションをつけることで、生成されるファイルの所有者を コマンド実施者と一緒にします。

生成結果

image 内で install した tool のバージョンになってます。
image.png

運用の効率化

コマンドが長くなるため、スクリプト化してMakefileに記載しておくと便利です。
以下は、参考程度のシェルスクリプトです。※動作確認は細かくしてません。

generate(クリックで展開)
#!/usr/bin/env bash
set -euo pipefail

# 出力先のクリーンアップ
rm -rf gen
mkdir -p gen

echo "Generating gRPC code..."

# プロジェクトルートで実行することを想定
docker run --rm \
    -u "$(id -u):$(id -g)" \
    -v "$PWD":/tmp/work \
    protoc \
    --go_out=./gen --go_opt=paths=source_relative \
    --go-grpc_out=./gen --go-grpc_opt=paths=source_relative \
    $(find proto -name '*.proto')

echo "Done."

おわり

Docker 化により、バージョン差異によるトラブルから解放されました。

参考リンク

11
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?