チュートリアル: Cloud Run での Filestore の使用


このチュートリアルでは、Filestore をネットワーク ファイル システムとして Cloud Run サービスにマウントし、複数のコンテナとサービス間でデータを共有する方法について説明します。このチュートリアルでは、Cloud Run の第 2 世代の実行環境を使用します。

第 2 世代の実行環境では、ネットワーク ファイル システムをコンテナ内のディレクトリにマウントできます。ファイル システムをマウントすると、ホストシステムとインスタンスの間でリソースを共有し、インスタンスがガベージ コレクションされた後もリソースを保持できます。

Cloud Run でネットワーク ファイル システムを使用するには、コンテナでファイル システムのマウントやアプリケーション プロセスなどの複数のプロセスを実行する必要があるため、高度な Docker の知識が必要です。このチュートリアルでは、実際の例を示しながら必要なコンセプトについて説明します。ただし、このチュートリアルをアプリケーションに合わせて変更する場合は、変更の影響を十分に確認してください。

デザインの概要

Filestore インスタンスは、Virtual Private Cloud(VPC)ネットワーク内でホストされます。VPC ネットワーク内のリソースは、プライベート IP アドレス範囲を使用して Google API やサービスと通信します。そのため、インスタンスに格納されているファイルにアクセスするには、クライアントが Filestore インスタンスと同じネットワーク上にある必要があります。Cloud Run サービスが VPC ネットワークに接続して Filestore と通信するには、サーバーレス VPC アクセス コネクタが必要です。サーバーレス VPC アクセスの詳細をご確認ください。

ファイルシステム アーキテクチャ

この図は、サーバーレス VPC アクセス コネクタを介して Filestore インスタンスに接続する Cloud Run サービスを示しています。Filestore インスタンスとコネクタは、最高のパフォーマンスを得るために、Cloud Run サービスと同じ VPC ネットワーク(デフォルト)内の同じリージョン / ゾーンに配置されます。

制限事項

  • このチュートリアルでは、ファイル システムの選択方法や本番環境に対応するための要件について説明しません。Filestore と利用可能なサービス階層の詳細をご確認ください。

  • このチュートリアルでは、ファイル システムを使用する方法やファイル アクセス パターンについても説明しません。

目標

  • ファイル共有として機能するデフォルトの VPC ネットワークに Filestore インスタンスを作成する。

  • 同じデフォルト VPC ネットワーク上にサーバーレス VPC アクセス コネクタを作成して、Cloud Run サービスに接続する。

  • システム パッケージと init プロセスを使用して、マウント プロセスとアプリケーション プロセスを管理する Dockerfile を構築する。

  • Cloud Run にデプロイし、サービスでファイル システムへのアクセスを確認する。

費用

このチュートリアルでは、Google Cloud の課金対象となる以下のコンポーネントを使用します。

始める前に

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

  4. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  5. Google Cloud プロジェクトで課金が有効になっていることを確認します

  6. IAM の権限は、Filestore インスタンスの作成など、Filestore オペレーションへのアクセス権のみを制御します。読み取りや実行など、ファイル共有でのオペレーションへのアクセス権を制御するには、POSIX のファイルへのアクセス許可を使用します。詳細については、アクセス制御をご覧ください。
  7. Cloud Run, Filestore, Serverless VPC Access, Artifact Registry, and Cloud Build API を有効にします。

    API を有効にする

  8. gcloud CLI をインストールして初期化します
  9. gcloud components update で Google Cloud CLI を更新します。

必要なロール

チュートリアルを完了するために必要な権限を取得するには、プロジェクトに対して次の IAM ロールを付与するよう管理者に依頼してください。

ロールの付与の詳細については、アクセスの管理をご覧ください。

必要な権限は、カスタムロールや他の事前定義ロールから取得することもできます。

gcloud のデフォルトを設定する

Cloud Run サービスを gcloud のデフォルトに構成するには:

  1. デフォルト プロジェクトを設定します。

    gcloud config set project PROJECT_ID

    PROJECT_ID は、このチュートリアルで作成したプロジェクトの名前に置き換えます。

  2. 選択したリージョン向けに gcloud を構成します。

    gcloud config set run/region REGION

    REGION は、任意のサポートされている Cloud Run のリージョンに置き換えます。

  3. Filestore 用に gcloud を構成します。

    gcloud config set filestore/zone ZONE
    

    ZONE は、サポートされている任意の Filestore ゾーンに置き換えます。

