はなちるのマイノート

Unityをメインとした技術ブログ。自分らしくまったりやっていきたいと思いますー!

【GCP + terraform】terraformを使用してCloud RunでGCSをMountして利用する(C#)

はじめに

今回Cloud RunにてCloud Storageのバケットをterraformを使用してマウントする方法を紹介したいと思います。

概要

公式ドキュメントには以下のやり方が載っています。

resource "google_cloud_run_v2_service" "default" {
  name     = "cloudrun-service"

  location     = "us-central1"
  deletion_protection = false


  template {
    execution_environment = "EXECUTION_ENVIRONMENT_GEN2"

    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello"
      volume_mounts {
        name       = "bucket"
        mount_path = "/var/www"
      }
    }

    volumes {
      name = "bucket"
      gcs {
        bucket    = google_storage_bucket.default.name
        read_only = false
      }
    }
  }
}

resource "google_storage_bucket" "default" {
    name     = "cloudrun-service"
    location = "US"
}

registry.terraform.io


ただlocationUS前提になっていたり、サービスアカウントの設定をしないとGCS上のデータを取得できなかったりとしたため、自身で上手くいった方法を紹介したいと思います。

GCSの構築

# GCSバケット構築
resource "google_storage_bucket" "default" {
  name          = "-------"
  location      = "ASIA-NORTHEAST1"
  force_destroy = true
}

nameは被りのないような名前にしないといけません。またforce_destoryを設定することで、バケット内にオブジェクトが存在していてもTerraformがバケットを削除できるようにします。

IAM・サービスアカウントの設定

# 外部からアクセスするようにIAM Policy設定
# allUsers(全てのユーザー)にroles/run.invoker(サービスとジョブの呼び出し、ジョブ実行のキャンセルが可能)を付与する
data "google_iam_policy" "noauth" {
  binding {
    role    = "roles/run.invoker"
    members = ["allUsers"]
  }
}

# IAMポリシーをCloud Runに適応する
resource "google_cloud_run_v2_service_iam_policy" "policy" {
  location    = "asia-northeast1"
  name        = google_cloud_run_v2_service.default.name
  policy_data = data.google_iam_policy.noauth.policy_data
}


# Cloud Run用のサービスアカウントを作成
resource "google_service_account" "cloud_run_service_account" {
  account_id   = "cloud-run-service-account"
  display_name = "Cloud Run Service Account"
}

# Cloud RunのサービスアカウントにGCSのAdmin権限を付与
resource "google_project_iam_member" "cloud_run_storage_admin" {
  project = var.project_id
  role    = "roles/storage.objectAdmin"
  member  = "serviceAccount:${google_service_account.cloud_run_service_account.email}"
}

IAMを使用したアクセス制御により、Cloud Runに外部からアクセスできるようにしました。このあたりは適宜変更してください。

またCloudRunからGCSにアクセスするためにサービスアカウントを定義してあげます。定義したサービスアカウントはCloud Runに設定してあげないと適応されないので注意してください。

Cloud Runの定義

resource "google_cloud_run_v2_service" "default" {
  name     = "sample"
  location = "asia-northeast1"
  ingress  = "INGRESS_TRAFFIC_ALL"
  deletion_protection = false

  template {
    service_account = google_service_account.cloud_run_service_account.email
    execution_environment = "EXECUTION_ENVIRONMENT_GEN2"

    containers {
      image = "asia-northeast1-docker.pkg.dev/-----:latest"
      volume_mounts {
        name       = "bucket"
        mount_path = "/mnt/gcs"
      }
    }

    volumes {
      name = "bucket"
      gcs {
        bucket    = google_storage_bucket.default.name
        read_only = false
      }
    }
  }
}

service_accountに対して、先ほど定義したサービスアカウントを設定してあげてください。

GCS上のファイルを表示するC#コード

正しくmountできているのかを確認できるようなサーバーを構築する.NETのプロジェクトを作成し、Artifact Registoryにアップロードしました。

// Program.cs
using System.Text;

var builder = WebApplication.CreateBuilder(args);
var port = Environment.GetEnvironmentVariable("PORT") ?? "8080";
var url = $"http://0.0.0.0:{port}";
var app = builder.Build();

app.MapGet("/", () =>
{
    var sb = new StringBuilder();
    var directoryPath = "/mnt/gcs";

    if (Directory.Exists(directoryPath))
    {
        var files = Directory.GetFiles(directoryPath, "*", SearchOption.AllDirectories);
        foreach (var file in files)
        {
            sb.AppendLine($"File: {file}");
            sb.AppendLine(File.ReadAllText(file));
        }
    }
    else
    {
        sb.AppendLine("Directory does not exist.");
    }

    return sb.ToString();
});

app.Run(url);

terraformにてGCSを/mnt/gcsフォルダにマウントしています。ですのでそのディレクトリ以下に対して、ファイルが存在したら表示をしています。

アップロード方法等は以下記事を参照してみてください。
www.hanachiru-blog.com

実際に動作している様子

Cloud Runのマウント情報

Cloud Console上でCloudRunのリビジョンからVOLUMESを確認すると、確かにCloud Storageバケットにマウント先が設定されていました。