4. Singularity 利用の手順

Singularity を用いてアプリケーションを利用するには、必要なイメージの取得ないし作成をしなくてはなりません。ここではユーザー自身でイメージを作成する流れを追ってみます。

イメージの作成を行う方法には大きく分けて3つあります。

  1. 元になるイメージを取得する。または他のイメージを再利用して変換する。

  2. イメージの元となるファイルシステムを展開しておき、手動でアプリケーション等をインストールし、イメージファイルへ変換する。

  3. イメージ作成の手順など記述した定義ファイルを用いて、Singularity に全ての作業を行わせる。

手動で行う方法は、作業者が環境構築に精通していて、かつ作業内容が単純である場合や、作成時に不具合が出た際のデバッグや簡易な修正には便利です。しかし、作業内容を別途保存しておかないと、再現が厳密にはできなくなる恐れがあります。イメージの作成のたびに手作業を行うよりは、定義ファイルを作成してリポジトリ等で管理し、バッチジョブとして実行できるようにしておくことで、高い再現性とリソースの有効利用が可能になります。

Singularity というソフトウエア自体には、定義ファイルを利用してイメージを作成する方法として、手元の環境を利用する方法と、クラウドサービスを使う方法が存在しますが、ここでは「富岳」では手元環境(「富岳」以外の ARM64 環境を含む)での作業のみを対象とします。

Singularity では、既存のコンテナイメージを再利用して自分のイメージを作成することができます。対象は Singularity イメージだけでなく Docker や OS の yum/apt のリポジトリ等が利用可能です。殆どの場合、何らかのベースイメージを元に変更を加えていくことになるでしょう。この文書では Docker hub で配布されている AlmaLinux や Ubuntu、ならびに Redhat 社が供給するコンテナ向け Universal Base Image(UBI) をベースにすることを考えます。

4.1. 「富岳」の Singularity 環境

「富岳」ではログインノードが x86_64 アーキテクチャのため、ARM アーキテクチャのイメージを操作するにはコンピューティングノードで作業する必要があります。ここではまず Singularity の動きを確認するため、インタラクティブジョブとして手作業をしてみます。昨年までは jobenv に singularity を指定する必要がありましたが、2024年4月からは不要になりました。なお、2024年6月現在、3.11-7 と 4.1.2-2 が利用可能です。

$ pjsub --interact -L "rscunit=rscunit_ft01,rscgrp=int,node=1,elapse=0:30:00"
[INFO] PJM 0000 pjsub Job XXXXXXX submitted.
[INFO] PJM 0081 ..connected.
[INFO] PJM 0082 pjsub Interactive job XXXXXXX started.
[a0XXXX@b31-3208c ~]$ singularity --version
SingularityPRO version 4.1.2-2.el8
[a0XXXX@b31-3200c ~]$ /opt/singularitypro311/bin/singularity --version
SingularityPRO version 3.11-7.el8
[a0XXXX@b31-3200c ~]$ /opt/singularitypro41/singularity --version
SingularityPRO version 4.1.2-2.el8

上記例では作業時間は30分です。これを過ぎると、ホームディレクトリ等へ保存されたもの以外の作業内容は失われる可能性があります。

4.2. コマンドラインでのイメージ作成

Docker hub や同じ形式でイメージを保持するリポジトリから取得する場合です。以下のようになります。

$ singularity pull centos_latest.sif docker://centos:latest
INFO:    Converting OCI blobs to SIF format
INFO:    Starting build...
Getting image source signatures
Copying blob 333cbcae3fb8 done
Copying config 424ef6ddfd done
Writing manifest to image destination
Storing signatures
<<..snip..>>
INFO:    Creating SIF file...
INFO:    Build complete:

$ singularity pull ubuntu2004.sif docker://ubuntu:20.04
$ singularity pull ubi8-python38.sif docker://registry.access.redhat.com/ubi8/python-38

docker 形式のリポジトリから SIF ファイルを生成します。一度取得した docker 形式のイメージは ~/.singularity/cache 以下に保存され、次回以降はアップデートがある部分のみダウンロードするので短時間で完了します。イメージ名(ファイル名)を省略することも可能で、その場合リポジトリ名から生成されたファイル名が使われます。また、アーキテクチャの指定が入っていませんが、Singularity は起動したマシンのアーキテクチャを取得しようとするので、コンピュートノードからは自動的に AARCH64 のイメージを取得します。マニュアルを見ると --arch オプションで指定できることになっていますが、3.X では取得先が library に限られていており、docker hub等、他の取得先に対してアーキテクチャの指定はできません。4.1 ではその制限はないので、ログインノード上で singularity pull --arch=arm64 docker://... のようにできます。