コードサンプルを取得する

使用するコードサンプルを取得するには:

  1. ローカルマシンにサンプルアプリのリポジトリのクローンを作成します。

    Node.js

    git clone https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git

    また、zip 形式のサンプルをダウンロードしてファイルを抽出してもかまいません。

    Python

    git clone https://github.com/GoogleCloudPlatform/python-docs-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

    Java

    git clone https://github.com/GoogleCloudPlatform/java-docs-samples.git

    または、zip 形式のサンプルをダウンロードし、ファイルを抽出してもかまいません。

  2. Cloud Run のサンプルコードが含まれているディレクトリに移動します。

    Node.js

    cd nodejs-docs-samples/run/filesystem/

    Python

    cd python-docs-samples/run/filesystem/

    Java

    cd java-docs-samples/run/filesystem/

コードについて

通常、コンテナ内では、単一のプロセスまたはアプリケーションを実行します。1 つのコンテナにつき 1 つのプロセスを実行すると、複数プロセスのライフサイクルを管理する複雑さが軽減されます(たとえば、再起動の管理、プロセスが失敗した場合のコンテナの終了、シグナルの送信やゾンビの子の刈り取りといった PID 1 問題など)。一方、Cloud Run でネットワーク ファイル システムを使用する場合、ファイル システムのマウント プロセスとアプリケーションの両方を実行するためにマルチプロセス コンテナを使用する必要があります。このチュートリアルでは、プロセスの障害時にコンテナを終了し、PID 1 問題を管理する方法について説明します。mount コマンドには、再試行を扱う機能が組み込まれています。

プロセス マネージャーを使用することで、コンテナのエントリポイントとして複数のプロセスを実行、管理できます。このチュートリアルでは、tini を使用します。これは、init の代わりになるもので、ゾンビプロセスをクリーンアップしてシグナル送信を行います。具体的には、この init プロセスにより、シャットダウン時の SIGTERM シグナルがアプリケーションに伝えられます。SIGTERM シグナルは、アプリケーションを正常に終了するためにキャッチされます。詳細については、Cloud Run 上のコンテナのライフサイクルをご覧ください。

Dockerfile で環境構成を定義する

この Cloud Run サービスには、デフォルト以外のシステム パッケージを 1 つ以上追加する必要があります。RUN 命令によって、tini が init プロセスおよび nfs-common としてインストールされ、NFS クライアントの最小限の機能が提供されます。Cloud Run サービスでのシステム パッケージの操作について詳しくは、システム パッケージ・チュートリアルを使用するをご覧ください。

次の一連の手順では、作業ディレクトリの作成、ソースコードのコピー、アプリの依存関係のインストールが行われます。

ENTRYPOINT は、CMD 命令の前に付加される init-process バイナリを指定します(この例では起動スクリプト)。これにより、単一の tini プロセスが起動され、受信したすべてのシグナルが、その子プロセスをルートとするセッションに代理転送されます。

CMD 命令は、イメージを動作させる際に実行されるコマンド(起動スクリプト)を設定します。また、ENTRYPOINT のデフォルトの引数も指定します。CMD と ENTRYPOINT の操作方法をご覧ください。

Node.js


# Use the official Node.js image.
# https://hub.docker.com/_/node
FROM node:20-slim

# Install system dependencies
RUN apt-get update -y && apt-get install -y \
    tini \
    nfs-common \
	libtool \
    && apt-get clean

# Set fallback mount directory
ENV MNT_DIR /mnt/nfs/filestore

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

# Install production dependencies.
RUN npm install --only=production

# Copy local code to the container image.
COPY . ./

# Ensure the script is executable
RUN chmod +x /app/run.sh

# Use tini to manage zombie processes and signal forwarding
# https://github.com/krallin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]

# Pass the wrapper script as arguments to tini
CMD ["/app/run.sh"]

Python

