はじめに
以下GitHubで、複数のDatabricksワークスペースをデータメッシュの概念に沿って管理するためのTerraformのサンプル実装を公開しました。本記事でこのサンプル実装について解説します。
なお、サンプル実装および本記事は、あくまで個人のアイデアをまとめたものであり、会社の見解を代表するものではない点に注意ください。
前提
- Terraformサンプル実装および本記事はDatabricks on AWSを対象としています
- 以下のバージョンのTerraformおよびプロバイダーを利用して動作確認を行っています
% terraform -v
Terraform v1.6.5
on darwin_arm64
+ provider registry.terraform.io/databricks/databricks v1.38.0
+ provider registry.terraform.io/hashicorp/aws v5.40.0
+ provider registry.terraform.io/hashicorp/random v3.6.0
+ provider registry.terraform.io/hashicorp/time v0.11.1
データメッシュとは
解説に入る前に、簡単にデータメッシュの定義と実際の例について記載します。
データメッシュの定義
データメッシュの定義は以下の通りです。
データメッシュとは、スケールするデータ分析プラットフォームに対する一連の原則と論理的アーキテクチャを表現するパラダイムです。大規模にデータからさらなる価値を資産として導出することを目的としています。データメッシュという用語は2019年にZhamak Dehghaniによて導入され、彼女の2020年の記事のData Mesh Principles and Logical Architectureで拡張されました。
データメッシュの論理的アーキテクチャのコアには4つの原則があります:
- ドメインオーナーシップ: 複数のドメインチーム、データ生成者がキャプチャからキュレーション、分析、再利用に至るライフサイクルを通じて自身のデータに完全な席んを持つ、分散アーキテクチャを導入します。
- 製品としてのデータ: データ分析ライフサイクルに製品管理原則を適用し、データ生成者の領域内外にいるであろうデータ利用者に提供されるデータの品質を保証します。
- セルフサービスのインフラストラクチャプラットフォーム: 相互運用可能なデータ製品を構築、実行、維持するための共通ツールと方法論を用いて、データ分析ライフサイクルにデータ不可知のアプローチを適用します。
- 統合されたガバナンス: 標準化を通じて組織のルールや業界の規制に準拠するデータエコシステムを確立します。
データメッシュの実例
データメッシュの実際の例としては以下のカケハシ様のアーキテクチャーをご覧頂くとイメージが湧きやすいと思います。(以下画像はカケハシ様SpeakerDeckより引用)
各ディレクトリの役割・用途
ここからTerraformサンプル実装の解説です。まずは各ディレクトリの役割・用途について記載します。名前や構造はあくまでサンプルですので、実際に利用する際には組織のデータメッシュ設計の実情に合わせて変更頂くのが良いと思います。
ディレクトリ | 役割・用途 |
---|---|
domains |
データドメイン用の基底ディレクトリ。配下に各ドメインのディレクトリを格納する。 |
domains/domain1 |
domain1 というデータドメイン用のディレクトリ。実際に利用する場合にはドメインを表す分かりやすい名前に変更するのが良い。 他のドメインがある場合は domains 配下に別のディレクトリを作成する。 |
domains/modules |
複数のデータドメインで利用するモジュール。 |
platform |
プラットフォーム用の基底ディレクトリ。データメッシュ全体の共通的な機能やインフラに関するファイルを格納する。 |
platform/01_workspace_setup |
データドメイン用のすべてのDatabricksワークスペースおよびそのAWSインフラの作成・管理用のファイルを格納。 |
platform/02_workspace_config |
01_workspace_setup で作成したDatabricksワークスペースに共通的に適用する設定やポリシーを管理するファイルを格納。 |
本サンプルではデータドメインとプラットフォームのファイルをまとめて1つのリポジトリで管理していますが、実際の利用シーンではデータドメインごとにリポジトリを分ける方が管理しやすい可能性がありますので、よく検討してみてください。
Terraformファイルの詳解
上記で各ディレクトリの役割・用途が理解できたと思いますので、次にどの順番でterraform apply
(これを便宜上、Terraform実行と呼称)するのか、そして各ファイルについて解説します。
実行の順番
まず実行の順番ですが、最初にDatabricksアカウントの管理者が以下の順番でterraform apply
を実行します。
-
platform/01_workspace_setup
: 複数のDatabricksワークスペースおよびそのAWSインフラを作成する -
platform/02_workspace_config
: 複数のDatabricksワークスペースに共通的な設定・ポリシーを適用する(サンプル実装では各ワークスペース管理者にCREATE_CATALOG
などの権限を付与)
上記が成功すると各データドメイン用のDatabricksワークスペースがReadyになります。以降は各データドメインのDatabricksワークスペース管理者が任意の管理作業を行う流れを想定しています。
ドメインごとの管理作業の例として、サンプル実装のdomains/domain1
では、ドメイン固有のデータ管理用のUnity Catalogのカタログと周辺リソースを作成・管理するtfファイルを含めています。
以降で各Terraformファイルの詳細について記載します。
platform/01_workspace_setup
複数のDatabricksワークスペースおよびそのAWSインフラを作成・管理します。主要なファイルについて以下で解説します。
プロバイダー (providers.tf
)
AWS、Databricksをプロバイダーとして利用します。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
databricks = {
source = "databricks/databricks"
}
random = {
source = "hashicorp/random"
}
}
}
provider "aws" {
region = var.region
}
provider "databricks" {
alias = "mws"
host = "https://accounts.cloud.databricks.com"
account_id = var.databricks_account_id
client_id = var.databricks_client_id
client_secret = var.databricks_client_secret
}
AWS
必要な権限・認証方法
- 実行の主体(プリンシパル)がAWS IAMのAdministratorAccessの権限を持っていることを想定しています
- AWSの認証は複数の方法があるので任意の方法を利用ください。アクセスキーやシークレットキーをハードコードするのではなく、AWS CLIでの
aws configure
実行で作成される認証情報ファイル、あるいは環境変数などを利用するのが良いと思います(認証方法の種類とその詳細については以下リンクを参照)
Databricks
必要な権限・認証方法
- ワークスペースレベルではなくアカウントレベルのサービスプリンシパルの
client_id
とclient_secret
を用いた認証を想定しています。さらに当該サービスプリンシパルはアカウント管理者の権限を持っていることを想定しています- アカウントレベルのサービスプリンシパルの作成方法については以下リンクを参照ください
- サービスプリンシパルを管理する | Databricks on AWS
-
account_id
は、アカウントコンソールの右上にある自身のメールアドレスをクリックした後に確認できます
メイン (main.tf
)
意味のあるまとまりに区切って説明します。
アカウント管理者グループの作成
アカウントレベルの管理者グループを作成し、そこに引数(variable)で指定したプリンシパル(ユーザーやグループ、サービスプリンシパル)を追加します。さらにアカウント管理者グループにaccount_admin
ロールを付与します。
resource "databricks_group" "account_admin" {
provider = databricks.mws
display_name = var.databricks_account_admin_group_name
}
resource "databricks_group_member" "account_admin" {
provider = databricks.mws
for_each = var.databricks_account_admin_principal_ids
group_id = databricks_group.account_admin.id
member_id = each.value
}
resource "databricks_group_role" "account_admin" {
provider = databricks.mws
group_id = databricks_group.account_admin.id
role = "account_admin"
}
Unity Catalogメタストアの作成
既存のUnity CatalogメタストアをDatabrickワークスペースに関連づけたい場合は、引数でメタストアのIDを指定します。もしメタストアのIDが指定されていない場合は、primary
という名前で新しくメタストアを作成し、アカウント管理者グループを所有者として設定します。count
で引数の指定有無に応じたリソース作成有無の制御をしています。
resource "databricks_metastore" "this" {
count = var.databricks_metastore_id == "" ? 1 : 0
provider = databricks.mws
name = "primary"
owner = databricks_group.account_admin.display_name
region = var.region
force_destroy = true
}
DatabricksワークスペースおよびAWSインフラの作成
DatabricksワークスペースとそのAWSインフラを作成するモジュールaws_databricks_mws
を呼び出します。引数で複数のDatabricksワークスペースを指定できるようになっています。
locals {
metastore_id = var.databricks_metastore_id == "" ? databricks_metastore.this[0].id : var.databricks_metastore_id
}
module "aws_databricks_mws" {
source = "./modules/aws_databricks_mws"
providers = {
aws = aws
databricks = databricks.mws
}
for_each = var.databricks_workspaces
# Common variables for all workspaces
region = var.region
databricks_account_id = var.databricks_account_id
databricks_metastore_id = local.metastore_id
# Workspace specific variables
prefix = each.value.prefix
vpc_cidr = each.value.vpc_cidr
public_subnets_cidr = each.value.public_subnets_cidr
private_subnet_pair = each.value.private_subnet_pair
tags = each.value.tags
workspace_admin_group_name = each.value.workspace_admin_group_name
workspace_admin_user_ids = each.value.workspace_admin_user_ids
}
モジュール aws_databricks_mws/main.tf
こちらのモジュールではDatabricksワークスペース関連の以下のリソースを作成・管理します。
- ワークスペース用のAWSインフラ(VPC関連リソース、S3バケット、IAMロール、IAMポリシー)
- ワークスペースおよびその周辺リソース(ストレージ設定、ネットワーク設定)
- ワークスペースとメタストアのアサインメント
- ワークスペースの管理者グループとADMIN権限、プリンシパルの関連付け
こちらは長いので全文はGitHub上のmain.tf
をご覧頂ければと思います。
なお、このモジュール自体は以下のサンプルを参考に、シンプル化して作成したものになります。
Tips: ワークスペースレベルのtoken
作成
一点Tipsとして、ワークスペース作成時にtoken
を指定しています。これにより、このTerraformを実行したサービスプリンシパルのトークンがワークスペースに作成されます。親のoutputs.tf
で出力されたこのトークンを使うことで、以降のワークスペースレベルの処理の自動化を楽かつ安全に行うことができます。
resource "databricks_mws_workspaces" "this" {
account_id = var.databricks_account_id
workspace_name = local.prefix
aws_region = var.region
credentials_id = databricks_mws_credentials.this.credentials_id
storage_configuration_id = databricks_mws_storage_configurations.this.storage_configuration_id
network_id = databricks_mws_networks.this.network_id
token {}
}
アウトプット (outputs.tf
)
メタストアのID、作成したワークスペースの管理者グループ名、ワークスペース名、サービスプリンシパルのトークン、ワークスペールURLを出力します。これらの情報を後続のplatform/02_workspace_config
の引数として用います。
output "databricks_metastore_id" {
value = local.metastore_id
}
output "databricks_workspaces_details" {
value = [for key, ws in module.aws_databricks_mws : {
databricks_workspace_admin_group_name = ws.databricks_workspace_admin_group_name
databricks_workspace_name = ws.databricks_workspace_name
databricks_workspace_token = ws.databricks_workspace_token
databricks_workspace_url = ws.databricks_workspace_url
}]
sensitive = true
}
引数
本プロジェクトでは、Terraformのプラクティスに従い、引数のファイルについてはGitHubでバージョン管理していません。具体的には、.gitignore
で*.tfvars
を除外しています。
引数のファイルを作成せずに、terraform apply
実行時にインタラクティブに引数を指定してももちろん良いですが、01_workspace_setup
ディレクトリの直下に以下のような引数をまとめたファイルterraform.tfvars
を作成すると楽に実行できます。内容はあくまでサンプル(ID系はすべてダミーの値)なので、自身のニーズに合わせて書き換えてください。
region = "ap-northeast-1"
databricks_account_id = "1234567a-304d-4e66-8c03-11b10d68ba23"
databricks_client_id = "1234567b-304d-4e66-8c03-11b10d68ba23"
databricks_client_secret = "1234567c-304d-4e66-8c03-11b10d68ba23"
databricks_account_admin_group_name = "account admins"
databricks_account_admin_principal_ids = [
"1234567890123456",
"6543210987654321"
]
databricks_workspaces = {
workspace1 = {
# S3などのリソース名の重複を回避するためにグローバルユニークになるプレフィクスを指定する
prefix = "random-prefix-domain1"
vpc_cidr = "10.109.0.0/16"
public_subnets_cidr = ["10.109.2.0/23"]
private_subnet_pair = ["10.109.4.0/23", "10.109.6.0/23"]
tags = {}
workspace_admin_group_name = "domain1-admin-group"
workspace_admin_user_ids = [
"1234567890123456",
"6543210987654321"
]
},
workspace2 = {
prefix = "random-prefix-domain2"
vpc_cidr = "10.110.0.0/16"
public_subnets_cidr = ["10.110.2.0/23"]
private_subnet_pair = ["10.110.4.0/23", "10.110.6.0/23"]
tags = {}
workspace_admin_group_name = "domain2-admin-group"
workspace_admin_user_ids = [
"1234567890123456",
"6543210987654321"
]
}
}
Terraform実行
ファイルの説明は以上で終わりです。実際の実行方法について説明します。
事前準備
AWS CLIのインストール、AWS CLIを利用するためのIAMユーザーのアクセスキーを準備します。以下Qiita記事の事前準備のセクションを参考に準備してください。
実行
ローカルにリポジトリをクローンし、対象のディレクトリに移動します。
$ git clone https://github.com/nakazax/aws-databricks-terraform-specific-examples
$ cd aws-databricks-terraform-specific-examples/examples/data_mesh_example/platform/01_workspace_setup
続いてTerraformの初期化を行います。
$ terraform init
Initializing the backend...
Initializing modules...
- aws_databricks_mws in modules/aws_databricks_mws
- aws_databricks_mws.aws_infra in modules/aws_databricks_mws/modules/aws_infra
Initializing provider plugins...
- Reusing previous version of hashicorp/time from the dependency lock file
- Reusing previous version of databricks/databricks from the dependency lock file
- Reusing previous version of hashicorp/random from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Installing hashicorp/time v0.11.1...
- Installed hashicorp/time v0.11.1 (signed by HashiCorp)
- Installing databricks/databricks v1.38.0...
- Installed databricks/databricks v1.38.0 (self-signed, key ID 92A95A66446BCE3F)
- Installing hashicorp/random v3.6.0...
- Installed hashicorp/random v3.6.0 (signed by HashiCorp)
- Installing hashicorp/aws v5.40.0...
- Installed hashicorp/aws v5.40.0 (signed by HashiCorp)
Partner and community providers are signed by their developers.
If you'd like to know more about provider signing, you can read about it here:
https://www.terraform.io/docs/cli/plugins/signing.html
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
念のためterraform plan
で作成・更新リソースのシミュレーションが問題ないかを確認します。
$ terraform plan
(中略)
Plan: 67 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ databricks_metastore_id = (known after apply)
+ databricks_workspaces_details = (sensitive value)
ここまで問題なければterraform apply
を実行します。問題ないかの確認が表示されますので yes
を入力してEnterを押します。
$ terraform apply
(中略)
Plan: 67 to add, 0 to change, 0 to destroy.
Changes to Outputs:
+ databricks_metastore_id = (known after apply)
+ databricks_workspaces_details = (sensitive value)
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
上記実行後、3-4分待って、以下のようにApply complete!
が表示されれば正常終了です。
(中略)
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table_association.private_route_table_associations[1]: Creation complete after 1s [id=rtbassoc-0ea195aef64c0e05c]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table_association.private_route_table_associations[0]: Creation complete after 1s [id=rtbassoc-09550156d7158df9d]
Apply complete! Resources: 67 added, 0 changed, 0 destroyed.
Outputs:
databricks_metastore_id = "1234567d-304d-4e66-8c03-11b10d68ba23"
databricks_workspaces_details = <sensitive>
実行結果の確認
terraform state list
コマンドで作成されたリソースを確認できます。上のセクションで記載した引数のサンプルを指定してterraform apply
を実行した場合、2つのワークスペースとその関連リソースが作成されます。
$ terraform state list
databricks_group.account_admin
databricks_group_member.account_admin["1234567890123456"]
databricks_group_member.account_admin["6543210987654321"]
databricks_group_role.account_admin
databricks_metastore.this[0]
module.aws_databricks_mws["workspace1"].databricks_group.workspace_admin
module.aws_databricks_mws["workspace1"].databricks_group_member.admin_user["5222559431330616"]
module.aws_databricks_mws["workspace1"].databricks_group_member.admin_user["7422702450545826"]
module.aws_databricks_mws["workspace1"].databricks_metastore_assignment.this
module.aws_databricks_mws["workspace1"].databricks_mws_credentials.this
module.aws_databricks_mws["workspace1"].databricks_mws_networks.this
module.aws_databricks_mws["workspace1"].databricks_mws_permission_assignment.workspace_admin
module.aws_databricks_mws["workspace1"].databricks_mws_storage_configurations.this
module.aws_databricks_mws["workspace1"].databricks_mws_workspaces.this
module.aws_databricks_mws["workspace1"].random_string.naming
module.aws_databricks_mws["workspace1"].time_sleep.wait_iam_role
module.aws_databricks_mws["workspace1"].time_sleep.wait_metastore_assignment
module.aws_databricks_mws["workspace2"].databricks_group.workspace_admin
module.aws_databricks_mws["workspace2"].databricks_group_member.admin_user["5222559431330616"]
module.aws_databricks_mws["workspace2"].databricks_group_member.admin_user["7422702450545826"]
module.aws_databricks_mws["workspace2"].databricks_metastore_assignment.this
module.aws_databricks_mws["workspace2"].databricks_mws_credentials.this
module.aws_databricks_mws["workspace2"].databricks_mws_networks.this
module.aws_databricks_mws["workspace2"].databricks_mws_permission_assignment.workspace_admin
module.aws_databricks_mws["workspace2"].databricks_mws_storage_configurations.this
module.aws_databricks_mws["workspace2"].databricks_mws_workspaces.this
module.aws_databricks_mws["workspace2"].random_string.naming
module.aws_databricks_mws["workspace2"].time_sleep.wait_iam_role
module.aws_databricks_mws["workspace2"].time_sleep.wait_metastore_assignment
module.aws_databricks_mws["workspace1"].module.aws_infra.data.aws_availability_zones.available
module.aws_databricks_mws["workspace1"].module.aws_infra.data.databricks_aws_assume_role_policy.this
module.aws_databricks_mws["workspace1"].module.aws_infra.data.databricks_aws_bucket_policy.this
module.aws_databricks_mws["workspace1"].module.aws_infra.data.databricks_aws_crossaccount_policy.this
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_eip.nat_gateway_elastic_ips[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_iam_role.cross_account_role
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_iam_role_policy.this
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_internet_gateway.igw
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_nat_gateway.nat_gateways[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_route_table.private_route_tables[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_route_table.private_route_tables[1]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_route_table.public_route_table
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_route_table_association.private_route_table_associations[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_route_table_association.private_route_table_associations[1]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_route_table_association.public_route_table_associations[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_s3_bucket.root_storage_bucket
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_s3_bucket_policy.root_bucket_policy
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_s3_bucket_public_access_block.root_storage_bucket
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_security_group.test_sg
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_subnet.private_subnets[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_subnet.private_subnets[1]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_subnet.public_subnets[0]
module.aws_databricks_mws["workspace1"].module.aws_infra.aws_vpc.main_vpc
module.aws_databricks_mws["workspace2"].module.aws_infra.data.aws_availability_zones.available
module.aws_databricks_mws["workspace2"].module.aws_infra.data.databricks_aws_assume_role_policy.this
module.aws_databricks_mws["workspace2"].module.aws_infra.data.databricks_aws_bucket_policy.this
module.aws_databricks_mws["workspace2"].module.aws_infra.data.databricks_aws_crossaccount_policy.this
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_eip.nat_gateway_elastic_ips[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_iam_role.cross_account_role
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_iam_role_policy.this
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_internet_gateway.igw
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_nat_gateway.nat_gateways[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table.private_route_tables[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table.private_route_tables[1]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table.public_route_table
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table_association.private_route_table_associations[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table_association.private_route_table_associations[1]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_route_table_association.public_route_table_associations[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_s3_bucket.root_storage_bucket
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_s3_bucket_policy.root_bucket_policy
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_s3_bucket_public_access_block.root_storage_bucket
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_security_group.test_sg
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_subnet.private_subnets[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_subnet.private_subnets[1]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_subnet.public_subnets[0]
module.aws_databricks_mws["workspace2"].module.aws_infra.aws_vpc.main_vpc
Databricksアカウントコンソールのワークスペースを見ると、複数のワークスペースが作成されています。
作成されたワークスペースの設定画面は以下のようになります。
アウトプットの確認
terraform output -json
コマンドでアウトプットに定義した情報を見ることができます。platform/02_workspace_config
の入力として使うので控えておきましょう。
$ terraform output -json
{
"databricks_metastore_id": {
"sensitive": false,
"type": "string",
"value": "1234567d-304d-4e66-8c03-11b10d68ba23"
},
"databricks_workspaces_details": {
"sensitive": true,
"type": [
"tuple",
[
[
"object",
{
"databricks_workspace_admin_group_name": "string",
"databricks_workspace_name": "string",
"databricks_workspace_token": "string",
"databricks_workspace_url": "string"
}
],
[
"object",
{
"databricks_workspace_admin_group_name": "string",
"databricks_workspace_name": "string",
"databricks_workspace_token": "string",
"databricks_workspace_url": "string"
}
]
]
],
"value": [
{
"databricks_workspace_admin_group_name": "domain1-admin-group",
"databricks_workspace_name": "hinak-dbc-ws-apne1-domain1",
"databricks_workspace_token": "1234567d-304d-4e66-8c03-11b10d68ba23",
"databricks_workspace_url": "https://dbc-e29e9444-3722.cloud.databricks.com"
},
{
"databricks_workspace_admin_group_name": "domain2-admin-group",
"databricks_workspace_name": "hinak-dbc-ws-apne1-domain2",
"databricks_workspace_token": "1234567e-304d-4e66-8c03-11b10d68ba23",
"databricks_workspace_url": "https://dbc-3d5a5b8d-8350.cloud.databricks.com"
}
]
}
}
(オプション) Terraformリソースの削除
terraform destroy
コマンドでリソース一式を削除できます。
platform/02_workspace_config
上記で作成したDatabricksワークスペースに共通的な設定・ポリシーを適用します。本サンプル実装では各ワークスペース管理者にCREATE_CATALOG
などの権限を付与します。
プロバイダー (providers.tf
)
サンプル実装では、2つのDatabricksワークスペースのプロバイダーを定義しています。もっと沢山のワークスペースを作成した場合は、コピー & ペーストでプロバイダーを増やします。
url
およびtoken
には、platform/01_workspace_setup
のアウトプットを使うのがスムーズだと思います。
terraform {
required_providers {
databricks = {
source = "databricks/databricks"
}
}
}
provider "databricks" {
alias = "domain1"
host = var.domain1.url
token = var.domain1.token
}
provider "databricks" {
alias = "domain2"
host = var.domain2.url
token = var.domain2.token
}
Terraformのプロバイダーの動的な定義
Terraformではfor_each
などと組み合わせてプロバイダーを動的に定義することは仕様上できないため、上記のように静的な形ですべてのプロバイダーを定義する必要があります。
メイン (main.tf
)
各ワークスペースの管理者グループに対して、カタログ作成に必要な権限一式を付与します。より多くのワークスペースがある場合はリソースセクションをコピー & ペーストして増やします。
resource "databricks_grant" "domain1" {
provider = databricks.domain1
metastore = var.databricks_metastore_id
principal = var.domain1.admin_group_name
privileges = ["CREATE_CATALOG", "CREATE_EXTERNAL_LOCATION", "CREATE_STORAGE_CREDENTIAL"]
}
resource "databricks_grant" "domain2" {
provider = databricks.domain2
metastore = var.databricks_metastore_id
principal = var.domain2.admin_group_name
privileges = ["CREATE_CATALOG", "CREATE_EXTERNAL_LOCATION", "CREATE_STORAGE_CREDENTIAL"]
}
メタストアレベルの操作に関する注意点
-
CREATE_CATALOG
権限などの付与はメタストアレベルの操作になります - メタストアレベルの操作は、メタストア管理者(Metastore Admin)が行うことができます
-
platform/01_workspace_setup
ではアカウント管理者グループ(account admins)をメタストア管理者に設定しています。そのため、Terraformを実行するプリンシパルがアカウント管理者グループに入っていれば問題なく実行できます - 既存のメタストアを利用する場合にはTerraformを実行するプリンシパルがメタストア管理者の一員になっていることを確認し、なっていなければ変更が必要になります
引数
以下は引数の例です。platform/01_workspace_setup
のアウトプットをコピー & ペーストするのが簡単です。
databricks_metastore_id = "1234567d-304d-4e66-8c03-11b10d68ba23"
domain1 = {
admin_group_name = "domain1-admin-group"
token = "1234567d-304d-4e66-8c03-11b10d68ba23"
url = "https://dbc-210868cc-1c64.cloud.databricks.com"
}
domain2 = {
admin_group_name = "domain2-admin-group"
token = "1234567e-304d-4e66-8c03-11b10d68ba23"
url = "https://dbc-08e13b97-9770.cloud.databricks.com"
}
Terraform実行
platform/01_workspace_setup
と同じ要領で実行できます。
$ cd aws-databricks-terraform-specific-examples/examples/data_mesh_example/platform/02_workspace_config
$ terraform init
$ terraform plan
$ terraform apply
実行結果
ワークスペースにアクセスし、カタログエクスプローラーからメタストアの権限を見ると、以下のようにCREATE CATALOG
などの権限がワークスペース管理者グループに付与されていることが分かります。
domains/domain1
以降は各データドメインのワークスペース管理者が、ドメインのニーズに合わせて任意のリソースの作成・管理を行なっていくことになります。
本サンプル実装のdomains/domain1
では、例として、ドメイン固有のデータ管理用のUnity Catalogのカタログと周辺リソースを作成・管理するtfファイルを含めてますので、その説明を簡単に記載します。
プロバイダー (providers.tf
)
自ドメインのDatabricksワークスペースをプロバイダーとして利用します。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
databricks = {
source = "databricks/databricks"
}
}
}
provider "aws" {
region = var.region
}
provider "databricks" {
alias = "domain1"
host = var.domain1.url
token = var.domain1.token
}
メイン (main.tf
)
モジュールを呼び出して、ドメイン固有のデータ管理用のUnity Catalogと周辺リソースを作成・管理します。
module "workspace_catalog1" {
source = "../modules/workspace_catalog"
providers = {
aws = aws
databricks = databricks.domain1
}
prefix = var.domain1.prefix
catalog_name = var.domain1.catalog_name
admin_group_name = var.domain1.admin_group_name
}
モジュール (modules/workspace_catalog/main.tf
)
以下のサンプル実装をほぼそのまま流用、若干の改変を行なったモジュールです。
以下のリソースを作成・管理します。いずれもワークスペースレベルになります。
- Unity Catalogのストレージクレデンシャル
- カタログ用のS3バケット
- DatabricksのコントロールプレーンからS3にアクセスする際に利用するIAMロール & IAMポリシー
- Unity Catalogの外部ロケーション
- Unity Catalogのカタログ
- ワークスペース管理者グループにストレージクレデンシャル、外部ロケーション、カタログの
ALL_PRIVILEGES
を付与
長いので実物は以下のGitHubでご覧ください。
引数
region = "ap-northeast-1"
domain1 = {
admin_group_name = "domain1-admin-group"
catalog_name = "domain1_main"
prefix = "random-prefix-domain1"
token = "1234567d-304d-4e66-8c03-11b10d68ba23"
url = "https://dbc-210868cc-1c64.cloud.databricks.com"
}
Terraform実行
platform/01_workspace_setup
と同じ要領で実行できます。
$ cd aws-databricks-terraform-specific-examples/examples/data_mesh_example/domains/domain1
$ terraform init
$ terraform plan
$ terraform apply
実行結果
ワークスペースのWeb UIでカタログエクスプローラーにアクセスし、ストレージクレデンシャル、外部ロケーション、カタログが作成されていることが確認できます。
ストレージクレデンシャル
外部ロケーション
カタログ
カタログ作成時にISOLATED
を指定したため、domain1
のワークスペースだけがこのカタログにアクセスできる状態になっています。
以上です。