Cloud Runを用いたシンプルなインフラ構成

# はじめに
こんにちは！株式会社80&Companyの技術広報です。
弊社の開発部署では毎週火曜日の朝9:30から社内勉強会を行なっています。

今回の記事は、SRE業務を行なっているエンジニアが社内勉強会で「**Cloud Run**を用いたシンプルなインフラ構成」について発表したものを紹介します。
SREを簡単に説明すると、Google社が提唱・実践した概念で、「サイト・リライアビリティ・エンジニア（**Site Reliability Engineer**）」の略称です。
サービスやプロダクトの信頼性の向上を図り、エンジニアが開発と運用の両方に携わることによって自動化・効率化し、企業の課題を解決する役割と言われています。

SREエンジニアが発表した**Cloud Run**を用いたシンプルなインフラ構成について、興味のある方は参考にしてみて下さい♪

# 読者の対象
* **Cloud Run**について知りたい方
* **Cloud Run**の導入を検討している方
* **Cloud Run**を用いたシンプルなインフラ構成に興味がある方

# テーマ選定の理由
発表者が**Cloud Run**を用いたシンプルなインフラ構成について発表した理由としては、サービスを手軽に公開・運用する仕組みに関心を持ち、それに適したインフラ構成に興味を持ったためです。

フロントエンド開発の際に用いるインフラ構成は、**Vercel**が適しています。
しかし、バックエンド開発の際に用いるインフラ構成があまり思いつかないと感じていたところ、**Cloud Run**というサービスが選択肢として適していると考えました。
また、公式のチュートリアルやクイックスタート等を見ている際に、チーム開発の場面で物足りない部分があったため、インフラ構成に少し手を加えることにより、開発の効率を上げる構成を考えてみようと思いました。

# Cloud Runとは？ざっくり概要
**Cloud Run**は、**Google Cloud Platform(GCP)** で提供されるマネージドなコンテナ実行環境であり、以下のような特徴があります。

* **スケーラビリティ**: トラフィックの増減に応じて自動的にコンテナをスケールするため、アプリケーションの負荷に応じて柔軟にサービスを拡大縮小することができる。
* **マネージドサービス**: サーバーの管理やオーケストレーションに必要な手間を省くため、開発者はアプリケーションのコンテナ化に集中できる。
* **セキュリティ**: 自動的にトラフィックの管理やアプリケーションのセキュリティ対策を行うため、開発者はアプリケーションのセキュリティ対策に集中できる。また、**GCP**のセキュリティ機能を利用することで、セキュリティを維持することができる。
* **料金**: 使用したリソースに応じて課金される従量制の課金方式を採用されており、実際に使用した分だけ支払うことができるため、コストを抑えることができる。

# インフラの構成
実際に考えたインフラ構成を下記の図に示しています。
**Cloud Run**に対してGitHubの連携、そこに**SecretManager**を加える構成です。

この**SecretManager**は、GCPのサービスの1つであり、機密情報などの重要な情報(例:データベースのパスワード)を管理して使っていくためのものです。
基本的に、**Cloud Run**は単体で動くものですが、今回は**GitHub Actions**を使いやすくするために手を加えました。
![スクリーンショット 2023-03-15 19.36.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3059557/9558dd18-4d5f-ca5a-b673-9889d64839c9.png)

# インフラ構成の特徴について
今回構築した**Cloud Run**を用いたシンプルなインフラ構成について、2つの特徴を説明します。
## 特徴1：GitHub Actionsによる初期構築&自動デプロイ
最近は、GitHubでコードを管理できますが、ブランチ単位でdevelopブランチにコードを上げた瞬間に、**GitHubActions**が走り、上がったコードが**Cloud Run**に更新されます。
自動デプロイの処理を**GitHub Actions**に追加しています。

まずは、**GitHub Actions**による初期構築について説明します。
GitHub上のデプロイとは、すでに存在するインフラの開発環境のコードを更新するというイメージが大きいと思います。
しかし、**Cloud Run**の場合は**Clud Run**自体が存在していない状況下では、**GitHub Actions**が走った際に**Cloud Run**を新規作成するため、実際に開発環境を作る際に**Clud Run**を作る作業が不要になります。
また**Cloud Run**がすでに存在する場合は、更新が行われます。

