こんにちは、SCSKの齋藤です。
本記事では、Terraformを使ってBigQueryのリソース(データセット・テーブル・スキーマ)をInfrastructure as Code(IaC)として管理する方法を解説します。
そもそもBigQueryとは?
BigQueryは、Google Cloudが提供するサーバーレスなデータウェアハウスです。
特徴は以下の通りです。
- SQLで大規模データを高速分析
標準SQLでペタバイト級のデータを数秒〜数分で集計・分析。 - サーバーレス
インフラ管理不要。ストレージやクエリのリソースは自動でスケール。 - コスト効率
ストレージとクエリ課金が分離されており、使った分だけ支払う従量課金。 - GCPサービスとの連携
Cloud Storage、Dataflow、Looker Studio など、他の GCP サービスとシームレスに連携。 これにより、データの収集、処理、可視化を統合的に行うことが可能。
なぜTerraformでBigQueryを管理するのか?
BigQueryはGCPコンソールやbqコマンドで手軽にテーブル作成できますが、TerraformでIaC化することで以下のメリットがあります。
- 環境ごとの再現性
開発 (dev)、ステージング (stg)、本番 (prd) など、異なる環境で同じ構成をコードで再現できます。環境の違いによる「あれ?動かない…」を撲滅! -
スキーマや設定のバージョン管理
テーブル定義、パーティション設定、クラスタリング設定などの変更履歴を Git で管理できます。 これにより、変更の追跡、ロールバック、監査が容易! -
自動化・レビューPull Request (PR) ベースでレビューを行い、CI/CD (Continuous Integration/Continuous Delivery) パイプラインによる自動反映が可能です。 これにより、変更の品質を向上させ、デプロイメントの効率アップ!
- ヒューマンエラー防止
手作業による設定ミスや漏れを防ぐことができます。 コードによる定義は、人為的な誤りを減らし、一貫性を保証!
ディレクトリ構造例
本記事で紹介する構成は、プロジェクトごと・データセットごとにモジュールを分割し、環境(dev/stg/prd)ごとにパラメータを切り替えられるようにしています。
terraform-bigquery/ └── プロジェクト名/ ├── envs/ │ │── dev/ │ │ ├── main.tf │ │ ├── backend.tf │ │ ├── provider.tf │ │ ├── terraform.tfvars │ │ └── variables.tf │ └── stg/ │ └── prd/ └── module/ └── dataset1/ ├── table1.yaml # テーブルスキーマ(YAML) ├── dataset1.tf # データセット・テーブル定義 └── variables.tf # モジュール変数
各ファイルの役割:
envs/dev/main.tf
:環境固有の設定を適用し、データセット構築に必要な各モジュールの呼び出しとその引数を定義envs/dev/backend.tf
:Terraform State を安全かつ共有可能な場所に保存するための設定(GCSバケットなど)envs/dev/provider.tf
:GCP プロバイダの認証情報、対象プロジェクト、リージョンなどを設定envs/dev/terraform.tfvars
:プロジェクトID、リージョン、サービスアカウントメールアドレスなど、環境によって異なる変数値の定義envs/dev/variables.tf
:main.tf で使用する変数の型、デフォルト値、説明などを定義し、外部からの入力インターフェースを提供module/dataset1/table1.yaml
:テーブルのカラム名、データ型、nullable 属性、説明などを記述した YAML 形式のスキーマ定義ファイルmodule/dataset1/dataset1.tf
:データセット自体の定義、および table1.yaml からスキーマを読み込んでテーブルを定義するTerraformリソース定義module/dataset1/variables.tf
:モジュール内で使用する変数(プロジェクトID、データセット名など)の型、デフォルト値、説明などを定義
実装例
envs/dev/main.tf
このファイルは、各データセットに対応するモジュールを呼び出す役割を担います。 source
パラメータでモジュールの場所を指定し、project_name
と region
変数を渡します。 環境ごとに異なる terraform.tfvars
ファイルを使用することで、同じコードで異なる環境をデプロイできます。
module "table1" { source = "../../module/table1" project_name = var.project_name region = var.region } module "table2" { source = "../../module/table2" project_name = var.project_name region = var.region }
module/dataset1/table1.yaml
このファイルは、テーブルのスキーマを YAML 形式で定義します。 name
、type
、mode
、description
などの属性を定義することで、テーブルのカラム構造を明確に記述できます。 YAML 形式を使用することで、可読性が向上し、メンテナンスが容易になります。
- name: extraction_time type: DATETIME mode: NULLABLE description: "データ抽出日時" - name: value type: STRING mode: NULLABLE description: "値" # ...(以下略)
module/dataset1/dataset.tf
このファイルは、データセットとテーブルのリソースを定義します。
google_bigquery_dataset
リソース:project
、location
、dataset_id
などの属性を定義して、データセットを作成します。google_bigquery_table
リソース:project
、dataset_id
、table_id
、description
などを定義して、テーブルを作成します。 。schema
属性: YAML ファイルからテーブルスキーマを読み込み、yamldecode
関数で YAML 形式から Terraform で使用できる形式に変換し、さらにjsonencode
関数でJSON形式にエンコードします。time_partitioning
ブロック: クエリのパフォーマンスを向上させるために、時間ベースのパーティショニングを設定します。type
(この例では “MONTH”) とfield
(パーティションキーとなるカラム名)clustering
属性: クエリのパフォーマンスを向上させるために、クラスタリングキーとなるカラム名を指定して、クラスタリングを設定します。deletion_protection
属性: テーブルの削除保護を有効にします。true
に設定することで、誤ってテーブルを削除するのを防止。
resource "google_bigquery_dataset" "dataset1" { project = var.project_name location = var.region dataset_id = "dataset1" } resource "google_bigquery_table" "table1" { project = google_bigquery_dataset.dataset1.project dataset_id = google_bigquery_dataset.dataset1.dataset_id table_id = "table1" description = "情報を取得" schema = jsonencode(yamldecode(file("${path.module}/table1.yaml"))) time_partitioning { type = "MONTH" field = "extraction_time" } clustering = ["value"] deletion_protection = true }
envs/dev/variables.tf
このファイルは、main.tf
やモジュールで使用する変数を定義します。以下の変数は、GCP プロジェクト ID とリージョンを指定するために使用されます。
variable "project_name" { type = string } variable "region" { type = string }
envs/dev/terraform.tfvars
project_name = "project1" region = "asia-northeast1"
envs/dev/provider.tf
このファイルは、GCP プロバイダを設定します。 以下の属性に、それぞれ project_name
と region
変数を設定します。
provider "google" { project = var.project_name region = var.region }
工夫ポイント
スキーマをYAMLで管理
テーブルのカラム定義を YAML で記述し、Terraform で yamldecode
→ jsonencode
して渡すことで、スキーマの可読性・メンテナンス性が大幅に向上します。 YAML は、構造化されたデータを記述するための人間にとって読みやすい形式であり、複雑なスキーマを管理するのに適しています。
パーティション・クラスタリングもIaCで管理
time_partitioning
や clustering
もコードで明示することで、クエリコスト最適化や運用ルールの徹底ができます。 time_partitioning { type = "MONTH" field = "extraction_time" } clustering = ["value"] deletion_protection = true
部分的なplan/applyで安全に反映
以下のように、特定のデータセットやテーブルだけを対象に plan/apply できます。他のリソースに影響を与えないので安心です。
bash terraform plan -target=module.dataset1 terraform apply -target=module.dataset1
テーブルの削除保護
deletion_protection = true
を設定しておけば、間違ってテーブルを削除してしまうのを防げます。本番環境では必須の設定です。
運用・変更の流れ
- スキーマ追加・変更:
- 該当する YAML ファイルにカラムを追加・修正。
- テーブル追加:
module/dataset名/
に新たな YAML ファイルとリソース定義 (.tf
ファイル) を追加。
- 環境ごとに反映:
dev/stg/prd
のmain.tf
で必要なモジュールを呼び出し、terraform apply
を実行。
- バージョン管理:
- すべての変更を Git で管理。
- Pull Request ベースでレビューを行い、CI/CD パイプラインを使用して自動的にデプロイ。
まとめ
BigQueryのテーブルやスキーマ、パーティション設定をTerraformでIaC化することで、再現性・自動化・レビュー性・ヒューマンエラー防止など多くのメリットが得られます。
- スキーマはYAMLで管理し、Terraformで読み込むと可読性・保守性が高まる
- パーティションやクラスタリングもコードで明示し、運用ルールを徹底
- dev/stg/prdなど複数環境も同じ構成を再現できる
- すべてgitでバージョン管理し、Pull Requestベースで安全に運用
BigQueryの運用に課題を感じている方、これからIaCに取り組みたい方は、ぜひTerraformによるBigQuery管理を試してみてください!