

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

# 使用自托管式 Jupyter notebook
<a name="managed-endpoints-self-hosted"></a>

您可以在 Amazon EC2 实例上托管和管理 Jupyter 或 JupyterLab 笔记本电脑，也可以作为*自托管 Jupyter 笔记本在自己的 Amazon EKS 集群上托管*和管理。然后，您可以使用自托管式 Jupyter notebook 运行交互式工作负载。以下各节介绍在 Amazon EKS 集群上设置和部署自托管式 Jupyter notebook 的过程。



**Topics**
+ [创建安全组](#managed-endpoints-self-hosted-security)
+ [创建 Amazon EMR on EKS 交互式端点](#managed-endpoints-self-hosted-create-me)
+ [检索交互式端点的网关服务器 URL](#managed-endpoints-self-hosted-gateway)
+ [检索身份验证令牌以连接到交互式端点](#managed-endpoints-self-hosted-auth)
+ [示例：部署 JupyterLab 笔记本](#managed-endpoints-self-hosted-example)
+ [删除自托管式 Jupyter notebook](#managed-endpoints-self-hosted-cleanup)

## 创建安全组
<a name="managed-endpoints-self-hosted-security"></a>

在创建交互式终端节点并运行自托管的 Jupyter 或 JupyterLab 笔记本之前，必须创建一个安全组来控制笔记本和交互式终端节点之间的流量。要使用 Amazon EC2 控制台或 Amazon EC2 SDK 创建安全组，请参阅《Amazon EC2 用户指南》**中[创建安全组](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html#creating-security-group)的步骤。您应该在要部署 Notebook 服务器的 VPC 中创建安全组。

要按照本指南中的示例进行操作，请使用与 Amazon EKS 集群相同的 VPC。如果您想将笔记本电脑托管在不同于 Amazon EKS 集群的 VPC 的 VPC 中，则可能需要在这两 VPCs者之间创建对等连接。有关在两者之间创建对等连接的步骤 VPCs，请参阅 Amazon [VPC 入门指南中的创建 VPC 对等连接](https://docs.aws.amazon.com/vpc/latest/peering/create-vpc-peering-connection.html)。

您需要安全组的 ID 才能在下一步中[创建 Amazon EMR on EKS 交互式端点](https://docs.aws.amazon.com/)。

## 创建 Amazon EMR on EKS 交互式端点
<a name="managed-endpoints-self-hosted-create-me"></a>

为 Notebook 创建安全组后，使用 [为虚拟集群创建交互式端点](create-managed-endpoint.md) 中的步骤创建交互式端点。您必须提供在 [创建安全组](#managed-endpoints-self-hosted-security) 中为 Notebook 创建的安全组 ID。

在以下配置覆盖设置中插入安全 ID 来代替以下配置：*your-notebook-security-group-id*

```
--configuration-overrides '{
    "applicationConfiguration": [
        {
            "classification": "endpoint-configuration",
            "properties": {
                "notebook-security-group-id": "your-notebook-security-group-id"
            }
        }
    ],
    "monitoringConfiguration": {
    ...'
```

## 检索交互式端点的网关服务器 URL
<a name="managed-endpoints-self-hosted-gateway"></a>

创建交互式端点后，使用 AWS CLI中的 `describe-managed-endpoint` 命令检索网关服务器 URL。您需要此 URL 才能将 Notebook 连接到端点。网关服务器 URL 是私有端点。

```
aws emr-containers describe-managed-endpoint \
--region region \
--virtual-cluster-id virtualClusterId \
--id endpointId
```

最初，您的端点处于 **CREATING** 状态。几分钟后，它会转换到 **ACTIVE** 状态。端点的状态为 **ACTIVE** 时即可使用。

记下 `aws emr-containers describe-managed-endpoint` 命令从活动端点返回的 `serverUrl` 属性。[部署自托管 Jupyter](https://docs.aws.amazon.com/) 或笔记本时，需要此 URL 才能将笔记本电脑连接到终端节点。 JupyterLab 

## 检索身份验证令牌以连接到交互式端点
<a name="managed-endpoints-self-hosted-auth"></a>

要从 Jupyter 或 JupyterLab 笔记本连接到交互式终端节点，必须使用 API 生成会话令牌。`GetManagedEndpointSessionCredentials`此令牌作为连接到交互式端点服务器的身份验证证明。

下面的输出示例将更详细地解释以下命令。

```
aws emr-containers get-managed-endpoint-session-credentials \
--endpoint-identifier endpointArn \
--virtual-cluster-identifier virtualClusterArn \
--execution-role-arn executionRoleArn \
--credential-type "TOKEN" \
--duration-in-seconds durationInSeconds \
--region region
```

**`endpointArn`**  
端点 ARN。您可以在 `describe-managed-endpoint` 调用中找到 ARN。

**`virtualClusterArn`**  
虚拟集群的 ARN。

**`executionRoleArn`**  
执行角色的 ARN。

**`durationInSeconds`**  
令牌的有效持续时间（以秒为单位）。默认持续时间为 15 分钟 (`900`)，最大持续时间为 12 小时 (`43200`)。

**`region` **  
与端点相同的区域。

输出应与以下示例类似。记下[部署自托管 Jupyter 或笔记本](https://docs.aws.amazon.com/)时将使用的`session-token`值。 JupyterLab 

```
{
    "id": "credentialsId",
    "credentials": {
        "token": "session-token"
    },
    "expiresAt": "2022-07-05T17:49:38Z"
}
```

## 示例：部署 JupyterLab 笔记本
<a name="managed-endpoints-self-hosted-example"></a>

完成上述步骤后，您可以尝试此示例过程，使用您的交互式终端节点将 JupyterLab 笔记本部署到 Amazon EKS 集群中。

1. 创建命名空间来运行 Notebook 服务器。

1. 在本地创建文件 `notebook.yaml`，包含以下内容。文件内容说明如下。

   ```
   apiVersion: v1
   kind: Pod
   metadata:
     name: jupyter-notebook
     namespace: namespace
   spec:
     containers:
     - name: minimal-notebook
       image: jupyter/all-spark-notebook:lab-3.1.4 # open source image 
       ports:
       - containerPort: 8888
       command: ["start-notebook.sh"]
       args: ["--LabApp.token=''"]
       env:
       - name: JUPYTER_ENABLE_LAB
         value: "yes"
       - name: KERNEL_LAUNCH_TIMEOUT
         value: "400"
       - name: JUPYTER_GATEWAY_URL
         value: "serverUrl"
       - name: JUPYTER_GATEWAY_VALIDATE_CERT
         value: "false"
       - name: JUPYTER_GATEWAY_AUTH_TOKEN
         value: "session-token"
   ```

   如果您要将 Jupyter notebook 部署到仅限 Fargate 的集群，请使用 `role` 标签标记 Jupyter Pod，如以下示例所示：

   ```
   ...
   metadata:
     name: jupyter-notebook
     namespace: default
     labels:
       role: example-role-name-label
   spec:
               ...
   ```  
**`namespace`**  
Notebook 部署所在的 Kubernetes 命名空间。  
**`serverUrl`**  
`describe-managed-endpoint` 命令在 [检索交互式端点的网关服务器 URL](#managed-endpoints-self-hosted-gateway) 中返回的 `serverUrl` 属性。  
**`session-token`**  
`get-managed-endpoint-session-credentials` 命令在 [检索身份验证令牌以连接到交互式端点](#managed-endpoints-self-hosted-auth) 中返回的 `session-token` 属性。  
**`KERNEL_LAUNCH_TIMEOUT`**  
交互式端点等待内核进入 **RUNNING** 状态的时间（以秒为单位）。将内核启动超时设置为适当的值（最长 400 秒），确保有足够的时间完成内核启动。  
**`KERNEL_EXTRA_SPARK_OPTS`**  
或者，您可以为 Spark 内核传递其他 Spark 配置。使用 Spark 配置属性的值设置此环境变量，如以下示例所示：  

   ```
   - name: KERNEL_EXTRA_SPARK_OPTS
     value: "--conf spark.driver.cores=2
             --conf spark.driver.memory=2G
             --conf spark.executor.instances=2
             --conf spark.executor.cores=2
             --conf spark.executor.memory=2G
             --conf spark.dynamicAllocation.enabled=true
             --conf spark.dynamicAllocation.shuffleTracking.enabled=true
             --conf spark.dynamicAllocation.minExecutors=1
             --conf spark.dynamicAllocation.maxExecutors=5
             --conf spark.dynamicAllocation.initialExecutors=1
             "
   ```

1. 将 Pod 规范部署到 Amazon EKS 集群：

   ```
   kubectl apply -f notebook.yaml -n namespace
   ```

   这将启动一台在 EKS 交互式终端节点上连接到你的 Amazon EMR 的最小 JupyterLab 笔记本电脑。等到 Pod 状态变成 **RUNNING**。您可以使用以下命令检查其状态：

   ```
   kubectl get pod jupyter-notebook -n namespace
   ```

   Pod 准备就绪时，`get pod` 命令会返回类似于以下内容的输出：

   ```
   NAME              READY  STATUS   RESTARTS  AGE
   jupyter-notebook  1/1    Running  0         46s
   ```

1. 将 Notebook 安全组附加到调度 Notebook 的节点。

   1. 首先，使用 `describe pod` 命令确定调度 `jupyter-notebook` Pod 的节点。

      ```
      kubectl describe pod jupyter-notebook -n namespace
      ```

   1. 在 [https://console.aws.amazon.com/eks/home\$1/](https://console.aws.amazon.com/eks/home#/clusters) clusters 中打开 Amazon EKS 控制台。

   1. 导航到 Amazon EKS 集群的**计算**选项卡，然后选择 `describe pod` 命令标识的节点。选择节点的实例 ID。

   1. 在**操作**菜单中，选择**安全** > **更改安全组**，附加您在 [创建安全组](#managed-endpoints-self-hosted-security) 中创建的安全组。

   1. 如果您要在上部署 Jupyter 笔记本窗格 AWS Fargate，请使用角色[]()标签创建一个应用于 Jupyter 笔记本窗格：

      ```
      cat >my-security-group-policy.yaml <<EOF
      apiVersion: vpcresources.k8s.aws/v1beta1
      kind: SecurityGroupPolicy
      metadata:
        name: example-security-group-policy-name
        namespace: default
      spec:
        podSelector:
          matchLabels:
            role: example-role-name-label
        securityGroups:
          groupIds:
            - your-notebook-security-group-id
      EOF
      ```

1. 现在，进行端口转发，这样你就可以在本地访问 JupyterLab 接口：

   ```
   kubectl port-forward jupyter-notebook 8888:8888 -n namespace
   ```

   运行后，导航到您的本地浏览器并访问`localhost:8888`以查看 JupyterLab 界面：  
![\[JupyterLab 开始屏幕的屏幕截图。\]](http://docs.aws.amazon.com/zh_cn/emr/latest/EMR-on-EKS-DevelopmentGuide/images/emr-on-eks-Jupyter-notebook-start.png)

1. 从 JupyterLab，创建一个新的 Scala 笔记本。下面是一个示例代码片段，您可以运行它来近似计算 Pi 的值：

   ```
   import scala.math.random
   import org.apache.spark.sql.SparkSession
   
   /** Computes an approximation to pi */
   val session = SparkSession
     .builder
     .appName("Spark Pi")
     .getOrCreate()
   
   val slices = 2
   // avoid overflow
   val n = math.min(100000L * slices, Int.MaxValue).toInt 
    
   val count = session.sparkContext
   .parallelize(1 until n, slices)
   .map { i =>
     val x = random * 2 - 1
     val y = random * 2 - 1
     if (x*x + y*y <= 1) 1 else 0
   }.reduce(_ + _)
   
   println(s"Pi is roughly ${4.0 * count / (n - 1)}")
   session.stop()
   ```  
![\[中 Scala 笔记本示例代码的屏幕截图。 JupyterLab\]](http://docs.aws.amazon.com/zh_cn/emr/latest/EMR-on-EKS-DevelopmentGuide/images/emr-on-eks-Jupyter-notebook-scala-program.png)

## 删除自托管式 Jupyter notebook
<a name="managed-endpoints-self-hosted-cleanup"></a>

准备好删除自托管式 Notebook 时，也可以删除交互式端点和安全组。按以下顺序执行操作：

1. 使用以下命令删除 `jupyter-notebook` Pod：

   ```
   kubectl delete pod jupyter-notebook -n namespace
   ```

1. 然后，使用 `delete-managed-endpoint` 命令删除交互式端点。有关删除交互式端点的步骤，请参阅 [删除交互式端点](delete-managed-endpoint.md)。最初，您的端点处于 **TERMINATING** 状态。清理完所有资源后，它将转换到 **TERMINATED** 状态。

1. 如果您不打算将在 [创建安全组](#managed-endpoints-self-hosted-security) 中创建的 Notebook 安全组用于其他 Jupyter notebook 部署，则可以将其删除。有关更多信息，请参阅《Amazon EC2 用户指南》中的[删除安全组](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/working-with-security-groups.html#deleting-security-group)。