AWS EC2(Ubuntu 16.04)にJupyterHub+R実行環境を構築する

2016.07.14

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

ブラウザ上で稼働する対話型実行環境『Python Notebook』(※参考)をリモートサーバー上で公開出来るサービスに『JupyterHub』というものがあります。当エントリでは、その環境をUbuntu16.04にインストールし、併せてJupyterHub上でR実行環境を整える手順についてもまとめてみたいと思います。

目次

下準備

今回導入を行うEC2環境はUbuntuとなります。バージョンは16.04。

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04 LTS"

下記エントリで導入を行った環境をそのまま活用してみました。

まず始めに、ログイン後の各種パッケージを最新のものに更新、次いで必要なパッケージを追加でインストールしておきます。

$ ssh -i rstudio_and_jupyterhub_key.pem ubuntu@xx.xxx.xx.xxx
The authenticity of host 'xx.xxx.xx.xxx (xx.xxx.xx.xxx)' can't be established.
RSA key fingerprint is xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'xx.xxx.xx.xxx' (RSA) to the list of known hosts.
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-22-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

0 packages can be updated.
0 updates are security updates.

$ 
$ sudo apt-get -y update
$ sudo apt-get -y upgrade
$ sudo apt-get -y install git gcc g++ make openssl libssl-dev libbz2-dev libreadline-dev libsqlite3-dev python-dev libmysqlclient-dev

Python3系環境のインストール

PythonHubを利用するにはPython3系の環境が必要となるので、PythonHub導入前にそちらの環境を整備します。今回の対象OSでは、導入されているバージョンは以下の様に2.7系でした。

$ python --version
Python 2.7.11+

Python実行環境の整備にはpyenvを活用します。以下コマンド実行で導入。

$ git --version
git version 2.7.4
$ git clone https://github.com/yyuu/pyenv.git ~/.pyenv
Cloning into '/home/ubuntu/.pyenv'...
remote: Counting objects: 13279, done.
remote: Total 13279 (delta 0), reused 0 (delta 0), pack-reused 13279
Receiving objects: 100% (13279/13279), 2.35 MiB | 0 bytes/s, done.
Resolving deltas: 100% (9243/9243), done.
Checking connectivity... done.

~/.bashrcファイルを開き、ファイル末尾に以下の内容を追記。保存後、再読み込みを行います。

$ vi ~/.bashrc
----
# 2016/07/11 Added
export PYENV_ROOT="${HOME}/.pyenv"
if [ -d "${PYENV_ROOT}" ]; then
export PATH=${PYENV_ROOT}/bin:$PATH
eval "$(pyenv init -)"
fi
$
$ source ~/.bashrc

pyenv install --listコマンドでインストール可能なPythonのバージョンを確認してみます。Python3系で利用可能な正式リリースバージョンは現時点では3.5.2となるようです。

$ pyenv install --list
Available versions:
  2.1.3
  2.2.3
  2.3.7
  2.4
  2.4.1
  :
  3.4.5
  3.5.0
  3.5-dev
  3.5.1
  3.5.2
  3.6.0a1
  3.6.0a2
  3.6-dev
  anaconda-1.4.0
  anaconda-1.5.0
  :  
  stackless-3.3-dev
  stackless-3.3.5
  stackless-3.4.1
$

pyenv installコマンドでバージョンを指定してインストール実施。

$ pyenv install 3.5.2
Downloading Python-3.5.2.tar.xz...
-> https://www.python.org/ftp/python/3.5.2/Python-3.5.2.tar.xz
Installing Python-3.5.2...
Installed Python-3.5.2 to /home/ubuntu/.pyenv/versions/3.5.2

pyenv versionsコマンドで切り替え可能なPythonのバージョン一覧を出してみます。3.5.2も一覧表示はされていますが、現在の環境とはなっていない模様。

$ pyenv versions
* system (set by /home/ubuntu/.pyenv/version)
  3.5.2

バージョンをpyenv globalで指定して切り替え、情報を反映させます。

