Catch up on everthing we announced at this year's Firebase Summit. Learn more

関数のデプロイとランタイム オプションを管理する

Firebase CLI コマンドを使用するか、関数のソースコードでランタイム オプションを設定することにより、関数をデプロイ、削除、変更できます。

関数をデプロイする

関数をデプロイするには、次の Firebase CLI コマンドを実行します。

$ firebase deploy --only functions

デフォルトでは、Firebase CLI によって index.js 内のすべての関数が同時にデプロイされます。プロジェクトに 6 つ以上の関数が含まれている場合は、特定の関数名で --only フラグを使用して、編集した関数のみをデプロイすることをおすすめします。このようにして特定の関数をデプロイすると、デプロイ プロセスが迅速化され、デプロイの割り当ての問題を回避できます。次に例を示します。

$ firebase deploy --only functions:addMessage,functions:makeUppercase

多くの関数をデプロイすると、標準の割り当てを超過し、HTTP 429 または 500 エラー メッセージが表示されることがあります。これを解決するには、10 個以下のグループで関数をデプロイします。

使用可能なコマンドの一覧については、Firebase CLI リファレンスをご覧ください。

デフォルトでは、Firebase CLI によって functions/ フォルダ内でソースコードが検索されます。別のフォルダを指定するには、firebase.json に次の行を追加します。

"functions": {
  "source": "another-folder"
}

関数を削除する

過去にデプロイした関数は、次の方法で削除できます。

  • functions:delete を使用して Firebase CLI で明示的に行う
  • Firebase コンソールの関数リストにあるコンテキスト メニューを使用して明示的に削除する
  • デプロイの前に index.js から関数を削除して暗黙的に行う

本番環境から関数を削除しようとするたびに、削除操作の確認を求められます。

Firebase CLI で明示的に関数を削除する方法では、複数の引数だけでなく関数のグループもサポートされ、特定のリージョンで実行されている関数を指定できます。また、確認メッセージをオーバーライドすることもできます。

# Delete all functions that match the specified name in all regions.
$ firebase functions:delete myFunction

# Delete a specified function running in a specific region.
$ firebase functions:delete myFunction --region us-east-1

# Delete more than one function
$ firebase functions:delete myFunction myOtherFunction

# Delete a specified functions group.
$ firebase functions:delete groupA

# Bypass the confirmation prompt.
$ firebase functions:delete myFunction --force

暗黙的に関数を削除する方法では、firebase deploy により index.js が解析され、ファイルから削除されたすべての関数が本番環境から削除されます。

関数の名前、リージョン、トリガーを変更する

本番トラフィックを処理している関数のリージョンまたはトリガー(またはそれらの名前)を変更する場合は、このセクションの手順に沿って、変更中にイベントが失われないようにしてください。以下の手順を行う前に、まず関数がべき等であることを確認します。これは、関数の新旧両方のバージョンが変更中に同時に実行されるためです。

関数の名前を変更する

関数の名前を変更するには、関数の名前を変更した新しいバージョンを index.js に作成してから、2 つの別々のデプロイ コマンドを実行します。最初のコマンドは新しい名前の関数をデプロイし、2 番目のコマンドは以前にデプロイされたバージョンを削除します。たとえば、webhook という関数の名前を webhookNew に変更する場合は、次のようにコードを変更します。

// before
const functions = require('firebase-functions');

exports.webhook = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

// after
const functions = require('firebase-functions');

exports.webhookNew = functions.https.onRequest((req, res) => {
    res.send("Hello");
});

続いて、次のコマンドを実行して新しい関数をデプロイします。

# Deploy new function called webhookNew
$ firebase deploy --only functions:webhookNew

# Wait until deployment is done; now both webhookNew and webhook are running

# Delete webhook
$ firebase functions:delete webhook

関数のリージョンを変更する

本番環境トラフィックを処理している関数のリージョンを変更する場合は、以下の手順を順番に実施すると、イベントが失われないようにできます。

  1. 関数の名前とリージョンを任意に変更します。
  2. 名前を変更した関数をデプロイします。これにより、一時的に両方のリージョンで関数が実行されます。
  3. 前の関数を削除します。

たとえば、現時点でデフォルトの関数リージョン us-central1webhook という関数があり、それを asia-northeast1 に移行する場合は、ソースコードを変更して関数の名前を変更してからリージョンを変更する必要があります。

// before
const functions = require('firebase-functions');

exports.webhook = functions
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

// after
const functions = require('firebase-functions');

exports.webhookAsia = functions
    .region('asia-northeast1')
    .https.onRequest((req, res) => {
            res.send("Hello");
    });

続いて、次のコマンドを実行してデプロイします。

$ firebase deploy --only functions:webhookAsia

これで 2 つの同じ関数が実行されます。webhookus-central1 で実行され、webhookAsiaasia-northeast1 で実行されます。

次に、webhook を削除します。

$ firebase functions:delete webhook

これで、関数は asia-northeast1 で実行される webhookAsia だけになります。

