Amazon Web Services ブログ

EMR 6.0.0 の Docker を使用して、Spark の依存関係の管理を簡素化する

強力なデータ処理エンジンである Apache Spark で、データアナリストやエンジニアリングチームが簡単に API やツールを使ってデータを分析できるようになります。しかし、チームで Pythonや R ライブラリの依存関係を管理するのが難しいことがあります。ジョブを実行する前に必要となる可能性がある依存関係のあるライブラリをすべてインストールし、ライブラリのバージョンの競合に対処するのは、時間がかかり、複雑な作業となります。Amazon EMR 6.0.0 では、Docker Hub および Amazon ECR からの Docker イメージを使用して依存関係をパッケージ化できるようにすることで、これを簡素化しています。このため、クラスター全体でクモの巣のような依存関係を管理する必要がなくなり、個々の Spark ジョブまたはノートブックの依存関係をパッケージ化し、管理できるようになります。

この投稿では、Docker を使って Amazon EMR 6.0.0 および EMR Notebooks でノートブックの依存関係を管理する方法を解説します。EMR 6.0.0 クラスターを起動し、ノートブック固有の Amazon ECR の Docker イメージを EMR Notebooks で使用します。

Docker イメージの作成

まず、Docker イメージを作成します。これには、Python 3 と最新バージョンの numpy Python パッケージを含めます。Dockerfile を使用して Docker イメージを作成します。このファイルは、イメージに含めるパッケージと設定を定義するものです。Amazon EMR 6.0.0 で使用する Docker イメージには、Java Development Kit (JDK) が含まれている必要があります。次の Dockerfile は、Amazon Linux 2 と Amazon Corretto JDK 8 を使用しています。

FROM amazoncorretto:8

RUN yum -y update
RUN yum -y install yum-utils
RUN yum -y groupinstall development

RUN yum list python3*
RUN yum -y install python3 python3-dev python3-pip python3-virtualenv

RUN python -V
RUN python3 -V

ENV PYSPARK_DRIVER_PYTHON python3
ENV PYSPARK_PYTHON python3

RUN pip3 install --upgrade pip
RUN pip3 install numpy 

RUN python3 -c "import numpy as np"

この Dockerfile を使用して Docker イメージを作成し、タグを付けて Amazon ECR にアップロードします。アップロード後、この Docker イメージを Spark ジョブのデフォルトイメージとして使用するように設定してある EMR 6.0.0 クラスターを起動します。Docker イメージを構築、タグ付け、アップロードするには、次の手順を実行してください。

  1. 次のコマンドを使用して、Dockerfile という名前のディレクトリと新しいファイルを作成します。
    $ mkdir pyspark-latest
    $ vi pyspark-latest/Dockerfile
  2. Dockerfile の内容をコピーして貼り付け、保存し、次のコマンドを実行して Docker イメージを構築します。
    $ docker build -t 'local/pyspark-latest' pyspark-latest/
  3. 次のコマンドを使用して、このチュートリアルの emr-docker-examples Amazon ECR リポジトリを作成します。
    $ aws ecr create-repository --repository-name emr-docker-examples
  4. 次のコマンドを使用して、ローカルで構築したイメージにタグを付け、123456789123.dkr.ecr.us-east-1.amazonaws.com を Amazon ECR エンドポイントに置き換えます。
    $ docker tag local/pyspark-latest 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-latest

    Docker イメージを Amazon ECR にプッシュする前に、ログインする必要があります。

  5. Amazon ECR アカウントのログイン行を取得するには、次のコマンドを使用します。
    $ aws ecr get-login --region us-east-1 --no-include-email
  6. get-login コマンドの出力を入力し、実行します。
    $ docker login -u AWS -p <password> https://123456789123.dkr.ecr.us-east-1.amazonaws.com 
  7. ローカルで構築したイメージを Amazon ECR にアップロードし、123456789123.dkr.ecr.us-east-1.amazonaws.com を Amazon ECR エンドポイントに置き換えます。次のコマンドをご参照ください。
    $ docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-latest

このプッシュが完了すると、Docker イメージを EMR クラスターで使用できるようになります。

Docker を有効にして EMR 6.0.0 クラスターを起動する

