Databricks on AWS デプロイ手順まとめ (顧客管理VPC)

# 概要
AWS 上かつ顧客管理 VPC 上で稼働する Databricks の構築方法です。

詳細に解説されている記事が豊富にありますが (参考 URL 参照)、AWS ポータルの触り方を結構忘れていたので、```Your VPC, custom``` で実装する手順を残しておきます。


# 手順 
### Cloudformation テンプレート
Cloudformation で構築します。
以下記事を参考にさせてもらいました。

https://dev.classmethod.jp/articles/getting-started-databricks/

YAML でテンプレートを書き、ローカル環境などに保存します。
今回は、

- VPC=```/22```
- Subnet=```/25```
- Region=```ap-northeast-1a```

で設定しています。
リソース名称や設定を細かく設定したい方は適宜変更しましょう。

```yaml:databricks-in-customer-managed-vpc-cloudformation-template.yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: Template for Databricks in Customer-managed VPC for ap-northeast-1

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/22
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: Databricks-VPC

  IGW:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: Databricks-IGW

  AttachIGW:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW
  
  PrivateSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.0/25
      Tags:
        - Key: Name
          Value: Databricks-Private-Subnet-a

  PrivateSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1c
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/25
      Tags:
        - Key: Name
          Value: Databricks-Private-Subnet-c

  PublicSubnetA:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/25
      Tags:
        - Key: Name
          Value: Databricks-Public-Subnet-a

  PublicSubnetC:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1c
      VpcId: !Ref VPC
      CidrBlock: 10.0.3.0/25
      Tags:
        - Key: Name
          Value: Databricks-Public-Subnet-c

  EIPA:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  NATGWA:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt EIPA.AllocationId
      ConnectivityType: public
      SubnetId: !Ref PublicSubnetA
      Tags:
        - Key: Name
          Value: Databricks-NATGW-a

  EIPC:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

  NATGWC:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt EIPC.AllocationId
      ConnectivityType: public
      SubnetId: !Ref PublicSubnetC
      Tags:
        - Key: Name
          Value: Databricks-NATGW-c


  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Databricks-Public-RouteTable

  PrivateRouteTableA:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Databricks-Private-RouteTable-a
  
  PrivateRouteTableC:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Databricks-Private-RouteTable-c


  PublicDefaultRoute:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref IGW
  
  PrivateDefaultRouteA:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTableA
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGWA
  
  PrivateDefaultRouteC:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref PrivateRouteTableC
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref NATGWC


  PublicRouteTableAssocA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref PublicRouteTable
  
  PublicRouteTableAssocC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnetC
      RouteTableId: !Ref PublicRouteTable
  
  PrivateRouteTableAssocA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetA
      RouteTableId: !Ref PrivateRouteTableA
  
  PrivateRouteTableAssocC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnetC
      RouteTableId: !Ref PrivateRouteTableC


  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: DataBricks-SecurityGroup
      GroupDescription: "Databricks SecurityGroup"
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: Databricks-SecurityGroup

Outputs:
  VPCID:
    Value: !Ref VPC
    Export: 
      Name: DataBricksVPCID

  PrivateSubnetIDA:
    Value: !Ref PrivateSubnetA
    Export: 
      Name: DataBricksPrivateSubnetIDA

  PrivateSubnetIDC:
    Value: !Ref PrivateSubnetC
    Export: 
      Name: DataBricksPrivateSubnetIDC

  SecurityGroupID:
    Value: !Ref SecurityGroup
    Export: 
      Name: DatabricksSecurityGroupID
```

### スタックの作成
先ほど保存した YAML をつかって Cloudformation でスタックを作成します。

スタックの作成をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/ea566aae-0989-2b6b-6911-aecae1951d7f.png)

YAML をアップロード、デザイナーで表示。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/d7c09c26-6ba1-6850-4fb5-28c7b25565c5.png)

Databricks を稼働させる VPC 構成はこのような形に。
テンプレートは S3 に保存し、スタックの作成 (クラウドに↑アイコン)をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/0bb9385a-a008-6cb6-9d33-3d9e81417c0d.png)

ステップ2へと進み、スタックの名称を指定。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/f932f4f6-9cb6-cc47-3508-5075fbcd4faa.png)

ステップ3のオプション設定は行わず、ステップ4レビューへと進み、スタックの作成をクリックすると、リソースの構築が始まります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/aa7d5797-60c2-24a3-3155-4178b568fef8.png)

デプロイが完了したら VPC コンソールに移動し、以下パラメータを控えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/ff002bbb-60d4-4fc4-3298-033765913fdd.png)


### Network Configrations 作成
Databricks の Admin コンソールに移り、network configration を設定します。別のWSとこれを共有することはないので、一意に識別しやすい名称を付けておきましょう
> Network Configration 名称例
```databricks-in-customer-managed-vpc-nw-config-01```

先ほど拾ったパラメータも入力、Add をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/316a6819-8501-e257-9776-46dfab510023.png)

以下で完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/2da17863-9220-c45b-7818-9784896c04f9.png)