関数のトリガータイプを変更する

Cloud Functions for Firebase デプロイの開発の進展に応じて、さまざまな理由により関数のトリガータイプを変更する必要が生じる場合があります。たとえば、次のような必要が生じることがあります。

  • 従来のストレージの onChange イベントから onFinalizeonDeleteonArchiveonMetadataUpdate に変更する(詳しくは、ベータ版から v1 または v2 へのアップグレード ガイドをご覧ください)。
  • あるタイプの Firebase Realtime Database または Cloud Firestore イベントから別のイベントに変更する(汎用の onWrite イベントをきめ細かな onCreate イベントに変更するなど)。

ソースコードを変更して firebase deploy を実行するだけでは、関数のイベントタイプを変更できません。エラーを回避するために、次の手順に従って関数のトリガータイプを変更します。

  1. 目的のトリガータイプを使用する新しい関数が含まれるように、ソースコードを変更します。
  2. 関数をデプロイします。これにより、一時的に新旧両方の関数が実行されます。
  3. Firebase CLI を使用して、本番環境から古い関数を明示的に削除します。

たとえば、従来の onChange イベントタイプを使用する objectChanged 関数があり、それを onFinalize に変更する場合は、まず関数の名前を変更して、onFinalize イベントタイプを使用するように編集します。

// before
const functions = require('firebase-functions');

exports.objectChanged = functions.storage.object().onChange((object) => {
    return console.log('File name is: ', object.name);
});

// after
const functions = require('firebase-functions');

exports.objectFinalized = functions.storage.object().onFinalize((object) => {
    return console.log('File name is: ', object.name);
});

続いて、古い関数を削除する前に、先に次のコマンドを実行して新しい関数を作成します。

# Create new function objectFinalized
$ firebase deploy --only functions:objectFinalized

# Wait until deployment is done; now both objectChanged and objectFinalized are running

# Delete objectChanged
$ firebase functions:delete objectChanged

ランタイム オプションを設定する

Cloud Functions for Firebase ではランタイム オプションを選択できます。設定できるランタイム オプションには、Node.js ランタイムのバージョン、関数ごとのタイムアウト、メモリ割り当て、関数インスタンスの最小数と最大数などがあります。

Node.js のバージョンを設定する

Firebase SDK for Cloud Functions 2.0.0 以降では、Node.js ランタイムを選択できます。プロジェクト内のすべての関数を、サポートされている以下のいずれかの Node.js バージョンに対応するランタイム環境のみで実行するように選択できます。

  • Node.js 16(ベータ版)
  • Node.js 14
  • Node.js 12
  • Node.js 10
  • Node.js 8(2020 年 6 月 8 日に非推奨化)Node.js 8 ランタイムへの関数のデプロイは、2020 年 12 月 15 日をもって Firebase CLI で無効になりました。デプロイ済みの関数の実行については、将来的に停止される予定です。Node.js 8 ランタイムにデプロイした関数がある場合は、Node.js 14 ランタイムにアップグレードすることをおすすめします。

Node.js のバージョンを設定するには:

初期化時に functions/ ディレクトリに作成された package.json ファイルの engines フィールドにバージョンを設定します。たとえば、バージョン 14 のみを使用するには、package.json の次の行を編集します。

  "engines": {"node": "14"}

engines フィールドは必須です。関数をデプロイして実行するには、サポートされているいずれかの Node.js バージョンを指定する必要があります。現在、firebase init functions はこのフィールドを 14 に設定します。

Node.js ランタイムをアップグレードする

Node.js ランタイムをアップグレードするには:

  1. プロジェクトで Blaze 料金プランを利用していることを確認します。
  2. Firebase CLI バージョン 8.6.0 以降を使用していることを確認します。
  3. 初期化時に functions/ ディレクトリに作成された package.json ファイルの engines の値を変更します。たとえば、バージョン 10 からバージョン 14 にアップグレードする場合、エントリは次のようになります。"engines": {"node": "14"}
  4. 必要に応じて、Firebase Local Emulator Suite を使用して変更をテストします。
  5. Firebase CLI v8.1.0 以降を使用して関数を再デプロイします。

スケーリング動作の制御

デフォルトでは、Cloud Functions for Firebase は受信リクエストの数に基づいて実行インスタンスの数をスケーリングします。トラフィックが減少すると、インスタンス数がゼロまでスケールダウンされる可能性があります。ただし、アプリでレイテンシを短縮する必要があり、コールド スタートの数を制限する場合は、ウォーム状態を維持し、いつでもリクエストを処理できるコンテナ インスタンスの最小数を指定して、このデフォルトの動作を変更できます。

同様に、受信リクエストに応じてスケーリングされるインスタンス数に最大数を設定して制限を設けることができます。この設定を使用して、コストの制御や、データベースなどのバッキング サービスへの接続数を制限できます。

コールド スタートの数を減らす