$ pyenv global 3.5.2
$ pyenv rehash

改めてバージョンを確認。3.5.2が指定・設定されている事を確認出来ました。

$ python --version
Python 3.5.2
$ pyenv versions
  system
* 3.5.2 (set by /home/ubuntu/.pyenv/version)

nvm/npm周りの環境整備

JupyterHub導入にはNode.jsが必要となるらしいのでこの辺りの環境についても最新版で整えたいと思います。nvm最新版を以下の形で導入。ターミナルの再ログインを行う旨促されるので、

$ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.31.2/install.sh | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  7766  100  7766    0     0  22104      0 --:--:-- --:--:-- --:--:-- 22125
=> Downloading nvm from git to '/home/ubuntu/.nvm'
=> Cloning into '/home/ubuntu/.nvm'...
remote: Counting objects: 4888, done.
remote: Total 4888 (delta 0), reused 0 (delta 0), pack-reused 4887
Receiving objects: 100% (4888/4888), 1.34 MiB | 0 bytes/s, done.
Resolving deltas: 100% (2925/2925), done.
Checking connectivity... done.
* (HEAD detached at v0.31.2)
  master

=> Appending source string to /home/ubuntu/.bashrc
=> You currently have modules installed globally with `npm`. These will no
=> longer be linked to the active version of Node when you install a new node
=> with `nvm`; and they may (depending on how you construct your `$PATH`)
=> override the binaries of modules installed with `nvm`:

/usr/local/lib
└── configurable-http-proxy@1.2.0

=> If you wish to uninstall them at a later point (or re-install them under your
=> `nvm` Nodes), you can remove them from the system Node as follows:

     $ nvm use system
     $ npm uninstall -g a_module

=> Close and reopen your terminal to start using nvm

再ログインを行い、nvm --versionで最新バージョンが導入されている事を確認します。

$ exit
logout
Connection to xxx.xx.xxx.xx closed.
$ ssh -i rstudio_and_jupyterhub_key.pem ubuntu@xxx.xx.xxx.xx
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-22-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  Get cloud support with Ubuntu Advantage Cloud Guest:
    http://www.ubuntu.com/business/services/cloud

7 packages can be updated.
7 updates are security updates.


*** System restart required ***
Last login: Fri Jul  8 xx:xx:xx:xx 2016 from xxx.xx.xxx.xx
$ nvm --version
0.31.2
$

nvm installコマンドで最新バージョンをインストールし、バージョンが更新されている事を確認。

$ nvm --version
0.31.2
$ node -v
v4.2.6
$ npm -v
3.5.2
$ nvm install v6.2.2
Downloading https://nodejs.org/dist/v6.2.2/node-v6.2.2-linux-x64.tar.xz...
######################################################################## 100.0%
Now using node v6.2.2 (npm v3.9.5)
Creating default alias: default -> v6.2.2
$ node -v
v6.2.2
$ npm -v
3.9.5

JupyterHub環境のインストール

JupyterHub環境のインストールにはpip/pip3を用います。

$ pip --version
pip 8.1.1 from /home/ubuntu/.pyenv/versions/3.5.2/lib/python3.5/site-packages (python 3.5)
$ pip3 --version
pip 8.1.1 from /home/ubuntu/.pyenv/versions/3.5.2/lib/python3.5/site-packages (python 3.5)

以下のパッケージをそれぞれインストール。

$ npm install -g configurable-http-proxy
$ pip3 install jupyterhub
$ pip install ipython[notebook] jupyterhub
$ jupyterhub --version
0.6.1

JupyterHubはPAMを認証方式として用いています。一番手っ取り早い認証の確認方法としてubuntuユーザーにパスワード設定を行って確認して見たいと思います。

$ sudo passwd ubuntu
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully

ひとまずオプション無しで起動してみます。色々怒られました...上から1つずつ見て行きましょう。

