Cloud Runでインフラを構成したときのメモ

# この記事について
下記の構成でCloud Runを利用してWebサーバーを構築するにあたり、考えたことや情報リソースを備忘録として記載していきます。
できるだけ公式ドキュメントのリンクを添えて正確な情報を残していきたいと思っています。

:::note alert
**この記事に記載ないこと**
- 細かい設定値や手順など
:::

# 構成
実際に構築したインフラの構成はこちらです。
ここには記載していないところで**ログの保存**や**死活監視**なども構成しているので、そちらについても記載していきます。
![Cloud Run Web Server.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/284251/1faddaaa-c55b-9d40-2998-afa31a3d3d2b.png)

## 可用性
### Cloud Run
- 冗長性
    - 自動冗長化 - Cloud Run には自動冗長性が備わっているため、高可用性のために複数のインスタンスを作成する必要がありません。
    - Cloud Run サービスはリージョン単位で、複数のゾーンにわたり自動的に複製されます。
    - ゾーンに障害が発生した場合、トラフィックは他のゾーンに自動的に転送されます。
    - データがリージョン間で複製されることはありません。お客様のトラフィックは、Cloud Run によって別のリージョンにルーティングされることはありません。リージョンに障害が発生した場合、障害が解決するとすぐに Cloud Run は使用可能になります。
- スケーリング
    - Cloud Run は、トラフィックに応じてゼロから N まで自動的にスケーリングし、コンテナ イメージのストリーミングを利用して高速に起動します。
- 負荷分散
    - Cloud Run はリージョナル サービスです。つまり、お客様はリージョンを選択できますが、リージョンを構成するゾーンは選択できません。データとトラフィックは、リージョン内のゾーン間で自動的に負荷分散されます。コンテナ インスタンスは、受信トラフィックに合わせて自動的にスケーリングされ、必要に応じてゾーン間で負荷分散されます。このようにゾーンごとに自動スケーリングを行うスケジューラが各ゾーンで維持されています。また、他のゾーンが受けている負荷を認識し、ゾーン障害に対応するためにゾーン内の追加容量をプロビジョニングします。