Amazon EMR で Docker を使用するには、Docker ランタイムのサポートを有効にして EMR クラスターを起動し、適切な設定を行って Amazon ECR アカウントに接続する必要があります。クラスターが Amazon ECR からイメージをダウンロードできるようにするには、クラスターのインスタンスプロファイルに、関連付けられた AmazonEC2ContainerRegistryReadOnly 管理ポリシーからのアクセス許可があることを確認してください。以下の最初のステップの設定では、Amazon ECR を使用して Docker イメージをダウンロードするように EMR 6.0.0 クラスターを設定し、すべての Spark ジョブのデフォルトの Docker イメージとして pyspark-latest Docker イメージを使用するように Apache Livy と Apache Spark を設定します。次の手順を完了し、クラスターを起動します。

  1. 次の設定でローカルディレクトリに emr-configuration.json という名前のファイルを作成します (123456789123.dkr.ecr.us-east-1.amazonaws.com を Amazon ECR エンドポイントに置き換えます)。
    [
       {
          "Classification":"container-executor",
          "Properties":{
    
          },
          "Configurations":[
             {
                "Classification":"docker",
                "Properties":{
                   "docker.privileged-containers.registries":"local,centos,123456789123.dkr.ecr.us-east-1.amazonaws.com",
                   "docker.trusted.registries":"local,centos,123456789123.dkr.ecr.us-east-1.amazonaws.com"
               }
             }
          ]
       },
       {
          "Classification":"livy-conf",
          "Properties":{
             "livy.spark.master":"yarn",
             "livy.spark.deploy-mode":"cluster",
             "livy.server.session.timeout":"16h"
          }
       },
       {
          "Classification":"hive-site",
          "Properties":{
             "hive.execution.mode":"container"
          }
       },
       {
          "Classification":"spark-defaults",
          "Properties":{
             "spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE":"docker",
             "spark.yarn.am.waitTime":"300s",
             "spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE":"docker",
             "spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG":"hdfs:///user/hadoop/config.json",
             "spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE":"123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-latest",
             "spark.executor.instances":"2",
             "spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG":"hdfs:///user/hadoop/config.json",
             "spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE":"123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-latest"
          }
       }
    ]

    この設定で、AWS CLI を使って EMR 6.0.0 クラスターを起動します。

  2. 次のコマンドを入力します (myKey を SSH でクラスターにアクセスするのに使用する EC2 キーペアの名前に置き換え、さらに subnet-1234567 をクラスターを起動するサブネット ID に置き換えます)。
    aws emr create-cluster \
    --name 'EMR 6.0.0 with Docker' \
    --release-label emr-6.0.0 \
    --applications Name=Livy Name=Spark \
    --ec2-attributes "KeyName=myKey,SubnetId=subnet-1234567" \
    --instance-type m5.xlarge --instance-count 3 \
    --use-default-roles \
    --configurations file://./emr-configuration.json

    クラスターが起動し、待機状態になったら、クラスターホストが Amazon ECR に対して自身を認証し、Docker イメージをダウンロードできることを確認します。

  3. EC2 キーペアを使用して、クラスターのコアノードの 1 つに SSH を接続します。
  4. 次のコマンドを入力して、Docker CLI コマンドを作成し、クラスターが Amazon ECR から Docker イメージをダウンロードするのに使用する認証情報 (12 時間有効) を作成します。
    $ aws ecr get-login --region us-east-1 --no-include-email
  5. get-login コマンドの出力を入力し、実行します。
    $ sudo docker login -u AWS -p <password> https://123456789123.dkr.ecr.us-east-1.amazonaws.com 

    このコマンドは、config.json ファイルを /root/.docker フォルダ内に作成します。

  6. 次のコマンドを使用して、作成した config.json ファイルを HDFS がある場所の /user/hadoop/ に配置します。
    $ sudo hdfs dfs -put /root/.docker/config.json /user/hadoop/

Docker と Amazon ECR 内のイメージで設定した EMR クラスターができたので、EMR Notebooks を使用してノートブックを作成および実行できます。

EMR Notebook の作成

EMR Notebooks は、Amazon EMR コンソールから直接利用できるサーバーレスの Jupyter ノートブックです。これで、基盤となるクラスターインフラストラクチャからノートブック環境を分離するため、SSH アクセスの設定やポート転送用のブラウザの設定に時間をかけずにノートブックにアクセスできます。EMR Notebooks は EMR コンソールの左側のナビゲーションにあります。

ノートブックを作成するには、以下の手順を実行してください。

  1. [ノートブック] (EMR コンソールにある) をクリックします。
  2. ご自身のノートブック名を選択します。
  3. [既存のクラスターを選択する] をクリックし、先ほど作成したクラスターを選択します。
  4. [ノートブックを作成する] をクリックします。
  5. ノートブックが準備完了ステータスになったら、[JupyterLabで開く] ボタンをクリックすると、新しいブラウザータブで開くことができます。ご自分の EMR Notebook の名前が付いた既定のノートブックが、デフォルトで作成されます。そのノートブックをクリックすると、カーネルを選択するように求められます。[PySpark] をクリックします。
  6. ノートブックの最初のセルに次の設定を入力し、▸(実行) をクリックします。
    %%configure -f
    {"conf": { "spark.pyspark.virtualenv.enabled": "false" }}
  7. ノートブックに次の PySpark コードを入力し、▸(Run) をクリックします。
    from pyspark.sql import SparkSession
    spark = SparkSession.builder.appName("docker-numpy").getOrCreate()
    sc = spark.sparkContext
    
    import numpy as np
    a = np.arange(15).reshape(3, 5)
    print(a)
    print(np.__version__)

出力は次のスクリーンショットのようになります。使用している numpy は最新 (この記事の執筆時点で 1.18.2) です。

