SPAサイトをGitHub ActionsでCloud Storageへアップロードする。あとCDNも設定する。

# はじめに

Google Cloud Platformを使い始めました。

備忘録として、作業の流れを記録していきます。

## API有効化の注意

場合によっては、必要なAPIを有効化する必要がありますが、それらは省略しています。

使用するのは、たぶん、Compute Engine APIです。

# Vueプロジェクト作成

SPAは何でもいいのですが、今回はVueを使います。

https://ja.vuejs.org/guide/quick-start.html

```shell
$ npm create vue@latest
```

プロンプトにメッセージが表示されるので選んでいきます。何を選んでもいいです。

```shell
$ cd <your-project>
$ npm i
$ npm run dev
```

すると、http://localhost:5173/ にこんな画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/47c2a8f0-2a63-896a-2747-39abf5e02593.png)

# GCPプロジェクト作成

記事の都合上、新しいプロジェクトから作成していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/e1bcb993-11e8-6cee-5d43-3352e3d570ee.png)

## GitHub Actionsで使用するサービスアカウントを作成

IAMと管理 -> サービスアカウントから、サービスアカウントを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/d3e30657-9239-1fb5-0844-23eb52e68b7f.png)

名前は、 `github-actions` にします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/16fcdf6c-dafb-9531-9b59-9759377d4852.png)

Storageオブジェクト管理者のロールを付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/60ddcad3-261e-80a5-1d47-2aeec5134632.png)

アカウントが作成されたら、鍵を作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/2cdab444-2fb2-313b-bb53-65c46eee4cac.png)

鍵を作成します。ここをクリックすると、選択肢のポップアップが表示されますが、JSONタイプのものを使います。そっちじゃないのは使ったことありません。そのあと、鍵の情報が入ったファイルの自動ダウンロードが始まります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/d0e62872-c5bf-ebcf-0b30-3958e889abd1.png)

ファイルはこんな感じです。 **公開リポジトリ等にアップロードしてはいけません。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/7dd5682c-fe4b-2577-0566-f435ea025bad.png)

この内容は、あとでGitHub ActionsのSecretに登録します。

## Cloud Storageのバケットを作成

ビルドしたvueアプリをデプロイするためのCloud Storageバケットを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/957dfd61-df53-207e-2a95-bc509acf6372.png)

名前は `vueapp` としておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/9204f01e-d243-5616-06fd-4e623a52b4c2.png)

バケットは公開するので、公開アクセス禁止設定は解除しておきます。後からでも解除できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/c836996a-956d-dab4-10c3-7cdd1cd83e9c.png)

バケットの公開設定をします。権限タブに行き、アクセス権を付与をクリック。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/98850ce6-6e68-8006-cef7-10104b70d48b.png)

`allUsers`にStorageオブジェクト**閲覧者**の権限をつけます。これで公開されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/6aa1f540-7049-8763-db91-acbacc32e1fe.png)

ウェブサイトの構成を編集します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/ce9b8956-62d1-ea3b-e462-71e2ae55bcc8.png)

これにより、 `/` へのアクセスで `index.html` が表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/a385e03e-a406-94a6-43a2-13124c1fdf57.png)



# GitHub Actionsを使ってバケットにデプロイする

プロジェクトにActionsのファイルを用意します。ChatGPTに作ってもらいました。

`<your-bucket>`のところを、作成したバケット名に変えてください。

```yaml:.github/workflows/deploy.yml
name: Deploy to Google Cloud Storage

on:
  push:
    branches:
      - main

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: Install dependencies
        run: npm install

      - name: Build project
        run: npm run build

      - name: Authenticate to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          credentials_json: ${{ secrets.GCP_SA_KEY }}

      - name: Upload Folder
        uses: google-github-actions/upload-cloud-storage@v2
        with:
          path: dist
          destination: <your-bucket>
          parent: false
```

上記のファイルで使用した `GCP_SA_KEY` を、GitHubに登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/e890e693-996a-b29a-a415-83e754a81ca3.png)

これで、Actionsが走って成功すると、アップロードされます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/82dee6ff-4640-0f91-b58f-cbfd2890098f.png)

ここで、 `index.html` の詳細を見てみます。公開URLをクリックしてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/e1f1d8b4-4c33-9676-aba8-da820110c4a6.png)

真っ白なページが表示されます。URLのパス部分がルートでないので、関連ファイルの読み込みに失敗しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/d66c5ee6-00e5-88f1-df5e-a4a60707b36f.png)

解決方法としては、Vueのほうの設定で、相対パスを使うように設定する方法があるかと思いますが、今回はCDNを使ってURLのパス部分がルートになるようにします。

# Cloud Storageの前段にCloud Load BalancingとCloud CDNを置く

ロードバランサを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/9882da64-abb1-8aa9-65f4-6d6b043ebc8d.png)

いろいろ選択肢がありますが、全部左の選択肢を選びました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/f1643373-f010-9b41-e3b8-4d87a96688aa.png)

ロードバランサの構成をしていきます。

フロントエンドの構成です。エフェメラルIPアドレスを使用して、HTTPSを使用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/2604d522-e337-f864-c312-af31b139837a.png)

証明書はGCPに作ってもらいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/ce1084d2-fb31-ad52-8902-075b22be5550.png)

次はバックエンドの構成です。

バックエンドバケットを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/85b27f52-ca4c-5833-3b52-30ba45f80559.png)

次の画面で、前に作ったCloud Storageのバケットを指定します。

また、ここでCloud CDNの設定とCloud Armorの設定があります。Cloud CDNは個人開発であっても十分払えるレベルかと思いますので、有効のままで行きます。

Cloud ArmorはWAFです。仕事なら有効にする必要があるかもしれませんが、Cloud StorageのURLでもファイルにアクセスできるので、どのくらい有用なのかわかりません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/f25e51fb-e13d-cd79-1abc-eefdd5835c48.png)

最後にルーティングですが、いまのところバケットしかないので、デフォルトのままです。ここにバックエンドとか追加のバケットが入ってくると、ルーティングを設定する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/f4820ca2-6a9c-5e26-9696-7422357e77ee.png)

# ロードバランサにドメイン名でアクセスするようDNSの設定をする

ロードバランサが作成された後で、詳細画面を見ます。

そこにロードバランサのIPアドレスが書いてあるのでメモします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/2080acce-c09b-3dd0-606a-ea19eef8d5dd.png)

先のフロントエンドの構成のところで入力したドメインに対して、Aレコードを設定します。

（私はドメイン名を別サービスで管理しているので画面は省略です）

さて、DNS設定が終わった後は、証明書ができるのを待ちます。証明書のことろのリンクをクリックすると、状況がわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/f44ff96c-4dcd-4307-cce8-ea5652fa9262.png)

この画面では、PROVISIONINGとなっており、証明書は作成されてないことがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/d802f44f-acc0-4b79-7de8-2cafce5c616c.png)

30分くらい待つと、ACTIVEになりました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/9d64a46f-c80f-43f4-19a0-00add4f55684.png)

# 設定したドメインでアクセスできるようになる

さて、それではページを開いてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172833/56d10b77-32c3-ca2e-a46b-d77a1bb936a3.png)

これで、GitHubにプッシュしたら、自動的にGCPへデプロイされる手筈が整いました。