$ jupyterhub
[I 2016-07-11 08:01:33.309 JupyterHub app:643] Writing cookie_secret to /home/ubuntu/jupyterhub_cookie_secret
[W 2016-07-11 08:01:33.373 JupyterHub app:304] 
    Generating CONFIGPROXY_AUTH_TOKEN. Restarting the Hub will require restarting the proxy.
    Set CONFIGPROXY_AUTH_TOKEN env or JupyterHub.proxy_auth_token config to avoid this message.
    
[W 2016-07-11 08:01:33.382 JupyterHub app:757] No admin users, admin interface will be unavailable.
[W 2016-07-11 08:01:33.382 JupyterHub app:758] Add any administrative users to `c.Authenticator.admin_users` in config.
[I 2016-07-11 08:01:33.382 JupyterHub app:785] Not using whitelist. Any authenticated user will be allowed.
[E 2016-07-11 08:01:33.392 JupyterHub app:1228] Failed to bind hub to http://127.0.0.1:8081/hub/
[E 2016-07-11 08:01:33.392 JupyterHub app:1296]
    Traceback (most recent call last):
      File "/home/ubuntu/.pyenv/versions/3.5.2/lib/python3.5/site-packages/jupyterhub/app.py", line 1294, in launch_instance_async
        yield self.start()
      File "/home/ubuntu/.pyenv/versions/3.5.2/lib/python3.5/site-packages/jupyterhub/app.py", line 1226, in start
        self.http_server.listen(self.hub_port, address=self.hub_ip)
      File "/home/ubuntu/.pyenv/versions/3.5.2/lib/python3.5/site-packages/tornado/tcpserver.py", line 126, in listen
        sockets = bind_sockets(port, address=address)
      File "/home/ubuntu/.pyenv/versions/3.5.2/lib/python3.5/site-packages/tornado/netutil.py", line 196, in bind_sockets
        sock.bind(sockaddr)
    OSError: [Errno 98] Address already in use

CONFIGPROXY_AUTH_TOKENのくだりはプロキシー認証トークンを設定する必要があるとの事。まずは設定ファイルを作成する必要がありますので以下コマンドで設定ファイルを作成し、

$ jupyterhub --generate-config
Writing default config to: jupyterhub_config.py

認証トークン文字列をドキュメントに倣って作成。

$ export CONFIGPROXY_AUTH_TOKEN=`openssl rand -hex 32`
$ echo $CONFIGPROXY_AUTH_TOKEN
05f5(以下略)c730

設定ファイルを編集し、該当箇所にトークン文字列を設定します。

$ vi jupyterhub_config.py
----
# The Proxy Auth token.
# 
# Loaded from the CONFIGPROXY_AUTH_TOKEN env variable by default.
# c.JupyterHub.proxy_auth_token = ''
c.JupyterHub.proxy_auth_token = '05f5(中略)c730'

admin user〜のくだりについても設定ファイルに必要な情報を追記する事で対応出来ます。以下2箇所に利用するユーザーの情報を追記。

$ vi jupyterhub_config.py
----
# DEPRECATED, use Authenticator.admin_users instead.
# c.JupyterHub.admin_users = set()
c.JupyterHub.admin_users = { 'ubuntu' }
----
# Use this to restrict which users can login. If empty, allow any user to
# attempt login.
# c.Authenticator.whitelist = set()
c.Authenticator.whitelist = { 'ubuntu' }

ポート8081に関する問題については、このポートをどのプロセスが掴んでいるかを確認してみたいと思います。Python3が掴んでいるようです。

$ sudo netstat -anp | grep 8081
tcp        0      0 127.0.0.1:8081          0.0.0.0:*               LISTEN      1248/python3

ひとまずはこのポートを掴んでいるプロセスをkillしてみます。

$ sudo kill 1248

killした後、改めてjupyterhubを起動してみます。エラーメッセージはだいぶ減りましたが新たなメッセージが表示されました。こちらはJupyterHubがSSL接続をデフォルト且つ推奨している為、証明書を設定しましょうね、使わない場合は--no-sslオプションを使って起動しましょう、という旨が表示されています。

