CentOS7 でPython3 環境を整える

#はじめに

Python 環境をCent OS で構築する際の手順をメモする．
あくまでも構築手順に関するメモなので，実際に本番環境で構築する際は，今回の情報で本番環境を構築・運用するわけではない．
環境は以下の通りで，VMware 上の仮想マシンで構築する．

- OS: Cent OS 7.5.1804
- 仮想化ソフト: VMware Workstation Pro 15.5.6 build-16341506
- CPU: 1 Processors
- メモリ: 1 GB
- ディスク: 50.0 GB
- Network Adapter: NAT (192.168.249.130/24)

やりたいことは以下のとおりである．

- Anaconda のインストール
- Qiskit のインストール
- JupyterHub の構築
- JupyterHub のサービス化

以下の手順からは，OS インストール済みで実施することを前提としている．
約束事として，\#はroot ユーザー，$ は一般ユーザー，>>> はpython実行中を表すプロンプトとする．

まず初めに，アップデートしておく．

```terminal:実行コマンド
# yum update 
```

次に，jupyter 用のユーザーを作成しておく．

```terminal:ユーザーの作成
# useradd jupyter
# passwd jupyter
ユーザー jupyter のパスワードを変更。
新しいパスワード:
新しいパスワードを再入力してください:
passwd: すべての認証トークンが正しく更新できました。
```

#Anaconda のインストール

まずは，インストールしたいバージョンのインストーラをダウンロードする．

```terminal:Anacondaインストールシェルのダウンロード
# wget https://repo.continuum.io/archive/Anaconda3-5.3.1-Linux-x86_64.sh
```

次に，ダウンロードしたインストーラを実行する．
初期設定の際，インストールディレクトリを尋ねられるが，初期設定ではなく/opt/anaconda3/ を設定する．それ以外は，yesで進める．

```terminal:インストールシェルの実行
# bash Anaconda3-5.3.1-Linux-x86_64.sh
...
Anaconda3 will now be installed into this location:
/root/anaconda3

  - Press ENTER to confirm the location
  - Press CTRL-C to abort the installation
  - Or specify a different location below

[/root/anaconda3] >>> /opt/anaconda3/  <- インストールディレクトリを変更する
```

一度シェルを再読み込みしないと，パスが読み込まれておらずconda コマンドが使用できないかもしれないので，再読み込みする．

```terminal:シェルプロファイルの再読み込み
# source ~/.bashrc
```

その後，試しにバージョン確認を実施する．

```terminal:Anacondaのバージョン確認
# conda --version
conda 4.8.4
```

Anaconda がインストールされており，バージョン情報が表示された．

#Qiskit のインストール

ここまでで，Anaconda のインストールが完了したので，次にQiskit をインストールする．

まずは，gcc をインストールする．

```terminal:gccのインストール
# yum install gcc
```

次に，Anaconda の仮想環境を起動し，そこでqiskit をインストールする．

```terminal:Qiskitのインストール
# conda create -n myenv python=3
# source activate myenv
(myenv) # pip install qiskit
```

インストールされているか，確認する．

```terminal:Qiskitのインストール確認
(myenv) # conda list | grep qiskit
qiskit                    0.21.0                   pypi_0    pypi
qiskit-aer                0.6.1                    pypi_0    pypi
qiskit-aqua               0.7.5                    pypi_0    pypi
qiskit-ibmq-provider      0.9.0                    pypi_0    pypi
qiskit-ignis              0.4.0                    pypi_0    pypi
qiskit-terra              0.15.2                   pypi_0    pypi
```

次に，インストールされているQiskit のバージョンを確認する．

```terminal:python実行
(myenv) # python
Python 3.8.5 (default, Sep  4 2020, 07:30:14) 
[GCC 7.3.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
```

Qiskit をインポートし，バージョン確認のコマンドを実行する．

```python:Qiskitのバージョン確認
>>> import qiskit
>>> qiskit.__qiskit_version__
{'qiskit-terra': '0.15.2', 'qiskit-aer': '0.6.1', 'qiskit-ignis': '0.4.0', 'qiskit-ibmq-provider': '0.9.0', 'qiskit-aqua': '0.7.5', 'qiskit': '0.21.0'}
```

確認が完了したら，Ctrl-D で，python を終了する．

#JupyterHub のインストール

```terminal:JupyterHubのインストール
# conda install -c conda-forge jupyterhub
# conda install notebook
```

インストールが完了したら，コンフィグファイルを作成していく．