- 参考
    - [Cloud Run](https://cloud.google.com/run?hl=ja)
    - [Cloud Run: サーバーレス コンテナの話](https://cloud.google.com/blog/ja/topics/developers-practitioners/cloud-run-story-serverless-containers)
    - [クラウド インフラストラクチャの停止に対する障害復旧の設計](https://cloud.google.com/architecture/disaster-recovery?hl=ja#cloud-run)

### Cloud Load Balancing
- スケーリング
    - Cloud Load Balancing は、ユーザーやトラフィックの増加に応じてスケールできます。トラフィックの予期せぬ急増が発生した場合も、世界中の各リージョンにトラフィックを転送して容易に対応できます。この自動スケーリングにプレウォーミングは必要なく、トラフィックがゼロの状態からフル稼働の状態までスケールするのに、わずか数秒しかかかりません。
- 参考
    - [Cloud Load Balancing の概要](https://cloud.google.com/load-balancing/docs/load-balancing-overview?hl=ja)

# デプロイ周り
Cloud Buildではコンテナイメージ（Dockerfile）をビルドしてGitHubから継続的なデプロイが行えるようにしました。
GitHubリポジトリの指定したブランチにCommitがPushされると、自動的にCloud BuildでコンテナイメージをビルドしてContainer Registryにビルドイメージを保存し、そのイメージをCloud Runにデプロイします。

設定についてはCloud Runサービスを作成するときに設定を行えます。
構成方法の詳細は「[Cloud Build を使用した Git からの継続的なデプロイ](https://cloud.google.com/run/docs/continuous-deployment-with-cloud-build?hl=ja)」や「[Cloud Build を使用した Cloud Run へのデプロイ](https://cloud.google.com/build/docs/deploying-builds/deploy-cloud-run?hl=ja)」を参照してください。

:::note warn
デプロイに失敗したら...
- GitHubのリポジトリ名に大文字が含まれているとデプロイすらできずにビルドに失敗するので小文字やハイフン等GCPの命名規則に合わせてリポジトリ名を設定してください。
- IAMにてCloud Buildのサービスアカウントに「Cloud Run 管理者（もしくはデベロッパー）」と「サービス アカウント ユーザー」のロールを付与します。
:::


# Cloud Run
今回はPHPの動くApacheを利用したWebサーバを構築したかったかつ、インフラの管理コストを削減したいと考えていたため[**Cloud Run**](https://cloud.google.com/run/docs/overview/what-is-cloud-run?hl=ja)を利用しました。

Cloud Runはフルマネージドのサーバーレスプラットフォームであり、スケーラブルなコンテナ型アプリを構築を行えます。

Cloud Runにはサービスとジョブがあり、ウェブリクエストまたはイベントに応答するコードの実行をする「**Cloud Run サービス**」と、作業（ジョブ）を実行し、作業の完了後に終了するコードの実行をする「**Cloud Run のジョブ**」があります。

Cloud Runでは主に下記のプロパティを設定します。
- デプロイ方法
- リージョン
- [CPUの割り当て](https://cloud.google.com/run/docs/configuring/cpu-allocation?hl=ja)
    - 「**リクエストの処理中にのみ CPU を割り当てる**」か「**CPU を常に割り当てる**」からCPUの割り当てを設定します。<br>割り当ての方法により料金が変わってくるので、[料金計算ツール](https://cloud.google.com/products/calculator?hl=ja)で見積もりを行うことをおすすめします。
- 自動スケーリング
    - [**最小インスタンス**](https://cloud.google.com/run/docs/configuring/min-instances?hl=ja)と[**最大インスタンス**](https://cloud.google.com/run/docs/configuring/max-instances?hl=ja)を指定します。
- [Ingress](https://cloud.google.com/run/docs/securing/ingress?hl=ja)
    - Cloud Runへのアクセスの制限を「**内部**」「**内部と Cloud Load Balancing**」「**すべて**」から設定します。
    - 今回はCloud Load Balancingを利用するので「**内部と Cloud Load Balancing**」を選択しました。
- 認証
    - 「**認証されていない呼び出しを許可する**」か「**認証が必要**」から認証の有無を指定します。<br>公開APIまたはウェブサイトを作成する場合は、「**認証されていない呼び出しを許可する**」を、認証で保護された安全なサービスが必要な場合は、「**認証が必要**」を選択します。
    - 今回は公開するWebサーバーなので「**認証されていない呼び出しを許可する**」を設定しました。
- [インスタンスあたりの最大同時リクエスト数の設定](https://cloud.google.com/run/docs/configuring/concurrency?hl=ja)
- [コンテナ構成](https://cloud.google.com/run/docs/configuring/containers?hl=ja)
    - コンテナポート
- [CPU 制限](https://cloud.google.com/run/docs/configuring/cpu?hl=ja)
- [メモリ制限](https://cloud.google.com/run/docs/configuring/memory-limits?hl=ja)
- [リクエスト タイムアウト](https://cloud.google.com/run/docs/configuring/request-timeout?hl=ja)
- [シークレット](https://cloud.google.com/run/docs/configuring/secrets?hl=ja)
- [環境変数](https://cloud.google.com/run/docs/configuring/environment-variables?hl=ja)
- [実行環境](https://cloud.google.com/run/docs/configuring/execution-environments?hl=ja)
- [HTTP/2](https://cloud.google.com/run/docs/configuring/http2?hl=ja)
- [ラベル](https://cloud.google.com/run/docs/configuring/labels?hl=ja)
- [サービス アカウント](https://cloud.google.com/run/docs/configuring/service-accounts?hl=ja)
- [Cloud SQL 接続](https://cloud.google.com/sql/docs/mysql/connect-run?hl=ja)
- [VPC 接続](https://cloud.google.com/run/docs/configuring/connecting-vpc?hl=ja)

# ロードバランサ
今回はWebサイトとして公開するWebサーバーをつくりたかったので、[**Cloud Load Balancing**](https://cloud.google.com/load-balancing?hl=ja)の**グローバル外部 HTTP(S) ロードバランサ**を利用しました。

実際の構築手順や各種設定値については「[Cloud Run、App Engine、または Cloud Functions でグローバル外部 HTTP(S) ロードバランサを設定する](https://cloud.google.com/load-balancing/docs/https/setup-global-ext-https-serverless?hl=ja)」を参照するとよいと思います。

大きくこちらの項目について対応していきました。
- [外部 IP アドレスを予約する](https://cloud.google.com/load-balancing/docs/https/setup-global-ext-https-serverless?hl=ja#ip-address)
    - ここで取得したIPアドレスをロードバランサに紐づけして、DNSのAレコードに設定します。
- [SSL 証明書リソースを作成する](https://cloud.google.com/load-balancing/docs/https/setup-global-ext-https-serverless?hl=ja#ssl_certificate_resource)
- [ロードバランサを作成する](https://cloud.google.com/load-balancing/docs/https/setup-global-ext-https-serverless?hl=ja#creating_the_load_balancer)
    - フロントエンドの構成
        - 下記のプロパティを設定してロードバランサのフロントエンドを構成します。
            - プロトコル
            - IPアドレス
            - ポート
            - SSL証明書
            - SSLポリシー（TLS 1.〇以上等）
            - HTTP から HTTPS へのリダイレクト
    - バックエンド サービスの構成
        - ロードバランサとバックエンド（Cloud Run）の紐づけを行います。
    - ホストルールとパスマッチャーの構成
        - ロードバランサで複数のバックエンドサービスと紐づけをするときに設定します。
- [Google Cloud Armor を有効にする](https://cloud.google.com/load-balancing/docs/https/setup-global-ext-https-serverless?hl=ja#enable-armor)
    - 分散型サービス拒否（DDoS）攻撃からロードバランサを保護したり、IP制限を設定することができるWAFサービスです。

# ログの保存
[**Cloud Logging**](https://cloud.google.com/logging?hl=ja)を利用してログのルーティングを行い、[**Cloud Storage**](https://cloud.google.com/storage?hl=ja)に保存を行いました。

Cloud Loggingの[ログエクスプローラ](https://cloud.google.com/logging/docs/view/logs-explorer-interface?hl=ja)を利用することでログデータを取得、表示、分析等ができますが、デフォルトでは[_Required ログバケット](https://cloud.google.com/logging/docs/routing/overview#required-bucket)にて「管理アクティビティ監査ログ」「システムイベント監査ログ」「アクセスの透明性ログ」を400日間保持し、[_Default ログバケット](https://cloud.google.com/logging/docs/routing/overview#default-bucket)にて_Requiredバケットに取り込まれなかったログを30日間保持します。

ログを長期保管しておく必要がある場合は別途ログをルーティングし保管する必要があります。
ログのルーティング（転送）先については「[シンクのエクスポート先のログを表示する](https://cloud.google.com/logging/docs/export/using_exported_logs?hl=ja)」を参照してください。

今回はCloud Storageにログをルーティングし保管することにしました。
ログをルーティングするには[シンクを構成](https://cloud.google.com/logging/docs/export/configure_export_v2?hl=ja#creating_sink)し制御します。

シンクの構成には主に以下のプロパティを設定します。
- シンクのエクスポート先
    - Cloud Loggingバケット
    - BigQueryテーブル
    - Cloud Storageバケット
    - Pub/Subトピック
    - Splunk
    - 他のCloudプロジェクト
- シンクに含めるログの選択
    - [Loggingのクエリ言語](https://cloud.google.com/logging/docs/view/logging-query-language?hl=ja)を利用してログのフィルタ式を記述します。
- （省略可）シンクに含めないログの選択

# 死活監視
Cloud Monitoringの[**稼働時間チェック**](https://cloud.google.com/python/monitor-and-debug/uptime-alert?hl=JA#creating_an_uptime_check)を利用して死活監視を行いました。

今回は指定したURLに対して定期的にアクセスを行い、期待通りのステータスコードでレスポンスが返ってくることを検証し、検証に失敗した場合に指定のメールアドレスにアラート（通知）を送信するように設定しました。

# 終わりに
今回はすべてコンソールにて構築を行いましたが、次回はTerraformなんかを使ってデプロイする方法を学んでいきたいと思っています。