$ jupyterhub
[I 2016-07-11 08:14:47.375 JupyterHub app:622] Loading cookie_secret from /home/ubuntu/jupyterhub_cookie_secret
[W 2016-07-11 08:14:47.405 JupyterHub app:743] 
    JupyterHub.admin_users is deprecated.
    Use Authenticator.admin_users instead.
[I 2016-07-11 08:14:47.421 JupyterHub app:1231] Hub API listening on http://127.0.0.1:8081/hub/
[E 2016-07-11 08:14:47.424 JupyterHub app:963] Refusing to run JuptyterHub without SSL. If you are terminating SSL in another layer, pass --no-ssl to tell JupyterHub to allow the proxy to listen on HTTP.

ここはひとまず--no-sslオプションで起動させて見ることにします。サーバーの起動自体は上手く行った様です。

$ jupyterhub --no-ssl
[I 2016-07-11 09:38:18.457 JupyterHub app:622] Loading cookie_secret from /home/ubuntu/jupyterhub_cookie_secret
[W 2016-07-11 09:38:18.484 JupyterHub app:743] 
    JupyterHub.admin_users is deprecated.
    Use Authenticator.admin_users instead.
[I 2016-07-11 09:38:18.499 JupyterHub app:1231] Hub API listening on http://127.0.0.1:8081/hub/
[W 2016-07-11 09:38:18.502 JupyterHub app:959] Running JupyterHub without SSL. There better be SSL termination happening somewhere else...
[I 2016-07-11 09:38:18.502 JupyterHub app:968] Starting proxy @ http://*:8000/
09:38:18.619 - info: [ConfigProxy] Proxying http://*:8000 to http://127.0.0.1:8081
09:38:18.623 - info: [ConfigProxy] Proxy API at http://127.0.0.1:8001/api/routes
[I 2016-07-11 09:38:18.706 JupyterHub app:1254] JupyterHub is now running at http://127.0.0.1:8000/

先述の手順で設定したユーザー名とパスワードでログインを試みますが...

setup-jupyterhub_01

暫く応答が無かった後、エラーとなってしまいました。

setup-jupyterhub_02

吐かれた実行ログを確認してみると幾つか権限が足りない旨のエラーメッセージが表示されている事を確認出来ます。一旦JupyterHubを停止させて該当箇所の解決を図ってみます。(※サーバー停止はCrtl+Cで行えます。)

[I 2016-07-11 08:32:45.872 JupyterHub log:100] 200 GET /hub/login?next= (@::ffff:36.12.52.51) 21.30ms
sh: 1: cannot create /run/motd.dynamic.new: Permission denied
Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-22-generic x86_64)
:
PermissionError: [Errno 13] Permission denied: '/home/ubuntu/.local/share'
:
    TimeoutError: Server at http://127.0.0.1:32964/user/ubuntu didn't respond in 30 seconds

該当箇所を確認してみるとrootユーザーの所有となっています。ここは実行ユーザーのubuntuに所有者を変更。

$ ls -lta /home/ubuntu/
total 52488
drwxr-xr-x  9 ubuntu ubuntu     4096 Jul 11 08:38 .
-rw-r--r--  1 ubuntu ubuntu     8192 Jul 11 08:38 jupyterhub.sqlite
-rw-rw-r--  1 ubuntu ubuntu    14901 Jul 11 08:10 jupyterhub_config.py
  :
drwx------  3 root   root       4096 May  8 22:36 .local
  :
-rw-r--r--  1 ubuntu ubuntu      675 Aug 31  2015 .profile
$ sudo chown -R ubuntu.ubuntu .local/
$ ls -lta /home/ubuntu/
total 52488
drwxr-xr-x  9 ubuntu ubuntu     4096 Jul 11 08:38 .
-rw-r--r--  1 ubuntu ubuntu     8192 Jul 11 08:38 jupyterhub.sqlite
-rw-rw-r--  1 ubuntu ubuntu    14901 Jul 11 08:10 jupyterhub_config.py
  :