# Use the official lightweight Python image.
# https://hub.docker.com/_/python
FROM python:3.11-slim

# Install system dependencies
RUN apt-get update -y && apt-get install -y \
    tini \
    nfs-common \
    && apt-get clean

# Set fallback mount directory
ENV MNT_DIR /mnt/nfs/filestore

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

# Install production dependencies.
RUN pip install -r requirements.txt

# Ensure the script is executable
RUN chmod +x /app/run.sh

# Use tini to manage zombie processes and signal forwarding
# https://github.com/krallin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]

# Pass the startup script as arguments to tini
CMD ["/app/run.sh"]

Java


# Use the official maven image to create a build artifact.
# https://hub.docker.com/_/maven
FROM maven:3-eclipse-temurin-17-alpine as builder

# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src

# Build a release artifact.
RUN mvn package -DskipTests

# Use Eclipse Temurin for base image.
# https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
FROM eclipse-temurin:18-jdk-focal

# Install filesystem dependencies
RUN apt-get update -y && apt-get install -y \
    tini \
    nfs-kernel-server \
    nfs-common \
    && apt-get clean

# Set fallback mount directory
ENV MNT_DIR /mnt/nfs/filestore

# Copy the jar to the production image from the builder stage.
COPY --from=builder /app/target/filesystem-*.jar /filesystem.jar

# Copy the statup script
COPY run.sh ./run.sh
RUN chmod +x ./run.sh

# Use tini to manage zombie processes and signal forwarding
# https://github.com/krallin/tini
ENTRYPOINT ["/usr/bin/tini", "--"]

# Run the web service on container startup.
CMD ["/run.sh"]

起動スクリプトでプロセスを定義する

起動スクリプトによってマウント ポイントとなるディレクトリが作成されます。これにより、Filestore インスタンスがアクセス可能になります。次に、スクリプトが mount コマンドを使用して Filestore インスタンスを接続します。具体的には、インスタンスの IP アドレスとファイル共有名をサービスのマウント ポイントに指定し、アプリケーション サーバーを起動します。mount コマンドには、再試行機能が組み込まれています。したがって、bash スクリプトをさらに追加する必要はありません。最後に、wait コマンドでは、バックグラウンド プロセスの終了をリッスンし、スクリプトを終了します。

Node.js

#!/usr/bin/env bash
set -eo pipefail

# Create mount directory for service.
mkdir -p $MNT_DIR

echo "Mounting Cloud Filestore."
mount -o nolock $FILESTORE_IP_ADDRESS:/$FILE_SHARE_NAME $MNT_DIR
echo "Mounting completed."

# Start the application
node index.js &

# Exit immediately when one of the background processes terminate.
wait -n

Python

#!/usr/bin/env bash
set -eo pipefail

# Create mount directory for service.
mkdir -p $MNT_DIR

echo "Mounting Cloud Filestore."
mount -o nolock $FILESTORE_IP_ADDRESS:/$FILE_SHARE_NAME $MNT_DIR
echo "Mounting completed."

# Run the web service on container startup. Here we use the gunicorn
# webserver, with one worker process and 8 threads.
# For environments with multiple CPU cores, increase the number of workers
# to be equal to the cores available.
# Timeout is set to 0 to disable the timeouts of the workers to allow Cloud Run to handle instance scaling.
exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app

Java

#!/usr/bin/env bash
set -eo pipefail

# Create mount directory for service
mkdir -p $MNT_DIR

echo "Mounting Cloud Filestore."
mount -o nolock $FILESTORE_IP_ADDRESS:/$FILE_SHARE_NAME $MNT_DIR
echo "Mounting completed."

# Start the application
java -jar filesystem.jar

# Exit immediately when one of the background processes terminate.
wait -n

ファイルを操作する

Node.js

ファイルシステムの操作については、index.js をご覧ください。

Python

ファイルシステムの操作については、main.py をご覧ください。

Java

ファイルシステムの操作については、FilesystemApplication.java をご覧ください。

