

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

# 安裝其他核心和程式庫
<a name="emr-jupyterhub-install-kernels-libs"></a>

當您在 Amazon EMR 上建立具有 JupyterHub 的叢集時，Docker 容器上會安裝預設的適用於 Jupyter 的 Python 3 核心，以及適用於 Sparkmagic 的 PySpark 和 Spark 核心。您可以安裝額外的核心。您也可以安裝其他程式庫和套件，然後將其匯入適當的 shell。

## 安裝核心
<a name="emr-jupyterhub-install-kernels"></a>

核心安裝在 Docker 容器中。要達成這件事最簡單的方法，就是以安裝命令來建立 bash 指令碼並將它儲存到主節點，然後使用 `sudo docker exec jupyterhub script_name` 命令，以在 `jupyterhub` 容器中執行指令碼。以下範例指令碼會安裝核心，然後在主節點的核心上安裝幾個程式庫，如此您便可在之後使用 Jupyter 的核心匯入該程式庫。

```
#!/bin/bash

# Install Python 2 kernel
conda create -n py27 python=2.7 anaconda
source /opt/conda/envs/py27/bin/activate
apt-get update
apt-get install -y gcc
/opt/conda/envs/py27/bin/python -m pip install --upgrade ipykernel
/opt/conda/envs/py27/bin/python -m ipykernel install

# Install libraries for Python 2
/opt/conda/envs/py27/bin/pip install paramiko nltk scipy numpy scikit-learn pandas
```

要在容器中安裝核心和程式庫，請開啟連線到主節點的終端機，將指令碼儲存在 `/etc/jupyter/install_kernels.sh`，並在主節點命令列上執行下列命令：

```
sudo docker exec jupyterhub bash /etc/jupyter/install_kernels.sh
```

## 使用程式庫並安裝其他程式庫
<a name="emr-jupyterhub-install-libs"></a>

機器學習的核心組合和適用於 Python 3 的資料科學程式庫，已經連同 JupyterHub 預先安裝於 Amazon EMR 上。您可以使用 `sudo docker exec jupyterhub bash -c "conda list" ` 與 `sudo docker exec jupyterhub bash -c "pip freeze"`。

如果 Spark 任務需要工作者節點上的程式庫，我們建議您使用引導操作來執行程式碼，以在建立叢集時安裝程式庫。叢集建立過程中，在所有叢集節點上執行的引導操作可簡化安裝。在叢集開始執行後，如果您在核心/工作者節點上安裝程式庫，該操作將更顯複雜。我們在此章節提供一個範例的 Python 計畫，說明如何安裝這些程式庫。

在此章節中顯示的引導操作和 Python 計畫範例，會在所有節點上使用儲存至 Amazon S3 的 bash 程式碼以安裝該程式庫。

下列範例中參考的指令碼使用 `pip` 安裝 paramiko、nltk、scipy、scikit-learn 以及適用於 Python 3 核心的 pandas：

```
#!/bin/bash

sudo python3 -m pip install boto3 paramiko nltk scipy scikit-learn pandas
```

在您建立指令碼之後，請將其上傳至 Amazon S3 中的位置，例如 `s3://amzn-s3-demo-bucket/install-my-jupyter-libraries.sh`。如需詳細資訊，請參閱《Amazon Simple Storage Service 使用者指南》**中的[上傳物件](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html)，以便您可以在引導操作或 Python 程式中使用此物件。

**使用 建立叢集時，指定在所有節點上安裝程式庫的引導操作 AWS CLI**

1. 建立類似先前範例的指令碼，並將它儲存至 Amazon S3 中的位置。我們使用範例 `s3://amzn-s3-demo-bucket/install-my-jupyter-libraries.sh`。

1. 使用 JupyterHub 來建立叢集，然後利用 `--bootstrap-actions` 選項的 `Path` 引數，來指定指令碼的位置，如下列範例所示：
**注意**  
包含 Linux 行接續字元 (\$1) 是為了提高可讀性。它們可以在 Linux 命令中移除或使用。對於 Windows，請將其移除或取代為插入符號 (^)。

   ```
   aws emr create-cluster --name="MyJupyterHubCluster" --release-label emr-5.36.2 \
   --applications Name=JupyterHub --log-uri s3://amzn-s3-demo-bucket/MyJupyterClusterLogs \
   --use-default-roles --instance-type m5.xlarge --instance-count 2 --ec2-attributes KeyName=MyKeyPair \
   --bootstrap-actions Path=s3://amzn-s3-demo-bucket/install-my-jupyter-libraries.sh,Name=InstallJupyterLibs
   ```

