MORITOMOMENT

登山好きエンジニアのテックブログ

プログラミング・アウトドア関連を中心に発信

Golangで実装したAPIをCloud Runにデプロイする

f:id:moritomo7315:20220213164539j:plain

やること

  • Go言語で作成したAPIをCloud Runへデプロイしてみる

Cloud Run とは

Cloud Runは簡単にいうと、自分が作成したdockerコンテナをそのままGCP上で動かすことができます。 さらにはコンテナ数のスケーリング新バージョンのローリングデプロイを自動でやってくれるなど、Cloud Runはフルマネージドなサービスです。

AWSのLambdaやGCPのCloud Functionsも似たようなサービスですが、これらは1関数をデプロイするといったものです。

また開発時はローカル環境でdockerで動かして、本番ではサーバに必要なライブラリをインストールしてようやくデプロイ、みたいなことをするケースが多いと思いますが、

Cloud Runの場合は環境変数だけ注意しておけば、ローカルと同じように本番環境もただdockerコンテナを動かすだけなので非常にデプロイが楽です。

それと、フルマネージドということで、Kubanetesなどの設定を頑張らなくてもスケーリングや負荷分散などの設定は画面をぽちぽちやるだけでできてしまいます。 最小コンテナ数、最大コンテナ数を決めることができたり1コンテナあたりの最大同時アクセス数やタイムアウト値なども設定できます。

Cloud Runはコンテナ起動時間に対して課金される課金システムです。最小コンテナ数を0に設定しておけばリクエストが全くない時間帯は課金されないように設定することも可能です(ただしコンテナ起動のオーバヘッドによるレスポンスの遅延などは気にする必要あり。)

ちなみに下記記事で紹介したDjangoで作成したWebアプリもCloud Runにデプロイして公開しています。

moritomo7315.hatenablog.com

Cloud Runを使ってみる

Google Cloud Platformのアカウント作成

GCPのページからサインアップしてください。 初回であれば$300分のクレジットが得られたり、新規限定でさまざまなサービスを無料でできる枠もあります。 個人で触ったりする分には課金枠に達しないので問題ないと思ってます。

cloud.google.com

gcloud CLIのインストール

mac osを使用しているので下記から実施しました。

cloud.google.com

上記urlでインストーラーをダウンロード後、下記コマンドでインストール。

cd ${インストーラのあるディレクトリ}
./google-cloud-sdk/install.sh

gcloud CLIにログインする

gcloud init


You must log in to continue. Would you like to log in (Y/n)?
→ Y # ここでYを入力する、サインアップしたemailアドレスとpasswordを聞かれると思う。

Pick cloud project to use:
 [1] moritomo
 [2] Create a new project
Please enter numeric choice or text value (must exactly match list
item):  1 # 新しいプロジェクトを作成する場合は "Create a new project"のものを選択 (この場合は1)

利用するGCPサービスの有効化

ここではCloud Runにデプロイに必要となるGCPのサービスをcliからアクセスできるように 各サービスのAPI利用を有効にします。

artifact registry

artifact registryはdocker imageを管理するrepositoryとして使用します。

Cloud Runにはartifact registry上のimagewを指定してデプロイすることができます。 artifact registryを使用することでdocker imageのバージョン管理なども簡単にできます。

下記コマンドでartifact registry apiの利用を有効化します。これによりローカルでビルドしたdocker imageをartifact registryにpushすることができます。

gcloud services enable artifactregistry.googleapis.com

さっそくCloud Runにデプロイしてみる

APIの準備

今回デプロイしてみるAPIは下記記事で紹介したGolangで実装した簡単なREST APIです。

moritomo7315.hatenablog.com

APIをCloud Run上にコンテナとして稼働させるためにはdocker imageを作成する必要があるのでDockerfileを用意します。

FROM golang:1.17 as build

# コンテナ上にアプリケーション(main.goのビルド成果物)を配置するdirectoryを作成
WORKDIR /app

