

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# Amazon EMR의 Jupyter Notebook
<a name="emr-jupyter"></a>

[Jupyter Notebook](https://jupyter.org/)은 실시간 코드, 수식, 가상화 및 설명 텍스트가 포함된 문서를 생성 및 공유하는 데 사용할 수 있는 오픈 소스 웹 애플리케이션입니다. Amazon EMR은 Jupyter Notebook으로 작업할 수 있는 세 가지 옵션을 제공합니다.

**Topics**
+ [EMR Studio](emr-studio-jupyter.md)
+ [EMR 노트북](emr-jupyter-emr-managed-notebooks.md)
+ [JupyterHub](emr-jupyterhub.md)

# EMR Studio
<a name="emr-studio-jupyter"></a>

Amazon EMR Studio는 Amazon EMR 클러스터에서 실행되는 완전관리형 [Jupyter Notebook](https://jupyter.org/)을 위한 웹 기반 통합 개발 환경(IDE)입니다. 팀이 R, Python, Scala 및 PySpark로 작성된 애플리케이션을 개발, 시각화 및 디버깅할 수 있도록 EMR Studio를 설정할 수 있습니다.

Amazon EMR에서 Jupyter Notebook을 사용할 때는 EMR Studio를 사용하는 것이 좋습니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [EMR Studio](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-studio.html)를 참조하세요.

# Jupyter Notebook에 기반한 Amazon EMR 노트북
<a name="emr-jupyter-emr-managed-notebooks"></a>

EMR Notebooks는 Amazon EMR 콘솔에 내장된 [Jupyter Notebook](https://jupyter.org/) 환경으로, 이를 통해 Jupyter Notebook을 빠르게 생성하고 Spark 클러스터에 연결한 후 콘솔에서 Jupyter Notebook 편집기를 열어 쿼리와 코드를 원격으로 실행할 수 있습니다. EMR 노트북은 안정적인 스토리지, 빠른 액세스 및 유연성을 위해 클러스터와 독립적으로 Amazon S3에 저장됩니다. 여러 노트북을 열고, 단일 클러스터에 여러 노트북을 연결하며, 서로 다른 클러스터에서 노트북을 재사용할 수 있습니다.

자세한 내용은 *Amazon EMR 관리 안내서*에서 [EMR 노트북](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-managed-notebooks.html)을 참조하세요.

# JupyterHub
<a name="emr-jupyterhub"></a>

[Jupyter Notebook](https://jupyter.org/)은 실시간 코드, 수식, 가상화 및 설명 텍스트가 포함된 문서를 생성 및 공유하는 데 사용할 수 있는 오픈 소스 웹 애플리케이션입니다. [JupyterHub](https://jupyterhub.readthedocs.io/en/latest/)를 사용하면 단일 사용자 Jupyter Notebook 서버의 여러 인스턴스를 호스팅할 수 있습니다. JupyterHub를 사용하여 클러스터를 생성하면 Amazon EMR이 클러스터의 프라이머리 노드에 Docker 컨테이너를 생성합니다. JupyterHub, Jupyter에 필요한 모든 구성 요소 및 [Sparkmagic](https://github.com/jupyter-incubator/sparkmagic/blob/master/README.md)이 컨테이너 내에서 실행됩니다.

Sparkmagic은 Jupyter Notebook이 Spark용 REST 서버인 [Apache Livy](emr-livy.md)를 통해 Amazon EMR에서 실행되는 [Apache Spark](https://aws.amazon.com/big-data/what-is-spark/)와 상호 작용할 수 있도록 하는 커널 라이브러리입니다. Spark 및 Apache Livy는 JupyterHub를 사용하여 클러스터 생성 시 자동으로 설치됩니다. Jupyter용 기본 Python 3 커널은 Sparkmagic에서 제공하는 PySpark 3, PySpark 및 Spark 커널과 함께 사용할 수 있습니다. 이러한 커널을 사용하면 Python 및 Scala를 사용하여 애드혹 Spark 코드 및 대화형 SQL 쿼리를 실행할 수 있습니다. Docker 컨테이너 내에 추가 커널을 수동으로 설치할 수 있습니다. 자세한 내용은 [추가 커널 및 라이브러리 설치](emr-jupyterhub-install-kernels-libs.md) 단원을 참조하십시오.

다음 다이어그램은 노트북 사용자 및 관리자용 해당 인증 방법을 사용하여 Amazon EMR에 있는 JupyterHub의 구성 요소를 보여줍니다. 자세한 내용은 [Jupyter Notebook 사용자 및 관리자 추가](emr-jupyterhub-user-access.md) 단원을 참조하십시오.

![\[JupyterHub architecture on EMR showing user authentication and component interactions.\]](http://docs.aws.amazon.com/ko_kr/emr/latest/ReleaseGuide/images/jupyter-arch.png)


다음 테이블에는 Amazon EMR이 JupyterHub를 통해 설치하는 구성 요소와 함께 Amazon EMR 7.x 시리즈의 최신 릴리스에 포함된 JupyterHub의 버전이 나열되어 있습니다.

이 릴리스에서 JupyterHub와 함께 설치된 구성 요소의 버전은 [릴리스 7.12.0 구성 요소 버전을 참조하세요](emr-7120-release.md).


**emr-7.12.0용 JupyterHub 버전 정보**  

| Amazon EMR 릴리스 레이블 | JupyterHub 버전 | JupyterHub와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-7.12.0 | JupyterHub 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-hdfs-zkfc, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 

다음 테이블에는 Amazon EMR이 JupyterHub를 통해 설치하는 구성 요소와 함께 Amazon EMR 6.x 시리즈의 최신 릴리스에 포함된 JupyterHub의 버전이 나열되어 있습니다.

이 릴리스에서 JupyterHub와 함께 설치된 구성 요소의 버전은 [릴리스 6.15.0 구성 요소 버전](emr-6150-release.md)을 참조하세요.


**emr-6.15.0용 JupyterHub 버전 정보**  

| Amazon EMR 릴리스 레이블 | JupyterHub 버전 | JupyterHub와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-6.15.0 | JupyterHub 1.5.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 

다음 테이블에는 Amazon EMR이 JupyterHub를 통해 설치하는 구성 요소와 함께 Amazon EMR 5.x 시리즈의 최신 릴리스에 포함된 JupyterHub의 버전이 나열되어 있습니다.

이 릴리스에서 JupyterHub와 함께 설치된 구성 요소의 버전은 [릴리스 5.36.2 구성 요소 버전](emr-5362-release.md)을 참조하세요.


**emr-5.36.2용 JupyterHub 버전 정보**  

| Amazon EMR 릴리스 레이블 | JupyterHub 버전 | JupyterHub와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-5.36.2 | JupyterHub 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 

Amazon EMR의 JupyterHub에 포함되어 있는 Python 3 커널은 3.6.4입니다.

`jupyterhub` 컨테이너 내에 설치되어 있는 라이브러리는 Amazon EMR 릴리스 버전 및 Amazon EC2 AMI 버전 간에 다를 수 있습니다.

**`conda`를 사용하여 설치된 라이브러리를 나열하려면**
+ 마스터 노드 명령줄에서 다음 명령을 실행합니다.

  ```
  sudo docker exec jupyterhub bash -c "conda list"
  ```

**`pip`를 사용하여 설치된 라이브러리를 나열하려면**
+ 마스터 노드 명령줄에서 다음 명령을 실행합니다.

  ```
  sudo docker exec jupyterhub bash -c "pip freeze"
  ```

**Topics**
+ [JupyterHub를 사용하여 클러스터 생성](emr-jupyterhub-launch.md)
+ [Amazon EMR에서 JupyterHub를 사용할 때 고려 사항](emr-jupyterhub-considerations.md)
+ [JupyterHub 구성](emr-jupyterhub-configure.md)
+ [Amazon S3에서 노트북의 지속성 구성](emr-jupyterhub-s3.md)
+ [프라이머리 노드 및 노트북 서버에 연결](emr-jupyterhub-connect.md)
+ [JupyterHub 구성 및 관리](emr-jupyterhub-administer.md)
+ [Jupyter Notebook 사용자 및 관리자 추가](emr-jupyterhub-user-access.md)
+ [추가 커널 및 라이브러리 설치](emr-jupyterhub-install-kernels-libs.md)
+ [JupyterHub 릴리스 기록](JupyterHub-release-history.md)

# JupyterHub를 사용하여 클러스터 생성
<a name="emr-jupyterhub-launch"></a>

 AWS Management Console AWS Command Line Interface또는 Amazon EMR API를 사용하여 JupyterHub로 Amazon EMR 클러스터를 생성할 수 있습니다. 단계 완료 후 자동으로 종료되는 옵션( AWS CLI의 `--auto-terminate` 옵션)을 사용하여 클러스터가 생성되지 않도록 해야 합니다. 또한, 관리자 및 노트북 사용자가 클러스터 생성 시 사용된 키 쌍에 액세스할 수 있어야 합니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [SSH 보안 인증을 위해 키 페어 사용](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-access-ssh.html)을 참조하세요.

## 콘솔을 사용하여 JupyterHub를 포함하는 클러스터 생성
<a name="emr-jupyterhub-launch-console"></a>

다음 절차를 사용하면 Amazon EMR 콘솔의 **고급 옵션**을 사용하여 JupyterHub가 설치된 클러스터를 생성합니다.

**Amazon EMR 콘솔을 사용하여 JupyterHub가 설치된 Amazon EMR 클러스터를 생성하는 방법**

1. 새 Amazon EMR 콘솔로 이동하고 측면 탐색에서 **이전 콘솔로 전환**을 선택합니다. 이전 콘솔로 전환할 때 예상되는 사항에 대한 자세한 내용은 [이전 콘솔 사용](https://docs.aws.amazon.com/emr/latest/ManagementGuide/whats-new-in-console.html#console-opt-in)을 참조하세요.

1. **클러스터 생성** 및 **고급 옵션으로 이동**을 선택합니다.

1. **소프트웨어 구성**에서 다음을 수행합니다.
   + **릴리스**에서는 emr-5.36.2를 선택하고 JupyterHub를 선택합니다.
   + Spark를 사용하는 경우 Glue 데이터 카탈로그를 Spark SQL의 AWS 메타스토어로 사용하려면 **Spark 테이블 메타데이터에 사용을** 선택합니다. 자세한 내용은 [Amazon EMR에서 Spark와 함께 AWS Glue 데이터 카탈로그 사용](emr-spark-glue.md) 단원을 참조하십시오.
   + **소프트웨어 설정 편집**에서 **구성 입력**을 선택하고 값을 지정하거나, **S3에서 JSON 로드**를 선택하고 JSON 구성 파일을 지정합니다. 자세한 내용은 [JupyterHub 구성](emr-jupyterhub-configure.md) 단원을 참조하십시오.

1. **단계 추가(선택 사항)**에서 클러스터가 생성될 때 실행할 단계를 구성하고, **마지막 단계가 완료된 후 클러스터 자동 종료**가 선택되어 있지 않은 상태에서 **다음**을 선택합니다.

1. **하드웨어 구성** 옵션을 선택하고 **다음**을 선택합니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [클러스터 하드웨어 및 네트워킹 구성](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-plan-instances.html)을 참조하세요.

1. **일반 클러스터 설정**에 대한 옵션을 선택하고 **다음**을 선택합니다.

1. 키 쌍을 지정한 상태로 **보안 옵션**을 선택하고 **클러스터 생성**을 선택합니다.

## 를 사용하여 JupyterHub로 클러스터 생성 AWS CLI
<a name="emr-jupyterhub-launch-cli"></a>

JupyterHub를 포함하는 클러스터를 시작하려면 `aws emr create-cluster` 명령을 사용하고 `--applications` 옵션에서 `Name=JupyterHub`를 지정합니다. 다음 예에서는 두 개의 EC2 인스턴스(마스터 하나와 코어 인스턴스 하나)를 사용하여 Amazon EMR에서 JupyterHub 클러스터를 실행합니다. 또한 디버깅이 활성화되어 있으며 로그는 `--log-uri`에 의해 지정된 대로 Amazon S3 위치에 저장됩니다. 지정된 키 페어는 클러스터에 있는 Amazon EC2 인스턴스에 액세스할 수 있는 권한만 부여합니다.

**참고**  
가독성을 위해 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
```

# Amazon EMR에서 JupyterHub를 사용할 때 고려 사항
<a name="emr-jupyterhub-considerations"></a>

Amazon EMR에서 JupyterHub를 사용할 때는 다음을 고려합니다.
+ 
**주의**  
사용자 노트북 및 파일은 마스터 노드에 있는 파일 시스템에 저장됩니다. 이 시스템은 클러스터 종료 시 유지되지 않는 임시 스토리지입니다. 클러스터가 종료되면 백업하지 않은 경우 이 데이터를 잃게 됩니다. `cron` 작업이나 해당 애플리케이션에 적합한 다른 수단을 사용하여 정기적인 백업을 예약해 두는 것이 좋습니다.  
또한, 컨테이너를 다시 시작하는 경우 컨테이너 내 구성 변경 사항도 유지되지 않습니다. 스크립트를 구성하거나 아니면 컨테이너 구성을 자동화하여 보다 쉽게 사용자 지정 구성을 재현할 수 있도록 하는 것이 좋습니다.
+ Amazon EMR 보안 구성을 사용하여 설정된 Kerberos 인증은 지원되지 않습니다.
+ [OAuthenticator](https://github.com/jupyterhub/oauthenticator)는 지원되지 않습니다.

# JupyterHub 구성
<a name="emr-jupyterhub-configure"></a>

클러스터 프라이머리 노드에 연결하고 구성 파일을 편집하면 Amazon EMR에 있는 JupyterHub 및 개별 사용자 노트북의 구성을 사용자 지정할 수 있습니다. 값을 변경한 후에는 `jupyterhub` 컨테이너를 다시 시작하세요.

다음 파일의 속성을 수정하여 JupyterHub 및 개별 Jupyter Notebook을 구성합니다.
+ `jupyterhub_config.py` - 기본적으로 이 파일은 프라이머리 노드의 `/etc/jupyter/conf/` 디렉터리에 저장됩니다. 자세한 내용은 JupyterHub 설명서에서 [Configuration basics](http://jupyterhub.readthedocs.io/en/latest/getting-started/config-basics.html)를 참조하세요.
+ `jupyter_notebook_config.py` - 이 파일은 기본적으로 `/etc/jupyter/` 디렉터리에 저장되며 `jupyterhub` 컨테이너에 기본값으로 복사됩니다. 자세한 내용은 Jupyter Notebook 설명서의 [Config file and command line options](https://jupyter-notebook.readthedocs.io/en/5.7.4/config.html)를 참조하세요.

`jupyter-sparkmagic-conf` 구성 분류를 사용하여 Sparkmagic을 사용자 지정할 수도 있습니다. 그러면 Sparkmagic에 맞게 `config.json` 파일의 값이 업데이트됩니다. 사용 가능한 설정에 대한 자세한 내용은 [GitHub의 example\$1config.json](https://github.com/jupyter-incubator/sparkmagic/blob/master/sparkmagic/example_config.json)을 참조하세요. Amazon EMR에서 애플리케이션과 함께 구성 분류를 사용하는 방법에 대한 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 섹션을 참조하세요.

다음 예시에서는 Sparkmagic 구성 분류 설정에 `MyJupyterConfig.json` 대한 파일을 참조하여 AWS CLI를 사용하여 클러스터를 시작합니다.

**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

```
aws emr create-cluster --use-default-roles --release-label emr-5.14.0 \
--applications Name=Jupyter --instance-type m4.xlarge --instance-count 3 \
--ec2-attributes KeyName=MyKey,SubnetId=subnet-1234a5b6 --configurations file://MyJupyterConfig.json
```

`MyJupyterConfig.json`의 샘플 콘텐츠는 다음과 같습니다.

```
[
    {
    "Classification":"jupyter-sparkmagic-conf",
    "Properties": {
      "kernel_python_credentials" : "{\"username\":\"diego\",\"base64_password\":\"mypass\",\"url\":\"http:\/\/localhost:8998\",\"auth\":\"None\"}"
      }
    }
]
```

**참고**  
Amazon EMR 버전 5.21.0 이상에서는 클러스터 구성을 재정의할 수 있으며, 실행 중인 클러스터의 각 인스턴스 그룹에 대해 추가 구성 분류를 지정할 수 있습니다. Amazon EMR 콘솔, AWS Command Line Interface (AWS CLI) 또는 AWS SDK를 사용하여이 작업을 수행할 수 있습니다. 자세한 내용은 [실행 중 클러스터의 인스턴스 그룹에 대해 구성 제공](https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps-running-cluster.html)을 참조하세요.

# Amazon S3에서 노트북의 지속성 구성
<a name="emr-jupyterhub-s3"></a>

Amazon EMR에서 JupyterHub 클러스터를 구성하여 사용자가 저장한 노트북이 클러스터 EC2 인스턴스의 임시 스토리지 외부에 있는 Amazon S3에 지속되도록 할 수 있습니다.

클러스터를 생성할 때 `jupyter-s3-conf` 구성 분류를 사용하여 Amazon S3 지속성을 지정합니다. 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 단원을 참조하십시오.

`s3.persistence.enabled` 속성을 사용하여 Amazon S3 지속성을 활성화하는 것 외에도 Amazon S3에서 `s3.persistence.bucket` 속성을 사용하여 노트북을 저장하는 버킷을 지정합니다. 각 사용자의 노트북은 지정된 버킷의 `jupyter/jupyterhub-user-name` 폴더에 저장됩니다. 버킷은 Amazon S3에 이미 있어야 하며 클러스터를 생성할 때 지정하는 EC2 인스턴스 프로필의 역할에는 버킷에 대한 사용 권한이 있어야 합니다(기본 역할: `EMR_EC2_DefaultRole`). 자세한 내용은 [AWS 서비스에 대한 Amazon EMR 권한에 대한 IAM 역할 구성을 참조하세요](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-iam-roles.html).

동일한 구성 분류 속성을 사용하여 새 클러스터를 시작하면 사용자는 저장된 위치의 콘텐츠로 노트북을 열 수 있습니다.

Amazon S3를 활성화한 상태에서 노트북의 모듈로 파일을 가져오면 파일이 Amazon S3에 업로드됩니다. Amazon S3 지속성을 활성화하지 않고 파일을 가져오면 파일이 JupyterHub 컨테이너에 업로드됩니다.

다음 예제에서는 Amazon S3 지속성을 활성화합니다. 노트북은 각 사용자의 `s3://MyJupyterBackups/jupyter/jupyterhub-user-name` 폴더에 저장됩니다. 여기서 `jupyterhub-user-name`은 사용자 이름(예: `diego`)입니다.

```
[
    {
        "Classification": "jupyter-s3-conf",
        "Properties": {
            "s3.persistence.enabled": "true",
            "s3.persistence.bucket": "MyJupyterBackups"
        }
    }
]
```

# 프라이머리 노드 및 노트북 서버에 연결
<a name="emr-jupyterhub-connect"></a>

JupyterHub 관리자 및 노트북 사용자는 SSH 터널을 사용한 다음 마스터 노드의 JupyterHub에 의해 지원되는 웹 인터페이스에 연결하여 클러스터 마스터 노드에 연결해야 합니다. SSH 터널을 구성하고 터널을 사용하여 웹 연결을 프록시하는 방법에 대한 자세한 내용은 *Amazon EMR 관리 안내서*에서 [클러스터에 연결](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-connect-master-node.html)을 참조하세요.

기본적으로 Amazon EMR의 JupyterHub는 프라이머리 노드의 **포트 9443**을 통해 사용할 수 있습니다. 내부 JupyterHub 프록시는 포트 9443을 통해 노트북 인스턴스도 지원합니다. JupyterHub 및 Jupyter 웹 인터페이스는 다음 패턴으로 URL을 사용하여 액세스할 수 있습니다.

**https://***MasterNodeDNS***:9443**

`c.JupyterHub.port` 파일에서 `jupyterhub_config.py` 속성을 사용하여 다른 포트를 지정할 수 있습니다. 자세한 내용은 JupyterHub 설명서에서 [Networking basics](http://jupyterhub.readthedocs.io/en/latest/getting-started/networking-basics.html)를 참조하세요.

기본적으로 Amazon EMR에 설치된 JupyterHub에서는 HTTPS를 사용한 SSL 암호화를 위해 자체 서명된 인증서를 사용합니다. 사용자는 연결 시 자체 서명된 인증서를 신뢰하라는 메시지를 받게 됩니다. 신뢰된 인증서 및 키를 자체적으로 사용할 수 있습니다. 마스터 노드의 `server.crt`에 있는 기본 인증서 파일, `server.key` 및 키 파일 `/etc/jupyter/conf/`를 자체 인증서 및 키 파일로 바꾸세요. `c.JupyterHub.ssl_key` 파일에 있는 `c.JupyterHub.ssl_cert` 및 `jupyterhub_config.py` 속성을 사용하여 SSL 재료를 지정하세요. 자세한 내용은 JupyterHub 설명서에서 [Security settings](https://jupyterhub.readthedocs.io/en/latest/tutorial/getting-started/security-basics.html)를 참조하세요. `jupyterhub_config.py`를 업데이트한 후 컨테이너를 다시 시작하세요.

# JupyterHub 구성 및 관리
<a name="emr-jupyterhub-administer"></a>

JupyterHub 및 관련 구성 요소는 Ubuntu 운영 체제를 실행하는 `jupyterhub`라는 Docker 컨테이너 내에서 실행됩니다. 컨테이너 내에서 실행 중인 구성 요소를 관리하는 방법에는 여러 가지가 있습니다.

**주의**  
컨테이너 내에서 수행하는 사용자 지정 작업은 컨테이너를 다시 시작하는 경우 유지되지 않을 수 있습니다. 스크립트를 구성하거나 아니면 컨테이너 구성을 자동화하여 보다 쉽게 사용자 지정 구성을 재현할 수 있도록 하는 것이 좋습니다.

## 명령줄을 사용하여 관리
<a name="emr-jupyterhub-administer-cli"></a>

SSH를 사용하여 마스터 노드에 연결되면 Docker 명령줄 인터페이스(CLI)를 사용하고 이름(`jupyterhub`)이나 ID로 컨테이너를 지정하여 명령을 실행할 수 있습니다. 예를 들어, `sudo docker exec jupyterhub command`는 컨테이너 내에서 실행 중인 애플리케이션이나 운영 체제에 의해 인식되는 명령을 실행합니다. 이 명령을 사용하면 운영 체제에 사용자를 추가하고 추가 애플리케이션 및 라이브러리를 Docker 컨테이너 내에 설치할 수 있습니다. 예를 들어, 기본 컨테이너 이미지에는 패키지 설치 시 사용할 Conda가 들어 있으므로 마스터 노드 명령줄에서 다음 명령을 실행하면 애플리케이션, Keras를 컨테이너 내에 설치할 수 있습니다.

```
sudo docker exec jupyterhub conda install keras
```

## 단계를 제출하여 관리
<a name="emr-jupyterhub-administer-steps"></a>

단계는 작업을 클러스터에 제출하는 방법입니다. 단계는 클러스터를 실행할 때 제출할 수도 있고, 실행 중인 클러스터에 제출할 수도 있습니다. 명령줄에서 실행하는 명령은 `command-runner.jar`를 사용하여 단계로 제출될 수 있습니다. 자세한 내용은 *Amazon EMR 관리 안내서*에서 [CLI 및 콘솔을 사용하여 단계 작업](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-work-with-steps.html) 및 [Amazon EMR 클러스터에서 명령 및 스크립트 실행](emr-commandrunner.md) 섹션을 참조하세요.

예를 들어 로컬 컴퓨터에서 다음 AWS CLI 명령을 사용하여 이전 예제에서 마스터 노드의 명령줄에서 수행한 것과 동일한 방식으로 Keras를 설치할 수 있습니다.

```
aws emr add-steps --cluster-id MyClusterID --steps Name="Command Runner",Jar="command-runner.jar",Args="/usr/bin/sudo","/usr/bin/docker","exec","jupyterhub","conda","install","keras"
```

또한 일련의 단계를 스크립트로 구성하고 스크립트를 Amazon S3에 업로드한 다음 `script-runner.jar`을 사용하여 클러스터를 생성하거나 스크립트를 단계로 추가할 때 스크립트를 실행할 수 있습니다. 자세한 내용은 [Amazon EMR 클러스터에서 명령 및 스크립트 실행](emr-commandrunner.md) 단원을 참조하십시오. 예제는 [예제: 여러 사용자를 추가하는 Bash 스크립트](emr-jupyterhub-pam-users.md#emr-jupyterhub-script-multuser) 섹션을 참조하세요.

## REST API를 사용하여 관리
<a name="emr-jupyterhub-administer-rest"></a>

Jupyter, JupyterHub 및 JupyterHub용 HTTP 프록시는 요청을 보내는 데 사용할 수 있는 REST API를 제공합니다. JupyterHub에 요청을 보내려면, 요청이 있는 API 토큰을 전달해야 합니다. 마스터 노드 명령줄에서 `curl` 명령을 사용하면 REST 명령을 실행할 수 있습니다. 자세한 정보는 다음 자료를 참조하세요.
+ API 토큰 생성에 대한 지침에 들어 있는 JupyterHub용 설명서의 [Using JupyterHub's REST API(JupyterHub의 REST API 사용)](http://jupyterhub.readthedocs.io/en/latest/reference/rest.html)
+ GitHub의 [Jupyter Notebook Server API](https://github.com/jupyter/jupyter/wiki/Jupyter-Notebook-Server-API)
+ GitHub의 [configurable-http-proxy](https://github.com/jupyterhub/configurable-http-proxy)

다음은 JupyterHub용 REST API를 사용하여 사용자 목록을 가져오는 방법을 보여주는 예제입니다. 이 명령은 이전에 생성된 관리 토큰을 전달하고 기본 포트 9443를 JupyterHub에 사용하여 보다 쉽게 볼 수 있도록 결과를 [jq](https://stedolan.github.io/jq/)에 보냅니다.

```
curl -XGET -s -k https://$HOST:9443/hub/api/users \
-H "Authorization: token $admin_token" | jq .
```

# Jupyter Notebook 사용자 및 관리자 추가
<a name="emr-jupyterhub-user-access"></a>

두 가지 방법 중 하나를 사용하면 사용자가 JupyterHub에 인증하여 노트북을 생성할 수 있으며, 선택적으로 JupyterHub를 관리할 수도 있습니다. 가장 쉬운 방법은 JupyterHub의 플러그형 인증 모듈(PAM)을 사용하는 것입니다. 또한 Amazon EMR에 설치된 JupyterHub는 [JupyterHub용 LDAP 인증자 플러그인](https://github.com/jupyterhub/ldapauthenticator/)을 지원하여 Microsoft Active Directory 서버와 같은 LDAP 서버로부터 사용자 ID를 가져옵니다. 각 인증 방법을 사용하여 사용자를 추가하는 방법에 대한 지침과 예제는 본 섹션에서 제공됩니다.

Amazon EMR의 JupyterHub에는 관리자 권한이 있는 기본 사용자가 있습니다. 사용자 이름은 `jovyan`이고, 암호는 `jupyter`입니다. 이 사용자를 관리자 권한이 있는 다른 사용자로 바꾸는 것이 매우 권장됩니다. 클러스터를 생성할 때 단계를 사용하거나 클러스터를 실행할 때 마스터 노드에 연결하여 그렇게 할 수 있습니다.

**Topics**
+ [PAM 인증 사용](emr-jupyterhub-pam-users.md)
+ [LDAP 인증 사용](emr-jupyterhub-ldap-users.md)
+ [사용자 위장](emr-jupyterhub-user-impersonation.md)

# PAM 인증 사용
<a name="emr-jupyterhub-pam-users"></a>

Amazon EMR에 설치된 JupyterHub에 PAM 사용자를 생성하는 방법은 두 단계의 프로세스로 이루어집니다. 첫 번째 단계는 마스터 노드의 `jupyterhub` 컨테이너에서 실행 중인 운영 체제에 사용자를 추가하는 것과 해당 사용자를 각 사용자의 홈 디렉터리에 추가하는 것입니다. 두 번째 단계는 이러한 운영 체제 사용자를 JupyterHub 사용자로 추가하는 것입니다. JupyterHub에서는 이 프로세스를 화이트리스팅이라고 합니다. 추가된 JupyterHub 사용자는 JupyterHub URL에 연결한 다음, 액세스를 위하 자신의 운영 체제 자격 증명을 제공하면 됩니다.

사용자가 로그인하면 JupyterHub는 해당 사용자용 노트북 서버 인스턴스를 엽니다. 이 인스턴스는 마스터 노드에 있는 사용자의 홈 디렉터리에 저장됩니다(`/var/lib/jupyter/home/username`). 노트북 서버 인스턴스가 없는 경우, JupyterHub에서 사용자의 홈 디렉터리에 노트북 인스턴스를 만듭니다. 다음 섹션에서는 여러 사용자를 추가하는 기초적인 bash 스크립트를 따라 운영 체제 및 JupyterHub에 사용자를 개별적으로 추가하는 방법을 보여줍니다.

## 컨테이너에 운영 체제 사용자 추가
<a name="emr-jupyterhub-system-user"></a>

다음 예제에서는 먼저 컨테이너 내에서 [useradd](https://linux.die.net/man/8/useradd) 명령을 사용하여 단일 사용자인 diego를 추가한 다음 해당 사용자용 홈 디렉터리를 만듭니다. 두 번째 명령에서는 [chpasswd](https://linux.die.net/man/8/chpasswd)를 사용하여 이 사용자를 위한 diego 암호를 설정합니다. 명령은 SSH를 사용하여 연결되어 있는 동안 마스터 노드 명령줄에서 실행됩니다. [단계를 제출하여 관리](emr-jupyterhub-administer.md#emr-jupyterhub-administer-steps)의 앞부분에 설명되어 있는 대로 단계를 사용하여 이 명령을 실행할 수도 있습니다.

```
sudo docker exec jupyterhub useradd -m -s /bin/bash -N diego
sudo docker exec jupyterhub bash -c "echo diego:diego | chpasswd"
```

## JupyterHub 사용자 추가
<a name="emr-jupyterhub-jupyterhub-user"></a>

JupyterHub의 **Admin** 패널이나 REST API를 사용하면 사용자 및 관리자를 추가하거나 사용자만 추가할 수 있습니다.

**JupyterHub의 Admin 패널을 사용하면 사용자 및 관리자를 추가하는 방법**

1. SSH를 사용하여 마스터 노드에 연결하고 관리자 권한이 있는 ID를 사용하여 https://*MasterNodeDNS*:9443에 로그인합니다.

1. **제어판**, **Admin**을 선택합니다.

1. **사용자**, **사용자 추가**를 선택하거나 **Admin**, **Add Admins(Admin 추가)**를 선택합니다.

**REST API를 사용하여 사용자를 추가하려면**

1. SSH를 사용하여 마스터 노드에 연결하고 마스터 노드에서 다음 명령을 사용하거나 하나의 단계로 명령을 실행합니다.

1. API 요청을 만들 관리자 토큰을 획득하고 다음 단계의 *AdminToken*을 해당 토큰으로 바꿉니다.

1. 다음 명령을 사용하되, *UserName*을 컨테이너 내에서 생성된 운영 체제 사용자로 바꿉니다.

   ```
   curl -XPOST -H "Authorization: token AdminToken" "https://$(hostname):9443/hub/api/users/UserName
   ```

**참고**  
JupyterHub 웹 인터페이스에 처음 로그인하면 자동으로 관리자가 아닌 JupyterHub 사용자로 추가됩니다.

## 예제: 여러 사용자를 추가하는 Bash 스크립트
<a name="emr-jupyterhub-script-multuser"></a>

다음 샘플 bash 스크립트는 이 섹션의 앞의 단계와 함께 연결되어 여러 JupyterHub 사용자를 생성합니다. 이 스크립트는 프라이머리 노드에서 직접 실행할 수도 있고, Amazon S3에 업로드한 다음 하나의 단계로 실행할 수도 있습니다.

이 스크립트는 먼저 사용자 이름 배열을 설정한 다음, `jupyterhub token` 명령을 사용하여 기본 관리자인 jovyan용 API 토큰을 생성합니다. 그런 다음 해당 사용자용 `jupyterhub` 컨테이너에 운영 체제 사용자를 생성합니다. 이때 최초 암호는 각 사용자 이름과 동일하게 지정됩니다. 마지막으로, REST API 작업을 호출하여 JupyterHub에 각 사용자를 생성합니다. 또한 스크립트의 앞부분에서 생성한 토큰을 전달하고 REST 응답을 `jq`에 보내 보다 쉽게 볼 수 있도록 해줍니다.

```
# Bulk add users to container and JupyterHub with temp password of username
set -x
USERS=(shirley diego ana richard li john mary anaya)
TOKEN=$(sudo docker exec jupyterhub /opt/conda/bin/jupyterhub token jovyan | tail -1)
for i in "${USERS[@]}"; 
do 
   sudo docker exec jupyterhub useradd -m -s /bin/bash -N $i
   sudo docker exec jupyterhub bash -c "echo $i:$i | chpasswd"
   curl -XPOST --silent -k https://$(hostname):9443/hub/api/users/$i \
 -H "Authorization: token $TOKEN" | jq
done
```

이 스크립트를 Amazon S3의 위치(예: `s3://amzn-s3-demo-bucket/createjupyterusers.sh`)에 저장합니다. 그런 다음 `script-runner.jar`을 사용하여 이를 하나의 단계로 실행하면 됩니다.

### 예제: 클러스터 생성 시 스크립트 실행(AWS CLI)
<a name="emr-jupyterhub-multuser-createcluster"></a>

**참고**  
가독성을 위해 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 \
--steps Type=CUSTOM_JAR,Name=CustomJAR,ActionOnFailure=CONTINUE,\
Jar=s3://region.elasticmapreduce/libs/script-runner/script-runner.jar,Args=["s3://amzn-s3-demo-bucket/createjupyterusers.sh"]
```

### 기존 클러스터에서 스크립트 실행(AWS CLI)
<a name="emr-jupyterhub-multuser-runningcluster"></a>

**참고**  
가독성을 위해 Linux 줄 연속 문자(\$1)가 포함됩니다. Linux 명령에 사용하거나 제외할 수 있습니다. Windows에서는 제외시키거나 캐럿(^)으로 바꿉니다.

```
aws emr add-steps --cluster-id j-XXXXXXXX --steps Type=CUSTOM_JAR,\
Name=CustomJAR,ActionOnFailure=CONTINUE,\
Jar=s3://region.elasticmapreduce/libs/script-runner/script-runner.jar,Args=["s3://amzn-s3-demo-bucket/createjupyterusers.sh"]
```

# LDAP 인증 사용
<a name="emr-jupyterhub-ldap-users"></a>

LDAP(Lightweight Directory Access Protocol)는 Active Directory 또는 OpenLDAP 서버와 같은 LDAP 호환 디렉터리 서비스 공급자에 저장된 사용자 및 컴퓨터와 같은 리소스에 해당하는 객체를 쿼리 및 수정하기 위한 애플리케이션 프로토콜입니다. Amazon EMR에서 JupyterHub와 함께 [JupyterHub용 LDAP 인증자 플러그인](https://github.com/jupyterhub/ldapauthenticator/)을 사용하여 사용자 인증에 LDAP를 사용할 수 있습니다. 이 플러그인은 LDAP 사용자용 로그인 세션을 처리하고 사용자 정보를 Jupyter에 제공합니다. 이렇게 하면 사용자가 LDAP 호환 서버에 저장된 자신의 ID에 대한 자격 증명을 사용하여 JupyterHub 및 노트북에 연결할 수 있습니다.

이 섹션의 단계에서는 다음 단계를 통해 JupyterHub용 LDAP 인증자 플러그인을 사용하여 LDAP를 설정 및 활성화하는 방법을 안내합니다. 마스터 노드 명령줄에 연결되어 있는 동안 단계를 수행해야 합니다. 자세한 내용은 [프라이머리 노드 및 노트북 서버에 연결](emr-jupyterhub-connect.md) 단원을 참조하십시오.

1. 호스트 IP 주소, 포트, 바인딩 이름 등과 같은 LDAP 서버에 대한 정보를 사용하여 LDAP 구성 파일을 생성합니다.

1. JupyterHub용 LDAP 인증자 플러그인을 활성화하도록 `/etc/jupyter/conf/jupyterhub_config.py`를 수정합니다.

1. `jupyterhub` 컨테이너 내에서 LDAP를 구성하는 스크립트를 생성하고 실행합니다.

1. 사용자용 LDAP를 조회한 다음, 해당 사용자를 위해 컨테이너 내에 홈 디렉터리를 생성합니다. JupyterHub를 사용하려면 노트북을 호스팅하는 홈 디렉터리가 있어야 합니다.

1. JupyterHub를 다시 시작하는 스크립트 실행

**중요**  
LDAP를 설정하기 전에, 네트워크 인프라를 테스트하여 LDAP 서버 및 클러스터 마스터 노드가 필요 시 통신할 수 있도록 합니다. TLS는 일반적으로 일반 TCP 연결을 통해 포트 389를 사용합니다. LDAP 연결에서 SSL을 사용하는 경우 SSL용 잘 알려진 TCP 포트는 636입니다.

## LDAP 구성 파일 생성
<a name="emr-jupyterhub-ldap-config"></a>

아래 예에서는 다음 자리 표시자 구성 값을 사용합니다. 이를 자신의 구현 상황에 맞는 파라미터로 바꿉니다.
+ LDAP 서버는 버전 3을 실행하고 있으며 포트 389에서 사용할 수 있습니다. 이 포트는 LDAP용 표준 비SSL 포트입니다.
+ 기본 고유 이름(DN)은 `dc=example, dc=org`입니다.

텍스트 편집기를 사용하여 다음과 유사한 내용으로 [ldap.conf](http://manpages.ubuntu.com/manpages/bionic/man5/ldap.conf.5.html) 파일을 생성합니다. LDAP 구현 상황에 적절한 값을 사용합니다. *host*를 LDAP 서버의 IP 주소 또는 확인 가능한 호스트 이름으로 바꿉니다.

```
base dc=example,dc=org
uri ldap://host
ldap_version 3
binddn cn=admin,dc=example,dc=org
bindpw admin
```

## JupyterHub용 LDAP 인증자 플러그인 활성화
<a name="emr-jupyterhub-ldap-plugin"></a>

텍스트 편집기를 사용하여 `/etc/jupyter/conf/jupyterhub_config.py` 파일을 수정하고 다음과 유사하게 [ldapauthenticator](https://github.com/jupyterhub/ldapauthenticator) 속성을 추가합니다. *host*를 LDAP 서버의 IP 주소 또는 확인 가능한 호스트 이름으로 바꿉니다. 이 예에서는 사용자 객체가 *people*이라는 조직 단위(OU) 내에 있으며 `ldap.conf`를 사용하여 앞에서 설정한 고유 이름 구성 요소를 사용한다고 가정합니다.

```
c.JupyterHub.authenticator_class = 'ldapauthenticator.LDAPAuthenticator'
c.LDAPAuthenticator.use_ssl = False
c.LDAPAuthenticator.server_address = 'host' 
c.LDAPAuthenticator.bind_dn_template = 'cn={username},ou=people,dc=example,dc=org'
```

## 컨테이너 내에서 LDAP 구성
<a name="emr-jupyterhub-ldap-container"></a>

텍스트 편집기를 사용하여 다음 콘텐츠가 포함된 bash 스크립트를 생성합니다.

```
#!/bin/bash

# Uncomment the following lines to install LDAP client libraries only if
# using Amazon EMR release version 5.14.0. Later versions install libraries by default.
# sudo docker exec jupyterhub bash -c "sudo apt-get update"
# sudo docker exec jupyterhub bash -c "sudo apt-get -y install libnss-ldap libpam-ldap ldap-utils nscd"
 
# Copy ldap.conf
sudo docker cp ldap.conf jupyterhub:/etc/ldap/
sudo docker exec jupyterhub bash -c "cat /etc/ldap/ldap.conf"
 
# configure nss switch
sudo docker exec jupyterhub bash -c "sed -i 's/\(^passwd.*\)/\1 ldap/g' /etc/nsswitch.conf"
sudo docker exec jupyterhub bash -c "sed -i 's/\(^group.*\)/\1 ldap/g' /etc/nsswitch.conf"
sudo docker exec jupyterhub bash -c "sed -i 's/\(^shadow.*\)/\1 ldap/g' /etc/nsswitch.conf"
sudo docker exec jupyterhub bash -c "cat /etc/nsswitch.conf"
 
# configure PAM to create home directories
sudo docker exec jupyterhub bash -c "echo 'session required        pam_mkhomedir.so skel=/etc/skel umask=077' >> /etc/pam.d/common-session"
sudo docker exec jupyterhub bash -c "cat /etc/pam.d/common-session"
 
# restart nscd service
sudo docker exec jupyterhub bash -c "sudo service nscd restart"
 
# Test
sudo docker exec jupyterhub bash -c "getent passwd"

# Install ldap plugin
sudo docker exec jupyterhub bash -c "pip install jupyterhub-ldapauthenticator"
```

스크립트를 마스터 노드에 저장한 다음 이를 마스터 노드 명령줄에서 실행합니다. 예를 들어, `configure_ldap_client.sh`라고 저장한 스크립트를 사용하여 파일을 실행 파일로 만듭니다.

```
chmod +x configure_ldap_client.sh
```

그런 다음 스크립트를 실행합니다.

```
./configure_ldap_client.sh
```

## Active Directory에 속성 추가
<a name="emr-jupyterhub-ldap-adproperties"></a>

데이터베이스에서 각 사용자를 찾고 적절한 항목을 만들려면, JupyterHub 도커 컨테이너에 Active Directory의 해당 사용자 객체에 대한 다음 UNIX 속성이 필요합니다. 자세한 내용은 [Clarification regarding the status of identity management for Unix (IDMU) and NIS server role in Windows Server 2016 technical preview and beyond](https://blogs.technet.microsoft.com/activedirectoryua/2016/02/09/identity-management-for-unix-idmu-is-deprecated-in-windows-server/) 기사의 *How do I continue to edit the GID/UID RFC 2307 attributes now that the Unix Attributes Plug-in is no longer available for the Active Directory Users and Computers MMC snap-in?* 섹션을 참조하세요.
+ `homeDirectory`

  사용자 홈 디렉터리의 위치이며 보통 `/home/username`입니다.
+ `gidNumber`

  다른 사용자가 아직 사용하지 않은 60000보다 큰 값입니다. 사용 중인 GID는 `etc/passwd` 파일에서 확인하세요.
+ `uidNumber`

  다른 그룹이 아직 사용하지 않은 60000보다 큰 값입니다. 사용 중인 UID는 `etc/group` 파일에서 확인하세요.
+ `uid`

  *username*과 같습니다.

## 사용자 홈 디렉터리 생성
<a name="emr-jupyterhub-ldap-directories"></a>

JupyterHub에서는 LDAP 사용자를 인증하고 인스턴스 데이터를 저장하기 위해 컨테이너 내에 홈 디렉터리가 있어야 합니다. 다음 예는 LDAP 디렉터리에 있는 두 명의 사용자 *shirley*와 *diego*를 보여줍니다.

첫 번째 단계는 다음 예에 표시된 대로 [ldapsearch](http://manpages.ubuntu.com/manpages/xenial/man1/ldapsearch.1.html)를 사용하여 각 사용자의 사용자 ID 및 그룹 ID 정보를 LDAP 서버에 조회하는 것입니다. 이때 *host*는 LDAP 서버의 IP 주소 또는 확인 가능한 호스트 이름으로 바꿉니다.

```
ldapsearch -x -H ldap://host \
 -D "cn=admin,dc=example,dc=org" \
 -w admin \
 -b "ou=people,dc=example,dc=org" \
 -s sub \
 "(objectclass=*)" uidNumber gidNumber
```

`ldapsearch`명령은 *shirley*와 *diego* 사용자를 위해 다음과 유사하게 표시되는 LDIF 형식 응답을 반환합니다.

```
# extended LDIF

# LDAPv3
# base <ou=people,dc=example,dc=org> with scope subtree
# filter: (objectclass=*)
# requesting: uidNumber gidNumber sn 

# people, example.org
dn: ou=people,dc=example,dc=org

# diego, people, example.org
dn: cn=diego,ou=people,dc=example,dc=org
sn: B
uidNumber: 1001
gidNumber: 100

# shirley, people, example.org
dn: cn=shirley,ou=people,dc=example,dc=org
sn: A
uidNumber: 1002
gidNumber: 100

# search result
search: 2
result: 0 Success

# numResponses: 4
# numEntries: 3
```

응답에서 획득한 정보로 컨테이너 내 명령을 실행하여 각 사용자의 일반 이름(`cn`)용 홈 디렉터리를 생성합니다. `uidNumber` 및 `gidNumber`를 사용하여 해당 사용자에 대한 홈 디렉터리용 소유권을 수정합니다. 다음 예시 명령은 사용자 *shirley*에 대해 이 작업을 수행합니다.

```
sudo docker container exec jupyterhub bash -c "mkdir /home/shirley"
sudo docker container exec jupyterhub bash -c "chown -R $uidNumber /home/shirley"
sudo docker container exec jupyterhub bash -c "sudo chgrp -R $gidNumber /home/shirley"
```

**참고**  
JupyterHub의 LDAP 인증자는 로컬 사용자 생성을 지원하지 않습니다. 자세한 내용은 [LDAP authenticator configuration note on local user creation](https://github.com/jupyterhub/ldapauthenticator#configuration-note-on-local-user-creation)을 참조하세요.  
로컬 사용자를 수동으로 생성하려면 다음 명령을 사용합니다.  

```
sudo docker exec jupyterhub bash -c "echo 'shirley:x:$uidNumber:$gidNumber::/home/shirley:/bin/bash' >> /etc/passwd"
```

## Jupyterhub 컨테이너 다시 시작
<a name="emr-jupyterhub-ldap-restart"></a>

`jupyterhub` 컨테이너를 다시 시작하려면 다음 명령을 실행합니다.

```
sudo docker stop jupyterhub
sudo docker start jupyterhub
```

# 사용자 위장
<a name="emr-jupyterhub-user-impersonation"></a>

Jupyter Notebook 내에서 실행되는 Spark 작업은 Amazon EMR에서 실행되는 동안 여러 애플리케이션을 통과합니다. 예를 들어 사용자가 Jupyter 내에서 실행하는 PySpark3 코드를 Sparkmagic이 수신하며, 이 Sparkmagic은 수신한 PySpark3 코드를 HTTP POST 요청을 사용하여 Livy로 제출합니다. 이때 Livy는 YARN을 사용해 클러스터에서 실행할 Spark 작업을 생성합니다.

기본적으로 이런 방식으로 제출된 YARN 작업은 최초로 작업을 시작한 사용자와 상관없이 사용자 `livy`로서 실행됩니다. *사용자 가장*을 설정함으로써 노트북 사용자의 사용자 ID 또한 YARN 작업과 관련된 사용자가 되도록 설정할 수 있습니다. 작업을 사용자 `shirley`와 연결된 `diego` 및 `livy` 모두로 시작한다기보다는, 각 사용자가 시작하는 작업이 각각 `shirley` 및 `diego`와 연결되는 것입니다. 이렇게 하면 Jupyter 사용량을 감사하고 조직 내에서 애플리케이션을 관리할 수 있습니다.

이러한 구성은 Sparkmagic의 Livy에 대한 호출이 인증되지 않는 경우에만 지원됩니다. 하둡 애플리케이션과 Livy 사이에 인증 또는 프록시 설정 계층을 제공하는 애플리케이션(Apache Knox Gateway 등)은 지원되지 않습니다. 이 섹션의 사용자 가장을 구성하는 단계는 JupyterHub와 Livy가 동일한 마스터 노드에서 실행되는 것을 가정했습니다. 애플리케이션에 별도의 클러스터가 있는 경우 Livy 마스터 노드에 HDFS 디렉터리가 생성되도록 [3단계: 사용자를 위한 HDFS 홈 디렉터리 생성](#Step3-UserImpersonation)을 수정할 필요가 있습니다.

**Topics**
+ [1단계: Livy 구성](#Step1-UserImpersonation)
+ [2단계: 사용자 추가](#Step2-UserImpersonation)
+ [3단계: 사용자를 위한 HDFS 홈 디렉터리 생성](#Step3-UserImpersonation)

## 1단계: Livy 구성
<a name="Step1-UserImpersonation"></a>

다음 예와 같이 클러스터를 생성하여 Livy 사용자 가장을 활성화할 때 `livy-conf` 및 `core-site` 구성 분류를 사용합니다. 구성 분류를 JSON으로 저장한 다음 클러스터를 생성할 때 참조하거나 구성 분류 인라인을 지정합니다. 자세한 내용은 [애플리케이션 구성](emr-configure-apps.md) 단원을 참조하십시오.

```
[
  {
    "Classification": "livy-conf",
    "Properties": {
      "livy.impersonation.enabled": "true"
    }
  },
  {
    "Classification": "core-site",
    "Properties": {
      "hadoop.proxyuser.livy.groups": "*",
      "hadoop.proxyuser.livy.hosts": "*"
    }
  }
]
```

## 2단계: 사용자 추가
<a name="Step2-UserImpersonation"></a>

PAM 또는 LDAP를 사용하여 JupyterHub 사용자를 추가합니다. 자세한 내용은 [PAM 인증 사용](emr-jupyterhub-pam-users.md) 및 [LDAP 인증 사용](emr-jupyterhub-ldap-users.md) 섹션을 참조하세요.

## 3단계: 사용자를 위한 HDFS 홈 디렉터리 생성
<a name="Step3-UserImpersonation"></a>

마스터 노드에 연결하여 사용자를 생성했습니다. 아직 마스터 노드에 연결된 상태에서 아래 콘텐츠를 복사하여 스크립트 파일에 저장합니다. 스크립트는 마스터 노드의 각 JupyterHub 사용자에게 HDFS 홈 디렉터리를 생성합니다. 스크립트는 사용자가 기본 관리자 사용자 ID, *jovyan*을 사용하는 것으로 가정합니다.

```
#!/bin/bash

CURL="curl --silent -k"
HOST=$(curl -s http://169.254.169.254/latest/meta-data/local-hostname)

admin_token() {
    local user=jovyan
    local pwd=jupyter
    local token=$($CURL https://$HOST:9443/hub/api/authorizations/token \
        -d "{\"username\":\"$user\", \"password\":\"$pwd\"}" | jq ".token")
    if [[ $token != null ]]; then
        token=$(echo $token | sed 's/"//g')
    else
        echo "Unable to get Jupyter API Token."
        exit 1
    fi
    echo $token
}

# Get Jupyter Admin token
token=$(admin_token)

# Get list of Jupyter users
users=$(curl -XGET -s -k https://$HOST:9443/hub/api/users \
 -H "Authorization: token $token" | jq '.[].name' | sed 's/"//g')

# Create HDFS home dir 
for user in ${users[@]}; 
do
 echo "Create hdfs home dir for $user"
 hadoop fs -mkdir /user/$user
 hadoop fs -chmod 777 /user/$user
done
```

# 추가 커널 및 라이브러리 설치
<a name="emr-jupyterhub-install-kernels-libs"></a>

Amazon EMR에서 JupyterHub를 포함하는 클러스터를 생성하는 경우, Jupyter용 기본 Python 3 커널 및 Sparkmagic용 PySpark 및 Spark 커널이 Docker 컨테이너에 설치됩니다. 추가 커널을 설치할 수 있으며, 추가 라이브러리 및 패키지를 설치한 다음 해당 셸을 위해 이를 가져올 수도 있습니다.

## 커널 설치
<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용 데이터 과학 라이브러리는 Amazon EMR에 JupyterHub와 함께 사전 설치되어 있습니다. `sudo docker exec jupyterhub bash -c "conda list" ` 및 `sudo docker exec jupyterhub bash -c "pip freeze"`를 사용할 수 있습니다.

Spark 작업에서 작업자 노드에 있는 라이브러리를 필요로 하는 경우, 부트스트랩 작업을 사용하여 클러스터 생성 시 라이브러리를 설치하는 스크립트를 실행하는 것이 좋습니다. 부트스트랩 작업은 클러스터 생성 프로세서 중에 모든 클러스터 노드에서 실행되므로 설치 작업을 간소화해 줍니다. 클러스터 실행 후 코어/작업자 노드에 라이브러리를 설치하는 경우, 작업이 더 복잡합니다. 이 섹션에서는 이러한 라이브러리 설치 방법을 보여주는 Python 예제 프로그램이 제공됩니다.

이 섹션에 표시된 부트스트랩 작업 및 Python 프로그램에서는 Amazon S3에 저장된 bash 스크립트를 사용하여 모든 노드에 라이브러리를 설치합니다.

다음 예제에서 참조되는 스크립트는 `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`)에 업로드합니다. 부트스트랩 작업이나 Python 프로그램에서 사용할 수 있도록 자세한 내용은 *Amazon Simple Storage Service 사용 설명서*에서 [객체 업로드](https://docs.aws.amazon.com/AmazonS3/latest/userguide/upload-objects.html)를 참조하세요.

**를 사용하여 클러스터를 생성할 때 모든 노드에 라이브러리를 설치하는 부트스트랩 작업을 지정하려면 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. **클러스터 생성** 및 **고급 옵션으로 이동**을 선택합니다.

1. **소프트웨어 및 단계** 및 **하드웨어**의 설정을 애플리케이션에 적절하게 지정합니다.

1. **일반 클러스터 설정** 화면에서 **부트스트랩 작업**을 확장합니다.

1. **부트스트랩 작업 추가**에서 **사용자 지정 작업**, **구성 및 추가**를 선택합니다.

1. **명칭**에 기억하기 쉬운 명칭을 입력합니다. **스크립트 위치**에, 스크립트가 있는 Amazon S3의 위치를 입력합니다(이 예제에서는 *s3://amzn-s3-demo-bucket/install-my-jupyter-libraries.sh*를 사용함). **선택적 인수**를 비워 두고 **추가**를 선택합니다.

1. 클러스터에 대한 다른 설정을 지정하고 **다음**을 선택합니다.

1. 보안 설정을 지정하고 **클러스터 생성**을 선택합니다.

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

# JupyterHub 릴리스 기록
<a name="JupyterHub-release-history"></a>

다음 테이블에는 애플리케이션과 함께 설치된 구성 요소 외에도 Amazon EMR의 최신 릴리스에 포함된 JupyterHub의 버전이 나열되어 있습니다. 각 릴리스의 구성 요소 버전은 [Amazon EMR 7.x 릴리스 버전](emr-release-7x.md), [Amazon EMR 6.x 릴리스 버전](emr-release-6x.md) 또는 [Amazon EMR 5.x 릴리스 버전](emr-release-5x.md)의 릴리스의 구성 요소 버전 섹션을 참조하세요.


**JupyterHub 버전 정보**  

| Amazon EMR 릴리스 레이블 | JupyterHub 버전 | JupyterHub와 함께 설치된 구성 요소 | 
| --- | --- | --- | 
| emr-7.12.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-hdfs-zkfc, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.11.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-hdfs-zkfc, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.10.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.9.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.8.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.7.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.6.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.5.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.4.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.3.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.2.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.36.2 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.1.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-7.0.0 | 1.5.0 | emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.15.0 | 1.5.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.14.0 | 1.5.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.13.0 | 1.5.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.12.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.11.1 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.11.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.10.1 | 1.5.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.10.0 | 1.5.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.9.1 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.9.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.8.1 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.8.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.7.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.36.1 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.36.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.6.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, hudi, hudi-spark, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.35.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.5.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.4.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.3.1 | 1.2.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.3.0 | 1.2.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.2.1 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.2.0 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.1.1 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.1.0 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.0.1 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-6.0.0 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.34.0 | 1.4.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.33.1 | 1.2.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.33.0 | 1.2.2 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.32.1 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.32.0 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.31.1 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.31.0 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.30.2 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.30.1 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.30.0 | 1.1.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.29.0 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.28.1 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.28.0 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.27.1 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.27.0 | 1.0.0 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.26.0 | 0.9.6 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.25.0 | 0.9.6 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.24.1 | 0.9.6 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.24.0 | 0.9.6 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.23.1 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.23.0 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.22.0 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.21.2 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.21.1 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.21.0 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.20.1 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.20.0 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.19.1 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.19.0 | 0.9.4 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.18.1 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.18.0 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.17.2 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.17.1 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.17.0 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.16.1 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.16.0 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.15.1 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.15.0 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.14.2 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.14.1 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 
| emr-5.14.0 | 0.8.1 | aws-sagemaker-spark-sdk, emrfs, emr-goodies, emr-ddb, hadoop-client, hadoop-hdfs-datanode, hadoop-hdfs-library, hadoop-hdfs-namenode, hadoop-kms-server, hadoop-yarn-nodemanager, hadoop-yarn-resourcemanager, hadoop-yarn-timeline-server, r, spark-client, spark-history-server, spark-on-yarn, spark-yarn-slave, livy-server, jupyterhub | 