Edited at

検証用コンテナはDocker?いいえ、Singularityです。


はじめに

ストックマークの森長です。

弊社では、AWS、GCP、AzureのGPUインスタンス、自前のGPUサーバを利用して、自然言語モデルのモデル化・検証を行っています。

以前は、Dockerを導入することで、他のメンバやプロジェクトと機械学習基盤を共有する場合でも、それぞれのコンテナで環境を分離していました。

しかし、メンバが増えてきたことと検証環境を多数作成したことで以下の懸念点が見えてきました。


  • Dockerコンテナを起動するために、利用ユーザにsudo権限を付与しなければならない。

  • sudo権限で別の利用者のDockerコンテナを(誤って)操作できてしまう。

  • Dockerコンテナとホストでディレクトリを共有すると、コンテナ内で作成・編集したファイルのownerがrootになってしまう。

本番環境ではあまり上記の懸念点は問題ないかもしれませんが、弊社の検証環境では多くのメンバが利用し、学習済モデルや学習データの入れ替え・コピー、ソースの改変が頻発するため、検証目的としては煩雑かつセキュリティ的にも微妙でした。

また、nvidia-dockerが必須だったため、docker以外の選択肢は考えていませんでした。

(nvidia-dockerが必須な理由は以前の記事で書いた通りです。)

しかし、今年になって記事タイトルにあるとおり、検証用コンテナをDockerからSingularityに移行しました。

Singularityは弊社の検証環境にフィットしましたので、Singularityの概要と簡単な利用方法を紹介します。


1. Singularityとは

Singularityは、科学および高性能コンピューティング環境用に設計されたオープンソースベースのコンテナプラットフォームであり、以下のような特徴があります。


  • 一般ユーザアカウントでコンテナを起動・停止可能


    • つまり、ユーザアカウントにsudo権限を付与しなくても良い!



  • Dockerイメージを利用可能


    • つまり、docker及びnvidia-dockerのコンテナイメージが使える!!



  • 実行ユーザアカウントの権限をそのままコンテナに引き継ぎ


    • つまり、コンテナ内でファイルの作成・編集をしてもownerは実行ユーザのまま!!!



  • GPUの仮想化に対応


    • つまり、コンテナ起動時にオプションを付与すれば、コンテナ内でGPUも利用できる!x 4



  • ホストの$HOME配下をコンテナにバインド(共有)


    • つまり、$HOME以外にも以下がデフォルトでコンテナ側に共有されるので、モデルや教師データの移動やコピーが楽 !x 5

    • システム管理者がユーザにバインドを許可していた場合は、ユーザ側でバインド元と先を指定することも可能です。



ホスト(バインド元)
コンテナ(バインド先)

$HOME
$HOME

/sys
/sys

/proc
/proc

/tmp
/tmp

/var/tmp
/var/tmp

/etc/resolv.conf
/etc/resolv.conf

/etc/passwd
/etc/passwd

$PWD
$PWD

他にも色々特徴がありますが、ここまででも便利なことが伝わったと思います。

それでは、早速Singularityのインストールを始めます。


2.Singularityのインストール

以前、構築したGPUによる機械学習基盤へSingularityをインストールしていきます。他のGPU環境でもこの記事のように適切なGPUドライバのインストールが終わっていれば、SingularityでGPUを利用できると思います。

サーバ構成
バージョン等

ディストリビューション
CentOS 7.5(最小構成)

ファイルシステム
xfs

GPU
NVIDIA GeForce RTX 2080

基本的には、公式ドキュメントのInstallationに従ってインストールを進めます。


2-1.インストールに必要なパッケージのインストール

CentOSでコンパイルに必要なパッケージを以下のコマンドでインストールします。ディストリビューションがdebian系の場合は、必要なパッケージを公式ドキュメントで確認してください。

$ sudo yum update -y && \

sudo yum groupinstall -y 'Development Tools' && \
sudo yum install -y \
openssl-devel \
libuuid-devel \
libseccomp-devel \
wget \
squashfs-tools


2-2.Goのインストールと環境変数の設定

Singularityのインストールには、Goが必要になります。

CentOSでは2-1.でインストールしたパッケージにGoが含まれているので、別途Goのインストールの必要はありませんが、以下のコマンドでGoの環境変数を設定する必要があります。

# 環境変数の設定

$ echo 'export GOPATH=${HOME}/go' >> ~/.bashrc
$ echo 'export PATH=/usr/local/go/bin:${PATH}:${GOPATH}/bin' >> ~/.bashrc
# 環境変数の読み込み
$ source ~/.bashrc

Singularityのインストール完了後は、追加したGOPATHとPATHを削除して問題ありません。


2-3. Singularityのダウンロード

Singularityのリリース状況をここで確認します。

今回のバージョンは3.1.1です。以下のコマンドでダウンロードします。

# バージョンを指定

