

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# 在 Amazon EMR 6.x 上使用 Docker 執行 Spark 應用程式
<a name="emr-spark-docker"></a>

**注意**  
所述的程序僅適用於 Amazon EMR 6.x 版。

透過 Amazon EMR 6.0.0，Spark 應用程式可以使用 Docker 容器來定義它們的程式庫相依性，而不用在叢集中的個別 Amazon EC2 執行個體上安裝相依項。要執行 Spark 與 Docker，您必須先設定 Docker 登錄檔並在提交 Spark 應用程式時定義其他參數。如需詳細資訊，請參閱[設定 Docker 整合](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-docker.html)。

在提交應用程式時，YARN 會叫用 Docker 以提取指定的 Docker 影像，並執行一個 Docker 容器內的 Spark 應用程式。這可讓您輕鬆定義並隔離依存項目。它可以使用作業執行所需的程式庫來減少引導或準備 Amazon EMR 叢集中執行個體的時間。

## 使用 Docker 執行 Spark 時的考量事項
<a name="emr-spark-docker-considerations"></a>

使用 Docker 執行 Spark 時，請確保符合以下先決條件：
+ `docker` 套件和 CLI 只安裝在核心和任務節點上。
+ 在 Amazon EMR 6.1.0 及更高版本上，您也可以使用下列命令在主節點上安裝 Docker。
  + 

    ```
    sudo yum install -y docker
    sudo systemctl start docker
    ```
+ `spark-submit` 命令應始終從 Amazon EMR 叢集的主執行個體上執行。
+ 用於解析 Docker 影像的 Docker 登錄檔必須使用具有 `container-executor` 分類索引鍵的分類 API 來定義，以便在啟動叢集時定義其他參數：
  + `docker.trusted.registries`
  + `docker.privileged-containers.registries`
+ 若要在 Docker 容器中執行 Spark 應用程式，以下為必要設定選項：
  + `YARN_CONTAINER_RUNTIME_TYPE=docker`
  + `YARN_CONTAINER_RUNTIME_DOCKER_IMAGE={DOCKER_IMAGE_NAME}`
+ 使用 Amazon ECR 擷取 Docker 映像檔時，您必須設定叢集以讓其自行驗證。若要執行此操作，您必須使用下列組態選項：
  + YARN\$1CONTAINER\$1RUNTIME\$1DOCKER\$1CLIENT\$1CONFIG=\$1DOCKER\$1CLIENT\$1CONFIG\$1PATH\$1ON\$1HDFS\$1
+ 在 Amazon EMR 6.1.0 及更高版本中，您不需要在啟用 ECR 自動身分驗證功能時使用列出的命令 `YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG={DOCKER_CLIENT_CONFIG_PATH_ON_HDFS}`。
+ 任何與 Spark 一起使用的 Docker 影像，都必須在該 Docker 影像中安裝 Java。

如需有關先決條件的詳細資訊，請參閱[設定 Docker 整合](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-docker.html)。

## 建立 Docker 映像檔
<a name="emr-spark-docker-image"></a>

Docker 影像是使用 Dockerfile 建立的，該檔案會定義要包含在映像中的套件和組態。以下兩個範例 Dockerfile 使用 PySpark 和 SparkR。

**PySpark Dockerfile**

從此 Dockerfile 建立的 Docker 影像包括 Python 3 和 NumPy Python 套件。該 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 pandas

RUN python3 -c "import numpy as np"
```

**SparkR Dockerfile**

從此 Dockerfile 建立的 Docker 影像包括 R 和 randomForest CRAN 套件。這個 Dockerfile 包括 Amazon Linux 2 和 Amazon Corretto JDK 8。

```
FROM amazoncorretto:8

RUN java -version

RUN yum -y update
RUN amazon-linux-extras install R4

RUN yum -y install curl hostname

#setup R configs
RUN echo "r <- getOption('repos'); r['CRAN'] <- 'http://cran.us.r-project.org'; options(repos = r);" > ~/.Rprofile

