

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 安装其它内核和库
<a name="emr-jupyterhub-install-kernels-libs"></a>

当你 JupyterHub 在 Amazon EMR 上创建集群时，Jupyter 的默认 Python 3 内核以及 Sparkmagic 的 Spark 内核将 PySpark 安装在 Docker 容器上。可以安装其它内核。还可以安装其它库和软件包，然后将它们导入相应的 shell。

## 安装内核
<a name="emr-jupyterhub-install-kernels"></a>

内核安装在 Docker 容器中。安装内核最简单的方式是，创建包含安装命令的清除脚本，将脚本保存到主节点，然后使用 `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>

Amazon EMR JupyterHub 上预装了一组适用于 Python 3 的核心机器学习和数据科学库。可以使用 `sudo docker exec jupyterhub bash -c "conda list" ` 和 `sudo docker exec jupyterhub bash -c "pip freeze"`。

如果 Spark 作业需要 Worker 节点上的库，建议使用引导操作运行脚本以在创建集群时安装库。集群创建过程中，引导操作将在所有集群节点上运行，这将简化安装。如果于集群运行后在核心/Worker 节点上安装库，则操作更复杂。我们在此部分中提供了示例 Python 程序以演示如何安装这些库。

此部分中演示的引导操作和 Python 程序示例都使用保存到 Amazon S3 的清除脚本在所有节点上安装库。

以下示例中引用的脚本将通过 `pip` 安装适用于 Python 3 内核的 paramiko、nltk、scipy、scikit-learn 和 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 新控制台，然后从侧面导航栏中选择**切换到旧控制台**。有关切换到旧控制台后预期情况的更多信息，请参阅 [Using the old console](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. 对于**名称**，输入易于理解的名称。对于**脚本位置**，请输入脚本在 Amazon S3 中的位置（我们使用的示例是 *s3://amzn-s3-demo-bucket/ install-my-jupyter-libraries .sh*）。保留 **Optional arguments (可选参数)** 为空，然后选择 **Add (添加)**。

1. 指定集群的其它设置，然后选择 **Next (下一步)**。

1. 指定安全设置，然后选择 **Create cluster (创建集群)**。

**Example 在运行集群的核心节点上安装库**  
在 Jupyter 内的主节点上安装库之后，可以通过不同的方式将库安装在运行的核心节点上。以下示例显示了编写为在本地计算机上运行的 Python 程序。当您在本地运行 Python 程序时，它会使用 of AWS Systems Manager 来运行示例脚本，如本节前面所示，该脚本将在集群的核心节点上安装库。`AWS-RunShellScript`  

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