Cloud Run に Golang のAPI サービスをデプロイしてみた
こんにちは、クラウドエース SRE ディビジョン の小堀内です。
最近、Google Cloud の学習の一環として、Golang で作成した API サービスを Cloud Run にデプロイしてみました。
その結果のアウトプットとして、本記事を執筆することにしました。
Cloud Run とは
Cloud Run の特徴を簡単にまとめると次のものが挙げられます。
- サーバーレス の コンピューティングサービス
- サーバー管理が不要なので開発者はアプリケーションのコードに集中することができる
- 自動スケーリング機能
- アプリケーションの負荷に合わせて自動的にコンテナーを起動/停止することができる
- コンテナーイメージのビルド と Cloud Run へのデプロイ
- 開発者はローカル環境でアプリケーションを開発し、簡単にデプロイすることができる
- HTTP リクエストに対応
- Web アプリケーションや API サービスを構築することができる
詳細については、Cloud Run 公式ドキュメント を参照してください。
Cloud Functions との違い
Google Cloud には、Cloud Run に似たサービスとして、Cloud Functions というものが存在します。
両者の違いについても調べてみました。
Cloud Run | Cloud Functions | |
---|---|---|
トリガー | HTTP リクエスト | Google Cloud 内の特定イベント/HTTP リクエスト |
デプロイ単位 | コンテナーイメージ | 関数 |
対応言語 | 多 | 少 |
カスタマイズ性 | 高 | 低 |
Cloud Run は、コンテナーイメージを使用するため、高度なカスタマイズが可能です。
Cloud Functions は、特定のイベントに対してトリガーされるため、サーバーレスのバックエンド処理に適しています。
デプロイするAPIサービスの概要
Cloud Spanner からデータを JSON 形式で取得します。
イメージ図
クライアント端末から Cloud Run に対して HTTP リクエストを送信して、Cloud Spanner からデータを受け取ります。
本来であれば、
- Cloud Run の冗長化
- ロードバランサー の設置
- Cloud Armor による DDos 対策 / IP 制限 / 地理制限
などの対策が必要となりますが、本記事では省略させていただきます。
また、ローカル環境の Golang のソースコードの build, push, deploy には Google Cloud Buildpacks を使用します。
Google Cloud Buildpacks とは
ソースコードからコンテナーイメージを自動的に生成するためのツールです。
特徴
- アプリケーションのビルドとデプロイが容易になり、迅速なアプリケーション開発が可能
- 柔軟なカスタマイズが可能
- Golang や Java など、複数の言語をサポート
デプロイ手順
それでは、ここからデプロイの手順を紹介していきます。
デプロイ対象のソースコードを用意
まずは、デプロイ対象のソースコードを用意します。
今回作成したソースコードは次のものになります。
package main
import (
"cloud.google.com/go/spanner"
"context"
"encoding/json"
"google.golang.org/api/iterator"
"log"
"net/http"
"time"
)
func main() {
/// パスと Spanner 読取ハンドラ の紐付け
http.HandleFunc("/", readHandler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
// Spanner 読取ハンドラ
func readHandler(w http.ResponseWriter, r *http.Request) {
// 結合クエリによって取得したレコードを格納するための構造体
type user struct {
UserId string
Name string
CreatedAtFromUser time.Time
ItemId *string
Qty *int64
CreatedAtFromUserItem *time.Time
}
// Spanner DB の用意
ctx := context.Background()
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
client, err := getDatabaseClient(ctx)
if err != nil {
http.Error(w, "InternalServerError", http.StatusInternalServerError)
log.Println(err)
return
}
defer client.Close()
// Statement によって SQL 文を実行
iter := client.ReadOnlyTransaction().Query(ctx, spanner.Statement{
SQL: `select User.UserId, User.Name, User.CreatedAt as CreatedAtFromUser,
UserItem.ItemId, UserItem.Qty, UserItem.CreatedAt as CreatedAtFromUserItem
from User left join UserItem
on User.UserId = UserItem.UserId`,
Params: nil,
})
// 上記クエリによって取得したレコードを DTO に格納する
var users []user
for {
row, err := iter.Next()
if err == iterator.Done {
iter.Stop()
break
}
if err != nil {
http.Error(w, "InternalServerError", http.StatusInternalServerError)
log.Println(err)
iter.Stop()
return
}
var user user
if err := row.ToStructLenient(&user); err != nil {
http.Error(w, "InternalServerError", http.StatusInternalServerError)
log.Println(err)
iter.Stop()
return
}
users = append(users, user)
}
// HTTP レスポンスとして JSON を返却
resp := map[string][]user{"Users": users}
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, "InternalServerError", http.StatusInternalServerError)
log.Println(err)
return
}
}
// Spanner の DB クライアントを取得する
func getDatabaseClient(ctx context.Context) (*spanner.Client, error) {
databaseName := "DATABASE_NAME"
client, err := spanner.NewClient(ctx, databaseName)
if err != nil {
return nil, err
}
return client, nil
}
Google Cloud Buildpacks の利用
次に、Google Cloud Buildpacks を利用して、
-
build
-
push
-
deploy
を行います。
build & push
ローカル環境で作成した Golang のソースコードを build して、コンテナーイメージ を作成します。
さらに、作成した コンテナーイメージ を Artifact Registry に push します。
# 1. ソースコードディレクトリに移動
$ cd path/to/your/app
# 2. プロジェクト ID を変数に格納
PROJECT_ID=your-project-id
# 3. Artifact Registry リポジトリ名を変数に格納
AR_REPO_NAME=your-repo-name
# 4. Artifact Registry パス/イメージ名:タグを変数に格納
$ IMAGE=asia-northeast1-docker.pkg.dev/$PROJECT_ID/$AR_REPO_NAME/sample:v1
# 5. Cloud Build で build して Artifact Registry に push
$ gcloud builds submit --pack image=$IMAGE
Artifact Registry への push に成功するとイメージの一覧に表示されるようになります。
deploy
次に、Artifact Registry に push したコンテナーイメージを元に、次の手順で Cloud Run へデプロイします。
Cloud Run サービスの作成
Artifact Registry に push されたコンテナーイメージを選択
コンテナーイメージを選択後、サービスの作成画面下部にある作成ボタンを押下します。
作成が完了すると Cloud Run サービスの詳細が表示されます。
deploy されたことを確認する
今回は JSON 形式でデータを取得する API サービスを作成したので、curl コマンド を使用して結果を確認してみます。
データを取得できることが確認できました。
おわりに
最近入社して、Google Cloud に関する学習を始めたところですが、便利なサービスの数に驚いています。
今後も様々なサービスを触り、そのアウトプットとして記事を執筆していく予定ですので、引き続きよろしくお願いいたします。
最後まで読んでいただきありがとうございました。
Discussion