はなちるのマイノート

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

【GCP, terraform】Cloud Runをterraformで構築して.NETで構築した最小構成のウェブサーバーをデプロイする

はじめに

今回はterraformを利用してCloudRunを構築しminimal API(ASP.NET Core + .NET 8)で構築したWebサーバーをデプロイする方法を紹介したいと思います。

具体的には以下の操作をしていきます。

  • terraformによるCloud Run構築
  • ASP.NET Coreによるプロジェクト作成
  • 作成したプロジェクトを実行するDockerfileを作成
  • Artifact RegistoryにDocker Imageをアップロード

Cloud Runの構築

以下のresourceを作成します。

  • google_cloud_run_v2_service : Cloud Runを構築
  • google_iam_policy : プロジェクトのIAMポリシーを設定
  • google_cloud_run_v2_service_iam_policy : IAMポリシーをCloud Runに設定

main.tf

# Cloud Run構築
resource "google_cloud_run_v2_service" "default" {
  name     = "sample"
  location = "asia-northeast1"
  ingress  = "INGRESS_TRAFFIC_ALL"

  template {
    containers {
      image = "us-docker.pkg.dev/cloudrun/container/hello"
    }
  }
}

# 外部からアクセスするように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
}

IAM を使用したアクセス制御  |  Cloud Run Documentation  |  Google Cloud

Cloud RunにアクセスできるURIを出力する

このコードは必須ではないですが、デプロイしたCloud RunにアクセスできるURIを出力させてあげると便利です。

outputs.tf

output "service_url" {
  value       = google_cloud_run_v2_service.default.uri
  description = "The URL on which the deployed service is available"
}
$ terraform apply

...

Outputs:

service_url = "https://-----.run.app"

その他のterraformコード

上記コードが大切な箇所ですが、それ以外に作成した.tfも貼っておきます。

provider.tf

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "6.2.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = "asia-northeast1"
}

variables.tf

variable "project_id" {
  description = "GCP Project ID"
}

全てのファイル構成は以下になります。

.
├── main.tf
├── outputs.tf
├── provider.tf
└── variables.tf

サイトを確認する

terraformを実行して、出力されたURIを開くと以下が表示されればOKです。

$ terraform init
$ terraform apply
正しくデプロイ できたときの表示

.NETのウェブサーバーを作成する

先程はus-docker.pkg.dev/cloudrun/container/helloというArtifact Registoryに挙げられているサンプル用のImageを利用していましたが、これを自身で作成したものに差し替えます。

まずは.NETでプロジェクトを作成する必要があります。やり方の詳細は以下の記事に書きました。
www.hanachiru-blog.com

# ASP.NET Core + .NET 8のプロジェクトを作成する
$ dotnet new web -o CloudRunSample -f net8.0

Program.cs

var builder = WebApplication.CreateBuilder(args);

// PORT という環境変数が設定されていればそれを利用し、されていなければ 8080 をポートに利用する
var port = Environment.GetEnvironmentVariable("PORT") ?? "8080";

// 0.0.0.0 にする理由 : https://zenn.dev/shake_sanma/articles/1c6475ba73da48
var url = $"http://0.0.0.0:{port}";

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run(url);

Dockerfileの作成

Mac M1では--platform linux/amd64を指定してビルドしないといけないのですが、その対応でBUILDPLATFORMTARGETARCHあたりが必要になってくるので少しめんどくさいです。

# .NET SDKのImage(https://mcr.microsoft.com/product/dotnet/sdk/about)を指定, .NET CLI + .NET runtime + ASP.NET Coreから成り立つ
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build-env
ARG TARGETARCH
WORKDIR /App

# 全てのファイルをコンテナにコピーする
COPY . ./

# csprojを見て依存関係を解決する
RUN dotnet restore -a $TARGETARCH

# ビルドしてpublishする
RUN dotnet publish -c Release -o out -a $TARGETARCH

# CloudRunSampleの実行
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /App
COPY --from=build-env /App/out .
ENTRYPOINT ["dotnet", "CloudRunSample.dll"]


以下がファイル構成になっています。重要でないファイルは省いています。

.
├── CloudRunSample
│   ├── CloudRunSample.csproj
│   ├── Dockerfile
│   └── Program.cs
└── terraforms
    ├── main.tf
    ├── outputs.tf
    ├── provider.tf
    └── variables.tf

Artifact RegistoryにDocker Imageをアップロードする

Artifact RegistoryDocker Imageをアップロードします。
クイックスタート: Docker コンテナ イメージを Artifact Registry に保存する  |  Artifact Registry documentation  |  Google Cloud

まずはgcloudがインストールされている前提でログインします。

$ gcloud auth login
$ gcloud init

まだレポジトリを作成していない場合はレポジトリを作成する必要があります。

$ gcloud artifacts repositories create cloud-sample --location=asia-northeast1 --repository-format=docker

cloud-sampleは任意の名前にしてOKです。

以下コマンドでDocker用のArtifact Registory認証を行い、

# Docker用Artifact Registory認証
$ gcloud auth configure-docker asia-northeast1-docker.pkg.dev

# docker buildの際に、Mac M1なら --platform linux/amd64 を付与してください
$ docker build ./ -t asia-northeast1-docker.pkg.dev/{PROJECT_ID}/cloud-sample/cloud-sample-image

# push
$ docker push asia-northeast1-docker.pkg.dev/{PROJECT_ID}/cloud-sample/cloud-sample-image

Cloud RunのDocker Imageを変更する

imageを先程アップロードしたものに差し替えます。

# Cloud Runを構築する
resource "google_cloud_run_v2_service" "default" {
  name     = "sample"
  location = "asia-northeast1"
  ingress  = "INGRESS_TRAFFIC_ALL"

  template {
    containers {
      image = "asia-northeast1-docker.pkg.dev/------:latest"
    }
  }
}

最後に適応します。

$ terraform apply
...
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

Outputs:

service_url = "https://---.run.app"

最後にservice_urlにアクセスして、Hello, Worldが表示されていたら成功です。

さいごに

今回はやりませんでしたがgoogle_artifact_registry_repositoryあたりを使ってArtifact Registory周りももっと自動化したいなと思ってます。
Terraform Registry