# ソースをコピー
COPY ./ ./
RUN go mod download

# 任意です
# 環境によって環境変数を読み分けるための設定(.env.${_STAGE}にあたる)
ARG _STAGE
ENV STAGE=${_STAGE}

# goファイルのビルド
RUN GOOS=linux GOARCH=amd64 go build -mod=readonly -v -o server

# docker コンテナの50001ポートをこのサービスのために使用
EXPOSE 50001

# apiサーバを起動
CMD GO_ENV=${STAGE} /app/server

artifact registryにrepositoryを作成

APIのdocker imageを保存しておくためのrepositoryをartifact registryに作成します。

※下記コマンドはartifact registory apiを有効化する必要があります。

REPOSITORY_NAME=go-rest-user-api # 自分のアプリの名前
LOCATION_NAME=us-west1 # artifact registryを作成したいリージョンロケーション名
gcloud artifacts repositories create ${REPOSITORY_NAME} \
--repository-format=docker --location=${LOCATION_NAME}

GCPのコンソールへアクセスする。

console.cloud.google.com

検索ボックスから「artifact registry」を入力すると、artifact registryのダッシュボードページへ遷移すると作成したレポジトリが確認できます。

f:id:moritomo7315:20220213152040p:plain

docker build と docker push

さっそくAPIのdocker imageを作成し、artifact registryにpushします。

docker build

REPOSITORY_NAME=go-rest-user-api # 自分のアプリの名前
LOCATION_NAME=us-west1 # artifact registryを作成した時と同じリージョンロケーション名
PROJECT_NAME=moritomo # ここは自分のGCPのproject nameをセット


# --build-arg _STAGE=devは筆者の場合.envを使用するためなので必要に応じて消してください。
# 引数がいらない場合: docker build  --tag ${LOCATION_NAME}-docker.pkg.dev/${GCP_PROJECT_NAME}/${REPOSITORY_NAME}/images .
docker build --build-arg _STAGE=dev --tag ${LOCATION_NAME}-docker.pkg.dev/${GCP_PROJECT_NAME}/${REPOSITORY_NAME}/images .


# docker imageが期待通りのTAG名で生成されているか確認
docker image ls
REPOSITORY                                                         TAG       IMAGE ID       CREATED         SIZE
us-west1-docker.pkg.dev/moritomo/go-rest-user-api/images           latest    5d497872ff41   8 minutes ago   1.59GB

docker push

# docker push ${タグ名}で artifact registryにpushする
docker push ${LOCATION_NAME}-docker.pkg.dev/${GCP_PROJECT_NAME}/${REPOSITORY_NAME}/images

再度、GCPのコンソールへアクセスしartifact registryのダッシュボードページへ遷移可能すると、pushされていることが確認できます。

f:id:moritomo7315:20220213152040p:plain

Cloud Runへデプロイ

GCPコンソールの検索ボックスから「cloud run」と入力しCloud Runのダッシュボードへアクセスします。

「サービスを作成」を押す

f:id:moritomo7315:20220213152521p:plain

「既存のコンテナ イメージから 1 つのリビジョンをデプロイする」の「選択」から、artifact registryにpushしたdocker imageを選択します。

f:id:moritomo7315:20220213152635p:plain

各設定は下記のようにしておけば問題ないです。 「サービス名」: 好きなサービス名(アプリと同じ名前にしてみました)

「リージョン」:好きなリージョン名

「CPU の割り当てと料金」: リクエストの処理中にのみにCPUを割り当てる

「自動スケーリング」:最小インスタンス0, 最大インスタンス数 1 (トライしてみるだけなのでここは1でいい)

Ingress」:すべてのトラフィックを許可する

「認証*」:認証が必要(念の為)

f:id:moritomo7315:20220213155143p:plain

「コンテナ、変数とシークレット、接続、セキュリティ」のトグルをクリックしてportの設定をします。