$ export VERSION=3.1.1
# 保存先を指定して移動
$ mkdir -p $GOPATH/src/github.com/sylabs && \
cd $GOPATH/src/github.com/sylabs
# Singularityをダウンロードして、展開後移動
$ wget https://github.com/sylabs/singularity/releases/download/v${VERSION}/singularity-${VERSION}.tar.gz && \
tar -xzf singularity-${VERSION}.tar.gz && \
cd singularity


2-4. Singularityのコンパイルとインストール

以下のコマンドでSingularityのコンパイルとインストールを行います。

$ ./mconfig && \

make -C ./builddir && \
sudo make -C ./builddir install

以上で、Singularityのインストールは完了です。


3. Singularityの利用方法

Singularityを利用するためには、以下の手順を行います。


  1. SingularityのコンテナであるSingularity Image File (SIF)コンテナ(もしくはsandboxコンテナ)をビルド

  2. SIFコンテナ(もしくはsandboxコンテナ)に対して、アクセス(shellやexec)

上記について具体的に以下記載します。


3-1. SIFコンテナ(もしくはsandboxコンテナ)のビルド

SIFコンテナは読取専用としてビルドされます。変更可能としたい際は、ビルド時にsandboxオプションを付与して、sandboxコンテナを作成します。

形式
概要

SIFコンテナ(デフォルト)
プロダクションに適した安定な読取専用ファイル。$HOME配下等はホスト側をバインドしているので、ユーザ権限の範囲で変更可能。

sandboxコンテナ(オプション)
変更可能なchrootディレクトリ。対話的な開発・検証向け。 コーディングの途中で、root権限でライブラリを追加したり、pipでinstallできる

SIFコンテナのビルド方法は、公式ドキュメントでbuildコマンドを利用する以下の5つが記載されています。



  1. Container Libiraryからビルド


  2. Docker Hubからビルド


  3. Singularity Hubからビルド

  4. マシン上の既存のコンテナ(もしくはsandboxコンテナ)からビルド

  5. Singularity定義ファイルからビルド

なお、buildコマンドにsandboxオプションを付与することでsandboxコンテナを作成できます。


3-1-1.Container Libiraryからビルド

公式のContainer Libiraryからダウンロードして、ビルドします。

