Cloud RunでCloud Storageバケットをマウントする

記事タイトルとURLをコピーする

G-gen の佐々木です。当記事では Cloud Run で Cloud Storage バケットをボリュームマウントする方法を解説します。

前提知識

Cloud Run とは

Cloud Run は Google Cloud のマネージドなコンテナ実行基盤を使用してアプリケーションを実行することができるサーバーレス コンテナコンピューティング サービスです。

HTTP リクエストをトリガーとする Cloud Run services と、手動もしくはスケジュール、ワークフローをトリガーとする Cloud Run jobs の 2種類が提供されています。当記事で紹介する機能は、いずれの Cloud Run でも使用することができます。

それぞれ、以下の記事でサービスの詳細を解説しています。

blog.g-gen.co.jp

blog.g-gen.co.jp

Cloud Storage(GCS)とは

Cloud Storage は Google Cloud が提供する容量無制限のオブジェクトストレージサービスであり、99.999999999% (イレブンナイン) の堅牢性を持つオブジェクトストレージを安価に利用することができます。

Cloud Storage の詳細は以下の記事で解説しています。

blog.g-gen.co.jp

ネイティブ機能によるマウント

Cloud Run では Cloud Storage FUSE を利用することで、Cloud Storage バケットをローカルファイルシステムとしてマウントし、コンテナからバケット内のオブジェクトにアクセスすることができます。従来の方法では、コンテナに Cloud Storage FUSE を明示的にインストールして実行する必要がありました。

2024年1月のアップデートにて、明示的に Cloud Storage FUSE をインストールしなくても、Cloud Run のネイティブ機能として Cloud Storage バケットをマウントすることができるようになりました。

ネイティブ機能では、従来の方法同様、Cloud Storage FUSE を使用してマウントする点は変わりませんが、FUSE に関する処理はサービスの裏側で行われるため、ユーザー側で FUSE の設定を行う必要がなくなります。Cloud Storage FUSE の制限事項や、従来の利用方法については、以下の記事で解説しています。

blog.g-gen.co.jp

当記事ではこれ以降、Cloud Run サービスを使用して、ネイティブ機能によるバケットのマウントを試してみます。

Cloud Storage バケットの作成

Cloud Run からファイルシステムとして使用する Cloud Storage バケットを作成します。

ここではバケット名を mybucket としていますが、実際のバケット名はグローバルに一意の名前を設定する必要があります。

# Cloud Storage バケットを作成する
$ gcloud storage buckets create gs://mybucket --location=asia-northeast1

バケットにテキストファイルをアップロード

作成したバケットにテキストファイル test.txt を配置しておきます。

# テキストファイルの作成
$ echo 'Hello, GCS!!' > test.txt
  
# テキストファイルをバケットにアップロード
$ gcloud storage cp test.txt gs://mybucket

Artifact Registry リポジトリの作成

Cloud Run にデプロイするコンテナイメージを格納するための Artifact Registory リポジトリを作成します。

# Artifact Registry リポジトリを作成する
$ gcloud artifacts repositories create myrepo \
    --repository-format=docker \
    --location=asia-northeast1

コンテナイメージの作成

使用するコード

当記事では、マウントした Cloud Storage バケットからテキストファイルの中身を読み取り、ブラウザ上に表示するだけの簡単な Web アプリケーションを作成します。

// main.go
package main
  
import (
    "fmt"
    "log"
    "net/http"
    "os"
)
  
func readGCS() (string, error) {
    // マウントした Cloud Storage バケットからテキストファイルを読み込む
    f, err := os.Open("/mnt/gcs/" + "test.txt")
    if err != nil {
        return "", err
    }
    defer f.Close()

    text := make([]byte, 1024)
    count, err := f.Read(text)
    if err != nil {
        return "", err
    }
    return string(text[:count]), nil
}
  
