Databricksコンテナサービスによるコンテナのカスタマイズ

[Customize containers with Databricks Container Services \| Databricks on AWS](https://docs.databricks.com/clusters/custom-containers.html) [2022/5/30時点]

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

Databricksコンテナサービスを使うことで、クラスターを作成する際にDockerイメージを指定することができます。以下のようなユースケースが考えられます。

- ライブラリのカスタマイズ: インストールされるシステムライブラリに対して完全なコントロールを持つことができます。
- ゴールデンコンテナ環境: お使いのDockerイメージが決して変更されないロックダウン環境となります。
- Docker CI/CDインテグレーション: お使いのDocker CI/CDパイプラインを用いてDatabricksとインテグレーションすることができます。

また、GPUデバイスを持つクラスター上のカスタムディープラーニング環境を作るためにDockerイメージを使うことができます。DatabricksコンテナサービスによるGPUクラスターの活用に関しては、[Databricks Container Services on GPU clusters](https://docs.databricks.com/clusters/gpu.html#databricks-container-services-on-gpu)をご覧ください。

コンテナが起動するたびに実行されるタスクに関しては、[initスクリプト](#initスクリプトを使う)を使います。

# 要件

:::note info
**注意**
Databricks機械学習ランタイムとDatabricks Runtime for GenomicsはDatabricksコンテナサービスをサポートしていません。
:::

- Databricksランタイム6.1以降。以前にDatabricksコンテナサービスを使ったことがある場合、ベースイメージをアップグレードする必要があります。最新のイメージに関しては、 https://github.com/databricks/containers で`6.x`とタグづけされているものを参照ください。
- お使いのDatabricksワークスペースでDatabricks Container Servicesが[有効化](https://docs.databricks.com/administration-guide/clusters/container-services.html)されている必要があります。
- お使いのマシンでは最新のDocker daemon(Client/Server Version 18.03.0-ceでの動作確認がされています)が稼働しており、ご自身の`PATH`で`docker`コマンドが使用できる必要があります。

# ステップ1: ベースを作成する

Databricksがビルド、テストしたDockerベースをビルドすることをお勧めします。最初からご自身でDockerベースをビルドすることも可能です。このセクションではこれら2つのオプションを説明します。

## オプション1: Databricksによってビルドされたベースを使う

このサンプルでは、Databricksランタイム9.0以降が稼働するクラスターをターゲットにする`9.x`タグを使用します。

```bash:Bash
FROM databricksruntime/standard:9.x
...
```

最新のpandasやurllibのような追加のPythonライブラリを指定するには、コンテナ固有バージョンの`pip`を使用します。`datatabricksruntime/standard:9.x`コンテナにおいては、以下を含めます。

```bash:Bash
RUN /databricks/python3/bin/pip install pandas
RUN /databricks/python3/bin/pip install urllib3
```

`datatabricksruntime/standard:8.x`以前のコンテナに関しては、以下を含めます。

```bash:Bash
RUN /databricks/conda/envs/dcs-minimal/bin/pip install pandas
RUN /databricks/conda/envs/dcs-minimal/bin/pip install urllib3
```

サンプルのベースイメージは、Docker Hubの https://hub.docker.com/u/databricksruntime でホストされています。これらのベースを生成するために使用されたDockerfilesは https://github.com/databricks/containers にあります。

:::note info
**注意**
ベースイメージ`databricksruntime/standard`と`databricksruntime/minimal`を、関係のない`databricks-standard`や`databricks-minimal`環境と混同しないでください。これらは、もはや利用できないDatabricks Runtime with Conda (Beta)に含まれるものです。
:::
 
## オプション2: 自分でDockerベースをビルドする

最初から自身でDockerベースをビルドすることもできます。Dockerイメージは以下の要件を満たす必要があります。

- JDK 8u191 as Java on the system PATH
- bash
- iproute2 ([ubuntu iproute](https://packages.ubuntu.com/search?keywords=iproute2))
- coreutils ([ubuntu coreutils](https://packages.ubuntu.com/search?keywords=coreutils))
- procps ([ubuntu procps](https://packages.ubuntu.com/search?keywords=procps))
- sudo ([ubuntu sudo](https://packages.ubuntu.com/search?keywords=sudo))
- Ubuntu Linux

自分で最初からイメージをビルドするためには、仮想環境を作成する必要があります。また、Python、R、GangliaなどDatabricksクラスターに含まれているパッケージを含める必要もあります。スタートするために、適切なベースイメージ(R向けの`databricksruntime/rbase`やPython向けの`databricksruntime/python`)を使用したり、[Dockerfiles in GitHub](https://hub.docker.com/u/databricksruntime)のサンプルを参照することができます。別の選択肢は、Databricksによってビルドされたミニマルのイメージ`databricksruntime/minimal`からスタートするというものです。

:::note info
**注意**
Ubuntu Linuxを使用することをお勧めします。しかし、Alpine Linuxを使うことも可能です。Alpine Linuxを使用するには、以下のファイルを含める必要があります。
- [alpine coreutils](https://pkgs.alpinelinux.org/package/v3.3/main/x86/coreutils)
- [alpine procps](https://pkgs.alpinelinux.org/package/v3.3/main/x86/procps)
- [alpine sudo](https://pkgs.alpinelinux.org/package/v3.3/main/x86/sudo)

さらに、こちらの[example Dockerfile](https://github.com/databricks/containers/blob/master/experimental/alpine/minimal/Dockerfile)にあるように、Pythonをセットアップする必要があります。
:::

:::note warn
**警告**
あなたのカスタムコンテナイメージをDatabricksクラスターで完全にテストしてください。ローカルあるいはビルドしたマシンでコンテナは動作するかもしれませんが、Databricksクラスターでコンテナが起動された際、クラスターが失敗する場合があり、特定の機能が利用不可となるから、場合によってはメッセージもなしにコンテナが動作を停止するかもしれません。最悪のシナリオでは、データを破壊したり、意図せずデータを外部に公開してしまうかもしれません。

念のためですが、Databricksサービスコンテナの利用は[Service Specific Terms](https://databricks.com/product-specific-terms)の対象となります。
:::

# ステップ2: ベースイメージをプッシュする

カスタムベースイメージをDockerレジストリにプッシュします。このプロセスは以下のレジストリでサポートされています。

- 認証なし、あるいはbasic認証の[Docker Hub](https://hub.docker.com/)
- IAMが設定された(Commercial Cloud Services (C2S)は例外)、[Amazon Elastic Container Registry \(Amazon ECR\)](https://aws.amazon.com/ecr/)
- basic認証の[Azure Container Registry](https://docs.microsoft.com/azure/container-registry/)

認証なし、basic認証の他のDockerレジストリも動作すると思われます。

:::note info
**注意**
DockerレジストリにDocker Hubを使っている場合、6時間の間に起動されることが予想されるクラスター数とレート制限が合致していることをチェックするようにしてください。これらのレート制限は、匿名ユーザー、有料サブスクリプションなしの認証ユーザー、有料サブスクリプションによって異なります。詳細は[the Docker documentation](https://docs.docker.com/docker-hub/download-rate-limit/)をご覧ください。この制限を超えると、`429 Too Many Requests`が返却されます。
:::

# ステップ3: クラスターを起動する

UIあるいはAPIを用いてクラスターを起動することができます。

## UIを使ってクラスターを起動する

1. DatabricksコンテナサービスをサポートするDatabricksランタイムバージョンを指定します。
![](https://docs.databricks.com/_images/custom-container-aws.png)
1. **Use your own Docker container**を選択します。
1. **Docker Image URL**フィールドにご自身のカスタムDockerイメージを入力します。

    DockerイメージURLのサンプル:

    | レジストリ | タグのフォーマット |
    |:--|:--|
    | Docker Hub  |  `<organization>/<repository>:<tag>` (例えば `databricksruntime/standard:latest`) |
    |  Amazon ECR |  `<aws-account-id>.dkr.ecr.<region>.amazonaws.com/<repository>:<tag>` |
    | Azure Container Registry  |  `<your-registry-name>.azurecr.io/<repository-name>:<tag>` |

1. 認証タイプを選択します。

## APIを使ってクラスターを起動する

1. [APIのトークンを生成します](https://docs.databricks.com/dev-tools/api/latest/authentication.html)。
1. ご自身のカスタムDockerベースを用いてクラスターを起動するために[Clusters API 2\.0](https://docs.databricks.com/dev-tools/api/latest/clusters.html)を使います。

    ```bash:Bash
    curl -X POST -H "Authorization: Bearer <token>" https://<databricks-instance>/api/2.0/clusters/create -d '{
      "cluster_name": "<cluster-name>",
      "num_workers": 0,
      "node_type_id": "i3.xlarge",
      "docker_image": {
        "url": "databricksruntime/standard:latest",
        "basic_auth": {
          "username": "<docker-registry-username>",
          "password": "<docker-registry-password>"
        }
      },
      "spark_version": "7.3.x-scala2.12",
      "aws_attributes": {
        "availability": "ON_DEMAND",
        "instance_profile_arn": "arn:aws:iam::<aws-account-number>:instance-profile/<iam-role-name>"
      }
    }'
    ```

    `basic_auth`の要件はお使いのDockerイメージタイプに依存します。

    - パブリックなDockerイメージの場合、`basic_auth`フィールドを*含めないでください*。
    - プライベートなDockerイメージの場合、ユーザー名とパスワードとしてサービスプリンシパルIDとパスワードを用いた`basic_auth`フィールドを含める必要があります。
    - Azure Container Registryの場合、サービスプリンシパルのIDとパスワードに対応する`basic_auth`フィールドを設定する必要があります。サービスプリンシパルの作成方法に関しては、[Azure Container Registry service principal authentication documentation](https://docs.microsoft.com/azure/container-registry/container-registry-auth-service-principal)をご覧ください。
    - Amazon ECRイメージの場合、`basic_auth`フィールドを含めないでください。イメージが存在するDockerリポジトリからDockerイメージをプルする権限を含む[インスタンスプロファイル](https://docs.databricks.com/dev-tools/api/latest/clusters.html#clusterawsattributes)を設定してクラスターを起動する必要があります。このためには、[インスタンスプロファイルを用いたS3バケットへのセキュアなアクセスのセットアップのステップ3からステップ5](https://qiita.com/taka_yayoi/items/446c7971be354f88c679#%E3%82%B9%E3%83%86%E3%83%83%E3%83%973-databricks%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89%E3%81%AB%E7%94%A8%E3%81%84%E3%81%9Fiam%E3%83%AD%E3%83%BC%E3%83%AB%E3%82%92%E3%83%A1%E3%83%A2%E3%81%99%E3%82%8B)の手順に従ってください。

    任意のイメージをプルする権限を持つIAMロールのサンプルです。リポジトリは`<arn-of-repository>`で指定します。

    ```json:JSON
     {
       "Version": "2012-10-17",
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
               "ecr:GetAuthorizationToken"
           ],
         "Resource": "*"
       },
       {
         "Effect": "Allow",
         "Action": [
             "ecr:BatchCheckLayerAvailability",
             "ecr:GetDownloadUrlForLayer",
             "ecr:GetrepositoryPolicy",
             "ecr:DescribeRepositories",
             "ecr:ListImages",
             "ecr:DescribeImages",
             "ecr:BatchGetImage"
           ],
           "Resource": [ "<arn-of-repository>" ]
         }
       ]
     }
    ```

    Amazon ECRイメージがDatabricksクラスターと異なるAWSアカウントに存在している場合、Databricksクラスターのアクセスを許可するためにクラスターのインスタンスプロファイルに加えて、[ECR repository policy](https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-policies.html)を使います。ECRリポジトリポリシーのサンプルを示します。`<arn-of-IAM-role>`で指定されたクラスターのインスタンスプロファイルにIAMポリシーの権限が移譲されます。

    ```json:JSON
    {
      "Version": "2012-10-17",
      "Statement": [{
        "Sid": "AllowCrossAccountPush",
        "Effect": "Allow",
        "Principal": {
          "AWS": "<arn-of-IAM-role>"
        },
        "Action": [
          "ecr:BatchCheckLayerAvailability",
          "ecr:BatchGetImage",
          "ecr:DescribeImages",
          "ecr:DescribeRepositories",
          "ecr:GetDownloadUrlForLayer",
          "ecr:GetrepositoryPolicy",
          "ecr:ListImages"
        ]
      }]
    }
    ```

# initスクリプトを使う

Databricksコンテナサービスのクラスターでは、Dockerコンテナにinitスクリプトを含めることができます。多くの場合、initスクリプトを使用するのではなく、(Dockerfileを用いて)直接Dockerのカスタマイズをすべきです。しかし、コンテナがビルドされるときではなく、コンテナが起動する際に特定のタスクが実行される必要があるケースがあります。これらのタスクに関してはinitスクリプトを使います。

例えば、カスタムコンテナ内でセキュリティdaemonを動作させたいとします。イメージビルドのパイプラインを通じて、Dockerイメージにdaemonをインストール・ビルドします。次に、daemonを起動するinitスクリプトを追加します。この例では、initスクリプトには`systemctl start my-daemon`のような行が追加されます。

APIでは、以下のようにクラスターの仕様の一部としてinitスクリプトを指定することができます。詳細は[InitScriptInfo](https://docs.databricks.com/dev-tools/api/latest/clusters.html#initscriptinfo)をご覧ください。

```json:JSON
"init_scripts": [
    {
        "file": {
            "destination": "file:/my/local/file.sh"
        }
    }
]
```

Databricksコンテナサービスイメージにおいては、initスクリプトをDBFSあるいはクラウドストレージに格納することもできます。

Databricksコンテナサービスクラスターを起動する際に以下のステップが実行されます。

1. クラウドプロバイダーからVMを取得します。
1. カスタムDockerイメージがお使いのリポジトリからダウンロードされます。
1. DatabricksがイメージからDockerコンテナを作成します。
1. DockerコンテナにDatabricksランタイムのコードがコピーされます。
1. initスクリプトが実行されます。[initスクリプトの実行順序](https://qiita.com/taka_yayoi/items/88cb46be00a175085f87#init%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AE%E5%AE%9F%E8%A1%8C%E9%A0%86%E5%BA%8F)をご覧ください。

DatabricksはDockerの`CMD`と`ENTRYPOINT`プリミティブは無視します。

### Databricks 無料トライアル

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