CentOS7にSingularity 3.0.3+GPU環境を構築する

# はじめに
初投稿です．よろしくおねがいします．
ラボの計算用サーバの環境を更新するついでに，流行りのコンテナ技術を導入しようとした時の備忘録です．コンテナにはDockerではなくSingularityを選びました．

SingularityについてはDockerほどのシェアがないのか，日本語の記事も少ないようですので，これから使おうと思っている人の役に少しでも立てたらいいかなと思います．

## 目指すこと
- CentOS7.6 + Singularity 3.0.3 + GPU環境(CUDA 10.0)をインストール
- Chainer + GPUのコンテナでexampleを試してみる
- Juliaコンテナを立ち上げてみる(番外編)

## 環境
- OS: CentOS 7.6 (最小構成でのインストール)
- Singularity: 3.0.3
- GPU: NVIDIA GeForce GTX780(本番環境ではTeslaを使用予定)
- 作業はsshによるリモートアクセス

## 作業の流れ
1. OSのインストールやリモートアクセスの設定など(本記事では省略)
2. CUDA Toolkitをインストール
3. GPU driverをインストール
4. Singularityインストール
5. ChainerのexampleをSingularityコンテナで実行してみる

よくあるCUDA環境のセットアップではGPUドライバのインストールを行ってからCUDAのインストールを行うように説明されていますが，CUDA10.0のインストーラを入れるとドライバもインストールされるようです．しかし，何故かそれだけだとSingularityでGPUが動かず，GPU driver単体のインストーラでドライバもインストールすると動くようになる現象に見舞われています．やはり，デバイスを指定してダウンロードしたドライバでないといけないのでしょうか・・・CUDAを入れず，GPU driver単体でインストールしてもやはり動かないようです（原因はわかりませんでした・・・

# Singularityとは
- HPC向けのコンテナ
- Dockerだと何かとroot権限が必要だがsingularityは各ユーザがコンテナ立ち上げなどできる
- 開発が盛んでバージョンがどんどん上がっている