drwx------  3 ubuntu ubuntu     4096 May  8 22:36 .local
  :
-rw-r--r--  1 ubuntu ubuntu      675 Aug 31  2015 .profile

改めてJupyterHubを起動させ、ブラウザアクセス&ログインを実施。今度はちゃんと表示されました!

setup-jupyterhub_03

メニューからPython3を選び、

setup-jupyterhub_04

試しに簡単なコードを打ってみます。ちゃんと結果も返って来る様です。

setup-jupyterhub_05

R実行環境をJupyterHubと連動させる

ここまでの手順でだいぶ長くなってしまいましたが、『もうちょっとだけ続くんじゃ』的な感じでもう少しお付き合い頂ければと思います。ここからの手順ではJupyterHubからRを利用出来るような設定を行います。

まずは事前に必要となるライブラリをapt-getコマンドでインストール。

$ sudo apt-get -y install libzmq3 
$ sudo apt-get -y install libzmq3-dev

そしてRを起動。Rはこのタイミングで既に下記バージョンのものが導入されていますのでこれをそのまま使います。

$ R --version
R version 3.3.0 (2016-05-03) -- "Supposedly Educational"
Copyright (C) 2016 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under the terms of the
GNU General Public License versions 2 or 3.
For more information about these matters see
http://www.gnu.org/licenses/.

$ R

R version 3.3.0 (2016-05-03) -- "Supposedly Educational"
Copyright (C) 2016 The R Foundation for Statistical Computing
Platform: x86_64-pc-linux-gnu (64-bit)

R is free software and comes with ABSOLUTELY NO WARRANTY.
You are welcome to redistribute it under certain conditions.
Type 'license()' or 'licence()' for distribution details.

  Natural language support but running in an English locale

R is a collaborative project with many contributors.
Type 'contributors()' for more information and
'citation()' on how to cite R or R packages in publications.

Type 'demo()' for some demos, 'help()' for on-line help, or
'help.start()' for an HTML browser interface to help.
Type 'q()' to quit R.

>

R環境上で以下パッケージインストールのコマンドを実行。CRAN mirrorサイトの選択を促される場合もありますので、その際は任意のサイトを選択する事でインストール作業が進みます。

> install.packages(c('rzmq','repr','IRkernel','IRdisplay'), repos = c('http://irkernel.github.io/', getOption('repos')))
Installing packages into ‘/usr/local/lib/R/site-library’
(as ‘lib’ is unspecified)
Warning in install.packages(c("rzmq", "repr", "IRkernel", "IRdisplay"),  :
  'lib = "/usr/local/lib/R/site-library"' is not writable
Would you like to use a personal library instead?  (y/n) y
Would you like to create a personal library
~/R/x86_64-pc-linux-gnu-library/3.3
to install packages into?  (y/n) y
:
:
** R
** inst
** preparing package for lazy loading
** help
*** installing help indices
** building package indices
** testing if installed package can be loaded
* DONE (IRkernel)

The downloaded source packages are in
	‘/tmp/RtmpF8P4HY/downloaded_packages’
>

R環境上でもう1つコマンドを実行。これで環境が整いました。

> IRkernel::installspec()
[InstallKernelSpec] Installed kernelspec ir in /home/ubuntu/.local/share/jupyter/kernels/ir

Rの環境はここで一旦抜けます。

> q()
Save workspace image? [y/n/c]: y
$

JupyterHubを再起動&再ログイン。JupyterHubのメニューにRが追加されている事を確認出来ました!

setup-jupyterhub_06

まとめ

だいぶ長くなってしまいましたが、Ubuntu16.04環境にJupyterHub及びR実行環境を整える手順についてのご紹介でした。今回の環境構築にあたってはだいぶ試行錯誤を重ねた形でしたが、調査結果としてある程度の形にまとめる事が出来たのでひと安心と言ったところです。つうかPythonHub、かなり便利な環境ですね。PythonやRの勉強でも色々と活用してみたいと思います。こちらからは以上です。