Dockerを1ミリも知らないマンが必要に迫られてSingularityでpythonのコードを走らせた話
SingularityっていうDocker的なサービスがあるらしいです。Dockerとの違いはサーバーとかで実行するときに管理者権限がいらないところらしく、一般ユーザーでも自由に自分の環境が作れるとのこと。
正直こういう話には疎い方なんですが、研究室のサーバーを新しくする際にSingularityを使ってね!と言われて存在を認識しました。それでも「サーバー使わなくても研究室にはローカルのマシンあるしなあ」と思って当分放っておくつもりだったらいきなり研究室に行けなくなってしまったので慌てて調べましたよ、という(だいたい1ヶ月前の)お話です。
で、とりあえず動かせるようにはなったんですが、そろそろ何をどうやったか忘れてしまいそうだったので備忘録としてまとめようと思い、この記事を書くことにしました。
手元のPCからサーバーに接続した先でSingularityを使う方法について書くので、まずはローカルPCでの設定から始めて、実際に実行するまでの流れをまとめていきたいと思います。ちなみに、ローカルのPCはmacです。ただ、公式の説明がそこらへんはしっかりしてるのでそこまで問題ないと思います。
下準備として手元のPC上でやること
ここにあらかた書いてあります。macの場合は、いったんvirtual boxとかvagrantをインストールして色々するみたいなコマンドが書いてあるので言われるがまま実行します。
$ brew cask install virtualbox && \ brew cask install vagrant && \ brew cask install vagrant-manager
まずこんな感じで必要なソフトウェアをダウンロードします。(homebrewは入っている前提です。)確かlinux前提だからmacだとvirtualboxとか入れなきゃいけないだけで、linuxならそのままいけるはず。そこらへんのこともまとめて上に貼ったページに書いてあります。
$ mkdir vm-singularity && \ cd vm-singularity
次にsingularityで色々するためのディレクトリを切ります。ディレクトリ名は適当でいい気がする。
$ export VM=sylabs/singularity-3.0-ubuntu-bionic64 && \ vagrant init $VM && \ vagrant up && \ vagrant ssh
最後にsingularityが入っているバーチャルマシンを立ち上げて中に入ります。家のネットの強さによっては結構時間がかかる気がします。以降の作業はずっとバーチャルマシン内で行います。
Singularityの使い方
Singularityを使ってpythonのコードを走らせるのに必要な最低限の知識だけ書こうと思います。というか自分自身がその最低限の知識しか持っていません。
Singularityはsifファイルというイメージファイルを使って自分が構築した環境を扱います。例えば、自分に必要なpythonの環境を構築したpyenv.sifというsifファイルがあったとしたら、以下のようなコマンドを実行するイメージです。
singularity exec pyenv.sif python main.py
自分で作ったsifファイル越しにpython main.py
みたいな普通のコマンドを実行すれば、sifファイルを作るときに構築した環境でコマンドを実行したのと同じ結果が得られます。
したがって、サーバー上でSingularityを使ってコードを走らせるまでには、
- root権限を持っている場所(ここではmacの上のvagrant)でsifファイルを作る
- そのsifファイルをサーバーにアップロードしてsingularityを使ってコードを走らせる(このときにはroot権限はいらない)
みたいな感じになります。
sifファイルの作り方
ここにsifファイルの作り方(に限らず色々)が詳しく書いてあります。
ざっくりまとめると、
- dockerとかがもう作っているイメージファイルから作る
- Singularity定義ファイルから作る
- sandboxコンテナをいったん作って、そこからsifファイルを作る
が選択肢になると思います。
dockerとかがもう作っているイメージファイルから作る
dockerとかが自分が作りたい環境とか、それの土台になるような環境をもう作って固めてくれている場合があります。その場合は、それをそのまま使ってsifファイルを作ることができます。
他にも選択肢はあるんですが、自分はdockerからしか試してないのでそのやり方を書きます。
ここからdockerがどういう環境を用意しているのかを調べることができます。例えば、pythonの環境をとりあえず作りたいな〜と思ったら、
こんな感じで検索するとpythonのページまでたどり着きます。
このページのTagsをクリックするとこんな感じでダウンロードできるイメージの一覧が見れます。
オレンジの線を引いたところが各イメージファイルを識別する名前で、dockerが作ったイメージからsifファイルを作るときにも使います。
このようにして自分がどんなイメージからsifを作るか決めたら、以下のようなコマンドを実行してsifファイルを作成します。
vagrant@vagrant:~$ sudo singularity build pyenv.sif docker://python:latest
docker://
から始めて、次にさっきオレンジの線を引いたイメージを識別する名前を入れます。とりあえずlatest
にしておくのでも問題ないっぽいです。
あと、buildにはroot権限が必要で、これがsifファイルを作るためにvagrantに入って作業をしている理由です。
Singularity定義ファイルから作る
定義ファイルというどういう環境を作るかを詳細に書いたファイルをまず作って、それから作る、という方法もあります。dockerとかから引っ張ってきたベースのイメージに追加で自分がインストールしたいものを指定してインストールすることとかができて、自分が作りたい環境を自由にカスタマイズすることができます。
こことか、最初に貼ったQiitaの記事とかに詳しいです。とりあえず、Bootstrap
でどこからダウンロードするのか、From
で具体的にどのイメージなのか、%post
でそのイメージをダウンロードした上で追加でどんなコマンドを走らせるのか、を書けば動くと思います。正直ちゃんと使ってないのでここら辺はあやふやです。
個人的には次に説明するsandboxを使った方法の方が対話的にできるし良くない?と思ったんですが、どんな環境を構築したかを定義ファイルに残しておけて再現が簡単という記述を見つけて「たしかに」と思いました。大体の場合は定義ファイルから作ることが推奨されている印象です。
sandboxコンテナをいったん作って、そこからsifファイルを作る
sandboxオプションをつけることで、sifファイルではなくsandboxコンテナを作って、そこで環境を構築することも可能です。この方法をとる場合は逐次コマンドを打ち込んで確認することができるので、そこはいいところなんじゃないかなあと思います。ただ、どういう風に環境構築したかをどこかに残しておけるわけではないので、定義ファイルから作った方がいいのかも。
vagrant@vagrant:~$ sudo singularity build --sandbox pyenv/ docker://python:latest
こんな感じで--sandbox
をつけて実行することで、sifファイルではなくディレクトリ(上の場合だとpyenv/
ディレクトリ)が作成されます。
このディレクトリに入って、対話的に環境を構築します。
vagrant@vagrant:~$ singularity shell pyenv/ Singularity pyenv:~> python --version Python 3.8.2 Singularity pyenv:~> python Python 3.8.2 (default, Apr 23 2020, 14:22:33) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import numpy Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named 'numpy'
singularity shell pyenv/
でpyenv/
ディレクトリに入ります。pythonのバージョンを確認したり、実際にpythonに入ったりすることができます。一方で、numpyが未インストールの状態であることも確認できます。
Singularity pyenv:~> exit exit Singularity pyenv:~> pip install numpy Defaulting to user installation because normal site-packages is not writeable Collecting numpy Downloading numpy-1.18.4-cp38-cp38-manylinux1_x86_64.whl (20.7 MB) |████████████████████████████████| 20.7 MB 96 kB/s Installing collected packages: numpy WARNING: The scripts f2py, f2py3 and f2py3.8 are installed in '/home/vagrant/.local/bin' which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning, use --no-warn-script-location. Successfully installed numpy-1.18.4
こういう風に自分が必要なものがsandboxコンテナにインストールされていない場合は、pipでnumpyをインストールしたりして自分の環境を作っていくことができます。
ちなみに、pipで追加のソフトウェアをインストールする分には問題なかったですが、apt-getとかでインストールするときにはroot権限でsandboxコンテナに入る必要があったはず。
こんな感じで自分が必要な環境の構築が終わったら、sandboxコンテナをsifファイルとして固めます。
sudo singularity build pyenv.sif pyenv/
これでsifファイルが作成できました。
sifファイルをサーバーにアップロードして実行する
ここまでで作成したsifファイルをscpとかでサーバーにアップロードします。その上で
singularity exec pyenv.sif python main.py
みたいな感じで走らせたいコードを実行します。このときに、ローカルでビルドしたSingularityとサーバー上のSingularityのバージョンが一致しないとエラー吐いたので気をつけた方がいいかも(少なくとも2と3の互換性はなさそうだった)。
GPUサーバーで実行するとき
GPUサーバーで実行するときには--nv
オプションをつけるとnvidiaのドライバとかをsifファイル内にインストールせずともサーバーのGPU環境を引き継いでくれるので便利です。
よくわかってないこと
dockerのどのイメージをベースにすべきなのかが全然わかってません。pytorchのコード走らせたいと思って https://hub.docker.com/r/pytorch/pytorch をベースにしてみたんですが、本当にそれが正しいのかはっきりしないです。
マジでなんとなく選んでるだけなので、どうするのが一般的なのかはちゃんと学ばないとなあと思っています。
まとめ
Singularityを本質的な理解をせずにとりあえず使った話をまとめました。正直Singularityでできることの一部しか活用できてない感がすごいので余裕があったらもう少し勉強したいです。