そのため、**Cloud Run**を使用すると初期構築がスムーズになります。
![スクリーンショット 2023-03-15 20.09.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3059557/b83e336f-662a-538d-4515-1967934dee57.png)

次に、**GitHub Actions**による自動デプロイについて説明します。
**GitHub Actions**のymlコードの全体像は下記です。

```yml
name: Build and Push Image

on:
  push:
    branches:
      - v1.0.0

env:
  SERVICE_NAME: ${{ secrets.SERVICE_NAME }}
  GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
  GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
  SERVICE_ACCOUNT: ${{ secrets.SERVICE_ACCOUNT }}
  SECRET_MANAGER_NAME: ${{ secrets.SECRET_MANAGER_NAME }}
  CLOUD_SQL_HOST: ${{ secrets.CLOUD_SQL_HOST }}

jobs:
  build-and-publish:
    name: Build and Push docker image
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          ref: ${{ github.ref }}

      - id: "auth"
        uses: "google-github-actions/auth@v0"
        with:
          credentials_json: "${{ env.GCP_SA_KEY }}"

      - name: "Set up Cloud SDK"
        uses: "google-github-actions/setup-gcloud@v0"
        with:
          version: "latest"
          project_id: ${{ env.GCP_PROJECT_ID }}

      - name: Configure docker to use the gcloud cli
        run: gcloud auth configure-docker --quiet

      - name: Move docker setting file 
        run: |
          mv run/* ./

      - id: "secrets"
        uses: "google-github-actions/get-secretmanager-secrets@v0"
        with:
          secrets: |-
            ENV_VARS:${{ env.GCP_PROJECT_ID }}/${{ env.SECRET_MANAGER_NAME }}

      - name: Create env file 
        run: |
          cat <<EOF > .env
          ${{ steps.secrets.outputs.ENV_VARS }}
          EOF

      - name: Build
        run: |
          docker build -t asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }} ./

      - name: Push
        run: |
          docker push asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }}

      - name: Deploy to Cloud Run
        run: |
          gcloud run deploy ${{ env.SERVICE_NAME }} \
            --image asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }} \
            --port 80 \
            --project ${{ env.GCP_PROJECT_ID }} \
            --region asia-northeast1 \
            --platform=managed \
            --allow-unauthenticated \
            --service-account=${{ env.SERVICE_ACCOUNT }} \
            --add-cloudsql-instances=${{ env.CLOUD_SQL_HOST }} \
            --quiet

```

**Cloud Run**のデプロイはとてもシンプルです。
一部分を切り抜いて、コードとともに流れを説明します。

1. ブランチからチェックアウトを行います
```yml
steps:
      - name: Checkout
        uses: actions/checkout@v2
        with:
          ref: ${{ github.ref }}
```

２. **Cloud Run**はGCPのサービスのため、GCPコンソールのgcloudにログインします
```yml
- name: "Set up Cloud SDK"
        uses: "google-github-actions/setup-gcloud@v0"
        with:
          version: "latest"
          project_id: ${{ env.GCP_PROJECT_ID }}
```

３. Dockerイメージを作ります
```yml
 - name: Build
        run: |
          docker build -t asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }} ./
```

４. ローカル環境で作ったdockerのイメージをGCPの方に上げます
```yml
 - name: Push
        run: |
          docker push asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }}
```

５. **Cloud Run**にデプロイします
`gcloud run deploy`というコマンドで、上記のコード上で作成された`--image asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }} \`のimage URLを指定し、デプロイすることができます。
```yml     
 - name: Deploy to Cloud Run
        run: |
          gcloud run deploy ${{ env.SERVICE_NAME }} \
            --image asia.gcr.io/${{ env.GCP_PROJECT_ID }}/${{ env.SERVICE_NAME }}:${{ github.sha }} \
            --port 80 \
            --project ${{ env.GCP_PROJECT_ID }} \
            --region asia-northeast1 \
            --platform=managed \
            --allow-unauthenticated \
            --service-account=${{ env.SERVICE_ACCOUNT }} \
            --add-cloudsql-instances=${{ env.CLOUD_SQL_HOST }} \
            --quiet
