CentOS でJupyter Notebookをサービス化する

#はじめに

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.129/24)

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

- Python 3 のインストール
- Qiskit のインストール
- Anaconda のインストール
- Jupyter のインストール
- Jupyter のサービス化

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

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

```terminal:OSのアップデート
# yum update 
```

#Python 3 のインストール

標準で使用できるPython 2 ではなく，Python 3 を使用したいので，インストールする．

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

インストール後，インストール確認も含めバージョン情報を表示する．
Python 3.6.8 がインストールされていることが分かる．

```terminal:Pythonのバージョン確認
# python3 --version
Python 3.6.8
```

また，python コマンドで今回導入したpython3 を使用したいため，設定を行う．

```terminal:プロファイル編集
# vim ~/.bashrc
```

.bashrc の末尾に，以下の内容を追記する．
追記後，一度ログアウトし，再度ログインする．

```bash:/root/.bashrc
alias python="python3" 
alias pip="pip3"
```

試しに，python コマンドでバージョン確認してみる．
python3 が指定されていることが分かる．

```terminal:Pythonのバージョン確認
# python --version
Python 3.6.8
```

#Anaconda のインストール

pyenv のインストールにgit が必要なため，まずはgit をインストールする．

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

pyenv をインストールしていく．

```terminal:pyenvのインストール
# git clone https://github.com/yyuu/pyenv.git ~/.pyenv
# pyenv install -l | grep anaconda
  anaconda-1.4.0
  anaconda-1.5.0
  anaconda-1.5.1
  anaconda-1.6.0
  anaconda-1.6.1
  anaconda-1.7.0
  anaconda-1.8.0
  anaconda-1.9.0
  anaconda-1.9.1
  anaconda-1.9.2
  anaconda-2.0.0
  anaconda-2.0.1
  anaconda-2.1.0
  anaconda-2.2.0
  anaconda-2.3.0
  anaconda-2.4.0
  anaconda-4.0.0
  anaconda2-2.4.0
  anaconda2-2.4.1
  anaconda2-2.5.0
  anaconda2-4.0.0
  anaconda2-4.1.0
  anaconda2-4.1.1
  anaconda2-4.2.0
  anaconda2-4.3.0
  anaconda2-4.3.1
  anaconda2-4.4.0
  anaconda2-5.0.0
  anaconda2-5.0.1
  anaconda2-5.1.0
  anaconda2-5.2.0
  anaconda2-5.3.0
  anaconda2-5.3.1
  anaconda2-2018.12
  anaconda2-2019.03
  anaconda2-2019.07
  anaconda3-2.0.0
  anaconda3-2.0.1
  anaconda3-2.1.0
  anaconda3-2.2.0
  anaconda3-2.3.0
  anaconda3-2.4.0
  anaconda3-2.4.1
  anaconda3-2.5.0
  anaconda3-4.0.0
  anaconda3-4.1.0
  anaconda3-4.1.1
  anaconda3-4.2.0
  anaconda3-4.3.0
  anaconda3-4.3.1
  anaconda3-4.4.0
  anaconda3-5.0.0
  anaconda3-5.0.1
  anaconda3-5.1.0
  anaconda3-5.2.0
  anaconda3-5.3.0
  anaconda3-5.3.1
  anaconda3-2018.12
  anaconda3-2019.03
  anaconda3-2019.07
  anaconda3-2019.10
  anaconda3-2020.02
```

最新のanaconda をインストールする．

```terminal:anacondaのインストール
# pyenv install anaconda3-5.3.1
```

設定をしていく．

```terminal:anacondaの設定
# pyenv rehash
# pyenv global anaconda3-5.3.1
# echo 'export PATH="$PYENV_ROOT/versions/anaconda3-5.3.1/bin/:$PATH"' >> ~/.bashrc
# source ~/.bashrc
# conda update conda
```

バージョンを確認してみる．

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

#Qiskit のインストール

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

```terminal:Qiskitのインストール
# pip install qiskit
```

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

```terminal:Qiskitのインストール確認
# 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実行
# python
```

```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 を終了する．

#Jupyter のインストール

次に，jupyter をインストールしてみる．
コマンド補完をしてみると，すでに jupyter がインストールされているようなので，実行してみると以下のエラーが出力された．

```terminal:jupyterの実行エラー
# jupyter --version
Traceback (most recent call last):
  File "/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter", line 7, in <module>
    from jupyter_core.command import main
