AWSにjupyter notebookを構築してリモートで使用する

# はじめに
自宅のPCがメモリ8GiBしかないため、32GiB環境を手に入れたいと思い、AWS上にLinuxインスタンスを立てようと思います。Linux上でjupyter notebookを起動し、リモートでブラウザからアクセスしてjupyterを使用します。

# 環境
- AWSアカウントは持っている前提とします

# 手順
## AWSインスタンス作成
サービスからEC2を選択し、インスタンスを作成します。
作成するインスタンスは下記のとおりです。

|No.|ステップ|選択|
|:---:|:---:|:---:|
|1|Amazon マシンイメージ (AMI)|Amazon Linux 2 AMI (HVM), SSD Volume Type|
|2|インスタンスタイプの選択|t2.micro (可変 ECU, 1 vCPU, 2.5 GHz, Intel Xeon Family, 1 GiB メモリ, EBS のみ)|
|3|インスタンスの詳細の設定|デフォルトのまま変更なし|
|4|ストレージの追加|30GiB|
|5|タグの追加|追加しない|
|6|セキュリティグループの設定|※下記参照|

セキュリティグループのインバウンド設定は下記のとおりです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211712/4828f153-c946-0bfe-9cac-ff03d2a36e56.png)

セキュリティグループのアウトバウンド設定は下記のとおりです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211712/173e3088-6e8f-d91f-8fdb-de7a5bdf3cf7.png)