func readGCSHandler(w http.ResponseWriter, r *http.Request) {
    text, err := readGCS()
    if err != nil {
        log.Printf("failed to read GCS: %v", err)
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    // text の内容をブラウザに表示する
    fmt.Fprintf(w, "%s", text)
}
  
func main() {
    log.Print("Starting server...")
    http.HandleFunc("/", readGCSHandler)

    port := os.Getenv("PORT")
    if port == "" {
        port = "8080"
    }
    log.Printf("Listening on port %s", port)

    if err := http.ListenAndServe(":"+port, nil); err != nil {
        log.Fatal(err)
    }
}
  

コンテナイメージのビルド

Cloud Build を使用してコンテナイメージをビルドし、Artifact Registry リポジトリにプッシュします。

当記事では Dockerfile を使用せず、Buildpack を使用してコンテナイメージをビルドします。Buildpack を使用することで、ソースコードを自動でパッケージ化し、デプロイ可能なコンテナイメージを生成することができます。

# Buildpack を使用してコンテナイメージをビルド
$ gcloud builds submit --pack image=asia-northeast1-docker.pkg.dev/myproject/myrepo/run-gcs

Cloud Run サービスの作成

コンソールから Cloud Run サービスを作成する場合

作成画面の「コンテナ、ボリューム、ネットワーキング、セキュリティ」項目でボリュームマウントの設定を行います。

まず、「ボリューム」タブでマウントするバケットを選択します。

マウント対象の Cloud Storage バケットを選択

そして「コンテナ」タブで、コンテナにマウントするボリュームとマウントパスの設定を行います。

コンテナにマウントするボリュームとマウントパスの設定

CLI で Cloud Run サービスを作成する場合

公式ドキュメントでは gcloud run service update コマンドを使用した方法が紹介されていますが、当記事では gcloud run deploy コマンドを使用してサービスを作成します。

いずれのコマンドでもサービスを新規作成することができますが、deploy コマンドでは --allow-unauthenticated オプションを使用して、未認証のサービス呼び出しを許可した状態でサービスを作成することができます。

# Cloud Run サービスの作成
$ gcloud run deploy run-gcs \
    --image=asia-northeast1-docker.pkg.dev/myproject/myrepo/run-gcs \
    --region=asia-northeast1 \
    --execution-environment=gen2 \
    --allow-unauthenticated \
    --add-volume=name=gcs,type=cloud-storage,bucket=mybucket \
    --add-volume-mount=volume=gcs,mount-path=/mnt/gcs

使用するオプションは以下のようになります。

オプション 説明
--image Artifact Registory リポジトリにプッシュしたコンテナイメージを指定します。
--region Cloud Run サービスを作成するリージョンを指定します。
--execution-environment Cloud Storage FUSE の使用には第2世代の Cloud Run を使用する必要があるため gen2 を指定します。
--allow-unauthenticated 未認証の Cloud Run サービスの呼び出しを許可します。
--add-volume マウントする Cloud Storage バケットの情報を指定します。
name には任意のボリューム名、type には cloud-storage を指定し、bucket で Cloud Storage バケットの名前を指定します。
--add-volume-mount volume には --add-volumename で指定した任意のボリューム名と同じものを指定します。
mount-path にはコンテナからバケットにアクセスするための任意のパスを設定します。当記事で使用するコードでは /mnt/gcs からバケットにアクセスします。

YAML ファイルから Cloud Run サービスを作成する場合

YAML ファイルから Cloud Run サービスを作成する場合は、以下のような YAML ファイルを用意します。

apiVersion: serving.knative.dev/v1
kind: Service
metadata:
  name: run-gcs
  labels:
    cloud.googleapis.com/location: asia-northeast1
spec:
  template:
    metadata:
      annotations:
        run.googleapis.com/execution-environment: GEN2  # Cloud Storage FUSE を使用する場合、第2世代の Cloud Run を使用する
    spec:
      containers:
      - image: asia-northeast1-docker.pkg.dev/myproject/myrepo/run-gcs  # Cloud Run で実行するコンテナイメージ
        ports:
        - name: http1
          containerPort: 8080
        resources:
          limits:
            cpu: 1000m
            memory: 512Mi
        volumeMounts:
        - name: gcs
          mountPath: /mnt/gcs  # コンテナからバケットにアクセスするためのパスを設定する
      volumes:
      - name: gcs  # 任意のボリューム名
        csi:
          driver: gcsfuse.run.googleapis.com
          volumeAttributes:
            bucketName: mybucket  # マウントするバケットの名前を指定する

YAML ファイルを使用した Cloud Run サービスの作成には、gcloud run services replace コマンドを使用します。

# Cloud Run サービスを作成する
$ gcloud run services replace service.yaml  

YAML ファイルからのデプロイでは metadata.annotations.run.googleapis.com/ingress の値として all を設定しても 未認証の呼び出しを許可 の設定ができないようなので、以下の gcloud コマンド使用して未認証のサービス呼び出しを許可します。

# 未認証のサービス呼び出しを許可する
$ gcloud run services add-iam-policy-binding run-gcs \
--role="roles/run.invoker" \
--member="allUsers" \
--region=asia-northeast1

動作確認

Cloud Run サービスのデプロイ後、サービスにアクセスするためのエンドポイントが生成されます(以下の出力例では Service URL の値)。

# コマンド出力例
Deploying container to Cloud Run service [run-gcs] in project [myproject] region [asia-northeast1]  
✓ Deploying new service... Done.  
  ✓ Creating Revision...              
  ✓ Routing traffic...        
  ✓ Setting IAM Policy...  
Done.  
Service [run-gcs] revision [run-gcs-00001-f7c] has been deployed and is serving 100 percent of traffic.
Service URL: https://run-gcs-ai4xxxxxxx-an.a.run.app

ブラウザでエンドポイントにアクセスすると、Cloud Storage バケットにアップロードしたテキストファイルの中身が表示されます。

バケットにアップロードしたテキストファイルの中身が表示される

佐々木 駿太 (記事一覧)

G-gen最北端、北海道在住のクラウドソリューション部エンジニア

2022年6月にG-genにジョイン。Google Cloud Partner Top Engineer 2025 Fellowに選出。好きなGoogle CloudプロダクトはCloud Run。

趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。