この PySpark コードは、YARN、Docker、作成した pyspark-latest イメージを使用して、EMR 6.0.0 クラスターで実行したものです。EMR Notebooks は、Apache Livy を使用して EMR クラスターに接続します。emr-configuration.json で指定された設定では、EMR クラスターの Spark および Livy インスタンスが、Docker と pyspark-latest Docker イメージをこのクラスターに送信されたすべての Spark ジョブのデフォルトの Docker イメージとして使用するようになっています。このため、numpy をクラスターノードにインストールしなくても使用できます。次のセクションでは、特定のノートブック用にさまざまな Docker イメージを作成し使用する方法について説明します。

特定のノートブックにカスタム Docker イメージを使用する

個々のワークロードには、特定のバージョンのライブラリ依存関係が必要であることがよくあります。個々のノートブックが独自の Docker イメージを使用できるようにするには、まず新しい Docker イメージを作成し、それを Amazon ECR にプッシュします。次に、デフォルトの pyspark-latest イメージではなく、この Docker イメージを使用するようにノートブックを設定します。

次の手順を実行します。

  1. numpy の特定のバージョン (1.17.5) で新しい Dockerfile を作成します。
    FROM amazoncorretto:8
    
    RUN yum -y update
    RUN yum -y install yum-utils
    RUN yum -y groupinstall development
    
    RUN yum list python3*
    RUN yum -y install python3 python3-dev python3-pip python3-virtualenv
    
    RUN python -V
    RUN python3 -V
    
    ENV PYSPARK_DRIVER_PYTHON python3
    ENV PYSPARK_PYTHON python3
    
    RUN pip3 install --upgrade pip
    RUN pip3 install 'numpy==1.17.5'
    
    RUN python3 -c "import numpy as np"
  2. 次のコマンドを使用して、Dockerfile という名前のディレクトリと新しいファイルを作成します。
    $ mkdir numpy-1-17
    $ vi numpy-1-17/Dockerfile
  3. 新しい Dockerfile の内容と次のコードを入力して、Docker イメージを構築します。
    $ docker build -t 'local/numpy-1-17' numpy-1-17/
  4. 次のコマンドを使用して、ローカルで構築したイメージにタグを付け Amazon ECR にアップロードし、123456789123.dkr.ecr.us-east-1.amazonaws.com を Amazon ECR エンドポイントに置き換えます。
    $ docker tag local/numpy-1-17 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:numpy-1-17 
    $ docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:numpy-1-17

    これで、numpy-1-17 Docker イメージが Amazon ECR で使用できるようになったので、新しいノートブックで使用できます。

  1. EMR Notebook に戻り新しいノートブックを作成し、[ファイル]、[新規]、[ノートブック] の順にクリックし、PySpark カーネルを選択します。EMR Notebook にデフォルトではなくこの特定の Docker イメージを使用するように指示するには、次の設定パラメータを使用する必要があります。
  1. ノートブックに次のコードを入力し (123456789123.dkr.ecr.us-east-1.amazonaws.com を Amazon ECR エンドポイントに置き換えます)、▸(Run) を選択します。
     %%configure -f
    {"conf": 
     { 
      "spark.pyspark.virtualenv.enabled": "false",
      "spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE": "123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:numpy-1-17",
      "spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE":"123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:numpy-1-17"
     }
    }

    PySpark コードがバージョン 1.17.5 を使用しているかどうかを確認するには、前と同じ PySpark コードを入力して numpy を使用し、バージョンを出力します。

  1. ノートブックに次のコードを入力し、[実行] をクリックします。
    from pyspark.sql import SparkSession
    spark = SparkSession.builder.appName("docker-numpy").getOrCreate()
    sc = spark.sparkContext
    
    import numpy as np
    a = np.arange(15).reshape(3, 5)
    print(a)
    print(np.__version__)

出力は次のスクリーンショットのようになります。使用している numpy バージョンは、numpy-1-17 Dockerイメージにインストールしたバージョン (1.17.5) です。

まとめ

この投稿では、Amazon EMR 6.0.0 と Docker を使用して、Spark の依存関係の管理を簡素化する方法をご紹介しました。Python の依存関係をパッケージ化する Docker イメージを作成し、Docker を使用するよう設定したクラスターを作成し、EMR Notebookでその Docker イメージを使って PySpark ジョブを実行しました。EMRでのDockerイメージの使用の詳細については、「Run Spark Applications with Docker Using Amazon EMR 6.0.0」に関する EMR ドキュメントをご参照ください。今後も、Amazon EMR の Apache Spark での新たな機能や改善に関する追加情報をお見逃しなく。

 


著者について

Paul Codding はアマゾン ウェブ サービスの EMR シニアプロダクトマネージャです

 

 

 

 

Suthan Phillips は AWS のビッグデータアーキテクトです。Suthan はアーキテクチャ面でのガイダンスを提供するためにお客様と連携し、Amazon EMR 上の複雑なアプリケーションのパフォーマンス強化を達成するお手伝いをしています。余暇には、太平洋岸北西地区でのハイキングと探検を楽しんでいます。