```terminal:コンフィグファイルの生成
(myenv) # cd /opt/
(myenv) # jupyterhub --generate-config
Writing default config to: jupyterhub_config.py
# ls -l
合計 44
drwxr-xr-x. 26 root root  4096  9月 18 18:49 anaconda3
-rw-r--r--.  1 root root 40275  9月 18 19:00 jupyterhub_config.py
drwxr-xr-x.  2 root root     6 10月 31  2018 rh
```

コンフィグファイルが作成できたら，編集していく．

```terminal:コンフィグファイルの編集
(myenv) # vim jupyterhub_config.py 
```

以下の内容を追記する．下2行は，サービス化のために必要な設定である．

```py:/opt/jupyterhub_config.py
c.Spawner.notebook_dir = '~/notebook'

c.Authenticator.whitelist = {'jupyter'}

c.Authenticator.admin_users = {'root'}

c.ConfigurableHTTPProxy.command = '/opt/anaconda3/envs/myenv/bin/configurable-http-proxy'

c.Spawner.cmd = ['/opt/anaconda3/envs/myenv/bin/jupyterhub-singleuser']
```

次に，JupyterHub を使用するユーザーのディレクトリを作成する．

```terminal:ユーザー用のディレクトリ作成
# mkdir -p /home/jupyter/notebook
# chown jupyter:jupyter /home/jupyter/notebook
```

JupyterHub を起動させる．

```terminal:JupyterHubの起動
# jupyterhub &
```

JupyterHub は，8000番のポートで実行されるので，8000番のポートを許可する．

```terminal:ファイアウォールの許可設定
# firewall-cmd --add-port=8000/tcp --permanent 
success
# firewall-cmd --reload 
success
```

ホストマシンから，http://192.168.249.130:8000/ にアクセスしてみる．

![jupyterhub.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/a5a65191-0cf1-a87f-47b6-e4349e43b3d9.png)

アクセスできた．

次に，jupyter ユーザーでログインしてみる．

![jupyterhub_loggedin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/124ea096-b7c8-08a3-2108-9af10095c4a7.png)


ログインできた．

Qiskit が実行できるか確認してみる．

![jupyterhub_qiskit.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/5630472b-239c-1c36-3e54-ccfcd6763c47.png)

実行できた．

#JupyterHub のサービス化

最後に，サービス化を行う．

各種設定を実施する．

```terminal:jupyterhubサービス化のための設定
# conda install --quiet --yes notebook jupyterhub nodejs configurable-http-proxy
# npm install -g configurable-http-proxy
# ln -s /usr/bin/nodejs /usr/bin/node
# npm -v
# npm cache clean -f
# npm install -g n
# n stable
```

サービス登録の定義ファイル作成のために，jupyterhub コマンドのパスを確認する．

```terminal:jupyterhubのパス確認
(myenv) # which jupyterhub
/opt/anaconda3/envs/myenv/bin/jupyterhub
```

情報が取得できたら，定義ファイルを作成する．

```terminal:定義ファイルの作成
(myenv) # vim /etc/systemd/system/jupyterhub.service
```

以下の内容を追記する．

```conf:/etc/systemd/system/jupyterhub.service
[Unit]
Description = JupyterHub

[Service]
Type=simple
PIDFile=/var/run/jupyterhub.pid
ExecStart=/opt/anaconda3/envs/myenv/bin/jupyterhub
WorkingDirectory=/opt/
Restart=always

[Install]
WantedBy = multi-user.target
```

定義ファイルが完成したら，読み込みを開始する．

```terminal:定義ファイル読み込み
# systemctl daemon-reload
```

読み込んだら，サービスを起動する．

```terminal:サービス起動
# systemctl start jupyterhub.service
```

サービスの状態を確認する．
一部エラーが出ているが，無事に起動はできており，ログインもできていた．
Qiskit も無事に動作している．