サービスを配布する

  1. Filestore インスタンスを作成します。

    gcloud filestore instances create INSTANCE_ID \
        --tier=basic-hdd \
        --file-share=name=FILE_SHARE_NAME,capacity=1TiB \
        --network=name="default"
    

    INSTANCE_ID は Filestore インスタンスの名前(例: my-filestore-instance)に置き換え、FILE_SHARE_NAME は Filestore インスタンスから提供されるディレクトリの名前(例: vol1)に置き換えます。インスタンスに名前を付けるファイル共有の命名をご覧ください。

    クライアント(Cloud Run サービス)が Filestore インスタンスに保存されているファイルにアクセスするには、そのインスタンスと同じネットワーク上に存在する必要があります。このコマンドでは、デフォルトの VPC ネットワークにインスタンスを作成して、無料の IP アドレス範囲を割り当てます。新しいプロジェクトはデフォルトのネットワークで開始されますが、別にネットワークを作成する必要はほぼありません。

    インスタンス構成の詳細については、インスタンスの作成をご覧ください。

  2. サーバーレス VPC アクセス コネクタを設定します。

    Filestore インスタンスに接続するには、Cloud Run サービスが Filestore インスタンスの承認済み VPC ネットワークにアクセスする必要があります。

    VPC コネクタごとに、コネクタ インスタンスを配置する独自の /28 サブネットが必要です。この IP 範囲は、VPC ネットワーク内の既存の IP アドレス予約と重複してはいけません。たとえば、10.8.0.0/28)はほとんどの新規プロジェクトで機能しますが、10.9.0.0/28)など、別の未使用のカスタム IP 範囲を指定することもできます。現在予約されている IP 範囲は、Google Cloud コンソールで確認できます。

    gcloud compute networks vpc-access connectors create CONNECTOR_NAME \
      --region REGION \
      --range "10.8.0.0/28"
    

    CONNECTOR_NAME は、アプリケーションの名前に置き換えます。

    このコマンドは、Filestore インスタンスと同じデフォルト VPC ネットワークに、e2-micro マシンサイズのコネクタを作成します。コネクタのマシンサイズを大きくすると、コネクタのスループットを向上させることができますが、コストも増加します。コネクタは、Cloud Run サービスと同じリージョンに存在する必要があります。サーバーレス VPC アクセスの構成の詳細をご確認ください。

  3. Filestore インスタンスの IP アドレスを格納する環境変数を定義します。

    export FILESTORE_IP_ADDRESS=$(gcloud filestore instances describe INSTANCE_ID --format "value(networks.ipAddresses[0])")
    
  4. サービス ID として機能するサービス アカウントを作成します。このアカウントには、デフォルトでは、プロジェクト メンバーシップ以外の権限は付与されません。

    gcloud iam service-accounts create fs-identity

    このサービスは、Google Cloud の他のサービスとやり取りする必要がないため、このサービス アカウントに追加の権限を割り当てる必要はありません。

  5. コンテナ イメージをビルドして Cloud Run にデプロイします。

    gcloud run deploy filesystem-app --source . \
        --vpc-connector CONNECTOR_NAME \
        --execution-environment gen2 \
        --allow-unauthenticated \
        --service-account fs-identity \
        --update-env-vars FILESTORE_IP_ADDRESS=$FILESTORE_IP_ADDRESS,FILE_SHARE_NAME=FILE_SHARE_NAME
    

    このコマンドは、VPC コネクタと第 2 世代の実行環境を指定し、Cloud Run サービスをビルドしてデプロイします。ソースからデプロイすると、Dockerfile に基づいてイメージがビルドされ、Artifact Registry リポジトリ(cloud-run-source-deploy)にイメージが push されます。

    ソースコードからのデプロイで詳細をご確認ください。

デバッグ

デプロイが失敗した場合は、Cloud Logging で詳細を確認してください。

  • 接続がタイムアウトした場合は、Filestore インスタンスの正しい IP アドレスを指定していることを確認します。

  • アクセスがサーバーから拒否された場合は、ファイル共有名が正しいことを確認します。

  • マウント プロセスからのログをすべて取得するには、次のように mount コマンドと --verbose フラグを組み合わせて使用します。mount --verbose -o nolock $FILESTORE_IP_ADDRESS:/$FILE_SHARE_NAME $MNT_DIR

