Google Cloud Pub/Sub を複数のProjectにまたがって利用する。またそのときの課金について


今回はPub/Subを複数のプロジェクトにまたがって利用する方法について調べていきます。

前回:Google Cloud Pub/Sub Java Client Library 入門 (サンプルはScala)

クロスプロジェクトアクセスの公式ドキュメント

アクセス制御

権限の付け方や、付ける範囲について説明されているので一度読んでみると良いと思います。

「料金は、リクエストされたリソースが含まれているプロジェクトに適用される」 とは

Google Cloud Pub/Subの料金ページに以下の記述があります。

Pub/Sub を複数のプロジェクトにまたがって使用する場合、Pub/Sub の料金は、リクエストされたリソースが含まれているプロジェクトに適用されます(サブスクリプションなど)。たとえば、プロジェクト A のサービス アカウントに、プロジェクト B(請求先アカウント B)のサブスクリプションに対するサブスクライバー アクセスが付与されている場合、請求先アカウント B には、サービス アカウント A がサブスクリプションから取得するデータの料金が課金されます。サブスクリプションがプロジェクト A に含まれている場合は、サブスクリプションがプロジェクト B 内のトピックに関連付けられていても、サブスクリプションから取得されるデータの料金はアカウント A に課金されます。

引用:料金 https://cloud.google.com/pubsub/pricing?hl=ja

何やら難しくて1回では分かりませんが、この辺りを調べていきます。

上記のケースは以下のようなシーンを想定しています。

  • プロジェクトBはTopicBを持っている
  • プロジェクトBはTopicBに紐づくSubscriptionBを持っている
  • プロジェクトAはサービスアカウントAを持っており、これには上記のSubscirptionBへのアクセス権が付与されている

この状態でプロジェクトAがSubscriptionBからメッセージ取得した場合は、Bに課金される。

「リクエストされたリソースが含まれているプロジェクトに適用されます(サブスクリプションなど)」というのはこういうことです。サブスクリプションなどと言っているのは、トピックも同様だからです。トピックはプロジェクトBが持っているので、誰がデータをpublishしようと、その転送料金が課されるのはプロジェクトBです。

後半の

「サブスクリプションがプロジェクト A に含まれている場合は、サブスクリプションがプロジェクト B 内のトピックに関連付けられていても、サブスクリプションから取得されるデータの料金はアカウント A に課金されます。」は前述のリソースの説明が理解できていれば簡単ですね。

  • プロジェクトBはTopicBを持っている
  • プロジェクトAはTopicBに紐づくSubscriptionAを持っている

この状態でプロジェクトAがメッセージ取得した場合は、Topicを持っているのはBですが、転送料金が課されるのはプロジェクトAです。(AがSubscriptionAリソースを持っているから)

本当にそうなのか?検証する

実際に複数のプロジェクトを作成して、検証してみます。

複数のプロジェクトをまたいだアクセス

上記の説明文にも「サブスクライバー アクセスが付与されている場合」とある通り、アクセスが付与されていなければ他のプロジェクトのリソースにアクセスできません。まずはその方法について説明します。

前述の例とほぼ同じですが以下のシーンを想定しています。

  • プロジェクトBはTopicBを持っており、プロジェクトAはそのTopicのメッセージを読みたい
  • プロジェクトAはServiceAccountAを持っており、このServiceAccountAがPubSubアクセス(Subscribe)できればよい

この状態で必要な権限設定、操作は以下です。

  1. プロジェクトAの開発者はServiceAccountAをPubSub編集者権限付きで作成する。
  2. プロジェクトBの開発者はTopicBに対するSubscriber権限をServiceAccountAに付与する
  3. プロジェクトAの開発者はTopicBを参照するSubscriptionAを作成する

1は単にIAM画面から作成するだけなので省略します。

2はプロジェクトB側のPubSub画面を開き、以下のように権限を付与します。

このときのメンバーはServiceAccountA(foo@myproject.iam.gserviceaccount.comみたいな文字列)、役割はPub/Sub サブスクライバーです。

最後に3ですが、ここは少し複雑です。まず他のプロジェクトのTopicを参照するSubscriptionを画面上から作成できないため、CUIを使う必要があります。そのとき、プロジェクトAの開発者は自身の認証tokenで作成すると権限エラーになります。作成が許可されているのはあくまでServiceAccountAだからです。

これを避けるために以下のように行います。

まず以下コマンドを必要に応じて変更し、ServiceAccountAでログインした状態にします。(gcloud auth active-service-account)

% gcloud auth activate-service-account pubsub@projectb1.iam.gserviceaccount.com --key-file=/Users/tsukaby/Desktop/myproject-1-foobar.json
Activated service account credentials for: [pubsub@projectb-1.iam.gserviceaccount.com]

そしてTopicBを参照するSubscriptionAを作成します。—topic-projectでプロジェクトBを指定します。

% gcloud beta pubsub subscriptions create tsukamotoSubscription --topic tsukamotoTopic --topic-project projectb-1
Created subscription [projects/projecta-1/subscriptions/tsukamotoSubscription].

冒頭のクロスプロジェクトアクセス時の料金について検証する

冒頭のリソースの理解が正しければ、ServiceAccountAでSubscriptionAを使ってTopicBからデータ取得した場合、課金されるのはプロジェクトBではなくAのはずです。実際に試してみました。

TopicBに常時Publishするアプリを動かしつつ、ServiceAccountAでSubscriptionAから常時Subscribeするアプリを動かします。無料枠である10GBを超えるとプロジェクトAにも課金されるはずです。

before

after

だいたい11GB転送したので、想定通りの金額がプロジェクトAに対して請求されています。

まとめ

IAM、権限を適切に設定することでクロスプロジェクトなPub/Subアクセスを実現しました。またそのときの課金についても調査しました。

次回はPubSubのデータをSparkで処理してみようと思います。

次回:Google Cloud Pub/Sub のデータをSpark Streamingで読む