🔥

Firebase Hosting と Cloud Run でサーバレスアプリを立ち上げる

2021/10/19に公開

Google Cloud のサービスを利用して、サーバレスアプリを立ち上げた時の手順です。

構成

  • フロントエンド:Nuxt.js SPA
    デプロイ先:firebase hosting
  • バックエンド:Python fastapi
    デプロイ先:Cloud Run

Nuxt.js でビルドした静的ファイルを Firebase Hosting にデプロイ、Python を Cloud Run にデプロイし、REST API として立ち上げます。

以下の公式サイトを参考に行いました。
https://firebase.google.com/docs/hosting/cloud-run?hl=ja

手順早見

  1. 前準備
    1. Google アカウントと GCP の準備
    2. プロジェクト生成
    3. 請求先の設定
    4. Clooud Run API の有効化
    5. Cloud SDK 導入
  2. バックエンド
    1. コードの記述
    2. コンテナの準備
      • firebase hosting の URL を許可する。
    3. Cloud Run にデプロイ
  3. フロントエンド
    1. 環境構築
      • Cloud Run の URL を記述
    2. nuxt.js プロジェクト作成
    3. Cloud Run との連携
    4. Firebase Hosting にデプロイ

前準備

Google アカウントと GCP の準備

GCP を持っていない場合は、以下を参考に GCP の登録まで行ってください。

https://www.apps-gcp.com/gcp-startup/

プロジェクト作成

Cloud Consoleへ移動し、プロジェクト名が表示されている部分をクリック

createproject1

「新しいプロジェクト」を選択します

createproject2_1

今回立ち上げる Web アプリのプロジェクトを作成します。

createproject2

請求先の設定

作成したプロジェクトに移動し、「ナビゲーションメニュー」→「お支払い」→「請求先アカウント」→「請求先アカウントを管理」へ移動します。

請求先アカウントが無ければ作成します。

作成した請求先アカウントをプロジェクトに紐づけ

Cloud Run を使用するために、プロジェクトと請求先アカウントが紐付いているか確認します。
私の場合は、下記のように請求先アカウントが紐付いた状態になっていました。

billing

Clooud Run API の有効化

cloud-sdk 導入

Cloud-SDK とは GCP 用の CLI です。
GCP 上のコンソールからでも使えるのですが、今回はローカルにインストールしました。
下記のコマンドで Cloud SDK をインストールします。

#Cloud SDK の配布 URI をパッケージ ソースとして追加
echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | sudo tee -a /etc/apt/sources.list.d/google-cloud-sdk.list

#apt-transport-https がインストールされていることを確認
sudo apt-get install apt-transport-https ca-certificates gnupg

#Google Cloud の公開鍵をインポート
curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key --keyring /usr/share/keyrings/cloud.google.gpg add -
#Cloud SDK を更新してインストール
sudo apt-get update && sudo apt-get install google-cloud-sdk

プロジェクトの準備

下記の構成でプロジェクトディレクトリを作成します。

sample-project/
└frontend/
└backend/
# 適当な階層で実行
mkdir sample-project
cd sample-project
mkdir frontend
mkdir backend

プロジェクト設定

下記は今回のプロジェクトで使う設定です。
以降の説明では変数値で説明しますので、
自身の環境に応じて書き換えてください。

変数名 変数値
project_id sample-project-33
フロントエンド service_id front-app
バックエンド service_id backend-app
firebase ホスティング URL https://sample-project.web.app
cloud run URL https://backend-app-vbppox-an.a.run.app

Cloud Run の有効化

Cloud Run API ページでプロジェクトを選択し、API を有効にします

enablecloudrun

バックエンド

コードの記述

backend 直下に main.py を下記の内容で作成。

from fastapi import FastAPI

app = FastAPI()