```terminal:サービス状態確認
(myenv) # systemctl status jupyterhub.service
● jupyterhub.service - JupyterHub
   Loaded: loaded (/etc/systemd/system/jupyterhub.service; enabled; vendor preset: disabled)
   Active: active (running) since 金 2020-09-18 21:27:20 JST; 7min ago
 Main PID: 3291 (python)
    Tasks: 7
   CGroup: /system.slice/jupyterhub.service
           └─3307 node /opt/anaconda3/envs/myenv/bin/configurable-http-proxy --ip --port 8000 --api-ip 127.0.0.1 --api-port 8001 --error-target http://...
           ‣ 3291 /opt/anaconda3/envs/myenv/bin/python /opt/anaconda3/envs/myenv/bin/jupyterhub

 9月 18 21:27:21 localhost.localdomain jupyterhub[3291]: 21:27:21.575 [ConfigProxy] info: 201 POST /api/routes/
 9月 18 21:27:21 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:21.577 JupyterHub app:2422] JupyterHub is now running at http://:8000
 9月 18 21:27:29 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:29.928 JupyterHub log:174] 200 GET /hub/spawn-pending/jupyter (jup...29.88ms
 9月 18 21:27:33 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:33.252 JupyterHub login:43] User logged out: jupyter
 9月 18 21:27:33 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:33.262 JupyterHub log:174] 302 GET /hub/logout -> /hub/login (jupy...16.03ms
 9月 18 21:27:33 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:33.276 JupyterHub log:174] 200 GET /hub/login (@::ffff:192.168.249.1) 8.34ms
 9月 18 21:27:40 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:40.212 JupyterHub base:663] User logged in: jupyter
 9月 18 21:27:40 localhost.localdomain jupyterhub[3291]: [I 2020-09-18 21:27:40.213 JupyterHub log:174] 302 POST /hub/login?next= -> /hub/spawn...12.63ms
 9月 18 21:27:40 localhost.localdomain python[3291]: pam_loginuid(login:session): Error writing /proc/self/loginuid: Operation not permitted
 9月 18 21:27:40 localhost.localdomain python[3291]: pam_loginuid(login:session): set_loginuid failed
Hint: Some lines were ellipsized, use -l to show in full.
```

最後に，サービスの自動化を有効にしておく．
これで，OS がシャットダウンしたとしても，起動と同時にサービスが立ち上がり今までと同様にいつでもWeb ブラウザからアクセスしてJupyter を利用できる．

```terminal:自動実行の有効化と確認
# systemctl enable jupyterhub
# systemctl is-enabled jupyterhub
enabled
```

実際，ゲストOS を再起動させてからホストマシンのWeb ブラウザよりアクセスを試みて，無事にアクセスおよびログインできた．

#おわりに
今回やりたかった，Qiskit が使える環境を全ユーザーに作成してWebブラウザから認証を通して利用してもらう環境の構築ができて9割満足である．
ただし，エラーが出ていたり環境構築的に不備があるところがあるので，今後はそのあたりを詰めていきたい．

やる気がいろいろと起きない中，半日を使って一気にまとめ上げることができたので，明日以降にウォーミングアップにはちょうど良かった．Jupyter Notebook のサービス化はすんなりいったのに，JupyterHub のサービス化は次々とエラーが発生し，一つ解決するのが困難だったため，もう二度と何もなしで実施はしたくないなあと感じた．(そのためにこの記事がある)

#今後の課題
- エラーの原因調査，解消
- JupyterHub のTLS 化
- 本番環境でも問題ない設定の実施 (そもそも設定の調査から)

#【参考】発生したエラーたち
- FileNotFoundError: [Errno 2] No such file or directory: 'configurable-http-proxy'
→ おそらく，c.ConfigurableHTTPProxy.command = '/opt/anaconda3/envs/myenv/bin/configurable-http-proxy' や conda install --quiet --yes notebook jupyterhub nodejs configurable-http-proxy，npm install -g configurable-http-proxy あたりで解決
- /usr/bin/env: node: そのようなファイルやディレクトリはありません → npm -v，npm cache clean -f，npm install -g n，n stable あたりで解決
- FileNotFoundError: [Errno 2] No such file or directory: 'jupyterhub-singleuser'  → c.Spawner.cmd = ['/opt/anaconda3/envs/myenv/bin/jupyterhub-singleuser'] で解決

#参考文献 
- https://qiita.com/cvusk/items/afa46c35d8d5f0d930ed
- https://qiskit.org/documentation/locale/ja/install.html
- https://ideanotes.cloud/2020/01/29/ubuntu-anaconda-opencv-failed/
- https://www.it-swarm-ja.tech/ja/node.js/nodejs%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB%E3%81%A7%E3%81%8D%E3%81%AA%E3%81%84%EF%BC%9A-usrbinenv%EF%BC%9Anode%EF%BC%9A%E3%81%9D%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%BE%E3%81%9F%E3%81%AF%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%88%E3%83%AA%E3%81%AF%E3%81%82%E3%82%8A%E3%81%BE%E3%81%9B%E3%82%93/1049453097/
- https://github.com/jupyterhub/jupyterhub/issues/313