試してみる

完成したサービスを試すには:

  1. ブラウザで、前述のデプロイの手順により提供された URL に移動します。
  2. 新しく作成したファイルが Filestore インスタンスに表示されます。
  3. ファイルをクリックすると内容が表示されます。

これらのサービスの開発を継続する場合、Google Cloud の他のサービスへの Identity and Access Management(IAM)アクセスが制限されます。他の多くのサービスにアクセスするには、追加の IAM ロールをこれらのサービスに与える必要があることにご注意ください。

費用の説明

1 TiB の Filestore インスタンスとサーバーレス VPC アクセス コネクタを使用してアイオワ(us-central1)でホストされているサービスの費用内訳の例:最新の料金については、個別の料金ページをご覧ください。

プロダクト 月額
Filestore(使用量では変わりません) 費用 = プロビジョニングされた容量(1,024 GiB または 1 TiB)× リージョン ティアの料金(us-central1)

基本 HDD ティア: 1,024 GiB × $0.16 / 月 = $163.84
ゾーン(SSD): 1,024 GiB × $0.25 / 月 = $256.00
Enterprise(SSD、利用可能なリージョン): 1,024 GiB × $0.45 / 月 = $460.80
サーバーレス VPC アクセス 費用 = マシンサイズの料金 × インスタンス数(最小インスタンス数はデフォルトで 2)

f1-micro: $3.88 × 2 インスタンス = $7.76
e2- micro: $6.11 × 2 インスタンス = $12.22
e2-standard-4: $97.83 × 2 インスタンス = $195.66
Cloud Run 費用 = CPU + メモリ + リクエスト数 + ネットワーキング
合計 $163.84 + $12.22 = $176.06 / 月 + Cloud Run の費用

このチュートリアルでは、基本 HDD ティアの Filestore インスタンスを使用しています。Filestore インスタンスのサービスティアは、そのインスタンス タイプとストレージの種類を組み合わせたものです。インスタンス タイプをアップグレードすることで、容量を増やし、スケーラビリティを向上することができます。ストレージの種類をアップグレードすることで、パフォーマンスを上げることができます。詳細については、ストレージ タイプに関する推奨事項をご覧ください。リージョンと容量も Filestore の料金に影響します。たとえば、アイオワ(us-central1)の基本 HDD ティア 1 TiB インスタンスの費用は、月に GiB あたり $0.16 かかるので、月当り約 $163.84 になります。

サーバーレス VPC アクセス コネクタは、インスタンスのサイズと数、下り(外向き)ネットワークによって課金されます。サイズと数を大きくすると、スループットが向上し、メッセージのレイテンシが短縮されます。マシンには、f1-micro、e2-micro、e2-standard-4 の 3 つのサイズがあります。インスタンスの最小数は 2 であるため、最小の費用はそのマシンサイズの費用の 2 倍になります。

Cloud Run の料金は、メモリ、CPU、リクエスト数、ネットワーキングなどのリソースの使用量に応じて課金され、100 ミリ秒単位で切り上げて計算されます。そのため、サービスの設定、リクエスト数、実行時間によって費用は異なります。このサービスでは、月額最低 $176.06 の料金が発生します。Google Cloud 料金計算ツールで見積もりを表示してご確認ください。

クリーンアップ

このチュートリアル用に新規プロジェクトを作成した場合は、そのプロジェクトを削除します。既存のプロジェクトを使用し、このチュートリアルで変更を加えずに残す場合は、チュートリアル用に作成したリソースを削除します。

プロジェクトを削除する

課金をなくす最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除するには:

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

チュートリアル リソースを削除する

  1. このチュートリアルでデプロイした Cloud Run サービスを削除します。

    gcloud run services delete SERVICE-NAME

    SERVICE-NAME は、選択したサービス名です。

    Cloud Run サービスは Google Cloud コンソールから削除することもできます。

  2. チュートリアルの設定時に追加した gcloud のデフォルト リージョン構成を削除します。

     gcloud config unset run/region
    
  3. プロジェクト構成を削除します。

     gcloud config unset project
    
  4. このチュートリアルで作成した他の Google Cloud リソースを削除します。

次のステップ