

# 자습서: JupyterLab에 Jupyter Notebook을 설정하여 ETL 스크립트 테스트 및 디버깅
<a name="dev-endpoint-tutorial-local-jupyter"></a>

이 튜토리얼에서는 로컬 시스템에서 실행 중인 JupyterLab의 Jupyter Notebook을 개발 엔드포인트에 연결합니다. 이렇게 하면 AWS Glue 추출, 변환, 로드(ETL) 스크립트를 배포하기에 앞서 대화식으로 이를 실행, 디버깅 및 테스트할 수 있습니다. 이 자습서에서는 Secure Shell(SSH) 전송을 사용하여 로컬 시스템을 AWS Glue 개발 엔드포인트에 연결합니다. 자세한 내용은 Wikipedia의 [Port forwarding](https://en.wikipedia.org/wiki/Port_forwarding)을 참조하세요.

## 1단계: JupyterLab과 Sparkmagic 설치
<a name="dev-endpoint-tutorial-local-jupyter-install"></a>

JupyterLab을 설치하려면 `conda` 또는 `pip`를 사용하면 됩니다. `conda`는 오픈 소스 패키지 관리 시스템 겸 환경 관리 시스템으로 Windows, macOS 및 Linux에서 실행됩니다. `pip`는 Python용 패키지 설치 프로그램입니다.

macOS에 설치하는 경우, Xcode가 설치되어 있어야 Sparkmagic을 설치할 수 있습니다.

1. JupyterLab, Sparkmagic과 관련 확장 프로그램을 설치합니다.

   ```
   $ conda install -c conda-forge jupyterlab
   $ pip install sparkmagic
   $ jupyter nbextension enable --py --sys-prefix widgetsnbextension
   $ jupyter labextension install @jupyter-widgets/jupyterlab-manager
   ```

1. `Location`에서 `sparkmagic` 디렉터리를 확인합니다.

   ```
   $ pip show sparkmagic | grep Location
   Location: /Users/username/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/site-packages
   ```

1. 디렉터리를 `Location`에 대하여 반환된 것으로 변경하고, Scala와 PySpark의 커널을 설치합니다.

   ```
   $ cd /Users/username/.pyenv/versions/anaconda3-5.3.1/lib/python3.7/site-packages
   $ jupyter-kernelspec install sparkmagic/kernels/sparkkernel
   $ jupyter-kernelspec install sparkmagic/kernels/pysparkkernel
   ```

1. 샘플 `config` 파일을 다운로드합니다.

   ```
   $ curl -o ~/.sparkmagic/config.json https://raw.githubusercontent.com/jupyter-incubator/sparkmagic/master/sparkmagic/example_config.json
   ```

   이 구성 파일에서 `driverMemory` 및 `executorCores`와 같은 Spark 관련 파라미터를 구성할 수 있습니다.

## 2단계: JupyterLab 시작
<a name="dev-endpoint-tutorial-local-jupyter-start"></a>

JupyterLab을 시작하면 기본 웹 브라우저가 자동으로 열리고 URL `http://localhost:8888/lab/workspaces/{workspace_name}`이 표시됩니다.

```
$ jupyter lab
```

## 3단계: SSH 포트 전송을 시작하여 개발 엔드포인트에 연결
<a name="dev-endpoint-tutorial-local-jupyter-port-forward"></a>

다음으로, SSH 로컬 포트 전송을 사용하여 로컬 포트(여기서는 `8998`)를 AWS Glue(`169.254.76.1:8998`)에 의해 정의된 원격 대상으로 전송합니다.

1. SSH에 액세스를 부여하는 별도의 터미널 창을 엽니다. Microsoft Windows에서라면 [Git for Windows](https://git-scm.com/downloads)에서 제공하는 BASH 셸을 사용해도 되고, 아니면 [Cygwin](https://www.cygwin.com/)을 설치해도 됩니다.

1. 다음과 같이 수정된 다음 SSH 명령을 실행합니다.
   + `private-key-file-path` 대신 개발 엔드포인트를 생성하는 데 쓴 퍼블릭 키에 상응하는 프라이빗 키를 포함한 `.pem` 파일에 대한 경로를 사용합니다.
   + `8998` 외의 다른 포트를 전송하는 경우, `8998` 대신 로컬에서 실제로 사용 중인 포트 번호를 사용합니다. 주소 `169.254.76.1:8998`이 원격 포트이며 이는 사용자가 변경하는 것이 아닙니다.
   + `dev-endpoint-public-dns`를 개발 엔드포인트의 퍼블릭 DNS 주소로 바꿉니다. 이 주소를 찾으려면 AWS Glue 콘솔에서 개발 엔드포인트로 이동하여 이름을 선택하고 [**엔드포인트 세부 정보(Endpoint details)**] 페이지에 목록으로 기재된 [**퍼블릭 주소(Public address)**]를 복사합니다.

   ```
   ssh -i private-key-file-path -NTL 8998:169.254.76.1:8998 glue@dev-endpoint-public-dns
   ```

   다음과 같은 경고 메세지가 표시됩니다.

   ```
   The authenticity of host 'ec2-xx-xxx-xxx-xx.us-west-2.compute.amazonaws.com (xx.xxx.xxx.xx)'
   can't be established.  ECDSA key fingerprint is SHA256:4e97875Brt+1wKzRko+JflSnp21X7aTP3BcFnHYLEts.
   Are you sure you want to continue connecting (yes/no)?
   ```

   **yes**를 입력하고 JupyterLab을 사용하는 동안 터미널 창을 열어둡니다.

1. SSH 포트 전송이 개발 엔드포인트와 올바로 함께 작동하는지 확인합니다.

   ```
   $ curl localhost:8998/sessions
   {"from":0,"total":0,"sessions":[]}
   ```

## 4단계: Notebook Paragraph의 Simple Script Fragment 실행
<a name="dev-endpoint-tutorial-local-jupyter-list-schema"></a>

이제 JupyterLab의 노트북이 개발 엔드포인트와 함께 작동하는 것이 정상입니다. 다음과 같은 스크립트 조각을 노트북에 입력하여 실행합니다.

1. Spark가 실행 중인지 확인합니다. 다음 명령을 사용하면 Spark에 `1`을 계산하여 값을 인쇄하도록 지시합니다.

   ```
   spark.sql("select 1").show()
   ```

1. AWS Glue Data Catalog 통합이 작동하는지 확인합니다. 다음 명령을 사용하면 테이블을 데이터 카탈로그에 목록으로 나열합니다.

   ```
   spark.sql("show tables").show()
   ```

1. AWS Glue 라이브러리를 사용하는 단순한 스크립트 조각이 작동하는지 확인합니다.

   다음 스크립트는 AWS Glue Data Catalog의 `persons_json` 테이블 메타데이터를 사용하여 샘플 데이터로부터 `DynamicFrame`을 생성합니다. 그런 다음 항목 수와 이 데이터 스키마를 출력합니다.

```
import sys
from pyspark.context import SparkContext
from awsglue.context import GlueContext
 
# Create a Glue context
glueContext = GlueContext(SparkContext.getOrCreate())
 
# Create a DynamicFrame using the 'persons_json' table
persons_DyF = glueContext.create_dynamic_frame.from_catalog(database="legislators", table_name="persons_json")
 
# Print out information about *this* data
print("Count:  ", persons_DyF.count())
persons_DyF.printSchema()
```

스크립트의 출력은 다음과 같습니다.

```
 Count:  1961
 root
 |-- family_name: string
 |-- name: string
 |-- links: array
 |    |-- element: struct
 |    |    |-- note: string
 |    |    |-- url: string
 |-- gender: string
 |-- image: string
 |-- identifiers: array
 |    |-- element: struct
 |    |    |-- scheme: string
 |    |    |-- identifier: string
 |-- other_names: array
 |    |-- element: struct
 |    |    |-- note: string
 |    |    |-- name: string
 |    |    |-- lang: string
 |-- sort_name: string
 |-- images: array
 |    |-- element: struct
 |    |    |-- url: string
 |-- given_name: string
 |-- birth_date: string
 |-- id: string
 |-- contact_details: array
 |    |-- element: struct
 |    |    |-- type: string
 |    |    |-- value: string
 |-- death_date: string
```

## 문제 해결
<a name="dev-endpoint-tutorial-local-jupyter-troubleshooting"></a>
+ JupyterLab 설치 중에 컴퓨터가 회사 프록시나 방화벽 뒤에 위치한 경우, 회사 IT 부서에서 관리하는 사용자 정의 보안 프로파일로 인해 HTTP 및 SSL 오류가 발생할 수 있습니다.

  다음은 `conda`가 자체 리포지토리에 연결할 수 없을 때 발생하는 일반적인 오류의 예시입니다.

  ```
  CondaHTTPError: HTTP 000 CONNECTION FAILED for url <https://repo.anaconda.com/pkgs/main/win-64/current_repodata.json>
  ```

  이것은 회사에서 Python 및 JavaScript 커뮤니티에서 광범위하게 사용되는 리포지토리로의 연결을 차단할 수 있기 때문에 발생할 가능성이 있습니다. 자세한 내용은 JupyterLab 웹 사이트의 [Installation Problems](https://jupyterlab.readthedocs.io/en/stable/getting_started/installation.html#installation-problems)를 참조하세요.
+ 개발 엔드포인트에 연결을 시도할 때 [*연결 거부됨(connection refused)*] 오류가 발생하는 경우 날짜가 지난 개발 엔드포인트를 사용하고 있는 것일 수 있습니다. 새로운 개발 엔드포인트를 생성해보고 다시 연결하십시오.