はじめに
以下のチュートリアルをやってみた。
ただし、まったく同じ手順ではなく、Container Registry ではなく、Artifact
Registry を利用したり、インスタンスタイプを指定するなどしている。
実際に操作している動画を YouTube にアップロードした。
事前準備
ツール類のインストール
以下のツールをインストールする。バージョンは、異なっても良い。
- go 1.19.3
- git 2.35.1.windows.2
- protoc 3.21.10
Google Cloud 環境の設定等
チュートリアルを実施するための Google Cloud プロジェクトは、作成済みとする。
gcloud コマンド類は、以下のサイトの手順でインストール済みとする。
プロジェクトを切り替える場合は、以下のようにする。
gcloud config set project プロジェクトID
API の有効化
以下の API を有効化しておく。
- Compute Engine API
- Service Control API
- Artifact Registry API
- Cloud Build API
- Kubernetes Engine API
手順は、Google Cloud コンソールで、対象のプロジェクトを切り替えて、「API
とサービス」→「ライブラリ」に移動、「API とサービスを検索」で該当 API
を検索してクリックする。
API の詳細画面で「有効にする」ボタンを押下する。
ファイアウォールについて
前提知識として、Compute Engine の VM インスタンスに設定するファイアウォール
ルールについて説明する。
ファイアウォール ルールは、「VPC ネットワーク」→「ファイアウォール」に「VPC
ファイアウォール ルール」として定義する。
ファイアウォール
ルールには、「ターゲットタグ」設定があり、ここで設定した値を、VM
インスタンスの「ネットワーク
タグ」に指定すると、ルールがそのインスタンスに適用される。
ファイアウォール
ルールは、初期状態で以下が存在する。ただし、タグは設定されておらず、すべてのインスタンスに自動的に適用される。
- default-allow-icmp
- default-allow-internal
- default-allow-rdp
- default-allow-ssh
ここで、ハマりポイントがあった。
チュートリアルでは、「http-server」というタグを利用しているが、初期状態では対応するファイアウォール
ルールの「default-allow-http」が、存在していない。この状態でインスタンスを作成しても、エラーにはならないが、外部からの
HTTP アクセスが、ファイアウォールで遮断される。
上記ファイアウォール ルールが作成されるタイミングは、Google Cloud
コンソールから、VM インスタンスを作成する時に、ファイアウォールで「HTTP
トラフィックを許可する」をチェックした場合となる。(手動で作成してもいいのかもしれないが、未確認)
gcloud
コマンドで実行する場合、「--tags=http-server」オプションを指定しただけでは、ファイアウォール
ルールが、自動で作成されることはない。
よって、適当なインスタンスを Google Cloud コンソールから「HTTP
トラフィックを許可する」をチェックして作成して、default-allow-http
ファイアウォール ルールが作成された事を確認して、インスタンスを削除する。
HTTPS の場合も同様なので、必要に応じてファイアウォール
ルールを作成する。このチュートリアルでは利用しないので、作成しなくてもよい。
チュートリアル実施
チュートリアルのソースをクローンする
git clone --depth 1 https://github.com/GoogleCloudPlatform/golang-samples.git
cd golang-samples\endpoints\getting-started-grpc
ローカル環境で実行する
start go run server/main.go
go run client/main.go
Google Endpoints のサービスを登録する
protocolbuf の定義ファイル(out.pb)を生成する
protoc --include_imports --include_source_info --descriptor_set_out out.pb helloworld/helloworld.proto
api_config.yaml ファイルの YOUR_PROJECT_ID を Google Cloud のプロジェクト
ID に書き換え、以下を実行する。
gcloud endpoints services deploy out.pb api_config.yaml
登録が完了すると、Google Cloud
コンソールの「エンドポイント」に、登録したサービスが表示される。
Artifacts Registry にリポジトリを作成する
この手順は、オリジナルには無い。
gcloud artifacts repositories create --repository-format=docker --location=asia-northeast1 helloworld-repo
Artifacts Registry のリポジトリに gRPC サーバの Docker イメージを登録する
go.mod および go.sum をコピーする。
ローカルで動作させる場合は、親ディレクトリにある、これらファイルを参照してくれるが、
Docker イメージ作成時にコピー対象から外れているため。
copy ..\go.* .
Dockerfile を以下のように変更する。
FROM golang:alpine
RUN apk update \
&& apk add git
COPY . /go/src/app
WORKDIR /go/src/app
RUN go install ./server
ENTRYPOINT ["/go/bin/server"]
リポジトリに Docker イメージの登録を実行する。YOUR_PROJECT_ID
をプロジェクトIDに変更すること。
gcloud builds submit --tag asia-northeast1-docker.pkg.dev/YOUR_PROJECT_ID/helloworld-repo/go-grpc-hello:1.0 .
Compute Engine にデプロイする
Compute Engine にデプロイする方法は、Docker が利用可能な VM
インスタンスを起動して、 その VM インスタンス上で、gRPC
を処理するサーバと、エンドポイントと gRPC を処理するサーバとの仲介をする
Extensible Service Proxy(ESP)をコンテナとして起動する。
Compute Engine の VM インスタンスを作成する
コマンドを実行すると、VM
インスタンスが起動する。途中でゾーンを選択する必要があるが、ここでは、asia-northeast1-b
とした。
インスタンスの OS は、「Container-Optimized OS」となる。 この OS
は、パッケージ管理ツールが無く、直接アプリなどをインストールしない前提で利用する。
その代わり、Docker を利用可能で、アプリケーションなどは、Docker
コンテナとして動作させることとなる。
gcloud compute instances create grpc-host --image-family cos-stable --image-project cos-cloud --tags=http-server --machine-type=e2-micro
VM インスタンスにアプリケーションをデプロイする
VM インスタンスに SSH 接続する。コマンドを実行すると、PuTTY が起動し、VM
インスタンスに接続された状態となる。以後の作業は、起動した PuTTY
ウィンドウで実施する。
gcloud compute ssh grpc-host
プロジェクト名および、エンドポイントサービス名を取得する
GOOGLE_CLOUD_PROJECT=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google")
SERVICE_NAME=hellogrpc.endpoints.${GOOGLE_CLOUD_PROJECT}.cloud.goog
Docker に Artifacts Registry 参照権限を付与する
docker-credential-gcr configure-docker --registries=asia-northeast1-docker.pkg.dev
コンテナネットワークを作成する
docker network create --driver bridge esp_net
gRPC サーバコンテナを起動する
docker run --detach --net=esp_net --name=grpc-hello asia-northeast1-docker.pkg.dev/${GOOGLE_CLOUD_PROJECT}/helloworld-repo/go-grpc-hello:1.0
エンドポイント用のプロキシコンテナを起動する
docker run \
--detach \
--name=esp \
--publish=80:9000 \
--net=esp_net \
gcr.io/endpoints-release/endpoints-runtime:1 \
--service=${SERVICE_NAME} \
--rollout_strategy=managed \
--http2_port=9000 \
--backend=grpc://grpc-hello:50051
VM インスタンスの IP を確認する
このコマンドは、ローカルマシン上で実行すること。
NAME が grpc-host となっている行の、EXTERNAL_IP が、外部からアクセスするための
IP となる。
gcloud compute instances list --filter=grpc-host
API キーを作成する
Google Cloud コンソールの「API
とサービス」→「認証情報」画面で、「+認証情報を作成」ボタンを押下し、「API
キー」を選択する。
表示された API キーをコピーしておく。
gRPC クライアントでアクセスする
ローカル PC 上のチュートリアルプロジェクトで実行する。api-key
オプションには、上記で作成した API キーを指定する。
go run client/main.go --api-key=AIza... --addr=<上記で調べたEXTERNAL_IP>:80 FOOBAR
クリーンアップ
VM インスタンスを削除する。
gcloud compute instances delete grpc-host
Kubernetes Engine にデプロイする
続いて、Kubernetes Engine にも gRPC サーバをデプロイしてみる。
kubectl コマンドをインストールする
kubectl コマンドは、gcloud
コマンドでインストールする。ローカルマシンで以下のコマンドを実行する。
gcloud components install kubectl
当方の環境では、Docker Desktop の kubectl が既にあり、PATH
の設定の関係で、そちらが優先され、
認証用プラグインなどで警告が出るため、Docker Desktop 側の kubectl.exe
をリネームして対応した。 Kubernetes Engine へのアクセスは、gcloud
でインストールする kubectl が推奨されているため、こちらを利用する。
Kubernetes クラスタを作成する
Autopilot クラスタの作成手順で、クラスタを作成する。オリジナルの手順では、ゾーンクラスタを作成している。
名前は、デフォルト(autopilot-cluster-1)、リージョンは、「asia-northeast1」
、ネットワークアクセスは、「一般公開クラスタ」を選択した。その他はデフォルトのままとした。作成完了まで多少時間がかかるようだ。
クラスタへアクセスするための認証情報を取得する
kubectl
で作成したクラスタへアクセスするための認証情報を取得する。autopilot-cluster-1
の部分は、作成したクラスタ名にすること。
コマンド実行が完了すると、設定が作成され、デフォルトの接続先となる。
gcloud container clusters get-credentials --region=asia-northeast1 autopilot-cluster-1
権限を設定する
Kubernetes Engine の Pod に権限を設定するために、Workload Identity
を利用する。 Workload Identity とは、Kubernetes Engine
クラスタ内の「Kubernetes サービス アカウント」を、「IAM サービス
アカウント」として機能させるための仕組みとなる。
Kubernetes 上で動作する Pod には、エンドポイント API
等へのアクセス権限が必要となる。 Kubernetes Engine の Autopilot クラスタ
における Pod への権限設定は、「Kubernetes サービス アカウント」を作成し、
次に、「IAM サービス アカウント」を作成して、各 API
アクセス権限を割り当て、「Kubernetes サービス アカウント」と対応付けした上で、
各 Pod の定義に「Kubernetes サービス アカウント」を指定することで行う。
このチュートリアルでは、Extensible Service Proxy(ESP)を動作させる Pod に権限が必要となる。
Kubernetes サービス アカウントを作成する
default ネームスペースに、Kubernetes サービス アカウントを作成する。
kubectl create serviceaccount grpc-hello-endpoint-ksa
作成されたことを確認する。
kubectl get serviceaccount
IAM サービス アカウントを作成する
gcloud iam service-accounts create grpc-hello-endpoint-gsa
作成されたことを確認する。
Google Cloud コンソールで確認する場合は、「IAM と管理」→「サービス
アカウント」で、
「grpc-hello-endpoint-gsa@YOUR_PROJECT_ID.iam.gserviceaccount.com」のような項目として表示される。
コマンドで確認する場合は、以下のようにする。
gcloud iam service-accounts list
IAM サービス アカウントにロールを付与する
ESP
に必要な権限は、エンドポイントを管理するためのサービスコントローラロールおよび、
Cloud Trace エージェントロール(各種情報収集用)となる。
サービスコントローラロールを付与する。YOUR_PROJECT_ID(2
箇所)をプロジェクトID に変更すること。
gcloud endpoints services add-iam-policy-binding hellogrpc.endpoints.YOUR_PROJECT_ID.cloud.goog --member serviceAccount:grpc-hello-endpoint-gsa@YOUR_PROJECT_ID.iam.gserviceaccount.com --role roles/servicemanagement.serviceController
Cloud Trace エージェントロールを付与する。YOUR_PROJECT_ID(2
箇所)をプロジェクトID に変更すること。
gcloud projects add-iam-policy-binding YOUR_PROJECT_ID --member serviceAccount:grpc-hello-endpoint-gsa@YOUR_PROJECT_ID.iam.gserviceaccount.com --role roles/cloudtrace.agent
Kubernetes サービス アカウントと IAM サービス アカウントを紐付ける
紐付けは、双方向に行う必要があるようだ。
IAM サービス アカウント側を設定。YOUR_PROJECT_ID(2 箇所)をプロジェクトID
に変更すること。
gcloud iam service-accounts add-iam-policy-binding grpc-hello-endpoint-gsa@YOUR_PROJECT_ID.iam.gserviceaccount.com --role roles/iam.workloadIdentityUser --member "serviceAccount:YOUR_PROJECT_ID.svc.id.goog[default/grpc-hello-endpoint-ksa]"
Kubernetes サービス アカウント側にアノテーションを設定。YOUR_PROJECT_ID(1
箇所)をプロジェクトID に変更すること。
kubectl annotate serviceaccount grpc-hello-endpoint-ksa iam.gke.io/gcp-service-account=grpc-hello-endpoint-gsa@YOUR_PROJECT_ID.iam.gserviceaccount.com
デプロイ用設定ファイルを修正する
deployment.yaml ファイル中の <YOUR_PROJECT_ID> をプロジェクトID
に変更する。
Pod のイメージは、Artifact Registry のリポジトリから取得するように、
「gcr.io/<YOUR_PROJECT_ID>/go-grpc-hello:1.0」の部分は、「asia-northeast1-docker.pkg.dev/<YOUR_PROJECT_ID>/helloworld-repo/go-grpc-hello:1.0」のようにする。
「serviceAccountName: grpc-hello-endpoint-ksa」行を追加する。
以上の修正をした結果は、以下のような差分となる。
diff --git a/endpoints/getting-started-grpc/deployment.yaml b/endpoints/getting-started-grpc/deployment.yaml
index f1e2321..b2ae498 100644
--- a/endpoints/getting-started-grpc/deployment.yaml
+++ b/endpoints/getting-started-grpc/deployment.yaml
@@ -40,18 +40,33 @@ spec:
labels:
app: grpc-hello
spec:
+ serviceAccountName: grpc-hello-endpoint-ksa
containers:
- name: esp
image: gcr.io/endpoints-release/endpoints-runtime:1
args: [
"-P", "9000",
"-a", "grpc://127.0.0.1:50051",
- "-s", "hellogrpc.endpoints.<YOUR_PROJECT_ID>.cloud.goog", # replace <YOUR_PROJECT_ID>
+ "-s", "hellogrpc.endpoints.YOUR_PROJECT_ID.cloud.goog", # replace <YOUR_PROJECT_ID>
"--rollout_strategy", "managed",
]
ports:
- containerPort: 9000
+ resources:
+ requests:
+ cpu: "250m"
+ memory: "500Mi"
+ limits:
+ cpu: "250m"
+ memory: "500Mi"
- name: echo
- image: gcr.io/<YOUR_PROJECT_ID>/go-grpc-hello:1.0 # replace <YOUR_PROJECT_ID>
+ image: asia-northeast1-docker.pkg.dev/YOUR_PROJECT_ID/helloworld-repo/go-grpc-hello:1.0 # replace <YOUR_PROJECT_ID>
ports:
- containerPort: 50051
+ resources:
+ requests:
+ cpu: "250m"
+ memory: "500Mi"
+ limits:
+ cpu: "250m"
+ memory: "500Mi"
Kubernetes クラスタにデプロイする
以下のコマンドで、デプロイする。デプロイ直後は、「Cannot schedule pods:
Insufficient cpu.」などのエラー表示となるが、 しばらくすると、正常に起動する。
ワークロードのイベントを確認することで、状態が確認できる。
kubectl apply -f deployment.yaml
クライアントで接続する
接続先 IP を参照する。コマンドを実行し、Pod の起動が完了すると、EXTERNAL_IP
の値をコピーする。
kubectl get svc grpc-hello --watch
クライアントを実行する。
go run client/main.go --api-key=AIza... --addr=<上記で調べたEXTERNAL_IP>:80 FOOBAR
クリーンアップ
kubectl delete -f deployment.yaml
gcloud container clusters delete --region=asia-northeast1 autopilot-cluster-1
gcloud iam service-accounts delete grpc-hello-endpoint-gsa@YOUR_PROJECT_ID.iam.gserviceaccount.com
gcloud artifacts repositories delete --location=asia-northeast1 helloworld-repo
gcloud storage rm --recursive gs://YOUR_PROJECT_ID_cloudbuild
gcloud endpoints services delete hellogrpc.endpoints.YOUR_PROJECT_ID.cloud.goog
参考資料
- ESP を使用した GKE 用 Cloud Endpoints のスタートガイド
- AutopilotでもCloud Endpointsがしたい
- Workload Identity を使用する
- ESPv2 を使用して Cloud Run 用の Cloud Endpoints gRPC を設定する