以下コマンドでは、centos7をビルドします。(URIがlibrary://から始まります)

$ sudo singularity build centos7.sif library://library/default/centos:latest

上記コマンドでは、Centos7.5.1804(Core)がビルドされました。

sandboxオプションを付与する場合は、以下のコマンドになります。なお、sandboxコンテナの場合は、出力がファイルからディレクトリ(chrootディレクトリ)に変更されますので、注意してください。

$ sudo singularity build --sandbox centos7/ library://library/default/centos:latest


3-1-2.Docker Hubからビルド

Docker Hubからダウンロードして、ビルドします。

以下コマンドは、centos7をビルドします。(URIがdocker://から始まります)

$ sudo singularity build centos7.sif docker://centos:latest

上記コマンドでは、Centos7.6.1810(Core)がビルドされました。Docker Hubのほうがバージョンが上ですね。


3-1-3.Singularity Hubからビルド

Singularity Hubからダウンロードして、ビルドします。

以下コマンドは、centos7をビルドします。(URIがshub://から始まります)

$ sudo singularity build centos7.sif shub://singularityhub/centos:latest

上記コマンドでは、Centos7.4.1708(Core)がビルドされました。こちらもDocker Hubのほうがバージョンが上ですね。


3-1-4. マシン上の既存のコンテナ(もしくはsanbbox)からビルド

すでにローカルに保存されているコンテナがある場合は、それをターゲットとして使用して、新しいコンテナをビルドできます。

これにより、コンテナ形式の変換ができます。

例えば、色々と変更を加えたdevelopmentというsandboxコンテナをproduction.sifというSIFコンテナに変換したい場合は、次のコマンドを使います。

$ sudo singularity build production.sif development/

上記のようにsandboxコンテナは後からSIFファイルに変更できますが、コンテナの再現性を考えるとSingulrity定義ファイルを更新して、Singularity定義ファイルからプロダクション用のSIFコンテナをビルドするほうが良いと思います。


3-1-5. Singularity定義ファイルからビルド

Singularity定義ファイルは、Dockerでいうdockerfileです。

Singularityでは、Singularity定義ファイルをかなり柔軟に記載できますので、詳細は公式ドキュメントのDefinition Filesを参照してください。

ここでは、以下のようにCentos7用のSingularity定義ファイル(centos7.def)を作成しています。

Bootstrpにdockerを指定すると、dokcerイメージを元にコンテナを作成できます。(他にもBootstrpにlibrary、shubやyum等指定できます。)


centos7.def

Bootstrap: docker

From:centos:latest

%post
yum update -y
yum install -y emacs vim

%environment
export PATH=/hoge/hoge:$PATH


以下のコマンドでSingularity定義ファイル(ここではcentos7.def)からビルドします。

$ sudo singularity build centos7.sif centos7.def

以上が5つのビルド方法になります。

私としては、3-1-5.のSigularity定義ファイルでBootstrapを用いてdockerイメージをイメージ元にする方法が、他のdockerを利用されている開発者の方との環境を合わせやすく、またビルド時に何をやっているのかが分かりやすいので、おすすめです。


3-2.Singularityコンテナへのアクセス

では、実際にビルドしたSingularityコンテナにアクセスします。

Singularityコンテナへのアクセス方法は以下の方法があります。どちらもDockerで慣れている方法だと思います。


  • shellコマンドでコンテナに入る

  • execコマンドでホスト側からコンテナ内のコマンドを実行


3-2-1.shellコマンドでのアクセス

以下のコマンドを実行すると、Singularityコンテナで新しいシェルが起動され、そのシェル上でコンテナにアクセスできます。なお、コンテナ内のユーザは、ホスト側と同じユーザになります。

# SIFコンテナにアクセスする場合

$ singularity shell centos7.sif

# sandboxコンテナにアクセスする場合
$ singularity shell centos7

また、以下のようにSingularityコンテナではなく、library://、docker://やshub://を指定した場合は、一時的なコンテナが作成され、シェルから抜けると一時的なコンテナが削除されます。

$ singularity shell library://library/default/centos:latest


3-2-2.execコマンドでのアクセス

execコマンドを使うことで、Singularityコンテナで任意のコマンドを実行できます。

execコマンドの後にSingularityコンテナを指定して、その後に実行したいコマンドを指定します。

# Singularityコンテナのsystemリリース情報を表示

$ singularity exec centos7.sif cat /etc/system-release

CentOS Linux release 7.6.1810 (Core)

また、shellと同様にlibrary://、docker://やshub://を指定した場合は、一時的なコンテナが作成され、一時的なコンテナ上でコマンドが実行され、その後一時的なコンテナは削除されます。

上記2つの方法で、Singularityコンテナにアクセス可能となります。


4.GPUの仮想化

Singularityでは、Dockerと同様にGPUを仮想化して利用できます。

実際にSingularityコンテナ内でGPUを利用できるか試してみます。


4-1. nvidia-smiコマンドの実行

今回は、nvidia-dockerのコンテナイメージを利用して、nvidia-smiコマンドが利用できるか試してみます。

SingularityコンテナでGPUを利用する場合は、shellやexecにnvオプションを付与します。

# nvidia-dockerのコンテナイメージからsifコンテナを作成

$ sudo singularity build cuda10.0-base.sif docker://nvidia/cuda:10.0-base

# execでnvidia-smiが起動することを確認
$ singularity exec --nv cuda10.0-base.sif nvidia-smi

# shellでsifコンテナのシェルにアクセス
$ singularity shell --nv cuda10.0-base.sif
# sifコンテナ内でnvidia-smiを実行
nvidia-smi

exec及びshellのどちらでも、以下の通りnvidia-smiで正常にGPUを確認できました。

+-----------------------------------------------------------------------------+

| NVIDIA-SMI xxx.xx Driver Version: xxx.xx CUDA Version: xx.xx |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce RTX 2080 Off | 00000000:01:00.0 Off | N/A |
| 28% 45C P0 49W / 215W | 0MiB / 7949MiB | 0% Default |
+-------------------------------+----------------------+----------------------+


4-2. PytorchのSNLIサンプルの実行

PyTorchのSNLIサンプルソースをCPUのみ、CPU+GPU(Docker)、CPU+GPU(Singularity)の3パターンで実行します。

ちなみに、SNLI(Standord Natural Language Inference)は自然言語推論のためのデータセットです。

PyTorchのサンプルソースでは、前提と仮説からなる2つの文章を用いて学習を行い、与えられた2つの文章が前提と仮説の関係になっているかどうかをクラス分類します。

実行結果は以下の通りです。

パターン
CPU
GPU
メモリ
epoch数
学習時間

CPUのみ
Core i7 8700K 3.7GHz
無し
32GB
5
3時間29分

CPU+GPU(Docker)
Core i7 8700K 3.7GHz
Geforce RTX2080
32GB
5
6分50秒

CPU+GPU(Singularity,SIFコンテナ)
Core i7 8700K 3.7GHz
Geforce RTX2080
32GB
5
6分43秒

上記の結果から、SingularityによるGPU仮想化でもDockerによるGPU仮想化と同等の性能は出せそうです。

なお、弊社の環境ではGPUをsandboxコンテナで利用すると性能がかなり落ちます。


まとめ

最後までお読みいただき、ありがとうございました。

今回は、Singularityの特徴と一通りの使い方を紹介しました。

まだまだ色々と便利な機能があるのですが、そちらについては公式ドキュメントをぜひ読んでみてください。色々発見があって面白いです。

Singularityの利用者が増え、これからさらにSingularityが便利になっていってくれると嬉しいです。