Terraformを用いたDatabricksワークスペース(E2)の配備

[Provision Databricks workspaces using Terraform \(E2\) \| Databricks on AWS](https://docs.databricks.com/dev-tools/terraform/e2-workspace.html) [2021/12/28時点]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

このガイドでは、[Databricks Terraformプロバイダー](https://qiita.com/taka_yayoi/items/691ee4909b0961de5ad1)を用いてDatabricksワークスペースと必要となる全てのAWSインフラストラクチャを作成する方法を説明します。ここで説明する手順は、[E2バージョンのプラットフォーム](https://qiita.com/taka_yayoi/items/7d209bc8d32bc5f2dba4#e2%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3)上のDatabricksアカウントにのみ適用されます。新しい全てのDatabricksアカウントとほとんどの既存アカウントはE2です。どのタイプのアカウントか不明の場合には、Databricks担当者にお問合せください。

:::note info
**実験段階**
Databricks TerraformプロバイダーはDatabricksやAWSに正式にサポートはされていません。これは、Databricksのフィールドエンジニアリングチームによってメンテナンスされ、as-isで提供されています。サービスレベルアグリーメント(SLA)は存在せず、AWSはいかなる保証も行いません。プロバイダーに問題を見つけた場合には、[GitHub Issue](https://github.com/databrickslabs/terraform-provider-databricks/issues/new/choose)を起票することで、時間が許す限りプロジェクトのメンテナーによってレビューされます。
:::

# E2ワークスペースに対するプロバイダーの初期化

このガイドでは、皆様がDatabricksアカウントオーナーの認証情報(`databricks_account_username`と`databricks_account_password`)を持っていることを前提としています。また、ご自身のアカウントID(`databricks_account_id`)を知っている必要があります。アカウントIDを取得するには、https://accounts.cloud.databricks.com/ にあるDatabricksアカウントコンソールにログインします。コンソールのサイドバーの左下からアカウントIDにアクセスすることができます。

このガイドはそのままの状態のものを提示しており、皆様の設定の基礎になることを意図しています。

```
variable "databricks_account_username" {}
variable "databricks_account_password" {}
variable "databricks_account_id" {}

variable "tags" {
  default = {}
}

variable "cidr_block" {
  default = "10.4.0.0/16"
}

variable "region" {
  default = "eu-west-1"
}

resource "random_string" "naming" {
  special = false
  upper   = false
  length  = 6
}

locals {
  prefix = "demo${random_string.naming.result}"
}
```

[ワークスペースを管理](https://docs.databricks.com/dev-tools/terraform/workspace-management.html)する前に、[VPC](#ステップ1-vpcの作成)、[ルートバケット](#ステップ2-ルートバケットの作成)、[クロスアカウントロール](#ステップ3-クロスアカウントiamロールの作成)、[Databricks E2ワークスペース](#ステップ4-databricks-e2ワークスペースの作成)、[ホストとトークンのoutput](#プロバイダーの設定)を作成する必要があります。また、`alias = "mws"`を指定してプロバイダーを初期化し、全ての`databricks_mws_*`リソースに対して`provider = databricks.mws`を使用しなくてはなりません。プロバイダーは皆様の環境内の自身専用のTerraformモジュール
内で全ての`databricks_mws_*`リソースを作成することを要求します。通常は、このモジュールがVPC、IAMロールも作成します。

```
terraform {
  required_providers {
    databricks = {
      source  = "databrickslabs/databricks"
    }
  }
}

provider "aws" {
  region = var.region
}

// initialize provider in "MWS" mode to provision new workspace
provider "databricks" {
  alias    = "mws"
  host     = "https://accounts.cloud.databricks.com"
  username = var.databricks_account_username
  password = var.databricks_account_password
}
```

# ステップ1: VPCの作成

必要となる全てのファイアウォールルールと共にAWS VPCを作成します。ネットワーキングに関する完全かつ最新の情報に関しては、[顧客管理VPC](https://qiita.com/taka_yayoi/items/f23bd799e1960e2eccbe)をご覧ください。AWS VPCは[databricks\_mws\_networks](https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs/resources/mws_networks)リソースとして登録されます。

```
data "aws_availability_zones" "available" {}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "2.70.0"

  name = local.prefix
  cidr = var.cidr_block
  azs  = data.aws_availability_zones.available.names
  tags = var.tags

  enable_dns_hostnames = true
  enable_nat_gateway   = true
  create_igw           = true

  public_subnets  = [cidrsubnet(var.cidr_block, 3, 0)]
  private_subnets = [cidrsubnet(var.cidr_block, 3, 1),
                     cidrsubnet(var.cidr_block, 3, 2)]

  default_security_group_egress = [{
    cidr_blocks = "0.0.0.0/0"
  }]

  default_security_group_ingress = [{
    description = "Allow all internal TCP and UDP"
    self        = true
  }]
}

resource "databricks_mws_networks" "this" {
  provider           = databricks.mws
  account_id         = var.databricks_account_id
  network_name       = "${local.prefix}-network"
  security_group_ids = [module.vpc.default_security_group_id]
  subnet_ids         = module.vpc.private_subnets
  vpc_id             = module.vpc.vpc_id
}
```

# ステップ2: ルートバケットの作成

一般的には**ルートバケット**と呼ばれるDBFSワークスペースストレージのためのAWS S3バケットを作成します。このプロバイダーには、必要なIAMポリシーのテンプレートを持つ[databricks\_aws\_bucket\_policy](https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs/data-sources/aws_bucket_policy)があります。お使いのAWS S3バケットは[databricks\_mws\_storage\_configurations](https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs/resources/mws_storage_configurations)リソースを用いて登録されなくてはなりません。

```
resource "aws_s3_bucket" "root_storage_bucket" {
  bucket = "${local.prefix}-rootbucket"
  acl    = "private"
  versioning {
    enabled = false
  }
  force_destroy = true
  tags = merge(var.tags, {
    Name = "${local.prefix}-rootbucket"
  })
}

resource "aws_s3_bucket_public_access_block" "root_storage_bucket" {
  bucket             = aws_s3_bucket.root_storage_bucket.id
  ignore_public_acls = true
  depends_on         = [aws_s3_bucket.root_storage_bucket]
}

data "databricks_aws_bucket_policy" "this" {
  bucket = aws_s3_bucket.root_storage_bucket.bucket
}

resource "aws_s3_bucket_policy" "root_bucket_policy" {
  bucket = aws_s3_bucket.root_storage_bucket.id
  policy = data.databricks_aws_bucket_policy.this.json
}

resource "databricks_mws_storage_configurations" "this" {
  provider                   = databricks.mws
  account_id                 = var.databricks_account_id
  bucket_name                = aws_s3_bucket.root_storage_bucket.bucket
  storage_configuration_name = "${local.prefix}-storage"
}
```

# ステップ3: クロスアカウントIAMロールの作成

クロスアカウントIAMロールは[databricks\_mws\_credentials](https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs/resources/mws_credentials)リソースを用いて登録されなくてはなりません。

```
data "databricks_aws_assume_role_policy" "this" {
  external_id = var.databricks_account_id
}

resource "aws_iam_role" "cross_account_role" {
  name               = "${local.prefix}-crossaccount"
  assume_role_policy = data.databricks_aws_assume_role_policy.this.json
  tags               = var.tags
}

data "databricks_aws_crossaccount_policy" "this" {
}

resource "aws_iam_role_policy" "this" {
  name   = "${local.prefix}-policy"
  role   = aws_iam_role.cross_account_role.id
  policy = data.databricks_aws_crossaccount_policy.this.json
}

resource "databricks_mws_credentials" "this" {
  provider         = databricks.mws
  account_id       = var.databricks_account_id
  role_arn         = aws_iam_role.cross_account_role.arn
  credentials_name = "${local.prefix}-creds"
  depends_on       = [aws_iam_role_policy.this]
}
```

# ステップ4: Databricks E2ワークスペースの作成

[databricks\_mws\_workspaces](https://registry.terraform.io/providers/databrickslabs/databricks/latest/docs/resources/mws_workspaces)リソースを用いてDatabricks E2ワークスペースを作成します。`provider = databricks.mws`と`provider = databricks.created_workspace`のよくある混乱を避けるために、ワークスペースを作成するコードと[ワークスペースを管理](https://qiita.com/taka_yayoi/items/012122880b728a33d781)するコードは別のTerraformモジュールに格納される必要があります。このため、以下のモジュールでは`databricks_host`と`databricks_token`のoutputを指定しなくてはなりません。

```
resource "databricks_mws_workspaces" "this" {
  provider        = databricks.mws
  account_id      = var.databricks_account_id
  aws_region      = var.region
  workspace_name  = local.prefix
  deployment_name = local.prefix

  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
}

// export host to be used by other modules
output "databricks_host" {
  value = databricks_mws_workspaces.this.workspace_url
}

// initialize provider in normal mode
provider "databricks" {
  // in normal scenario you won't have to give providers aliases
  alias = "created_workspace"
  host = databricks_mws_workspaces.this.workspace_url
}

// create PAT token to provision entities within workspace
resource "databricks_token" "pat" {
  provider = databricks.created_workspace
  comment  = "Terraform Provisioning"
  lifetime_seconds = 86400
}

// export token for integration tests to run on
output "databricks_token" {
  value     = databricks_token.pat.token_value
  sensitive = true
}
```

# プロバイダーの設定

[Terraformを用いたエンドツーエンドのDatabricksワークスペース管理](https://qiita.com/taka_yayoi/items/012122880b728a33d781)では、プロバイダーに対して以下の設定を使います。

```
provider "databricks" {
  host = module.ai.databricks_host
  token = module.ai.databricks_token
}
```

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)