RUN Rscript -e "install.packages('randomForest')"
```

如需有關 Dockerfile 語法的更多資訊，請參閱 [Dockerfile 參考文件](https://docs.docker.com/engine/reference/builder/)。

## 使用 Amazon ECR 的 Docker 映像檔
<a name="emr-spark-docker-ECR"></a>

Amazon Elastic Container Registry (Amazon ECR) 是一種完全受管的 Docker 容器登錄檔，可讓您輕鬆存放、管理和部署 Docker 容器映像。使用 Amazon ECR 時，叢集必須設定為信任您的 ECR 執行個體，而且您必須設定身分驗證，才能讓叢集使用來自 Amazon ECR 的 Docker 映像檔。如需詳細資訊，請參閱[設定 YARN 以存取 Amazon ECR](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-docker.html#emr-docker-ECR)。

若要確保 Amazon EMR 主機可以存取 Amazon ECR 中存放的映像，叢集擁有的許可必須來自與執行個體設定檔相關聯的 `AmazonEC2ContainerRegistryReadOnly` 政策。如需詳細資訊，請參閱 [`AmazonEC2ContainerRegistryReadOnly` 政策](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html#AmazonEC2ContainerRegistryReadOnly)。

在此範例中，叢集必須使用下列其他組態來建立，以確保 Amazon ECR 登錄檔受到信任。使用您的 Amazon ECR 端點取代 *123456789123.dkr.ecr.us-east-1.amazonaws.com* 端點。

```
[
  {
    "Classification": "container-executor",
    "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"
        }
      }
    ],
    "Properties": {}
  }
]
```

**搭配使用 PySpark 和 Amazon ECR**

以下範例使用 PySpark Dockerfile，並將被標記並上傳到 Amazon EC。上傳 Dockerfile 後，您可以執行 PySpark 作業並從 Amazon ECR 中參閱 Docker 映像檔。

啟動叢集後，使用 SSH 連接到核心節點，並執行以下命令以從 PySpark Dockerfile 範例建構本機 Docker 影像。

首先，建立一個目錄和一個 Dockerfile。

```
mkdir pyspark
vi pyspark/Dockerfile
```

貼上 PySpark Dockerfile 的內容，並執行以下命令來建構一個 Docker 影像。

```
sudo docker build -t local/pyspark-example pyspark/
```

為範例建立 `emr-docker-examples` ECR 儲存庫。

```
aws ecr create-repository --repository-name emr-docker-examples
```

標記在本機建構的映像並上傳至 ECR，並以您的 ECR 端點取代 *123456789123.dkr.ecr.us-east-1.amazonaws.com*。

```
sudo docker tag local/pyspark-example 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
sudo docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
```

使用 SSH 連線到主節點，並準備具有 `main.py` 檔名的 Python 指令碼。將下列內容貼入 `main.py` 檔案並儲存。

```
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)
```

在 Amazon EMR 6.0.0 中，若要提交作業，請參考 Docker 映像檔的名稱。定義其他組態參數，以確定任務執行使用 Docker 做為執行時間。使用 Amazon ECR 時，`YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG` 必須參考 `config.json` 檔案，該檔案包含用於向 Amazon ECR 進行驗證的登入資料。

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--num-executors 2 \
main.py -v
```

在 Amazon EMR 6.1.0 及更高版本中，若要提交作業，請參考 Docker 映像檔的名稱。啟用 ECR 自動身分驗證時，請執行以下命令。

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:pyspark-example
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--num-executors 2 \
main.py -v
```

當任務完成時，請記下 YARN 應用程式 ID，並使用下列命令來取得 PySpark 任務的輸出。

```
yarn logs --applicationId application_id | grep -C2 '\[\['
LogLength:55
LogContents:
[[ 0  1  2  3  4]
 [ 5  6  7  8  9]
 [10 11 12 13 14]]
```

**搭配使用 SparkR 和 Amazon ECR**

下面的範例使用將被標記並上傳到 ECR 的 SparkR Dockerfile。一旦 Dockerfile 上傳後，您便可以執行 SparkR 作業並從 Amazon ECR 中參考 Docker 映像檔。

啟動叢集後，使用 SSH 連接到核心節點，並執行以下命令以從 SparkR Dockerfile 範例建構本機 Docker 影像。

首先，建立一個目錄和 Dockerfile。

```
mkdir sparkr
vi sparkr/Dockerfile
```

貼上 SparkR Dockerfile 的內容，並執行以下命令來建構一個 Docker 影像。

```
sudo docker build -t local/sparkr-example sparkr/
```

標記在本機建構的映像並上傳至 Amazon ECR，並使用您的 Amazon ECR 端點取代 *123456789123.dkr.ecr.us-east-1.amazonaws.com*。

```
sudo docker tag local/sparkr-example 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
sudo docker push 123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
```

使用 SSH 連接到主節點，並準備具有 `sparkR.R` 名稱的 R 指令碼。將以下內容貼到 `sparkR.R` 檔案。

```
library(SparkR)
sparkR.session(appName = "R with Spark example", sparkConfig = list(spark.some.config.option = "some-value"))

sqlContext <- sparkRSQL.init(spark.sparkContext)
library(randomForest)
# check release notes of randomForest
rfNews()

sparkR.session.stop()
```

在 Amazon EMR 6.0.0 中，若要提交作業，請參考 Docker 映像檔的名稱。定義其他組態參數，以確定任務執行使用 Docker 做為執行時間。使用 Amazon ECR 時，`YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG` 必須參考 `config.json` 檔案，該檔案包含用於向 ECR 進行驗證的登入資料。

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
DOCKER_CLIENT_CONFIG=hdfs:///user/hadoop/config.json
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_CLIENT_CONFIG=$DOCKER_CLIENT_CONFIG \
sparkR.R
```

在 Amazon EMR 6.1.0 及更高版本中，若要提交作業，請參考 Docker 映像檔的名稱。啟用 ECR 自動身分驗證時，請執行以下命令。

```
DOCKER_IMAGE_NAME=123456789123.dkr.ecr.us-east-1.amazonaws.com/emr-docker-examples:sparkr-example
spark-submit --master yarn \
--deploy-mode cluster \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.executorEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_TYPE=docker \
--conf spark.yarn.appMasterEnv.YARN_CONTAINER_RUNTIME_DOCKER_IMAGE=$DOCKER_IMAGE_NAME \
sparkR.R
```

當任務完成後，請記下 YARN 應用程式 ID，並使用下面的命令來取得 SparkR 任務的輸出。此範例包含測試，以確定 randomForest 程式庫、安裝的版本和版本備註都可以使用。

```
yarn logs --applicationId application_id | grep -B4 -A10 "Type rfNews"
randomForest 4.6-14
Type rfNews() to see new features/changes/bug fixes.
Wishlist (formerly TODO):

* Implement the new scheme of handling classwt in classification.

* Use more compact storage of proximity matrix.

* Allow case weights by using the weights in sampling?

========================================================================
Changes in 4.6-14:
```