クラウド同上

サーバーレスをコンテナで!Cloud Runで必ず抑えておきたい5つのことを検証してみた〜フルマネージド基礎編①

Author
iijima
Lv:3 Exp:2509

はじめまして!
SRE所属です、よろしくお願いします。

最近サーバーレスという言葉がクラウド界隈でよく聞かれるようになりました。

サーバーレスはプロビジョニングやスケーリングなどのインフラ管理を一切する必要がなく、アプリケーション開発だけに集中できる点が魅力的です!

また呼ばれた時だけ起動して必要がなくなったら停止するので、
無駄なリソースを消費しません。

GCPではサーバーレスのサービスをいくつも提供しています。
本記事ではGCPのサーバーレスサービスの1つであるCloud Runをご紹介します。

Cloud Runってどんなサービスか大体は知っているけどもう少し詳しく知りたい!という方のために、多くのケースで必要となるであろう以下の5つのポイントについて検証、手順の確認をしましたのでご紹介します。

①サービスを作成してHTTPS接続する
②カスタムドメインを設定する
③IAMでアクセス制御する
④Cloud Storageに接続する
⑤リビジョン管理が出来るか確認してみる

Cloud Runの概要については、公式ドキュメントをご参照ください。

なお後述で説明しますが、Cloud Runのプラットフォームはフルマネージド、GKE、GKE On-Premの3種類があります。

今回フルマネージド編ということで、
この記事はフルマネージドのCloud Runを対象にしています。

Cloud Runはコンテナをサーバーレスで実行するサービス

Cloud Runは一言で言うと、
コンテナをサーバーレスで実行する」サービスです。

GCPのサーバーレスのサービスといえば他にCloud Functionsなどもあります。
Cloud Functionsは「コードをサーバレスで実行する」サービスです。

コンテナにはアプリケーションだけでなくランタイムも含めるので、
Cloud RunはCloud Functionsで提供しているランタイム以外にも対応できます。

プラットフォームは3種類

Cloud Runのプラットフォームは、

①Cloud Run(フルマネージド)
②GKE上で動かすCloud Run for Anthos on Google Cloud
③GKE On-Prem上で動かすCloud Run for Anthos deployed on VMware

の3種類があります。

①Cloud Run(フルマネージド)の場合は、完全にGoogleがインフラを管理してくれますので、ユーザーはコンテナの開発だけに専念できます。

②Cloud Run for Anthos on Google Cloudと③Cloud Run for Anthos deployed on VMwareの場合は、Kubernetes上でサーバーレスを実現するプラットフォームであるKnativeを、自分で用意したクラスターにデプロイします。スケーリングやプロビジョニングは自動ですが、クラスターのリソースの範囲内で行われます。

上記のような違いがあるため、一部動作が①と②と③で異なっています。

今回は①Cloud Run(フルマネージド)を対象として検証しています。

検証1 サービスを作成してHTTPS接続する

早速Cloud Runのサービスを作成して、
そのサービスにHTTPS接続できるか検証してみましょう。

まずはQuickStartの手順に従って、Cloud Runのサービスを作成してみます。

Cloud Shellにログインして、プロジェクトを設定します。

$ gcloud config set project  プロジェクト名

次にCloud Runサービスを作成します。

$ gcloud beta run deploy apps-gcp --image gcr.io/cloudrun/hello --platform=managed --region asia-northeast1 --allow-unauthenticated

上記のコマンドでフルマネージドのプラットフォームに、
apps-gcpという名前のサービスを東京リージョンに作成しています。
コンテナはCloud Runのサンプルアプリを使用しています。
–allow-unauthenticatedオプションで、外部からのアクセスを許可しています。

URLが表示されますので、サービスが作成できたことをブラウザから確認します。

サービスを作成して、HTTPS接続できることが確認できました!
コンテナを用意していれば、超簡単にサービスを作成できます。

検証2 カスタムドメインを設定する

検証1ではサービスに与えられたURLは、
https://apps-gcp-xxxxxxxxx.run.app/
のようになっています。

検証2では、カスタムドメインを設定してHTTPSアクセスできるか検証します。

フルマネージドの場合、自分がドメイン所有者であることを証明する必要があります。
(Google Domainsから購入してアカウントと紐づいている場合は必要ありません。)

以下のコマンドで、ドメインが表示されることを確認します。
私はGoogle Domainsからドメインを購入したのですでにドメインが表示されています。

$ gcloud domains list-user-verified
ID
xxx.com

表示されない場合は、ドメインの所有者であることを証明します。

$ gcloud domains verify BASE-DOMAIN

証明が終わったら、カスタムドメインを設定したサービスdomain-mappingsを作成します。