SingularityはDockerほど浸透していないためか，日本語の情報がわりと少ないようです．少しでもこれから使おうという人の役に立てばと思います．Qiitaだと[こちら](https://qiita.com/daikumatan/items/a1f442777f9b7bc13112)などがSingularityの情報が色々まとまっていました．

# CUDAインストール
色々とインストール記事が出ているので，詳細は専門の記事を参照してください．
ざっと自分がやった流れを以下にまとめます．

* 公式のCUDAインストールガイドは[こちら](https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html)．

まずは[ダウンロードサイト](https://developer.nvidia.com/cuda-downloads)からインストーラをダウンロード．今回はrpmでインストールするので，Installer Typeはrpm(local)を選択．

必要なパッケージをインストールしておく．
(wgetは後々使うので入れておく)

```shell:
sudo yum install -y pciutils wget
sudo yum install -y kernel-devel-$(unman -r) kernel-header-$(unman -r) gcc make
```

EPELリポジトリが必要なのでこれをインストール．

```shell:
sudo yum install -y epel-release
```

CUDAリポジトリをインストール

```shell:
sudo rpm --install <cuda-repo-...(落としてきたrpmファイル名)>
```

CUDAインストール．終わったら再起動．

```shell:
sudo yum clean expire-cache
sudo yum install -y cuda
sudo reboot
```

PATHとLD_LIBRARY_PATHの設定を.bashrcに記載しておく．記載したら.bashrcの再読込もしくはターミナルの再起動をしておきます．

```shell:
export PATH=/usr/local/cuda-10.0/bin:${PATH}
export LD_LIBRARY_PATH=/usr/local/cuda-10.0/lib64:${LD_LIBRARY_PATH}
```

# GPU driverのインストール
[公式サイト](https://www.nvidia.com/Download/index.aspx?lang=en-us)で自分のGPUに合ったドライバをダウンロードしてくる．

ダウンロードしてきたNVIDIA-Linux-x86_64-hogehoge.runを実行．

```shell:
sudo bash NVIDIA-Linux...hogehoge.run
```

終わったら再起動しておく．

```shell:
sudo reboot
```

基本的にはYesで進めれば大丈夫ですが，X window systemは入れていないので，これに関係する項目はNoを選択すればOK．

# Singularityのインストール
ここからが本番．
主な参考文献は以下の通りです．

* [公式サイト](https://www.sylabs.io/docs/)
* [GitHubリポジトリ](https://github.com/sylabs/singularity)
* [GitHubリポジトリのInstallation Instructions](https://github.com/sylabs/singularity/blob/master/INSTALL.md)

基本的にはGitHubリポジトリのInstallation Instructionsにある解説に沿って作業を行いました．CentOSなのでパッケージインストールはyum系コマンドを選びます．詳細は公式サイトのドキュメントやGitHubのinstructionsを参照してください．

## 1. 必要なパッケージのインストール
Singularityのインストールと運用に必要なパッケージをインストールしていく．SingularityにはGo言語が使われているらしい．

```shell:
sudo yum groupinstall -y 'Development Tools'
sudo yum install -y epel-release
sudo yum install -y golang openssl-devel libuuid-devel libseccomp-devel squashfs-tools
```

Githugのガイドにはgoのインストール手順も書いてありますが，CentOSの場合はyumで入ってしまうのでスキップしつつ，GOPATHの設定に進みます．

## 2. 環境変数の設定
GOPATHなる環境変数の設定を行います．これはSingularityのインストールで使われる変数のようです・・・(無視して進めたらエラーになりました)．
GOPATHの設定は.bashrcに書いておきます．

```shell:
# 開いた.bashrcに以下を記載
export GOPATH=${HOME}/go
export PATH=/usr/local/go/bin:${PATH}:${GOPATH}/bin
```

.bashrcに上記環境変数の設定をしたら.bashrcの再読み込みをします．

```shell:
source ~/.bashrc
```

## 3. リポジトリからのCloneとインストール
Githubからリポジトリをクローンしてきます．

```shell:
# 作業するディレクトリを作成
mkdir -p ${GOPATH}/src/github.com/sylabs
cd ${GOPATH}/src/github.com/sylabs
# clone
git clone https://github.com/sylabs/singularity.git
# クローンしたフォルダ内へ
cd singularity
```

この作業をした時点でのLatest versionは3.0.3だったので，このバージョンをチェックアウト．

```shell:
git checkout v3.0.3
```

あとは公式ドキュメントの通り，コンパイルとインストールを行います．

```shell:
# 下準備とコンパイル
./mconfig
cd ./builddir
make
# インストール
sudo make install
```

これでインストール完了です．以下のコマンドでバージョンが表示されれば成功です．

```shell:
singularity version
```

また，

```shell:
singularity -h
```
でコマンド一覧のヘルプを開けます．

# ChainerのコンテナでExampleを回してみる(GPU付き)
SingularityはDockerイメージをSingularityのコンテナイメージに変換して使うことができるので，DockerHubで公開されている資産を活用できます．流行りの深層学習関係のコンテナも使えます．ここではchainerのコンテナを試してみます．

Singularityのコンテナはhoge.sifと呼ばれるファイルで存在します(Singularity Image File: SIF)．これはユーザの任意の場所にダウンロードしておけばOKで，使いたいときにsingularityコマンドでこのコンテナのシェルにアクセスするような感じです．

## 1. Dockerコンテナをダウンロード&Singularityコンテナに変換

```shell:
singularity build chainer.sif docker://chainer/chainer:latest-python3
```

dockerfileをdockerhubからダウンロードし，chainer.sifファイルとしてsingularity向けのイメージファイルをビルドします．
なお，イメージのダウンロードは，

* [Singularity Hub](https://singularity-hub.org)から落とすときは，shub://<落としたいイメージ名>
* [dockerhub](https://hub.docker.com)の場合は，docker://<落としたいイメージ名>

とすれば選べます．

## 2. chainerのexampleをダウンロード
chainerのexampleは[公式サイト](https://chainer.org)のMNISTを学習するものを使います．
まずは，公式サイトに書いてある通り，ダウンロードして解凍．
場所は先の手順でSIFを保存したのと同じディレクトリとします．

```shell:
wget https://github.com/chainer/chainer/archive/v5.2.0.tar.gz
tar xzf v5.2.0.tar.gz
```

## 3. singularityコンテナで実行
singularityではdockerのexecコマンドと同様，引数に与えたコマンドをコンテナ内で実行するコマンドがあります．ここではこれを使います．

実際に，MNISTを学習するexampleを回してみましょう．

```shell:
singularity exec --nv chainer.sif python3 chainer-5.2.0/examples/mnist/train_mnist.py -g 0
```

--nvオプションの詳細については私もまだ把握できていませんが，GPUを用いる場合に必要です．

-g 0オプションはchainerのexampleのオプションです．これをつけないとtrain_mnist.pyはGPUを使ってくれません．

これでエラーなく実行できればコンテナからgpuでexampleを実行できたことになります．

# 番外編：Juliaコンテナを動かしてみる
先ほどはexecコマンドを使ってみましたが，ここではJuliaのコンテナをダウンロードしてきて，コンテナ内のシェルに入ってみようと思います．

```shell:
# dockerhubからJuliaイメージをダウンロード&sifファイルを作成
singularity build julia.sif docker://julia
# Juliaコンテナのシェルに入る
singularity shell julia.sif

# 入ったシェル内でJuliaを走らせてみる
julia
```

こんな感じで，コンテナ内のシェルに入るのも簡単です．ただし，.sifファイルは読み込み専用ファイルなので，コンテナ内で新しいパッケージのインストール(apt installなど)をしようとするとエラーとなります．
そのときは書き込みできる形でbuildする必要がありますが，そこらへんはまた別の機会にまとめたいと思います(まだ私もしっかり把握しきれていないので・・・)．

# まとめ
HPC向けコンテナのSingularityをインストールし，コンテナ内からGPUを利用する手順についてざっとまとめてみました．私も初めて使うので，変なところがたくさんありそうですので，気づかれたらコメントをお願いいたします．

ご覧の通り，Dockerと違い，Singularityではroot権限がなくてもコンテナの立ち上げや利用ができますので，研究室など，共有サーバで複数のユーザがアクセスして計算資源を使いたいといった場面に便利ではないでしょうか．

それに，コンテナの特徴である，一度環境を構築すれば簡単に配布できる，というメリットもあります．何よりdockerhubの膨大な資産が使えるのが素晴らしいですね．これで簡単に深層学習環境を構築してゴリゴリ回せそうです．

もう少しSingularityを使ってみて，知識がついてきたら，使い方についてもまとめてみたいと思います．