出来上がった SIF イメージの実体は SquashFS という形式になっています。SquashFS は tar.gz ファイルを直接マウントするような方式であり、起動すると読み込み専用となります。そのため、SIF イメージの中身をあとから操作することはできません。イメージの中にアプリケーションやランタイムをインストールするには、後述する定義ファイルを用いてビルドする方法と、一度ファイルシステムに展開してから再度 SIF イメージへ変換する方法があります。また、イメージを直接変更せず、書き込みできる領域を重ね合わせる overlay 機能を用いると、実行時のみ有効な変更を施したり、SIF イメージ一つに対して特定のディレクトリやファイルのみ載せ替えて使うこともできます。

ファイルシステムに展開されたイメージは sandbox と呼ばれ、build コマンドに対し --sandbox オプションを追加して作成します。保存先はディレクトリになり、その中にイメージが展開されています。そのディレクトリは、本来 root がオーナーとなるファイルが全て、ユーザー自身がオーナーとなっており、コンテナを起動しなくても中身をインタラクティブに編集することができます。

$ singularity build --sandbox ubuntu2004 docker://ubuntu:20.04
INFO:    Starting build...
Getting image source signatures
Copying blob 32d7611b468c skipped: already exists
Copying blob e5be16fdc306 skipped: already exists
Copying blob a361e87bde5e [--------------------------------------] 0.0b / 0.0b
Copying config ff84d45488 done
Writing manifest to image destination
Storing signatures
2021/03/31 12:00:00  info unpack layer: sha256:32d7611b468cbc07986302f1a8e74d92e30a1f11cdfa8bc2900aedda2758d050
<<..snip..>>
INFO:    Creating sandbox directory...
INFO:    Build complete: ubuntu2004

$ cd ubuntu2004
$ touch foobar
$ ls -l

実のところ、ここまでの使い方では pull コマンドと build コマンドでは --sandbox オプションの有無以外、結果に差はありません。なお、sandbox に展開したイメージから SIF ファイルを作成することも、その逆も build コマンドでできます。

$ singularity build from_sandbox.sif ubuntu2004
$ singularity build --sandbox from_SIF ubuntu2004.sif

なお注意点として、sandbox ディレクトリ自体は当然ながら書き込み可能ですが、sandbox イメージからコンテナを起動すると SIF イメージと同じくリードオンリーとなります。つまり sandbox から起動しても、イメージ内のシステムにアプリケーションをインストールできません。書き込み可能なモードで起動する場合は --writable オプションを指定します(SIF イメージには使えません)。ただし root 権限はありません、コンテナ内で su 等を用いて root 権限を取得することもできません。そのため、root 権限を必要とする、例えば dnf, yum, rpm, dpkg 等のパッケージ管理コマンド等は、後述する --fakeroot を使う必要があります。ただし、コンテナ外から sandbox 内にファイルをコピーしたり、それをさらに SIF に変換することは可能です。

$ singularity exec from_sandbox.sif ls -l /foobar

次に、できたイメージを用いてコンテナを起動してみましょう。

4.3. イメージからのコンテナ起動

コンテナを起動する方法のうち、Singularity の shell コマンドを使い、コンテナ内でシェルを起動してみます。ホストOSの情報と比較してみましょう。

$ uname -a
Linux c27-0200c 4.18.0-513.5.1.el8_9.aarch64 #1 SMP Fri Sep 29 05:50:39 EDT 2023 aarch64 aarch64 aarch64 GNU/Linux
$ whoami
a0XXXX
$cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="8.9 (Ootpa)"
<<..snip..>>

$ singularity shell ubuntu2004.sif
Singularity> uname -a
Linux c27-0200c 4.18.0-513.5.1.el8_9.aarch64 #1 SMP Fri Sep 29 05:50:39 EDT 2023 aarch64 aarch64 aarch64 GNU/Linux
Singularity> whoami
a0XXXX
Singularity> cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
<<..snip..>>

「富岳」の OS は Redhat Enterprise Linux 8.9 であるにもかかわらず、コンテナ起動後はカーネルとユーザーはそのまま Ubuntu 20.04.2 LTS となっています。ここではホスト OS の Redhat 系のコマンドは使えず、イメージ内の Ubuntu のコマンドのみ利用可能です。ただし、カーネルはそのままなのでカーネルの機能やバージョンに強く依存するようなアプリケーションは動作に支障がでる可能性はあります。