# CORSのエラーを避けるために、originsにfirebase hostingのURLを追加しておく。
origins = [
    {Firebase-hosting_URL},
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get("/")
def read_root():
    return {"hello": "world"}

origins の Firebase-hosting_URL は後述します

コンテナの準備

Dockerfile を準備します。

FROM python:3.9-slim

# Allow statements and log messages to immediately appear in the Knative logs
ENV PYTHONUNBUFFERED True

# Copy local code to the container image.
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./

# Install production dependencies.
RUN pip install fastapi uvicorn

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port","8080"]

fastapi 立ち上げに最低限必要なものに絞っています

GCP プロジェクトとの紐づけ

gcloud コマンドを使用して GCP のプロジェクトと、ローカルのプロジェクトを紐づけます

$ gcloud init
# 新規プロジェクトを作成
Pick configuration to use:2 Create a new configuration
#ローカルのプロジェクト名を入力
Enter configuration name. Names start with a lower case letter and
contain only lower case letters a-z, digits 0-9, and hyphens '-':sample-project
#使用するGoogleアカウントを選択
Choose the account you would like to use to perform operations for
this configuration:1 xxx@gmail.com
#GCP上の紐付けるプロジェクトを選択
Pick cloud project to use:sample-project-33

Cloud Run にデプロイ

これで cloud Run にデプロイする準備が整いました。

backend ディレクトリに移動して、下記コマンドでコンテナをビルドしてみます。

gcloud builds submit --tag gcr.io/sample-project-33/backend-app

ビルドが完了すると、Container Registry に、バックエンドのイメージがアップロードされている事が確認出来ます。

/images/firebase_cloud_run/registory.png

続いて Cloud Run へデプロイを行います

# イメージを選択し、Cloud Runへデプロイする
$ gcloud run deploy --image gcr.io/sample-project-33/backend-app
#サービス名の入力
Service name (backend-app):Enter
#リージョンの選択
Please specify a region:
Please enter your numeric choice:3 asia-northeast1
#未認証の呼び出しを許可
Allow unauthenticated invocations to [eventsearch] (y/N)?  y

成功すると、Deploy 結果が表示されます。
Service URL にアクセスしてみてください。

✓ Deploying... Done.
  ✓ Creating Revision...
  ✓ Routing traffic...
  ✓ Setting IAM Policy...
Done.
Service [backend-app] revision [backend-app-00006-nil] has been deployed and is serving 100 percent of traffic.
Service URL: https://backend-app-vbppox-an.a.run.app

ブラウザで「hello-world!」と表示されれば成功です。
{Service URL}/docs と打つと、Swaggar UI が立ち上がっていることも確認できます。

これでバックエンド側は完成です。

またデプロイコマンドの選択は、引数で一括指定することも出来ます

gcloud run deploy backend-app --image gcr.io/sample-project-33/backend-app --region asia-northeast1 --allow-unauthenticated

GCP コンソールの Cloud Run を開くと、動作しているサービスを確認出来ます。

deploycloudrun.png

フロントエンド

続いてフロントエンド側を作成します。

環境構築

node, yarn, firebase-tools をインストールします。

sudo apt install -y nodejs npm
# npm 経由でyarnをインストール
sudo npm install -g yarn
yarn global add firebase-tools

フロントエンドの手順は docker で作成しても問題ありません。
docker で構築したコードは github で公開しています。

nuxt.js プロジェクト作成

nuxt-app 作成

yarn create nuxt-app

nuxt-app 作成時の選択は下記にしました。

create-nuxt-app v3.7.1
✨  Generating Nuxt.js project in .
? Project name: frontend-app
? Programming language: TypeScript
? Package manager: Yarn
? UI framework: Bootstrap Vue
? Nuxt.js modules: Axios - Promise based HTTP client
? Linting tools: ESLint, Prettier
? Testing framework: None
? Rendering mode: Single Page App
? Deployment target: Static (Static/Jamstack hosting)
? Development tools: jsconfig.json (Recommended for VS Code if you're not using typescript)
? Continuous integration: None
? Version control system: None

プロジェクトを作成し終わったら、早速実行してみます

yarn dev

指定された URL(localhost:3000?)にアクセスし、下記が表示されたらプロジェクトの初期化完了です。

welcomtonuxt

Cloud Run(バックエンド)との連携

axios で cloud run へ接続するコードを書きます

index.vue

<template>
  <div class="container">
    <button @click="getHello()">connect cloud run</button>
    <p>{{ posts }}</p>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import axios from "axios";
export default Vue.extend({
  data() {
    return {
      posts: "",
    };
  },
  methods: {
    async getHello() {
      const response = await axios.get(
        "https://backend-app-vbppox-an.a.run.app/"
      );
      this.posts = response.data;
    },
  },
});
</script>

完成したら再度します

yarn dev

ブラウザで下記の画面が表示されたら、"connect cloud run"を押して、cloud run との接続を確認します。

画像のように{"hello":"world"}と表示されたらフロントエンドの完成です。

helloworld

Firebase Hosting にデプロイ

続いて firebase と連携します。

firebase init hosting
? Allow Firebase to collect CLI usage and error reporting information? Yes
i  To change your data collection preference at any time, run `firebase logout` and log in again.

=== Project Setup
? Please select an option: Add Firebase to an existing Google Cloud Platform project
? Select the Google Cloud Platform project you would like to add Firebase: sample-project-33 (sample-project)

=== Hosting Setup

Your public directory is the folder (relative to your project directory) that
will contain Hosting assets to be uploaded with firebase deploy. If you
have a build process for your assets, use your build's output directory.

? What do you want to use as your public directory? dist
? Configure as a single-page app (rewrite all urls to /index.html)? Yes
? Set up automatic builds and deploys with GitHub? No
✔  Wrote dist/index.html

i  Writing configuration info to firebase.json...
i  Writing project information to .firebaserc...

✔  Firebase initialization complete!

ブラウザに firebase へ連携する画面が表示されます。

連携するアカウントを選択し、OK を押す。

selectaccount

allow

successfull

firebasegithublogin

Visit this URL on this device to log in:
https://accounts.google.com/o/oauth2/auth?client_id=563584335869-fgrhgmd47bqnekij5i8b5pr03ho849e6.apps.googleusercontent.com&scope=email%20openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloudplatformprojects.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Ffirebase%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform&response_type=code&state=1009920591&redirect_uri=http%3A%2F%2Flocalhost%3A9005

Waiting for authentication...

✔  Success! Logged in as {googleアカウント}

作成したプロジェクトを firebase hosting にデプロイします

yarn build
yarn generate
firebase deploy

Deploy complete!と出たら完成です。
表示されている Hosting URL にアクセスしてみてください

  Deploy complete!

Project Console: https://console.firebase.google.com/project/sample-project-33/overview
Hosting URL: https://sample-project-33.web.app
Done in 102.11s.

この段階では、CORS エラーにより cloud run へアクセスできません。
バックエンドの main.py, origins に Hosting URL を追加します

origins = [
    "https://sample-project-33.web.app",
]

改めて gcloud へ[ビルド&デプロイ](#Cloud Run にデプロイ)を行います。

完了後、Hosting URL にアクセスし、"connect cloud run"ボタン押下で Hello world が出たら
firebase hosting と cloud run の連携が完成です。

helloworld

最終的なディレクトリ構成

sample-project/
└frontend/
 └
└backend/
 └main.py
 └Dockerfile
 └firebase.json
 -dist
 └その他nuxt.js関連のファイル・ディレクトリ多数

今回はここで終了です。

使用したコード

使用したコードは github に載せています。

  • frontend

https://github.com/m1asak2/sample-frontend

  • backend

https://github.com/m1asak2/sample-backend

引き続き CI/CD 編 を書きます。

記事予告:cloud run と firebase hosting の CI/CD 環境を構築する。

Discussion