ModuleNotFoundError: No module named 'jupyter_core'
```

一度conda からjupyter をインストールしてみる．

```terminal:jupyterのインストール
# conda install jupyter
```

すると，以下のようなエラーが出力されてインストールが完了しない．

```terminal:jupyterインストール時のエラー
failed with initial frozen solve. Retrying with flexible solve.
Solving environment: - 強制終了
```

ググってみて，以下のコマンドを実行してみた．

```terminal:condaのアップデート
# conda update --all
```

上記のコマンドでもエラーがでた．次に試しに以下のコマンドを実行した．

```terminal:OpenCVのインストール
# conda install -c menpo opencv
```

こっちはうまくいった．再度jupyter をインストールしてみる．

```terminal:jupyterのインストール再挑戦
# conda install jupyter
Collecting package metadata (repodata.json): done
Solving environment: done

# All requested packages already installed.
```

ちゃんとインストールされているようにみえる．
バージョン情報を確認してみる．

```terminal:jupyterのバージョン確認
# jupyter --version
4.4.0
```

ちゃんとインストールされていて，動作もする．

Jupyter Notebook の設定を行う．

```terminal:jupyterの起動準備
# jupyter --path
config:
    /root/.jupyter
    /root/.pyenv/versions/anaconda3-5.3.1/etc/jupyter
    /usr/local/etc/jupyter
    /etc/jupyter
data:
    /root/.local/share/jupyter
    /root/.pyenv/versions/anaconda3-5.3.1/share/jupyter
    /usr/local/share/jupyter
    /usr/share/jupyter
runtime:
    /run/user/1000/jupyter
# mkdir ~/.jupyter
# touch ~/.jupyter/jupyter_notebook_config.py
# mkdir ~/jupyter_files
# touch ~/jupyter_files/test.py
# ipython
```

```python:ログインパスワードの設定
Python 3.7.0 (default, Oct  9 2018, 10:31:47) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.5.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from notebook.auth import passwd

In [2]: passwd()
Enter password: 
Verify password: 
Out[2]: 'sha1:da72b0981831:41b14f79bbfeda08322cfdb3a056a58fc70c65ea'

In [3]: exit
```

Out[2] のパスワードのハッシュ値は次のコンフィグファイルの編集で使用するため，テキストエディタ等に控えておく．

```terminal:コンフィグファイルの編集
vim ~/.jupyter/jupyter_notebook_config.py
```

コンフィグファイルに以下を追記する．
パスワードのハッシュ値については，ログインパスワードの設定のところで出力された値をそれぞれコピー&ペーストすること．

```py:/root/.jupyter/jupyter_notebook_config.py
c = get_config()

c.NotebookApp.ip = '*'
c.NotebookApp.open_browser = False
c.NotebookApp.port = 8888
c.NotebookApp.password = u'sha1:da72b0981831:41b14f79bbfeda08322cfdb3a056a58fc70c65ea'
c.NotebookApp.notebook_dir = '/root/jupyter_files/'
```

Jupyter Notebook を起動する．本環境はお試し環境であり，root ユーザーで設定しているので，以下のコマンドを実行する．

```terminal:notebookの起動
# jupyter notebook --allow-root
```

その後，Web ブラウザを用いてhttp://localhost:8888/ にアクセスしてみる．

![JN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/5c4016d8-c29f-784e-a88d-760372c47174.png)

アクセスできたので，先ほど設定したログインパスワードでログインしてみる．

![JNlogined.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/11bf3256-4c8a-7f58-20a9-f383e9029032.png)

無事ログインできた．先ほど作成した確認用のファイルtest.py も確認できる．

次に，ホストマシンのWeb ブラウザを用いてアクセスできるようにする．
ファイアウォールでポート8888 を許可する．

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

ホストマシンのWeb ブラウザからhttp://192.168.249.129:8888/ にアクセスしてみる．

![JN_host.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/438083/86d4da02-0a1c-8556-a01e-f54be40e23ae.png)

無事にアクセスできた．

#Jupyter のサービス化

Jupyter をsystemd で制御できるように設定する．まずは，jupyter のパスを確認する．

```terminal:jupyterのパス確認
# which jupyter
/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter
```

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

<b>※以下の内容ではうまく実行できません</b>

```conf:/etc/systemd/system/notebook.service
[Unit]
Description = Jupyter Notebook

[Service]
Type=simple
PIDFile=/var/run/jupyter-notebook.pid
ExecStart=/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter notebook
WorkingDirectory=/root/
User=root
Group=root
Restart=always

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

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