次に ls すると以下のように、ホームディレクトリがそのまま見えています。ただし見えるのは自分自身のホームディレクトリに限られます。これを確認するのに ls -al /home や ls -al ~/.. 等を実行してみてください。自身以外のユーザーのホームディレクトリが見えていないことが分かります。

Singularity> ls -l
total 440172
drwxr-xr-x 1 a0XXXX rccs-aot      4096 Mar 31 12:30 ubuntu2004
-rwxr-xr-x 1 a0XXXX rccs-aot  26320896 Mar 31 12:00 ubuntu2004.sif

Singularity> ls -l ..
drwx------ 1 a0XXXX rccs-aot      4096 Mar 31 12:30 a0XXXX

さらに cat /etc/passwd ないし cat /etc/group とすると、自身のエントリーだけが追加されていることが分かります。そのため、コンテナ内から他のユーザーのホームディレクトリへアクセスするような場合は工夫が必要となります。

Singularity> cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
<<..snip..>>
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
a0XXXX:x:1XXXX:1XXXX::/home/rccs-aot/a0XXXX:/bin/bash

sandbox 内のファイルを直接コンテナ外で確認すると分かりますが、このユーザー追加はコンテナの起動時に行われるもので、イメージ内には取り込まれていません。

また、同じくプロセス空間も共有されているので、コンテナの内外で ps コマンドの出力は変わりませんし、kill コマンドによるシグナル送信も相互に可能です。

次に、シェルを起動せずコンテナ内で直接コマンドを実行してみます。ここでは singularity の exec コマンドを用いてイメージを指定して起動します。イメージは SIF ファイルや sandbox イメージのほか、イメージのリポジトリを指定することもできます。先ほど sandbox から変換したイメージに、作成したファイルがあるかどうかも確認してみましょう。

$ singularity exec ubuntu2004.sif cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
<<..snip..>>

$ singularity exec from_sandbox.sif ls -l /foobar
-rwxr-xr-x 1   root     root         0 Mar 31 12:45 /foobar

$ singularity exec ubuntu2020 cat /etc/os-release
$ singularity exec docker://centos:latest cat /etc/passwd
INFO:    Converting OCI blobs to SIF format
INFO:    Starting build...
<<..snip..>>

コンテナ内の環境でコマンドが実行できたと思います。また、ユーザー自身が作ったファイルが SIF へ変換したら root がオーナーとなっていることが分かります。

リポジトリを指定した場合は上記の通り SIF イメージへの変換を行った上で実行されます。同じ指定をすると、キャッシュにダウンロードした元イメージとリポジトリを比較して更新があれば差分がダウンロードされ、再度 SIF へ変換されます。更新がなければ作られた SIF をそのまま使います。そのため直接 SIF を使うよりも起動は遅くなりますが、常に最新版を使いたい場合や、SIF イメージをファイル名で管理したくない場合には便利です。イメージの内容を固定したい場合や起動のオーバーヘッドを最小化したい場合には原則として SIF イメージを利用が推奨されます。sandbox からの実行や、Docker イメージ等の直接実行は、オーバーヘッドやメリット・デメリットに注意して利用してください。

ホームディレクトリはコンテナ内でも共有されているので、そこにあるファイルをコンテナ内から利用してみましょう。SIF イメージファイルの先頭をコンテナ内のコマンドで見てみます。

$ singularity exec ubuntu2004.sif head -n 1 ubuntu2004.sif
#!/usr/bin/env run-singularity

コンテナ内からホームディレクトリのファイルへアクセスできました。他のファイルがある場合はそれも試してみてください。

ここでもうひとつわかることは、SIF イメージはスクリプトになっているということです。2行目以降はバイナリになっていますが、この部分は squashfs という圧縮ファイルシステムでイメージ本体が収められています。そのため内部にあるファイルの総量に比べ、SIF ファイルのサイズはかなり小さくなります。結果として SIF イメージはキャッシュにのりやすく、ホームディレクトリ内に細かいファイルを展開するよりも共有ストレージへの、特にメタデータアクセス負荷が低いという特徴があります。そのためアプリケーションの起動が高速かつ安定します。

スクリプトなので、SIF イメージは直接起動することができます。やってみましょう。

$ ./ubuntu2004.sif
Singularity>

プロンプトが出てきてそのまま操作できます。つまり、単純に作られた SIF イメージを直接起動すると shell コマンドを使ったのと同じになります。また、コマンドをオプションとして与えると exec コマンドの実行と同じになります。

$ ./ubuntu2004.sif cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.2 LTS (Focal Fossa)"
<<..snip..>>

Singularity を用いることで、システムに用意された環境にとらわれず、自由なユーザー環境をアプリケーションの実行環境として使い分けられることが分かります。