## サーバへの接続
sshクライアントはTeratermを使用しました。インストール方法と接続方法は[**こちら**](https://dev.classmethod.jp/cloud/aws/aws-beginner-ec2-ssh/)の手順通りに行いました。

ログイン後、rootユーザに切り替えます。以降の操作は管理者として実行します。

```
$ sudo su -
```

AWSの初期設定では、sshが鍵を使用した認証になっています。複数のクライアントからアクセスする場合は鍵を配布するのが大変なので、パスワード認証のほうが楽だと思います。
パスワード認証への変更の仕方は[**こちら**](https://aws.amazon.com/jp/premiumsupport/knowledge-center/ec2-password-login/)の手順で実施しました。

タイムゾーンを日本に設定します。設定の仕方は[**こちら**](https://qiita.com/nikuruyo/items/19504660c50efe3c24c2)の手順で実施しました。

## Anacondaのインストール
Anacondaのインストール方法は[**こちら**](http://kuro-rera.hatenablog.com/entry/2018/02/04/195136)を参考にしました。

自宅PCで[**Anacondaのサイト**](https://www.anaconda.com/download/#linux)から64-Bit (x86) Installer (652.5 MB)をダウンロードします。構築時はPython 3.7 versionでした。
WinSCPを用いて、作成したLinuxインスタンスにインストーラを移動します。

WinSCPのインストールは[**こちら**](http://proengineer.internous.co.jp/content/columnfeature/9414)が参考になります。
WinSCPの鍵認証でAWSインスタンスにアクセスするには[**こちら**](https://ts0818.hatenablog.com/entry/2017/07/24/191352)が参考になります。

インスタンスかに直接ダウンロードもできます。wgetをインストールします。

```
$ yum install wget
```
サイトからanacondaをダウンロードします。

```
$ wget https://repo.continuum.io/archive/Anaconda3-2018.12-Linux-x86_64.sh
```
[こちら](https://qiita.com/otsukaaaa/items/9ed0b3eba324a4bb5883
)を参考にしました。


下記コマンドを実行し、インストールします。途中でインストールのパスが聞かれます。今回は`/root/anaconda3/`としました。

```bash
$ sh Anaconda3-2018.12-Linux-x86_64.sh
```

Anacondaインストール過程で、zipを解凍できない時があります。そのときはbunzip2をインストールします。

```
$ yum install bzip2
```
インストール後は下記コマンドでパスを通しました。

```bash
$ export PATH=/root/anaconda3/bin:$PATH
```
ここで、`/root/anaconda3`の部分はインストール先のパスです。

## 仮想環境作成
下記コマンドで仮想環境を作成します。

```bash
conda create -n py37 python=3.7.1 anaconda
```
`anaconda`オプションでパッケージ全部入りのpython環境をつくれます。

仮想環境については[**こちら**](https://qiita.com/ozaki_physics/items/985188feb92570e5b82d)が参考になります。

## jupyter notebook設定
notebookやデータを保管するディレクトリを作成します。

```
$ cd ~ # rootで操作しているので/rootに移動します
$ mkdir work
```

仮想環境をアクティブ化します。

```bash
$ source activate py37
```

jupyterの設定を行います。[**こちら**](http://rf00.hatenablog.com/entry/2018/01/01/160820)を参考にしました。

jupyterのログインパスワードを設定します。

```bash
$ ipython
In [1]: from notebook.auth import passwd
In [2]: passwd()
Enter password:
Verify password: 
Out[3]: 'sha1:...' # 暗号化された文字列をコピーしておく
```
最後に表示された`'sha1:...'`の部分を控えておきます。

次にサーバに設定する鍵を生成します。

```
$ cd ~ # rootで操作しているので/rootに移動します
$ mkdir .jupyter
$ cd .jupyter
$ openssl req -x509 -nodes -days 365 -newkey rsa:1024 -keyout mykey.key -out mycert.pem
```
jupyter notebookのコンフィグを設定します。

```bash
$ vi /root/.jupyter/jupyter_notebook_config.py

c = get_config()
c.NotebookApp.ip='0.0.0.0' # 任意のipアドレスからアクセス可
c.NotebookApp.password = 'sha1:...' # コピーしておいた文字列
c.NotebookApp.open_browser=False # jupyter起動時にブラウザはを自動で開かない
c.NotebookApp.port=適当なポート番号 # サーバーのportで今回は8888
c.NotebookApp.certfile = u'/root/.jupyter/mycert.pem' # サーバ証明書
c.NotebookApp.keyfile  = u'/root/.jupyter/mykey.key' # 秘密鍵
c.NotebookApp.notebook_dir = '/root/work' #  jupyterのWebUIから見えるファイル構造のルート
```

下記コマンドでjupyterを起動します。

```
$ jupyter notebook --ip='0.0.0.0' --allow-root &
```
自宅のPCのブラウザでサーバに`https://サーバのip:8888`にアクセスすると、パスワード入力を求められるので、ログインします。

jupyterを止めるときは下記コマンドでプロセスIDを探し、

````
$ ps aux | grep jupyter
```
`kill`コマンドでプロセスを終了します。

```
$ kill ここにプロセスID
```


## jupyter自動起動
上記の設定だとサーバを起動するたびにjupyterを手動で起動する必要があります。そこでサーバ起動と同時に自動でjupyterが起動するようにします。

[**こちら**](https://qiita.com/taka4sato/items/2c3397ff34c440044978)を参考にしました。

起動スクリプトを作成します。

```
$ touch ~/start_jupyter.sh
```
起動スクリプトを編集します。

```
$ vi ~/start_jupyter.sh

/root/anaconda3/envs/py37/bin/jupyter notebook --ip='0.0.0.0' --allow-root &
```
ファイルの権限を変更します。

```
$ chmod 755 start_jupyter.sh
```
`rc.local`に実行コマンドを追加します。(このやり方はCentOS7では古いので[サービス化](https://qiita.com/tontonyoga/items/50536ddf22d740d8ecaa)した方が良いです。)

```
$ vi /etc/rc.d/rc.local

sudo sh '/root/start_jupyter.sh'
```

CentOS7以降だと起動しない場合があります（[参考](https://kantaro-cgi.com/blog/etc-server/cant_run_rclocal_centos7.html)）。実行権限を付与します。

```
$ chmod u+x /etc/rc.d/rc.local
```
root権限で`shutdown -r now`でEC2を再起動します。
ブラウザでサーバにアクセスし、jupyterのlogin画面が出たら成功です。

## AMIからサーバを再作成
ここまでサーバを構築出来たら、サーバのイメージを作成します。そして作成されたAMIを元に好きなスペックでサーバを立て直します。私はC5.4xlargeインスタンス（メモリ32GiB、ストレージ100GiB）で作成しなおしました。1時間約80円です。まあまあします。

# おまけ
データの移動などのために、`ec2-user`のディレクトリの権限を開放しておくと便利だと思い、`chmod 777 ec2-user`をしたら、外部からsshで接続できなくなりました。
次のコマンドで元に戻りました。

```
$ chmod 755 ec2-user
```

# おわりに
AWSにjupyterを構築しました。噂ではGCPのほうがコストが安くなるとかで、そちらも試してみたいです。