web開発をメインに頑張っているCです!

web開発やモバイル開発に携わっている方なら、もしかしたら一度はfirebase、もしくは、
GCP(Google Cloud Platform)のサーバーレスサービスを使用したことがあるのではないのでしょうか。

私も小規模なサービスやスタブサーバーのために、過去に何度かfirebase functionsにお世話になったことがあります。

特に「cloud functions for firebase」は本当に手軽にセットアップできて、とても便利ですよね。

とあるとき、「cloud functions for firebase」ではなく、「google cloud functions」の方でサーバーレスサーバーを作る必要が初めて生じて、「cloud functions for firebase」と比べて少し勝手も違ったので、自分の経験を記事にして今回共有させて頂きたいと思いました。

技術スタック

以下、今回の開発に使用した主な技術スタックです。

項目 VERSION
node v16.4.0
express 4.18.1
@google-cloud/functions-framework 3.1.1

前提

「google cloud functions(以後、GCF)」の利用には、以下の作業が事前に済ませることをおすすめ致します。

詳細は省略させていただきますが、大まかな流れは箇条書きさせていただきます。

  • gcpのアカウントは作成済みであること
  • 手元でgcloudコマンドを導入済みなこと
  • gcloudコマンドでログイン済み、且つ、作成したgcpプロジェクトに切り替え済みなこと
  • 手元のPCにnode.js(ver16系)を導入済みであること(ローカルでの動作確認に使用します)

GCFが推奨するnode.jsのバージョンは16系です。詳細は下記をご参照ください。

https://cloud.google.com/functions/docs/concepts/nodejs-runtime?hl=ja

セットアップ

プロジェクトフォルダの作成とpackage.jsonを作成

まずは、プロジェクトフォルダを用意しましょう。

// プロジェクトフォルダを作成
$ mkdir -p /path/to/project_root/
$ cd /path/to/project_root/

//このindex.jsファイルにサーバースクリプトを記述してゆきます
$ touch inde.js

次に必要なライブラリの導入のために、package.jsonを準備します。

// package.jsonを作成。
// 表示される質問はとりあえず全てEnterで飛ばします(後でいくらでも調整できるので)
$ cd /path/to/project_root/
$ npm init

// package.jsonに今回導入するライブラリを追記してゆきます。
// また、合わせてnpmコマンドも記述しましょう。
// 以下が今回のサンプルしようした例です(細かいことはコメントで残しておきます)。
$ ls package.json 
package.json

// cat package.json
{
  "name": "gcf-sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js", //プロジェクトルートにindex.jsを配置しているときの書き方です。
  "scripts": {
    "start": "npx functions-framework --target=helloworld --port=30081" //これでサーバーを手元で起動します(動作確認用)。
  },
  "engines": {
    "node": "16" //今回使用するランタイムのバージョンをここで指定しています。
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@google-cloud/functions-framework": "^3.1.1", //こちらがgcpのサーバーレスフレームワークです。
    "express": "^4.18.1" //サーバーのサンプルをかんたんにするために、webフレームワークを使用しました。
  }
}

package.jsonで定義したライブラリをインストール

package.jsonに記載したライブラリを実際に手元にインストールします。

インストールに成功すれば後、node_modulesフォルダが作成されます。

インストールは、以下のコマンドで実施します。

$ cd /path/to/project_root/
$ npm i

サーバーのスクリプトを用意

以下は、今回用意した簡単なGCFのHTTP関数です。(helloworld関数)

こちらの例を使用して、手元でサーバー起動をします。

// 下から5行目のスクリプトが今回用意した。HTTP関数です。
// nameクエリパラメータを渡せば動的な一文を返し、そうでなれば固定値を返却する、
// 簡単なものとなっております。

// $ cd /path/to/project_root/
// $ vi index.js

exports.helloworld = (req, res) => {
  let name = req.query.name || "anonymous";
  name = `hello ${name} from gcf`;
  res.status(200).send(name);
}

では、以下のコマンドで、サーバーの起動を試しましょう。

$ cd /path/to/project_root/
$ npm run start

起動がうまくいくとターミナルに以下のログが表示されます。

> gcf-sample@1.0.0 start
> npx functions-framework --target=helloworld --port=30081