```

上記の説明が、特徴1の**GitHub Actions**による初期構築＆自動デプロイの流れです。

## 特徴2：環境変数の保守性
Laravelなどのフレームワークを始め、近年は.envファイルで環境変数を管理する方法が一般的になりました。
環境変数の扱い方は色々ありますが、多くの場合は環境固有の設定情報を環境変数で管理します。

### **GitHub Actions**を使う場合

例えば**GitHub Actions**にはSecretという機能があり、GitHubのページで大事な情報を登録した際に、**GitHub Actions**のプログラムの中でその情報を安全に使用することができます。
取得したSecretで.envを生成するという方法がありますが、Laravelなどになると、このSecretの数がとても多くなってしまい、1個1個登録することが大変なため今回この手法を使用しません。

また**ECS**、**Elastic Beans Talk**であれば、AWSサービス自体に環境変数を設定するということを行うが、今回の主題である手軽に簡単に作るからは外れてくるため、この手法も使用しません。

### **GitHub Actions**を使わない場合（今回のポイント）

今回はGCPの**SecretManager**を使用して環境変数を扱います。
**GitHub Actions**の中で**SecretManager**にアクセスして、**SecretManager**に登録された情報を取得します。
![スクリーンショット 2023-03-15 20.15.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3059557/02482dc2-ab3c-cd2e-7d75-075cfe65cfbe.png)

インフラを操作していない方がアプリケーションの中で環境変数を追加、編集することが頻繁に出てくると思います。
そういった時でも**SecretManager**を使用することにより、GCPのコンソールの中に入り、画面の中を容易に変更することができます。**SecretManager**の使用は有用です。

# 運用でよく発生する保守作業に対応できるのか？
次に上記のインフラ構成がアプリケーション上で出てくる問題に対応できるかについて説明します。

* 環境変数を変更したい
    * 実際にアプリケーション、サービスを運用していく中で、更新を行うことが可能です。GCPの画面の中で簡単に変更し、再度デプロイした場合に反映が可能です。
* データベースを確認したい
    * **Cloud Run**には**Cloud Sql**というサービスがあります。データベースを確認したいときは**Cloud Sql**に連携、アクセスをしてsqlのコマンドで確認できます。
* ログを調査したい
    * **Cloud Run**はログを自動で**Cloud Logging**に保存されているため調査が可能です。
* Dockerfileの情報を変更したい
    * ローカル環境のコードを変更することにより、反映することが可能です。
* サーバースペックを変更したい
    * **GitHub Actions**で**Cloud Run**のサービスをデプロイするときに、CPUやメモリなども指定できるため、その部分を変更することにより、スペックを変更することが可能です。

# 応用的な構成
上記では、シンプルなインフラ構成を説明しました。
さらに応用的なインフラ構成を構築したい場合は、下記を試しましょう。
* ロードバランサの設置
    * Google Cloudロードバランサ(GCLB)と連携することができ、外部からのアクセスを複数の**Cloud Run**に振り分けることが可能です。
* **Cloud Run**発のIPアドレスの固定
    * **Cloud Run**からのアクセスを全てCloud NATに通すことができ、IPアドレスの固定が可能です。
* DDoS対策
    * Google Cloudロードバランサ(GCLB)と連携ができるため、ロードバランサにCloud Armorを設置することで、DDoS対策が可能です。

# シンプルなインフラ構成を構築した感想
* 簡単なアプリケーションを運用する場面において、今回のような管理するリソースが少なく、自動デプロイの機能が整備された構成は十分使用が可能である
* 今回のようにシンプルなインフラ構成は、構築が早い点や複数人でインフラを管理する際に仕様理解の工数が少なく済ませることができる点で有用である

# 最後に
今回は、弊社社内勉強会で発表された「**Cloud Run**を用いたシンプルなインフラ構成」について扱いました。
今後も継続的に80&Companyでの社内勉強会の取り組みを発信していきます！
[Qiita Organization](https://qiita.com/organizations/80andco)や[Twitter](https://twitter.com/80andcoDev)公式アカウントのフォローもよろしくお願いいたします！
最後まで読んでいただきありがとうございます！