Google Cloud Functions(第2世代)をTypescriptで作ってデプロイする
前提
- firebaseではなくGCF
- gcloudコマンドはインストール&認証済み
- 必要なAPIは有効化済み
まずはjsでやる
いきなりTypescriptでやろうとしたけど関係ないところで色々ハマって原因の切り分けが面倒なのでまずはシンプルにjsからやりましょう
ファイルの準備
# プロジェクト作成
npm init
# パッケージのインストール
npm i @google-cloud/functions-framework
touch index.js
デプロイするファンクションを用意
第1世代と第2世代で異なるようです。
Pub/Subトリガーなどもありますが、今回はHttpトリガーで行います。
// index.js
const functions = require("@google-cloud/functions-framework");
functions.http("sample", (req, res) => {
res.status(200).send("sushi");
});
この時点でファイル構成はこのようになっているはずです
┬ node_modules
├ index.js
├ package-lock.json
└ package.json
デプロイ
package.json
のmain
で実行するファイルを指定します。
ついでにデプロイ用のコマンドも設定しておきましょう
{
"name": "function-sample",
"version": "1.0.0",
"description": "",
+ "main": "index.js",
"scripts": {
+ "deploy": "gcloud functions deploy sample --gen2 --runtime=nodejs18 --trigger-http --allow-unauthenticated",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"@google-cloud/functions-framework": "^3.3.0"
}
}
デプロイコマンドのそれぞれの意味は以下です
gcloud functions deploy \
# ファンクション名
sample \
# 第2世代を指定
--gen2 \
# ランタイム
--runtime=nodejs18 \
# Httpトリガーを指定
--trigger-http \
# 未認証状態でも呼び出しを許可
--allow-unauthenticated
ランタイムはランタイムサポートから選べます
リージョンは指定しなくてもコマンドラインで選べるようになってます
指定する場合は以下のように指定します
# 東京
--region asia-northeast1
それではデプロイを実行しましょう
npm run deploy
実行すると.gloudignore
が作られますが、事前に作っておいても大丈夫です。
ここで指定したファイルはアップロードする対象から除外されます。
中身は下記のようになってます
# .gloudignore
.gcloudignore
.git
.gitignore
アップロードされるファイルは以下のコマンドで確認できます
gcloud meta list-files-for-upload
# 表示される下記がアップロードされるファイル
# index.js
# package-lock.json
# package.json
しばらく時間がかかるかと思いますがエラーなどでなければデプロイ完了です
デプロイ後に表示されるURLやGCPのコンソールからURLが確認できるので、そこにアクセスすればデプロイしたファンクションの結果が表示されます
~~~~~~~
url: https://asia-northeast1-project-xxxxxxxxxxx.cloudfunctions.net/sample
--allow-unauthenticated
で誰でも呼び出せる状態になっているので、確認できたらこのファンクションは削除しておきましょう
エラー
ちなみに私は以下のエラーでしばらくハマりました
ビルドまでは問題ありませんでしたがCloud Runのあたりでエラーになりデプロイに失敗します。
Ready condition status changed to False for Service sample with message:
Revision 'sample-00001-kuc' is not ready and cannot serve traffic.
The user-provided container failed to start and listen on the port defined provided by the PORT=8080 environment variable.
Logs for this revision might contain more information.
ポートのリッスンに云々などと書かれているのであらぬところを疑ったりしていましたが、
原因はindex.js
に記載しているファンクション名と、デプロイコマンドで指定するファンクション名が異なっていたためでした
// index.js
functions.http(
"sample", // <- これがサンプルコードからコピペしたままになってた
(req, res) => {
res.status(200).send("sushi");
});
gcloud functions deploy \
sample # <- ここと同じ名前にしましょう
Typescriptでやる
それでは本題のTypescriptを使っていきましょう
まずはtsファイルを用意
# パッケージのインストール
npm i -D typescript
# index.tsを用意
rm index.js
mkdir src
touch src/index.ts
# tsconfig.json
touch tsconfig.json
中身はほとんど変わりません
// src/index.ts
import * as functions from "@google-cloud/functions-framework";
functions.http("sample", (req, res) => {
res.status(200).send("tempura");
});
tsconfig.jsonはこんな感じです
{
"compilerOptions": {
"target": "es2016",
"module": "commonjs",
"esModuleInterop": true,
"strict": true,
"outDir": "dist"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Cloud Buildを使ってビルドすることもできるようですが
今回はトランスパイル済みのものをアップロードするので、事前にトランスパイルします
npx tsc
この時点でファイル構成は以下のようになっているはずです
┬ dist
│ └ index.js
├ node_modules
├ src
│ └ index.ts
├ index.js
├ package-lock.json
└ package.json
tsファイルはいらないので.gcloudignore
を編集します
# .gloudignore
.gcloudignore
.git
.gitignore
+ src/**
+ tsconfig.json
gcloud meta list-files-for-upload
# アップロードされるファイル
# package-lock.json
# package.json
# dist/index.js
実行するファイルの場所が変わったのでpackage.json
も変更します
{
...
- "main": "index.js",
+ "main": "dist/index.js",
...
}
ローカルテスト
ちなみローカルで動作確認はこちら
トランスパイルしたファイルも問題なさそうです
npx functions-framework --target=sample
curl localhost:8080
# tempura
デプロイ
ここまできたら後は同じようにデプロイするだけです
ちなみにpackage.jsonにbuildコマンドを設定しているとCloud Buildでこれが実行されてしまい失敗するので別の名前にしましょう。
ついでに今回は認証が必要になるように変更します。
{
...
script: {
- "build": "tsc",
+ "pre-build": "tsc",
- "deploy": "gcloud functions deploy sample --gen2 --runtime=nodejs16 --trigger-http --allow-unauthenticated --region asia-northeast1",
+ "deploy": "gcloud functions deploy sample --gen2 --runtime=nodejs16 --trigger-http --region asia-northeast1",
...
}
あとは同じようにデプロイします
一度--allow-unauthenticated
で作ったファンクションを上書きしても認証が必要に変更されなかったので、一度削除してからもう一度デプロイしました。
詳しく調べてませんが、GCPのコンソールからも変更できなさそうだったのでそういう仕様なのかもしれません。
npm run deploy
動作確認しておしまい。お疲れ様でした。
# 未認証だとエラー
curl https://asia-northeast1-xxxxxxxxxxxxxxxxx.cloudfunctions.net/sample
# <html><head>
# <meta http-equiv="content-type" content="text/html;charset=utf-8">
# <title>403 Forbidden</title>
# </head>
# <body text=#000000 bgcolor=#ffffff>
# <h1>Error: Forbidden</h1>
# <h2>Your client does not have permission to get URL <code>/sample</code> from this # server.</h2>
# <h2></h2>
# </body></html>
# 認証情報付きで送る
curl -H "Authorization: bearer $(gcloud auth print-identity-token)" https://asia-northeast1-xxxxxxxxxxxxxxxxx.cloudfunctions.net/sample
# tempura
Discussion