30歳からのプログラミング

30歳無職から独学でプログラミングを開始した人間の記録。

Google Cloud クライアントライブラリがアクセスするプロジェクトはどのように決まるのか

Google Cloud のクライアントライブラリを使うと API を通して Google Cloud のリソースにアクセスすることができる。
そして多くの場合どのプロジェクトのリソースにアクセスするのかを指定する必要があるが、その指定方法は複数ある。
この記事では、プロジェクトを指定する方法としてどのようなものがあるのか、そしてどの指定方法が優先されるのか、について述べていく。

この記事の内容は以下の環境で動作確認している。

  • npm パッケージ
    • @google-cloud/storage@7.14.0
  • dbt
    • dbt-core@1.9.1
    • dbt-bigquery@1.9.0

サンプルの準備

以下は対象のプロジェクトの Cloud Storage のバケット一覧を表示するコードで、クライアントライブラリ@google-cloud/storageを使って書いている。

// bucket.js
const { Storage } = require("@google-cloud/storage");

const storage = new Storage();

async function listBuckets() {
  try {
    const [buckets] = await storage.getBuckets();
    buckets.forEach((bucket) => console.log(bucket.name));
  } catch (err) {
    console.error("Error:", err);
  }
}

listBuckets();

このコードを使って、「対象のプロジェクト」を指定する方法を示していく。

なお、「対象のプロジェクト」にアクセスするための認証情報は利用可能になっているものと見做す。
クライアントライブラリに認証情報を渡す方法は以下の記事に書いた。

numb86-tech.hatenablog.com

各プロジェクトに以下のバケットが存在するものとして、話を進めていく。

  • project-a
    • bucket-a
  • project-b
    • bucket-b
  • project-x
    • bucket-x
  • project-y
    • bucket-y

準備が整ったので、優先順位が低い順に、プロジェクトを指定する方法を紹介していく。

プロジェクトを指定しなかった場合

まず最初に、いかなる方法でもプロジェクトを指定していなかった場合にどうなるのか、確認しておく。

$ node bucket.js
Error: Error: Unable to detect a Project Id in the current environment.

上記のようなエラーになる。

gcloud CLI の project プロパティ

gcloud CLI のprojectプロパティが存在すれば、それが使われる。

なので例えば以下のように設定すると、project-aプロジェクトにあるbucket-aが表示される。

$ gcloud config set core/project project-a

$ node bucket.js
bucket-a

gcloud CLI のプロパティについては、以下の記事に詳しく書いた。

numb86-tech.hatenablog.com

この記事に書いたようにgcloud config setよりも環境変数が優先されるので、環境変数CLOUDSDK_CORE_PROJECTproject-bを設定すると、bucket-bが表示されるようになる。

$ export CLOUDSDK_CORE_PROJECT=project-b

$ node bucket.js
bucket-b

CLOUDSDK_CORE_PROJECTは unset しておく。

$ unset CLOUDSDK_CORE_PROJECT

GOOGLE_APPLICATION_CREDENTIALS に設定した JSON ファイルの project_id

環境変数GOOGLE_APPLICATION_CREDENTIALSには JSON ファイルを指定するが、そのファイルのproject_idキーの値でも、対象のプロジェクトを指定できる。

GOOGLE_APPLICATION_CREDENTIALSについての説明も、以下の記事に書いている。

numb86-tech.hatenablog.com

以下の結果になるため、projectプロパティよりもGOOGLE_APPLICATION_CREDENTIALSproject_idが優先されることが分かる。

$ export GOOGLE_APPLICATION_CREDENTIALS=sa-key.json

$ less sa-key.json| grep 'project_id'
  "project_id": "project-b",

$ gcloud config list | grep 'project'
project = project-a

$ node bucket.js
bucket-b

GOOGLE_CLOUD_PROJECT

環境変数GOOGLE_CLOUD_PROJECTにプロジェクトIDを設定すると、ここまで紹介した設定方法よりも優先される。

$ export GOOGLE_CLOUD_PROJECT=project-x

$ node bucket.js
bucket-x

コード内に直接書かれたプロジェクトID

コード内に直接プロジェクトIDを書けば、それが最優先される。

// bucket.js
const { Storage } = require("@google-cloud/storage");

const storage = new Storage({ projectId: "project-y" }); // project-y を指定

async function listBuckets() {
  try {
    const [buckets] = await storage.getBuckets();
    buckets.forEach((bucket) => console.log(bucket.name));
  } catch (err) {
    console.error("Error:", err);
  }
}

listBuckets();
$ node bucket.js
bucket-y

まとめ

整理すると、以下の優先順位で、対象のプロジェクトが決まる。

  1. コード内に直接書かれたプロジェクトID
  2. GOOGLE_CLOUD_PROJECT
  3. GOOGLE_APPLICATION_CREDENTIALSに設定した JSON ファイルのproject_id
  4. gcloud CLI のprojectプロパティ

dbt

データウェアハウスとして BigQuery を使用し OAuth 方式で認証を行った dbt においても、プロジェクトを明示しなかった場合は、この記事で説明した内容に基づいて対象のプロジェクトが決まる。

profiles.ymlを以下の内容にし、他の yml ファイル等でもプロジェクトを指定しなかった場合などが、このケースにあたる。

my_profile_1:
  target: dev
  outputs:
    dev:
      type: bigquery
      method: oauth
      dataset: dest

なお、公式ドキュメントには以下のように書かれているが、これまで述べてきたようにgcloud config setよりもCLOUDSDK_CORE_PROJECTGOOGLE_CLOUD_PROJECTが優先されるので注意する。

If you do not specify a project/database and are using the oauth method, dbt will use the default project associated with your user, as defined by gcloud config set. https://docs.getdbt.com/docs/core/connect-data-platform/bigquery-setup