Serving function...
Function: helloworld
Signature type: http
URL: http://localhost:30081/

ブラウザ側で以下のURLでアクセスすれば、ブラウザ側でもレスポンス結果を確認できます。

アクセスに利用するURLの例

http://localhost:30081/
http://localhost:30081/?name=taro

ブラウザではこのように表示されました。

デプロイの準備

.gitignoreや、.gcloudignore を以下のように準備します。

.gcloudignore は初めてデプロイ時に自動で作成されますが、私は以下のように自分で用意しました。

.gitignore

node_modules

.gcloudignore

node_modules
#!include:.gitignore
# do not ignore built (or dist) folder for gcloud:
!/build
!/dist

今回の記事ではnose.jsのみで作成していますが、実際の業務では typescript + express.jsを用いました。

余談ですが、 typescript + express.js でデプロイしたときのビルド先を任意のフォルダ(lib)に指定していました。

そして、なんどやってもデプロイに失敗するというドハマりしました。

理由は簡単で、デプロイ時に .gcloudignore に、自分が指定したビルド先のフォルダ(lib)を無視しないようにという記述をしないといけなかったのです。

.gcloudignoreが自動生成されるときはデフォルトで上のように「!/build」、「!/dist」の行が入ります。
ビルド先の同様の名前にすれば私と同じハマり方をせず済むと思います。

「cloud functions for firebase」ではこの周りはあまり気にしていなかったので、ちょっとしたトラップでした笑

デプロイのコマンド

以下に、デプロイのコマンド例を記載致します。

# プロジェクトディレクトリに移動して、デプロイコマンドを叩いています
cd /path/to/project_root/ && \
  gcloud functions deploy helloworld \
    --entry-point helloworld \
    --trigger-http \
    --runtime nodejs16 \
    --project {AWESOME_PROJECT_NAME} \
    --region {AWESOME_RESION_NAME} \
    --allow-unauthenticated \
    --memory=256MB \
    --verbosity debug

上記のコマンドのオプションに対応する簡単な説明です。

プション名 説明
entry-point cloud functionが実行されたときに最初に実行される関数名の指定
trigger-http HTTPトリガー
runtime ランタイム(2022年10月時点、node.jsはver16がサポートバージョンです)
project GCPのプロジェクト名の指定
region リージョンの指定
allow-unauthenticated パブリック関数に変更。すべての呼び出しを許可する
memory 関数にマウントさせるメモリ
allow-verbosity デプロイ中に詳細なログ出力を有効にします。

細かいオプションの説明は、以下の説明や、更新サイトをご参照ください。

https://cloud.google.com/sdk/gcloud/reference/functions/deploy

また、上記のコマンドは長いですので、`npm run start` のように、npmコマンドとして登録しておき、簡単に叩けるようにしましょう。

例 `npm run deploy` のようなコマンドで私は登録しました。

実際にデプロイ

では、上のデプロイコマンドをnpmスクリプトに登録した前提で、
以下のコマンドを叩いて、実際にデプロイしてみましょう。

$ cd /path/to/project_root/
$ npm run deploy

デプロイ後、gcp > google cloud functions 画面に移動し、自分が作成した helloworld 関数が作成されたかを確認しましょう。

うまくいってれば、画面に以下のような関数のレコードが表示されます。

あとは、デプロイ後のURLを管理画面で調べて、ブラウザから問題なく動作するかも確認しましょう。

実際の本番URLは、ご自身の管理画面でご確認ください。

以下は、例です。

https://asia-northeast1-{GCP_PROJECT_NAME}.cloudfunctions.net/helloworld

https://asia-northeast1-{GCP_PROJECT_NAME}.cloudfunctions.net/helloworld?name=taro

うまく行けば、おそらく本番URLでも、手元で確認できた同じ結果が確認できるかと思います。

最後に

このように簡単ですが、シンプルなHTTP関数を「google cloud functions」で用意してみました。

もし初めて 「google cloud functions」を作成されるなら、自分の今回の記事がお役に立てた嬉しいです。

それでは、素敵な開発ライフを!



ギャップロを運営しているアップフロンティア株式会社では、一緒に働いてくれる仲間を随時、募集しています。 興味がある!一緒に働いてみたい!という方は下記よりご応募お待ちしております。
採用情報をみる