$ gcloud beta run domain-mappings create --service apps-gcp --domain cloudrun.ドメイン名 --platform=managed --region=asia-northeast1
Creating......done.
Waiting for certificate provisioning. You must configure your DNS records for certificate issuance to begin.
NAME      RECORD TYPE  CONTENTS
cloudrun  CNAME        ghs.googlehosted.com.

カスタムドメインを設定すると、自動的にフルマネージドの証明書が発行されます。

フルマネージド環境のCloud Runの場合は、
自前の証明書をアップロードすることは現時点(2019/09)ではできません。

続いてCLIの結果に出てきたインストラクションに従って、DNSレコードを更新します。

Google Domainsの場合、DNS>カスタムレコードを選択して以下のように設定します。

設定はこれで完了です!
設定したサブドメインにアクセスすると、正しく画面が表示されています。

Let’s Encryptの証明書が自動で作成されていることがわかりますね。

Cloud Runのサービスにカスタムドメインを設定して、
HTTPS接続ができることが確認できました。

検証3 IAMでアクセス制御する

Cloud Runは他のサービス同様にIAMでアクセス制御ができます。

IAM(Identity and Access Management)はGCPの基本となる権限管理機能で、誰が(ユーザー、グループまたはサービスアカウント)どのリソースに対するどのようなアクセス権限を持つかを定義することで、リソースに対してのアクセス制御を設定することができます。

検証3では、自分だけにCloud Runサービスへのアクセスを許可できるか検証します。

先ほどは、
–allow-unauthenticationオプションで全てのユーザーにアクセスを許可しました。

apps-gcpサービスのIAMの設定を確認してみます。

$ gcloud beta run services get-iam-policy apps-gcp --region=asia-northeast1
bindings:
- members:
  - allUsers
  role: roles/run.invoker
etag: BwWUdIq620k=
version: 1

全てのユーザーにアクセスを許可していますね。
以下のコマンドで–allow-unauthenticationで設定したものを外します。

$ gcloud beta run services remove-iam-policy-binding apps-gcp --region=asia-northeast1 --member=allUsers --role=roles/run.invoker
Updated IAM policy for service [apps-gcp].
etag: BwWUdeofg1g=
version: 1

少し時間をおいてからアクセスすると、
アクセス権限がないのでForbiddenが表示されます。

$ curl https://cloudrun.xxxxx.com/

<title>403 Forbidden</title>

続いて自分にだけアクセスする権限を付与します。(自分がオーナーの場合はIAMの設定がされていなくてもサービスにアクセスできるので、この手順は必要ありません。)

$ gcloud beta run services add-iam-policy-binding apps-gcp --region=asia-northeast1 --member=user:ユーザー --role=roles/run.invoker
Updated IAM policy for service [apps-gcp].
bindings:
- members:
  - user:ユーザー
  role: roles/run.invoker
etag: BwWUdjdYyIw=
version: 1

下記のようにcurlコマンドを実行すると失敗します。

$ curl https://cloudrun.xxxxxx.com/

<title>403 Forbidden</title>

Authorizationヘッダーに自分の認証トークンを設定してcurlすると成功します。

$ curl -H "Authorization: Bearer $(gcloud auth print-identity-token)" https://cloudrun.xxxxxx.com/

<title>Congratulations | Cloud Run</title>

IAMのアクセス制御を設定して、自分だけにアクセスを許可するようCloud Runサービスを構成できることを確認できました。

検証4 Cloud Storageに接続する

Cloud Runはサービスアカウントを使って、他GCPサービスに接続できます。
検証4では、Cloud RunからCloud Storageに接続できるか検証します。

フルマネージドのCloud Runでは、デフォルトで
サービスアカウント にCompute Engine default service account (PROJECT_NUMBER-compute@developer.gserviceaccount.com)を使用します。

–service-accountオプションを使用してサービスを作成することで、サービスアカウントを変更可能です。
Compute Engine default service accountはGCE用のサービスアカウントですので、基本的にはCloud Runサービス専用のサービスアカウントを作成して、そちらを利用します。

Cloud Storageにあるオブジェクトのテキストを表示するアプリケーションを作成します。

ca-iijima-cloudrun-testというバケットに、
「Cloud Run Success!!」と書かれたcloudrun.txtを予め配置しています。

package main

import (
  "cloud.google.com/go/storage"
  "context"
  "fmt"
  "io/ioutil"
  "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
  ctx := context.Background()
  client, err := storage.NewClient(ctx)
  if err != nil {
     // TODO: Handle error.
  }
  bkt := client.Bucket("ca-iijima-cloudrun-test")
  obj := bkt.Object("cloudrun.txt")

  reader, err := obj.NewReader(ctx)
  if err != nil {
     panic(err)
  }

  b, err := ioutil.ReadAll(reader)
  if err != nil {
     panic(err)
  }

  fmt.Fprintf(w, "%s", string(b))
}