### Credential configuration 作成
先ほどと同様に WS をデプロイするための権限も設定していきます。config の名称を入れ、External ID は控えておきます。まだ Add は押しません。

> Network Configration 名称例
```databricks-in-customer-managed-vpc-credential-config-01```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/34eb3748-44db-363d-7cfc-40d9a513cd83.png)

AWS IAM コンソールに移り、ロールを作成をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/4bc57150-66c1-6ba9-060d-a0a09c49ffef.png)

アプリケーションからのアクセスを許可する必要があるので、このロールを利用できる Databricks の AWS アカウントID (```414351767826```) を指定、External ID を入力。ロール名をいれてロールの作成をクリック。
> Credential configuration 名称例
```databricks-in-customer-managed-vpc-credential-01```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/359cb37e-6635-6300-bc92-079a6b62ebdc.png)


作成したロールを選択し、インラインポリシーを記述。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/0c5bf0c1-5ecd-b134-ff8d-74380c934f95.png)

書き換える必要のある変数は4つです。

|変数|概要|
|:--|:--|
|ACCOUNTID|顧客の AWS アカウント ID|
|VPCID|Cloudformation で作成した VPC の ID|
|REGION|Databricks WS をデプロイするリージョン|
|SECURITYGROUPID|Cloudformation で作成した SG の ID|

インラインポリシーのひな形はこちら。
> databricks-ws-inline-policy

```json:inline_polisy
{
    "Version": "2012-10-17",
    "Statement": [
        {
        "Sid": "NonResourceBasedPermissions",
        "Effect": "Allow",
        "Action": [
            "ec2:CancelSpotInstanceRequests",
            "ec2:DescribeAvailabilityZones",
            "ec2:DescribeIamInstanceProfileAssociations",
            "ec2:DescribeInstanceStatus",
            "ec2:DescribeInstances",
            "ec2:DescribeInternetGateways",
            "ec2:DescribeNatGateways",
            "ec2:DescribeNetworkAcls",
            "ec2:DescribePrefixLists",
            "ec2:DescribeReservedInstancesOfferings",
            "ec2:DescribeRouteTables",
            "ec2:DescribeSecurityGroups",
            "ec2:DescribeSpotInstanceRequests",
            "ec2:DescribeSpotPriceHistory",
            "ec2:DescribeSubnets",
            "ec2:DescribeVolumes",
            "ec2:DescribeVpcAttribute",
            "ec2:DescribeVpcs",
            "ec2:CreateTags",
            "ec2:DeleteTags",
            "ec2:RequestSpotInstances"
        ],
        "Resource": [
            "*"
        ]
        },
        {
        "Sid": "InstancePoolsSupport",
        "Effect": "Allow",
        "Action": [
            "ec2:AssociateIamInstanceProfile",
            "ec2:DisassociateIamInstanceProfile",
            "ec2:ReplaceIamInstanceProfileAssociation"
        ],
        "Resource": "arn:aws:ec2:REGION:ACCOUNTID:instance/*",
        "Condition": {
            "StringEquals": {
            "ec2:ResourceTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Sid": "AllowEc2RunInstancePerTag",
        "Effect": "Allow",
        "Action": "ec2:RunInstances",
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:volume/*",
            "arn:aws:ec2:REGION:ACCOUNTID:instance/*"
        ],
        "Condition": {
            "StringEquals": {
            "aws:RequestTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Sid": "AllowEc2RunInstanceImagePerTag",
        "Effect": "Allow",
        "Action": "ec2:RunInstances",
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:image/*"
        ],
        "Condition": {
            "StringEquals": {
            "aws:ResourceTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Sid": "AllowEc2RunInstancePerVPCid",
        "Effect": "Allow",
        "Action": "ec2:RunInstances",
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:network-interface/*",
            "arn:aws:ec2:REGION:ACCOUNTID:subnet/*",
            "arn:aws:ec2:REGION:ACCOUNTID:security-group/*"
        ],
        "Condition": {
            "StringEquals": {
            "ec2:vpc": "arn:aws:ec2:REGION:ACCOUNTID:vpc/VPCID"
            }
        }
        },
        {
        "Sid": "AllowEc2RunInstanceOtherResources",
        "Effect": "Allow",
        "Action": "ec2:RunInstances",
        "NotResource": [
            "arn:aws:ec2:REGION:ACCOUNTID:image/*",
            "arn:aws:ec2:REGION:ACCOUNTID:network-interface/*",
            "arn:aws:ec2:REGION:ACCOUNTID:subnet/*",
            "arn:aws:ec2:REGION:ACCOUNTID:security-group/*",
            "arn:aws:ec2:REGION:ACCOUNTID:volume/*",
            "arn:aws:ec2:REGION:ACCOUNTID:instance/*"
        ]
        },
        {
        "Sid": "EC2TerminateInstancesTag",
        "Effect": "Allow",
        "Action": [
            "ec2:TerminateInstances"
        ],
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:instance/*"
        ],
        "Condition": {
            "StringEquals": {
            "ec2:ResourceTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Sid": "EC2AttachDetachVolumeTag",
        "Effect": "Allow",
        "Action": [
            "ec2:AttachVolume",
            "ec2:DetachVolume"
        ],
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:instance/*",
            "arn:aws:ec2:REGION:ACCOUNTID:volume/*"
        ],
        "Condition": {
            "StringEquals": {
            "ec2:ResourceTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Sid": "EC2CreateVolumeByTag",
        "Effect": "Allow",
        "Action": [
            "ec2:CreateVolume"
        ],
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:volume/*"
        ],
        "Condition": {
            "StringEquals": {
            "aws:RequestTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Sid": "EC2DeleteVolumeByTag",
        "Effect": "Allow",
        "Action": [
            "ec2:DeleteVolume"
        ],
        "Resource": [
            "arn:aws:ec2:REGION:ACCOUNTID:volume/*"
        ],
        "Condition": {
            "StringEquals": {
            "ec2:ResourceTag/Vendor": "Databricks"
            }
        }
        },
        {
        "Effect": "Allow",
        "Action": [
            "iam:CreateServiceLinkedRole",
            "iam:PutRolePolicy"
        ],
        "Resource": "arn:aws:iam::*:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot",
        "Condition": {
            "StringLike": {
            "iam:AWSServiceName": "spot.amazonaws.com"
            }
        }
        },
        {
        "Sid": "VpcNonresourceSpecificActions",
        "Effect": "Allow",
        "Action": [
            "ec2:AuthorizeSecurityGroupEgress",
            "ec2:AuthorizeSecurityGroupIngress",
            "ec2:RevokeSecurityGroupEgress",
            "ec2:RevokeSecurityGroupIngress"
        ],
        "Resource": "arn:aws:ec2:REGION:ACCOUNTID:security-group/SECURITYGROUPID",
        "Condition": {
            "StringEquals": {
                "ec2:vpc": "arn:aws:ec2:REGION:ACCOUNTID:vpc/VPCID"
            }
        }
        }
    ]
    }
```

