😸

Terraformでlocalのpubsub emulator(google cloud)に対してデプロイをする

2024/04/06に公開

概要

こんにちは、近藤です。

最近、個人開発でpubsubのローカル環境を整えたいとう出来事がありました。
この記事ではその時の経験をもとに、Terraformを使用してローカル環境に設置したGoogle CloudのPub/Subエミュレータへのデプロイメントプロセスを紹介します。
この記事では以下のことが実現できるようになります。

  1. エミュレータを起動し、クラウド環境と同様にTerraformからデプロイできるローカル環境の構築。
  2. エミュレータの起動とTerraformによるデプロイを一つのシェルスクリプトで実行すること。

当初の目標は、docker-composeのみでこれらのプロセスを完結させることでしたが、時間の制約上、シェルスクリプトで立ち上げをする方法に落ち着きました。この方法により、Terraformを用いて一貫してトピックやサブスクリプションなどを管理することが可能になり、環境による命名の誤りやその他のエラーを減少させることができます。これにより、「ローカルで動作すれば本番環境でも動作する」という信頼性が向上すると考えます。

この記事を書く理由は、同様の情報が少なく、具体的な内容が記載されていないことにあります。(私の調査不足の可能性もあるので悪しからず)

実際に作成したリポジトリを使用し、以下のステップに沿って内容を共有します:

動作確認

  1. Google Cloud SDKを用いたエミュレータの起動
  2. エミュレータに対してTerraformを使用してPub/Subのトピックとサブスクリプションを作成する
  3. Next.jsを使用して簡単なアプリを作成し、トピックとサブスクリプションの動作確認をする

コンテナ化とシェルスクリプトによる実行の有効化

  1. コンテナを使用してエミュレータを起動可能にする
  2. コンテナの起動とTerraformによるデプロイを行うシェルスクリプトの作成

具体的な実装手順を共有することで、皆さんの開発作業に少しでも貢献できれば幸いです。

リポジトリ

https://github.com/yoshifumi-kondo/pubsub-emulator-with-terraform/tree/for-blog

動作確認

まず動作確認を行います。私は特にPub/Subのエミュレータの実行環境を用意するのも初めてで、Terraformにも慣れていないので一つ一つ動作を確認していきます。慣れ親しんだ人にとっては冗長かもしれませんので読み飛ばしてください。

Google Cloud SDKを用いたエミュレータの起動

まず、Google Cloudの公式ドキュメントを参照し、エミュレータを起動します。Google Cloud SDKとPub/Subエミュレータコンポーネントのインストールを済ませた後、以下のコマンドを実行し立ち上げます。

gcloud beta emulators pubsub start --project=PUBSUB_PROJECT_ID

project名は適当な値を入れます。私はTerraformにてemulator-projectという名前でプロジェクトを管理しているので、emulator-projectという値で実行します。

エミュレータに対してTerraformを使用してPub/Subのトピックとサブスクリプションを作成する

上記のフローでエミュレータが立ち上がったことを確認し、以下のようなTerraformファイルを作ります。

main.tf

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 4.0"
    }
  }
}

provider "google" {
  project = "emulator-project"

  pubsub_custom_endpoint = "http://localhost:8085/v1/"
}
resource "google_pubsub_topic" "example_topic" {
  name = "example-topic"
}

resource "google_pubsub_subscription" "example_subscription" {
  name  = "example-subscription"
  topic = google_pubsub_topic.example_topic.name
}

project名はエミュレータを立ち上げた時の名前に合わせます。

project = "emulator-project"

ここでポイントとなるのが以下の設定です。

pubsub_custom_endpoint = "http://localhost:8085/v1/"

この設定は、TerraformがGoogle Cloud Pub/SubのAPIと通信する際に使用するエンドポイントをカスタマイズするものです。通常、TerraformのGoogleプロバイダーはGoogle Cloudの実際のサービスエンドポイントに対してAPIリクエストを行いますが、この設定を使用することで、代わりにローカルに実行されているPub/Subエミュレータに対してリクエストを行うように指示します。

Next.jsを使用して簡単なアプリを作成し、トピックとサブスクリプションの動作確認をする

動作確認のため以下のアプリを作りました。

  1. エミュレータからトピックとサブスクリプションを選択できるようにする
  2. 選択したトピックにメッセージを送れる
  3. メッセージを受け取れる

next.js 絶妙にインターバルを長くしてしまいました

今回はTerraformとエミュレータにフォーカスしているので、アプリの詳細な説明は行いません。動作を見ると無事に動いていそうですね!

コンテナ化とシェルスクリプトによる実行の有効化

これまでのフローでエミュレータの立ち上げと、Terraformでのデプロイができました。ではそれをコンテナ化して、より便利に使えるようにしていきましょう。

コンテナを使用してエミュレータを起動可能にする

特別なことはせず、純粋にGoogle Cloud SDKを用いたエミュレータの起動をコンテナ化するだけです。プロジェクト名がTerraformと一致することだけ気をつけてください。私の場合は、emulator-projectになります。

Dockerfile

FROM google/cloud-sdk:464.0.0

# Install the PubSub emulator component using apt-get
RUN apt-get update && apt-get install -y google-cloud-cli-pubsub-emulator

ENV PUBSUB_EMULATOR_HOST=0.0.0.0:8085

EXPOSE 8085

CMD ["sh", "-c", "gcloud config set project emulator-project && gcloud beta emulators pubsub start --host-port=0.0.0.0:8085"]

ルートディレクトリにdocker-compose.ymlを置き、docker-compose upで立ち上がるようにします。

コンテナの起動とTerraformによるデプロイを行うシェルスクリプトの作成

本当はdocker-compose upだけで済ましたかったのですが、コンテナ起動後にTerraformが実行されず、うまくいきませんでした。そのため、下記のようなシェルスクリプトを用意しました。

start.sh

#!/bin/bash

docker-compose up -d

echo "Waiting for PubSub Emulator to start..."
attempts=0
max_attempts=10
while ! nc -z localhost 8085; do
  if [ $attempts -eq $max_attempts ]; then
    echo "Failed to connect to PubSub Emulator after $max_attempts attempts. Exiting."
    exit 1
  fi
  attempts=$((attempts + 1))
  sleep 5
done
echo "PubSub Emulator started"

echo "Waiting for 10 seconds to ensure PubSub Emulator is fully initialized..."
sleep 10

cd terraform
terraform init
terraform apply -auto-approve

whileループの部分は、Pub/Subエミュレータが起動して準備ができるまで待つ機能を持っています。具体的には、ローカルの8085番ポートでエミュレータがリッスンを開始するのを確認するために繰り返し接続を試みます。接続が成功すると、エミュレータが準備完了であると判断し、Terraformによるデプロイを行います。

以上で、エミュレータを立ち上げ、Terraformでデプロイできるようになりました。

終わりに

同様のことをしたい人がいるのかなと思いつつ、参考となるものは見つけられませんでした。私の調査能力のなさゆえかもしれません。

これでローカル環境でも本番環境に近い形でPub/Subを使えるようになりました。この記事が、同じような問題に直面している方の助けになれば幸いです。

参考

コミューン株式会社

Discussion