func main() {
  http.HandleFunc("/", handler)
  http.ListenAndServe(":8080", nil)
}

Dockerfileを作成します。

FROM golang:1.13

WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]

続いてCloud Buildを使って、コンテナを作成してContainer Registryにpushします。

$ gcloud builds submit --tag gcr.io/PROJECT-ID/apps-gcp .

Container Registryにコンテナイメージが存在することを確認します。

$ gcloud container images list
NAME
gcr.io/PROJECT-ID/apps-gcp

新しくCloud Runのサービスapps-gcp-gcsを作成します。

$ gcloud beta run deploy apps-gcp-gcs --image gcr.io/PROJECT-ID/apps-gcp --platform=managed --region asia-northeast1 --allow-unauthenticated

curlで接続できるか確認します。

$ curl  https://apps-gcp-gcs-w4bqq77n7q-an.a.run.app
Cloud Run Success!!

オブジェクトを読み込んで、「Cloud Run Success!!」を表示できていますね!

続いて、Compute Engineデフォルトサービスアカウントから、
編集者権限を剥奪してcurlしてみます。(変更が反映されるまで少々タイムラグがあります)

curlで接続できるか確認します。

$ curl  https://apps-gcp-gcs-w4bqq77n7q-an.a.run.app
Service Unavailable

GCSへのアクセス権限を剥奪したので失敗しましたね。
検証が終わったら、編集者権限を再び付与してください。

以上、検証4ではCloud RunサービスからCloud Storageにアクセスできることを確認しました。

検証5 リビジョン管理が出来るか確認してみる

検証5ではCloud Runでアプリケーションのリビジョン管理が出来るか確認してみるます。

公式ドキュメントの図のように、Cloud Runのリソースモデルはサービスが複数のリビジョンを含む構成です。最新のリビジョンのみがリクエストを処理します。

検証4で作成したサービスapps-gcp-gcsのリビジョンを確認します。
コンソールから見ると1つあります。

新しいコンテナをデプロイして、
apps-gcp-gcsのサービスを更新してみましょう。

アプリケーションを修正します。
「revision 00002:」という文字列を追加しました。

fmt.Fprintf(w, "revision 00002: %s", string(b))

新しいコンテナを作成してContainer Registryにpushします。

$ gcloud builds submit --tag gcr.io/PROJECT-ID/apps-gcp .

リビジョンをデプロイします。

$ gcloud beta run deploy apps-gcp-gcs --image gcr.io/PROJECT-ID/apps-gcp --platform=managed --region asia-northeast1

リビジョンが作成されて、
トラフィックが新バージョンに割り当てられているのがわかります。

curlで確認すると、トラフィックがきちんと割り振られています。

$ curl  https://apps-gcp-gcs-w4bqq77n7q-an.a.run.app
revision 00002: Cloud Run Success!!

トラフィックがないリビジョンは削除できますが、
トラフィックがあるリビジョンは削除できません。

$ gcloud beta run revisions delete apps-gcp-gcs-00002 --platform=managed --region=asia-northeast1
Revision [apps-gcp-gcs-00002] will be deleted.

Do you want to continue (Y/n)?  y

ERROR: (gcloud.beta.run.revisions.delete) FAILED_PRECONDITION: Revision "apps-gcp-gcs-00002" cannot be directly deleted because it is actively serving.

今回は新しいコンテナをデプロイすることでリビジョンを作成しましたが、
Cloud Runの変数やタイムアウトを変更しても、新しいリビジョンが作成されます。

トラフィック分割やフェールバックの機能が追加されていくと、
さらに使いやすくなりそうですね!

以上新しいコンテナをデプロイしてリビジョンを作成することで、
リビジョン管理が出来ることを確認できました。

まとめ

以上Cloud Runについて多くのケースで必要となるであろう5つの点について検証しました。

検証してみて、Cloud Runのお手軽さに感動しました。
コンテナを用意していれば、簡単にコンテナをサーバーレスで実行できます。
自動でスケーリングしてくれますし、インフラの面倒をみる必要はありません!

また料金もコンテナが稼働している時だけ課金されるので、
比較的リーズナブルなサービスと言えます。

ベータ期間中は一定量無料でCloud Runを利用できますので、是非試してみてください!(最新の料金は公式ドキュメント をご確認ください)

Cloud Runの構成方法やContinuous Deploy(CD)など、
まだ検証できてないところは次回の記事でご紹介したいと思います。

ご一読ありがとうございました!

次の記事を読み込んでいます
次の記事を読み込んでいます
次の記事を読み込んでいます
次の記事を読み込んでいます