ポリシーの記述まで終わったら ロール ARN をコピーし、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/331d8496-4314-fcc2-d396-2d3294bb04ae.png)

Databricks コンソールの Role ARN にペースト、Add をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/79f6c8a9-c2b4-e4db-c2fd-a0c68cca624e.png)

これで Credential Configuration の設定は完了
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/87760f80-f30d-2220-fd30-92164b393585.png)

### Storage configuration 作成
最後にストレージの設定をします。Databricks の DBFS がここに収まる形です。

ストレージ名称とバケット名を入力、Generate Bucket Policy をクリックし、出力された JSON をコピーしたら、Add をクリック。
> databricks-in-customer-managed-vpc-storage-01

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/08d95656-a889-28f5-086e-063297bb19ad.png)

AWS S3 コンソールへ移り、先ほど指定したバケット名で S3 を構築
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/e760280a-8caf-f668-9e0a-ae0ad8be4a8f.png)

バケットのバージョニングは有効化推奨です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/20a4ee6f-788b-1196-389e-37e50d56fde8.png)

構築したバケットのアクセス許可からバケットポリシーの編集と進み、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/4ce2838e-4518-e54a-5328-b89a0a5632b8.png)

先ほどコピーした JSON をペースト、変更の保存をクリックして完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/c4db3c17-60f8-c7c9-b281-42ed1aa9e33f.png)

### WS デプロイ
最後のステップです。

Workspace から Create Workspace と進み、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/692a1b85-ccf6-d6fe-4210-51e6bbee1120.png)

ワークスペースの名称、URL を入力、ここまでで作成した Configration 3つを選択、Save をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/fa4c304d-7ba8-a765-030f-164dcef021b5.png)

ステータスが running になれば完成
![2021-11-12_13h18_23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/269e373d-5245-0f40-942b-636746362f7f.png)

作成した WS を選択すると明細を確認できます。URL をクリックすると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/c2461dba-3398-b61c-4aa8-a9dbecbd394f.png)

Databricks のルートアカウントでアクセスできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/52e054ad-601e-1693-bbfd-0e8a5e766079.png)


### 備考：デプロイがうまくいかない場合に確認すること
Credential Configuration の設定が以下で正しいかチェック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/166ef65e-0a5c-898f-478f-cd6cd67d89cf.png)

Service Control Policy でクロスアカウントアクセスを Deny しているかどうかチェック
もし Deny されているようなら Databricks がクロスアカウントの役割を引き受けられるようにホワイトリストでの登録が必要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/363781/d4a108ea-fc43-92dc-a7ae-8fdc8535fbf9.png)


### 参考 URL
トラブルシュートが必要な時は Databricks 弥生さんの記事群が参考になります。





https://qiita.com/taka_yayoi/items/125231c126a602693610

https://qiita.com/taka_yayoi/items/f63cc77afe4eef58d4e0#create-workspace%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%97%E3%81%A6%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97%E3%82%92%E9%96%8B%E5%A7%8B

https://qiita.com/taka_yayoi/items/f23bd799e1960e2eccbe

https://qiita.com/taka_yayoi/items/9e04f78ff025f77e52a6

https://qiita.com/taka_yayoi/items/483f3392a7b40b89c152