```terminal:サービス起動
# systemctl start notebook
```

サービスの状態を確認すると，失敗していた．

```terminal:サービスの状態確認(失敗)
# systemctl status notebook
● notebook.service - Jupyter Notebook
   Loaded: loaded (/etc/systemd/system/notebook.service; disabled; vendor preset: disabled)
   Active: failed (Result: start-limit) since 金 2020-09-18 15:21:44 JST; 1min 8s ago
  Process: 18766 ExecStart=/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter notebook (code=exited, status=1/FAILURE)
 Main PID: 18766 (code=exited, status=1/FAILURE)

 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service: main process exited, code=exited, status=1/FAILURE
 9月 18 15:21:44 localhost.localdomain systemd[1]: Unit notebook.service entered failed state.
 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service failed.
 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service holdoff time over, scheduling restart.
 9月 18 15:21:44 localhost.localdomain systemd[1]: Stopped Jupyter Notebook.
 9月 18 15:21:44 localhost.localdomain systemd[1]: start request repeated too quickly for notebook.service
 9月 18 15:21:44 localhost.localdomain systemd[1]: Failed to start Jupyter Notebook.
 9月 18 15:21:44 localhost.localdomain systemd[1]: Unit notebook.service entered failed state.
 9月 18 15:21:44 localhost.localdomain systemd[1]: notebook.service failed.
```

原因をいろいろ考えていると，最初の起動は--allow-root を付与していたのに，今回の設定ファイルでは付与し忘れていたのを思い出した．
以下のように設定ファイルを再編集する．

```conf:/etc/systemd/system/notebook.service
[Unit]
Description = Jupyter Notebook

[Service]
Type=simple
PIDFile=/var/run/jupyter-notebook.pid
ExecStart=/root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter notebook --allow-root
WorkingDirectory=/root/
User=root
Group=root
Restart=always

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

再度，設定ファイルの読み込みをしてサービスを起動させる．

```terminal:設定ファイル再読み込みとサービス起動
# systemctl daemon-reload
# systemctl start notebook
```

サービスの状態を確認する．

```terminal:サービスの状態確認(成功)
# systemctl status notebook
● notebook.service - Jupyter Notebook
   Loaded: loaded (/etc/systemd/system/notebook.service; enabled; vendor preset: disabled)
   Active: active (running) since 金 2020-09-18 15:29:38 JST; 3min 8s ago
 Main PID: 19068 (jupyter-noteboo)
    Tasks: 1
   CGroup: /system.slice/notebook.service
           └─19068 /root/.pyenv/versions/anaconda3-5.3.1/bin/python /root/.pyenv/versions/anaconda3-5.3.1/bin/jupyter-notebook --...

 9月 18 15:29:38 localhost.localdomain systemd[1]: Started Jupyter Notebook.
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [W 15:29:39.391 NotebookApp] WARNING: The notebook server is listeni...nded.
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.393 NotebookApp] The port 8888 is already in use, trying...port.
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.423 NotebookApp] JupyterLab extension loaded from /root/...erlab
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.423 NotebookApp] JupyterLab application directory is /ro...r/lab
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.426 NotebookApp] Serving notebooks from local directory:...files
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.426 NotebookApp] The Jupyter Notebook is running at:
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.426 NotebookApp] http://(localhost.localdomain or 127.0....8889/
 9月 18 15:29:39 localhost.localdomain jupyter[19068]: [I 15:29:39.427 NotebookApp] Use Control-C to stop this server and s...ion).
Hint: Some lines were ellipsized, use -l to show in full.
```

今度は無事に立ち上がった見たい．
自動実行を有効にする．

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

自動起動が有効化された．確認のため，ゲストOSを再起動したあと，ホストマシンから先ほどのURL でアクセスしてみたが，無事にアクセスできた．これで常にJupyter Notebook が立ち上がっている状態になり，Web ブラウザを用いて利用可能になった．

#おわりに

今回試してみて思ったのが，root ユーザーでの実行は推奨されていないうえ，コマンドもオプションが必要になってきていろいろ面倒なので，サービスユーザーを作成して当ユーザーでサービスを実行したほうが良いと感じた．
あと，別記事で書いていますが，これやるならJupyterHub の方がよいと感じた．

#参考文献 
- https://qiita.com/iamdaisuke/items/3671032a18f5c4bf37d1
- https://qiskit.org/documentation/locale/ja/install.html
- https://ideanotes.cloud/2020/01/29/ubuntu-anaconda-opencv-failed/