**若要在使用主控台建立叢集時指定在所有節點上安裝程式庫的引導操作**

1. 導覽至新的 Amazon EMR 主控台，然後從側邊導覽選取**切換至舊主控台**。如需有關切換至舊主控台時預期情況的詳細資訊，請參閱[使用舊主控台](https://docs.aws.amazon.com/emr/latest/ManagementGuide/whats-new-in-console.html#console-opt-in)。

1. 選擇 **Create cluster (建立叢集)**，然後選擇 **Go to advanced options (前往進階選項)**。

1. 為您的應用程式指定適用的 **Software and Steps (軟體和步驟)** 和 **Hardware (硬體)** 設定。

1. 在 **General Cluster Settings (一般叢集設定)** 畫面中，展開 **Bootstrap Actions (引導操作)**。

1. 在 **Add bootstrap action (新增引導操作)** 中，選擇 **Custom action (自訂動作)**、**Configure and add (設定和新增)**。

1. 在 **Name (名稱)** 中，輸入易記的名稱。針對**指令碼位置**，輸入指令碼在 Amazon S3 中的位置 （我們使用的範例為 *s3：//amzn-s3-demo-bucket/install-my-jupyter-libraries.sh)。*讓 **Optional arguments (選擇性引數)** 留白，然後選擇 **Add (新增)**。

1. 為您的叢集指定其他設定，然後選擇 **Next (下一步)**。

1. 指定安全性設定，然後選擇 **Create cluster (建立叢集)**。

**Example 在執行中叢集的核心節點上安裝程式庫**  
在 Jupyter 中的主節點上安裝程式庫之後，您可以在執行中的核心節點上以各種方式安裝程式庫。以下範例顯示了本機電腦上執行的已撰寫 Python 計畫。當您在本機執行 Python 程式時，它會使用 `AWS-RunShellScript` AWS Systems Manager 執行範例指令碼，如本節稍早所示，在叢集的核心節點上安裝程式庫。  

```
import argparse
import time
import boto3


def install_libraries_on_core_nodes(cluster_id, script_path, emr_client, ssm_client):
    """
    Copies and runs a shell script on the core nodes in the cluster.

    :param cluster_id: The ID of the cluster.
    :param script_path: The path to the script, typically an Amazon S3 object URL.
    :param emr_client: The Boto3 Amazon EMR client.
    :param ssm_client: The Boto3 AWS Systems Manager client.
    """
    core_nodes = emr_client.list_instances(
        ClusterId=cluster_id, InstanceGroupTypes=["CORE"]
    )["Instances"]
    core_instance_ids = [node["Ec2InstanceId"] for node in core_nodes]
    print(f"Found core instances: {core_instance_ids}.")

    commands = [
        # Copy the shell script from Amazon S3 to each node instance.
        f"aws s3 cp {script_path} /home/hadoop",
        # Run the shell script to install libraries on each node instance.
        "bash /home/hadoop/install_libraries.sh",
    ]
    for command in commands:
        print(f"Sending '{command}' to core instances...")
        command_id = ssm_client.send_command(
            InstanceIds=core_instance_ids,
            DocumentName="AWS-RunShellScript",
            Parameters={"commands": [command]},
            TimeoutSeconds=3600,
        )["Command"]["CommandId"]
        while True:
            # Verify the previous step succeeded before running the next step.
            cmd_result = ssm_client.list_commands(CommandId=command_id)["Commands"][0]
            if cmd_result["StatusDetails"] == "Success":
                print(f"Command succeeded.")
                break
            elif cmd_result["StatusDetails"] in ["Pending", "InProgress"]:
                print(f"Command status is {cmd_result['StatusDetails']}, waiting...")
                time.sleep(10)
            else:
                print(f"Command status is {cmd_result['StatusDetails']}, quitting.")
                raise RuntimeError(
                    f"Command {command} failed to run. "
                    f"Details: {cmd_result['StatusDetails']}"
                )


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("cluster_id", help="The ID of the cluster.")
    parser.add_argument("script_path", help="The path to the script in Amazon S3.")
    args = parser.parse_args()

    emr_client = boto3.client("emr")
    ssm_client = boto3.client("ssm")

    install_libraries_on_core_nodes(
        args.cluster_id, args.script_path, emr_client, ssm_client
    )


if __name__ == "__main__":
    main()
```