go-micro について
go-micro は、microservice 用のサーバーを構築するための Go 言語のフレームワークです。gRPC による(同期型)API サーバー、および、Cloud Pub/Sub などのメッセージブローカーから受信したイベントを処理する(非同期型)API サーバーを簡単に作成することができます。ここでは、GCP の以下のサービスと組み合わせて、go-micro を利用する手順を紹介します。
・Google Kubernetes Engine (GKE) : go-micro で作ったサービスを GKE の Pod としてデプロイします。
・Cloud Pub/Sub : メッセージブローカーとして Cloud Pub/Sub を使用します。
go-micro はさまざまな機能のバックエンドをプラグインで選択できるようになっており、ここでは、Service Registory 機能として、Pod の Annotation を使用する Kubernetes Registry Plugin と、メッセージブローカーとして Cloud Pub/Sub を使用する googlepubsub Plugin を組み合わせて利用します。
事前準備
まずは、GCP のプロジェクトを作成します。ここでは、プロジェクト ID は「go-micro-test」とします。次に GKE で Kubernetes のクラスターを作成しますが、Pod から Cloud Pub/Sub などの外部サービスを利用できるよう、Access scopes には「Allow full access to all Cloud APIs」を指定してください。
この後の作業は、Cloud Shell からも行うことができますが、ここでは、GCE の VM を使って、開発用サーバーを用意しておくことにします。(Cloud Shell を使う場合は、ここは飛ばして、次のセクションに進んでください。)はじめに、適当なサイズの VM インスタンスを起動します。OS はデフォルトの Debian です。Kubernetes と同様に、Access scopes には「Allow full access to all Cloud APIs」を指定してください。
インスタンスが起動したら、SSH でログインして、Protocol buffer のコンパイラと Go 言語の開発環境を用意します。
sudo apt update sudo apt -y upgrade sudo apt install -y build-essential git protobuf-compiler wget https://golang.org/dl/go1.14.6.linux-amd64.tar.gz tar -xvzf go1.14.6.linux-amd64.tar.gz sudo mv go /usr/local cat <<'EOF' >>~/.bashrc export GOROOT=/usr/local/go export GOPATH=~/go export PATH=$GOPATH/bin:$GOROOT/bin:$PATH EOF
コンテナイメージをビルドするために Docker をインストールします。
sudo apt install -y apt-transport-https ca-certificates curl software-properties-common gnupg2 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" sudo apt update sudo apt install -y docker-ce sudo usermod -aG docker $USER
ここで一度、サーバーを再起動しておきます。
sudo reboot
再起動後に、再度、SSH でログインして、環境が用意できたことを確認します。
$ go version go version go1.14.6 linux/amd64 $ protoc --version libprotoc 3.0.0 $ docker version Client: Docker Engine - Community Version: 19.03.12 API version: 1.40 Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:45:52 2020 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 19.03.12 API version: 1.40 (minimum version 1.12) Go version: go1.13.10 Git commit: 48a66213fe Built: Mon Jun 22 15:44:23 2020 OS/Arch: linux/amd64 Experimental: false containerd: Version: 1.2.13 GitCommit: 7ad184331fa3e55e52b890ea95e65ba581ae3429 runc: Version: 1.0.0-rc10 GitCommit: dc9208a3303feef5b3839f4323d9beb36df0a9dd docker-init: Version: 0.18.0 GitCommit: fec3683
go-micro のインストールと動作確認
必須ではありませんが、開発中に便利なので、goimports コマンドを入れておきます。
go get golang.org/x/tools/cmd/goimports
go-micro の実行に必要なモジュールをインストールします。
go get github.com/golang/protobuf/{proto,protoc-gen-go} GO111MODULE=on go get github.com/micro/micro/v2 GO111MODULE=on go get github.com/micro/protoc-gen-micro/v2
サンプルサービスを生成して、go-micro が正しくインストールされていることを確認します。--namespace オプションは、サービス名を World Wide でユニークにするために、FQDN 逆順命名規約で Namespace を指定します。
cd $GOPATH/src micro new --namespace=com.example --gopath=false sample cd sample
$GOPATH/src/sample 以下に次のようなテンプレートが生成されています。
$ tree . . ├── Dockerfile ├── generate.go ├── go.mod ├── handler │ └── sample.go ├── main.go ├── Makefile ├── plugin.go ├── proto │ └── sample │ └── sample.proto ├── README.md └── subscriber └── sample.go
この時、デフォルトで用意された go.mod の内容に注意してください。
go.mod
module sample go 1.13 // This can be removed once etcd becomes go gettable, version 3.4 and 3.5 is not, // see https://github.com/etcd-io/etcd/issues/11154 and https://github.com/etcd-io/etcd/issues/11931. replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
etcd と grpc のモジュールの非互換依存問題があるため、それを回避するための replace エントリが記載されています。自動生成されるテンプレートを使わないと、こういった点にはまる事があるので注意してください。
また、Makefile も用意されているので、次のコマンドでバイナリーのビルドができます。(この時、proto ファイルのコンパイルも行われます。)
make build
出来上がったバイナリーは、ローカルで実行することもできます。
$ ./sample-service 2020-08-06 11:50:28 file=v2@v2.9.1/service.go:200 level=info Starting [service] com.example.service.sample 2020-08-06 11:50:28 file=grpc/grpc.go:864 level=info Server [grpc] Listening on [::]:39755 2020-08-06 11:50:28 file=grpc/grpc.go:881 level=info Broker [http] Connected to 127.0.0.1:39849 2020-08-06 11:50:28 file=grpc/grpc.go:697 level=info Registry [mdns] Registering node: com.example.service.sample-a764a88f-35ea-4bc5-a603-a5a1e133fff2 2020-08-06 11:50:28 file=grpc/grpc.go:730 level=info Subscribing to topic: com.example.service.sample
gRPC の Listen ポートはランダムに割り当てられますが、Service Discovery 機能があるので気にしなくても構いません。(デフォルトでは、mDNS による discovery 機能が提供されます。)
別のターミナルから SSH ログインして、micro コマンドでサービスの状態を確認してみます。
$ micro list services com.example.service.sample micro.http.broker $ micro get service com.example.service.sample Endpoint: Sample.Call Request: { message_state MessageState { no_unkeyed_literals NoUnkeyedLiterals do_not_compare DoNotCompare do_not_copy DoNotCopy message_info MessageInfo } int32 int32 unknown_fields []uint8 name string } Response: { message_state MessageState { no_unkeyed_literals NoUnkeyedLiterals do_not_compare DoNotCompare do_not_copy DoNotCopy message_info MessageInfo } int32 int32 unknown_fields []uint8 msg string } ...
Sample.Call というエンドポイントの API があることがわかります。次のように、サービス名とエンドポイント名を指定して、gRPC のリクエストを投げることもできます。
$ micro call com.example.service.sample Sample.Call '{"name": "world!"}' { "msg": "Hello world!" }
proto ファイルが読める方であれば、proto/sample/sample.proto を見ると API の仕様がわかります。
これで、基本的な動作確認ができました。先ほど起動したサービスは、Ctrl+C で停止しておきます。
次のパートでは、GKE 上にサービスをデプロイします。