Generalのコンテナポート: 50001 (これはDockerfileでEXPOSEしているport番号を指定してください)

他の設定に関しては本番サービスでは下記は割と使うんだろうなと思います

変数とシークレット :必要であれば環境変数をセット

gRPCを利用する場合→ 接続:「http/2 エンドツーエンドを使用する」にチェック

Capacity : 1コンテナあたりのスペックを指定できます

設定し終わったら「作成」ボタンをCloud Runサービスの作成を完了する。

f:id:moritomo7315:20220213161817p:plain

「作成」ボタンを押してしばらく待つと、サービスが出来上がります。

これでデプロイ完了です。

f:id:moritomo7315:20220213161917p:plain

動作確認してみる。

今回はデプロイ時に認証を必要とするという設定にしました。

なのでまずはgcloudにログインしているユーザに作成サービスへのアクセス権限できるようにIAMを設定します。

先ほど作成したサービス名と自分がログインしているメールアドレスを指定して下記コマンドを実行します。

gcloud run services add-iam-policy-binding ${作成したサービス名} \
  --member='user:自分のメールアドレス' \
  --role='roles/run.invoker'


Please specify a region:
 [1] asia-east1
 [2] asia-east2
 [3] asia-northeast1
 [4] asia-northeast2
 [5] asia-northeast3
 [6] asia-south1
 [7] asia-south2
 [8] asia-southeast1
 [9] asia-southeast2
 [10] australia-southeast1
 [11] australia-southeast2
 [12] europe-central2
 [13] europe-north1
 [14] europe-west1
 [15] europe-west2
 [16] europe-west3
 [17] europe-west4
 [18] europe-west6
 [19] northamerica-northeast1
 [20] northamerica-northeast2
 [21] southamerica-east1
 [22] southamerica-west1
 [23] us-central1
 [24] us-east1
 [25] us-east4
 [26] us-west1
 [27] us-west2
 [28] us-west3
 [29] us-west4
 [30] cancel
Please enter your numeric choice:  26  # サービスを作成したリージョンに一致する番号を入力してみた

GCPの認証トークンは下記のコマンドで確認できます。

gcloud auth print-identity-token

このトークンを使用して、作成したCloud Runサービスにもアクセスすることができるので、下記のようにGET リクエストを実施します。 Cloud RunのURLは下記のようにサービスのダッシュボードからコピーできます(赤四角の部分)。 f:id:moritomo7315:20220213162835p:plain

curl -H \
"Authorization: Bearer $(gcloud auth print-identity-token)" \
https://${セキュリティのためendpointはバインドしてます}/api/users | jq .

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   667  100   667    0     0   1515      0 --:--:-- --:--:-- --:--:--  1519
{
  "status": 200,
  "message": "ユーザ情報取得に成功しました。",
  "user_count": 5,
  "users": [
    {
      "id": "CRe4XPnE8DjD4bjk7n2Y",
      "name": "testuser6",
      "prefecture": "神奈川県",
      "createdAt": "2022-01-29T13:52:38.936004Z",
      "updatedAt": ""
    },
    {
      "id": "HAnwlDB7I7G6VVUtmkfw",
      "name": "testuser4",
      "prefecture": "",
      "createdAt": "",
      "updatedAt": ""
    },
    {
      "id": "oaAwBZMSdmEC4OEbr99B",
      "name": "testuser5",
      "prefecture": "東京都",
      "createdAt": "2022-01-29T12:00:00Z",
      "updatedAt": "2022-01-29T13:50:59.146083Z"
    }
  ]
}

まとめ

  • 今回はGo言語で作成したAPIをCloud Runにデプロイしてみた。
  • Dockerfileを使ってローカル開発してる人は簡単にCloud Runにデプロイすることができる。
  • スケーリングの細かい設定(コンテナ数の下限・上限)やタイムアウト値を簡単に設定できるからCloud Runってすごい