ソースコードで関数の最小インスタンス数を設定するには、runWith パラメータを使用します。このランタイム オプションは、RuntimeOptions インターフェースに準拠する JSON オブジェクトを受け入れます。これにより、minInstances の値が定義されます。たとえば、次の関数ではウォーム状態を維持する最小インスタンス数を 5 に設定しています。

exports.getAutocompleteResponse = functions
    .runWith({
      // Keep 5 instances warm for this latency-critical function
      minInstances: 5,
    })
    .https.onCall((data, context) => {
      // Autocomplete a user's search term
    });

minInstances の値を設定する際は、次の点を考慮してください。

  • Cloud Functions for Firebase が minInstances の設定を超えてアプリをスケーリングした場合、このしきい値を上回る各インスタンスにコールド スタートが発生することになります。
  • コールド スタートは、トラフィックの急増があるアプリに特に大きな影響を及ぼします。アプリのトラフィックが急増する場合、minInstances に大きな値を設定すると、トラフィックが増加するたびにコールド スタートが発生するのを減らすことができ、レイテンシが大幅に短縮されます。トラフィックが一定しているアプリの場合、コールド スタートがパフォーマンスに大きな影響を与えることはほとんどありません。
  • 最小インスタンス数の設定は本番環境では意味がありますが、通常、テスト環境では避ける必要があります。テスト プロジェクトではゼロにスケールし、本番環境プロジェクトではコールド スタートを減らすようにするには、FIREBASE_CONFIG 環境変数に基づいて minInstances を設定します。

    // Get Firebase project id from `FIREBASE_CONFIG` environment variable
    const envProjectId = JSON.parse(process.env.FIREBASE_CONFIG).projectId;
    
    exports.renderProfilePage = functions
        .runWith({
          // Keep 5 instances warm for this latency-critical function
          // in production only. Default to 0 for test projects.
          minInstances: envProjectId === "my-production-project" ? 5 : 0,
        })
        .https.onRequest((req, res) => {
          // render some html
        });
    

関数の最大インスタンス数を制限する

関数のソースコードで最大インスタンス数を設定するには、runWith パラメータを使用します。このランタイム オプションは、RuntimeOptions インターフェースに準拠する JSON オブジェクトを受け入れます。これにより、maxInstances の値が定義されます。たとえば次の関数では、仮想上のレガシー データベースの過負荷を防ぐためにインスタンス数の上限を 100 に設定しています。

exports.mirrorOrdersToLegacyDatabase = functions
    .runWith({
      // Legacy database only supports 100 simultaneous connections
      maxInstances: 100,
    })
    .firestore.document("orders/{orderId}")
    .onWrite((change, context) => {
      // Connect to legacy database
    });

HTTP 関数が maxInstances の上限までスケールアップされると、新しいリクエストは 30 秒間キューに入れられ、その間にいずれのインスタンスも使用可能にならない場合は、レスポンス コード 429 Too Many Requests で拒否されます。

最大インスタンス数の設定に関するベスト プラクティスについては、こちらの maxInstances を使用する際のベスト プラクティスをご覧ください。

タイムアウトとメモリ割り当てを設定する

場合によっては、長いタイムアウト値や大容量のメモリ割り当てに関して、関数に特別な要件が存在することがあります。これらの値は、Google Cloud Console または関数のソースコード(Firebase のみ)で設定できます。

関数のソースコードでメモリ割り当てとタイムアウトを設定するには、Firebase SDK for Cloud Functions 2.0.0 で導入された runWith パラメータを使用します。このランタイム オプションは、RuntimeOptions インターフェースに準拠する JSON オブジェクトを受け入れます。これにより、timeoutSecondsmemory の値が定義されます。たとえば、次のストレージ関数は 1 GB のメモリを使用し、300 秒経過するとタイムアウトします。

exports.convertLargeFile = functions
    .runWith({
      // Ensure the function has enough memory and time
      // to process large files
      timeoutSeconds: 300,
      memory: "1GB",
    })
    .storage.object()
    .onFinalize((object) => {
      // Do some complicated things that take a lot of memory and time
    });

timeoutSeconds の最大値は 540 または 9 分です。 関数に割り当てられるメモリ容量は、その関数に割り当てられた CPU に対応します。memory の値として有効なものは次のとおりです。

  • 128MB — 200 MHz
  • 256MB — 400 MHz
  • 512MB — 800 MHz
  • 1GB — 1.4 GHz
  • 2GB — 2.4 GHz
  • 4GB — 4.8 GHz
  • 8GB — 4.8 GHz

Google Cloud Console でメモリ割り当てとタイムアウトを設定するには:

  1. Google Cloud Console で、左側のメニューから [Cloud Functions] を選択します。
  2. 関数のリストで関数名をクリックして、関数を選択します。
  3. トップメニューの [編集] アイコンをクリックします。
  4. [割り当てられるメモリ] というプルダウン メニューから、メモリ割り当てを選択します。
  5. [詳細] をクリックして詳細オプションを表示し、[タイムアウト] テキスト ボックスに秒数を入力します。
  6. [保存] をクリックして関数を更新します。