yNagaokaのブログ

このブログはNGS解析初心者がつまずいた部分と解決方法をまとめた覚書のようなものです。

WSLがストレージを異常に圧迫する問題を解決したときの覚書

はじめに

私はWindowsユーザーでWSLを利用しているのですが、最近PCが異常にフリーズするしデータ解析中にストレージ不足のエラーが頻発するようになりました。
色々な記事を参考にしてストレージを開放するために奮闘したのでその作業の覚書を残しておこうと思います。

状況確認

256GのLaptop PCを使っておりストレージの空き容量が1GBを下回っている状況です。WSL2にUbuntu20.04をインストールしておりDockerやSingularityCE、R、Python、関連ツールもインストールしています。初めにPCの設定画面からストレージの項目を開き、重いアプリケーションは何かを確認しました。一番はAdobe creative cloudでした。確かにPhotoshopIllustratorなど沢山インストールしていてバックアップも頻発に取るアプリなので納得なのですがそれでも数GBの範囲です。他に1GBを超えるようなものは見当たりません。また、ダウンロードやゴミ箱にあるファイルも全て消去済みです。

対策1:Dockerの整理

1) 使用容量の確認と不要なdocker imagesの消去

初めに以下のコマンドでどの項目が容量を圧迫しているのかを確認しました。

$ df -h

その結果、Dockerが最も容量を消費していたので整理することにしました。
次に以下のコマンドでDockerの何がどのくらい容量を消費しているのかを確認しました。
(以下の出力結果は整理後の状態です。整理前を残すのを忘れました。当時はImagesとBuild Cacheがかなりの容量を占めていました。)

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          1         1         60.11GB   0B (0%)
Containers      2         0         0B        0B
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B

Imageが一番多く容量を消費していたので、あまり使用していないDocker imagesを合計で40G程度消去しました。

2) キャッシュのクリア

次にDocker imageをbuildする際に残るキャッシュ (Build Cache) も容量を圧迫していたので以下のコマンドで消去しました。

$ docker builder prune

再度使用容量を確認すると無事消去できていることが確認できました。

対策2:SingularityCEの整理

3) キャッシュのクリア

Docker imagesと比べてSingularity imageは半分以下のサイズであり、頻繁に使用しているのでSIF (Singularity image file)は消去したくない。なのでBuild時に残るキャッシュのみを消去しました。

$ singularity cache clean --all

こちらも無事消去できたので一旦PCを再起動し、設定画面からストレージを確認しました。50Gほどの空き容量ができていたので一先ず良しと思い作業を終了しました。
しかし、後日ストレージ不足のエラーが再度出現します。

対策3:DockerとDocker Desktopのアンインストール

4) Dockerストレージドライバーの確認

色々調べているとDockerのストレージドライバーが重くなっているのではないか?という記事を見つけたので確認してみました。
docker infoではバージョンやイメージの数などが色々出力されます。Storage Driverという項目を見つけて確認してください。

# Dockerストレージドライバーがどれかや諸々を確認したい場合  
$ docker info 
Storage Driver: overlay2

# 以下のコマンドだとストレージのみ確認できます。
$ docker info | grep "Storage Driver"

どうやらストレージはoverlay2のようです。

5) ストレージの容量の確認  

/var/lib/docker/overlay2はデフォルトの保存先です。

sudo df -h /var/lib/docker/overlay2
[sudo] password for ynagaoka:
Filesystem      Size  Used Avail Use% Mounted on
/dev/sdc        251G   51G  188G  22% /

容量を確認してみるとそこまで圧迫している感じではありません。しかし、Dockerが依然としてストレージを圧迫している状況なのでアンインストールも視野に入れることにしました。

6) Dockerアンインストール前の再確認

Dockerをアンインストールする前に最後の抵抗を試みました。以下のコマンドを実行し、imageやキャッシュ諸共全て消去しました。 このコマンドは他人がPullしたimageやBuild中のキャッシュなど全てを消し去るので、共通のPCやサーバーなどで実行しないように注意してください。 不安な場合はdocker system prune -hでコマンドの使い方を確認してください。

$ docker system prune -af

実行後、再起動しストレージを確認しましたが容量は回復しませんでした。
どうしたものかと悩みましたが、またダウンロードすればいい話なので一度DockerとDocker Desktopをアンインストールすることにしました。

7) Dockerのアンインストール

Dockerの古いバージョンがインストールされている可能性があったので以下のコマンドで消去しました。

$ sudo apt-get remove docker docker-engine docker.io containerd runc

apt-getを実行したときに、上のパッケージがインストールされていないと表示されれば OK です。

次に、以下のコマンドでDocker Engine、CLI、Containerd、Docker Compose パッケージをアンインストールします。

$ sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-compose-plugin

ホスト上のImage、Container、Volume、カスタマイズした設定ファイルは自動的に削除されず/var/lib/docker/等に保持されるため以下のコマンドで消去します。

$ sudo rm -rf /var/lib/docker
$ sudo rm -rf /var/lib/containerd

Docker Desktopはアプリの項目から手動でアンインストールしました。
dockerと打ち込み、コマンドが無いというエラーが出ればアンインストール完了です。 再起動しストレージを確認しましたが、容量は空きませんでした。。。

対策3:WSL driversの圧縮

8) ext4.vhdxの圧縮

Dockerのアンインストール後、もう一度df -hで容量を調べたら今度は何故かWSLがストレージの大半を占めるようになっていました。

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
none            238G  237G   0G  99% /usr/lib/wsl/drivers

色々な記事を見た結果、原因は/usr/lib/wsl/driversなのでここにあるファイルを圧縮すればいいらしいという事が分かりました。
早速以下の手順で圧縮することにしました。(ここからはPowershellで行います。)

9) Powershellを起動し以下の手順でコマンドを実行する。

・WSLをシャットダウン

$ wsl --shutdown

UbuntuのPATHを確認

$ ls $HOME\AppData\Local\Packages\
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2023/10/16     12:03                CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc

上のコマンドの出力結果からUbuntuと名の付くファイルを探します。 私の場合はCanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgscでした。
・該当ディレクトリーに移動して中身の確認

$ cd $HOME\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc
$ ls 
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2022/09/29      9:51         LocalState
$ cd LocalState
$ ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2024/03/08     14:13   165451661312 ext4.vhdx

ext4.vhdxが今回の圧縮対象のファイルです。

・diskpartを起動(ここからの操作はdiskpartで行う)

$ diskpart

・該当ファイルを選択

DISKPART> select vdisk file=C:\Users\nagao\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\LocalState\ext4.vhdx
DiskPart により、仮想ディスク ファイルが選択されました。#これが表示されればOK

・attach

DISKPART> attach vdisk readonly
 
100% 完了しました
DiskPart により、仮想ディスク ファイルがアタッチされました。 #このログでOK

・圧縮

DISKPART> compact vdisk

100% 完了しました

DiskPart により、仮想ディスク ファイルは正常に圧縮されました。

・Detach

DISKPART> detach vdisk
DiskPart により、仮想ディスク ファイルがデタッチされました。

・完了

DISKPART> exit

・圧縮されているかUbuntuを起動して確認

$ df -h
Filesystem      Size  Used Avail Use% Mounted on
none            238G  180G   58G  76% /usr/lib/wsl/drivers

なんと58Gも圧縮できていて、その分のPCストレージが回復しました!
今回はストレージを圧迫していたDockerを消去したら、今度はext4.vhdxが容量を圧迫し始めるという現象でしたが無事に解決することができました。

ローカルのDocker imagesからSingularity imageを作りたいときの覚書

はじめに

最近はSingularityの使い勝手がよく感じられて、Docker imageをbulidしてはSIFを作製しています。色々なツールを使っていると、あるものはPython3.9が必要だったり、あるものは3.7が必要だったりnumpyやpandasのバージョンが特定のものじゃないとエラーになったり...というのを経験します。そこで、Dockerを使ってそれぞれのツールに適したConda環境を作製してSingularity imageにすることにしました。がしかし、色々と詰め込んでいたらDocker imageのサイズが大きくなりすぎてしまいpushできないという状況に陥りました。そんなときの覚書です。色々と試しましたがpushできない問題は解決できていません。。。

今回何がしたかったのか

以前の記事 ynagaoka.hatenablog.com
で書いたようにSingularity image (SIFファイル)はDockerHubにアップロードされているDocker imageからbuildすることができます。
作製したオリジナルのDocker imageを何らかの経緯で公開・他者と共有する必要がある場合は、DockerHubにアップロードする必要があります。ここにアップロードしておけばローカルのDocker imageを消去しても、再度pullすることで使用できます。PCの容量を圧迫しないためにも作製したDocker imageはDockerHubにアップロードしておくのが良いでしょう。Singularity imageを作製するのも楽です。
注意点は無料版のDockerを利用している場合、アップロードしたDocker imageは開発途中や未発表のものでも基本的に一般公開となり誰でも利用できる状態になることです。これが嫌だという場合は無料版でも1つのRepositoryに限りプライベートにできるのでこの設定をしておくのが良いでしょう。
前置きが長くなりましたが僕が何をやろうとしたのかというと、自分で作製したDocker imageをDockerHubにアップロードし、それを基にSingularity imageを作製しようとしたわけです。

問題点

Dockerfileからimageを作製してDockerHubにpushしたところunauthorized: authentication requiredというエラーが出現しました。ログは下記 (imegeの名前は適当です。)

$ docker push yunagaoka/XXX:latest
The push refers to repository [docker.io/yunagaoka/XXX]
e395ddd90784: Layer already exists 
10d409a506d1: Layer already exists 
9496213096b0: Layer already exists 
8e0a710a5b19: Layer already exists 
c5281a67b2ea: Layer already exists 
7c81a2cd73a3: Layer already exists 
ae9c36ce183c: Pushing [==================================================>]  12.52GB
36f0da07ddc7: Layer already exists 
c31c719464dd: Layer already exists 
3a2bb5d558b6: Layer already exists 
0914ed36d165: Layer already exists 
3ba0366e3919: Layer already exists 
11e30c0ea9b3: Layer already exists 
7a08d5b6af48: Layer already exists 
02bb5b88bf7b: Layer already exists 
c4688e47e324: Layer already exists 
88c461480888: Layer already exists 
68792e5280b6: Layer already exists 
f46aa005659a: Layer already exists 
b0cf95f783d1: Layer already exists 
843c029bd148: Layer already exists 
5f70bf18a086: Layer already exists 
01d4e4b4f381: Layer already exists 
unauthorized: authentication required

pushに失敗したようです。色々調べてトラブルシューティングをしました。 エラーの内容からこれは原因では無いだろうなというものも試しています。

考えられる原因1:アカウントが間違っているかログインに失敗している。

これはログアウトとログインで解消するか試しました。コマンドは以下です。

$ docker logout
$ docker login
Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/
Username: yunagaoka
Password:
Login Succeeded

再ログインできたので再度pushを試しましたが効果なし同じエラーです。

考えられる原因2:Repositoriy名等が間違っている

これはDockerHubにyunagaoka/XXXというRepositoriyが存在しない場合に起こりえます。今回はyunagaoka/XXXという場所に何回もpushした実績があるので原因では無いでしょう。 ある記事ではTagを変更するとうまく行ったというものもあったので変更して試してみました。コマンドは下記です。

$ docker tag <IMAGE ID> yunagaoka/XXX:<New tag>

これでも改善しませんでした。

考えられる原因3:認証トークンが期限切れ

Dockerにloginする際パスワードの代わりに認証トークンを使用することができます。このトークンの期限が切れているのではないか?というものです。今回ログインに認証トークンは使用していませんが、新しくトークンを作製してそれを使ってログイン、再度pushを試しました。

  1. アクセストークンを生成するにはまずhub.docker.com にログインします。

  2. 画面右上に表示されている自分のユーザー名をクリックして、Account Settingsを押します。

  3. Security > New Access Token を実行します。
    Descriptionは適当に書いて、プルダウンからAccess permissionsを選びます。ここでは全て行える様にRead,Write,Deleteを選択します。

  4. 次の画面でトークンが表示されるので、それをコピーして保存します。 誤ってコピー前に表示画面を閉じてしまうとトークンを再表示することはできないので、消去して再発行する必要があります。

ログアウトし、作製したトークンを使ってログイン、再度pushしましたがこれもまた失敗です。

考えられる原因4:~/.docker/config.jsonの不備

config.jsonの内容を変更するとうまく行くという記事を見つけました。 github.com docker.ioの部分をhttps://index.docker.io/v1/に変更すると良いみたいです。
変更前

{
        "auths": {
                "docker.io": {
                        "auth": "XXXXX",
                        "email": "your email"
                }
        }
}

変更後

{
        "auths": {
                "https://index.docker.io/v1/": {
                        "auth": "XXX",
                        "email": "your email"
                }
        }
}

cat ~/.docker/config.jsonで確認してみますが、自分の場合は既にこの形式になっていた...これも不発です。

考えられる原因4:回線速度の問題!?

調べていくと同じ問題を抱えている人が多くいました。

gitlab.com

Docker imageのサイズが大きすぎてpushに時間がかかり、タイムアウトになる。そのせいでエラーが出るのではないか?という考えに至りました。imageのサイズはというと27.3Gで、pushにかかる時間を計ってみると7分程度でした。

$ docker images
REPOSITORY           TAG         IMAGE ID       CREATED         SIZE
yunagaoka/XXX       0.9.2       d14a39797cbf   4 hours ago     27.3GB

試しに同じRepositoryに対して17Gくらい大きさのimageを作製してpushしてみたら成功しました。かかった時間は4分30秒程度でした。
次に、もう少し大きい21Gくらいのimageをpushしてみたら失敗しました。かかった時間は5分30秒程度でした。
もしかすると、push時間が5分を超えるとunauthorized: authentication requiredになってしまうのかもしれません。 結局DockerHubにpushすることは諦め別の方法でSIFを作製することにしました。 (後日談:思い出した時に再度pushしたら何故か成功しました。何が原因だったのか...)

ローカルのDocker imagesからSingularity imageを作る

とりあえずSIFが作製できれば良いので、ローカルのDocker imagesから作製することにしました。方法は以下を参照しました。

docs.sylabs.io

方法1 : ローカルのdocker imageから直接.sifを作製

少し時間がかかりますがこれが一番簡単な方法です。コマンドは下記です。

$ singularity build <SIF image name> docker-daemon://<user name>/<Repository>:<Tag>
例$ sudo singularity build XXX.0.9.2.sif docker-daemon://yunagaoka/XXX:0.9.2

sudoなしでエラーが出る場合はつけてください。
しばらくすると.sifができます。

方法2 : docker saveを使用して.tarを作製し、それをもとに.sifを作製する

  1. まず、docker imagesでDocker image のIDを確認します。
  2. IDをもとに.tarを作成(パーミッションエラーが出る場合はsudoを使用。その場合は次のbulidにもsudoをつける)
$ docker save <IMAGE ID> -o <tar file name>
例$ docker save 4776877a2b64 -o XXX.0.9.2.tar

しばらくすると.tarができます。
3. .tarをもとに.sifを作製

$ singularity build <SIF image name> docker-archive://<tar file name>
例$ singularity build XXX.0.9.2.sif docker-archive://XXX.0.9.2.tar

しばらくすると.sifができます。
方法2では.tarからDocker imageに変換することもできるのでローカルの容量を節約したい場合はこちらの方が良いかもしれません。

$ tar tvf <tar file name> #中身を確認できます
$ docker load -i <tar file name> #tarをimageに変換できます

方法3としてDefinition Filesを使ってもSIFを作製できますが、とりあえず上記で事足りたのでスキップします。

今回はローカルのDocker imageからSingularity imageを作製しましたが、根本のDockerHubにpushできない問題は解決できていません。どなたか解決方法をご存じでしたら教えて頂ければ幸いです。

Dockerとは何か?の覚書ーその1

はじめに

NGS解析を始めると様々な解析ツールを使う機会が増え、GitHubやDockerHubで公開しているものに出会うと思います。それらを全く知らない初心者からしたら何それ?どうやって使うの?といった感じになると思います。ウェット出身の私もそうでした。今回はDockerに関しての基礎知識や使い方に関して簡単にまとめたいと思います。

Dockerとは?

・Dockerは、アプリケーションを開発・実行するためのオープンプラットフォームのことです。Container (コンテナ)と呼ばれる仮想環境を構築し、コンテナ内で様々な解析コマンドを実行することができます。

・コンテナには、アプリケーション (解析コマンド等) を実行するために必要なもの(PythonやRのツールなど)全てが含まれています。また、コンテナ自体を他の人に配布することがでるため、同一のコンテナを得た人全員が、同じ方法で確実に同じ作業をすることができます。ホストPC上で何をインストールしていても問題ありません。
Reference : https://www.docker.com/resources/what-container/

Docker image・コンテナとは?

Docker image

Docker image (イメージ)とは、コンテナを作成する命令が入った読み込み専用のテンプレートのことです。DockeHubからダウンロードすることが可能で、このイメージからコンテナを作成します。

・イメージはDockerfileというテキストファイルを使って自分で作成することも可能です。このDockerfileにはイメージを生成して実行するまでの手順を記載します。何を、どの順番で、どのバージョンをインストールするかもこのファイルに記載します

コンテナ

・コンテナとは、イメージが実行状態となったインスタンス (場所・環境) のことです。コンテナに対する生成、実行、停止、移動、削除などの操作は Docker API などを使って行われます。コンテナは、複数のネットワークへの接続、ストレージの追加を行うことができます。 コンテナを削除すると、その時点での状態に対して変更がかかっていたとしてもイメージに反映されていないものは消失しますが、コンテナ内で行った変更 (新しいツールのインストールなど) をコンテナ内からイメージに反映させることも可能です。

・コンテナはイメージや生成、実行するために設定したオプションによって定義されます。デフォルトでは、コンテナは他のコンテナやホストマシンとは、程よく分離されています。コンテナに属するネットワーク、ストレージ、基盤となるサブシステムなどをどの程度切り離すかはコンテナを起動する際のオプション設定で制御することが可能です。この部分を簡単に言うと、何もオプションを設定せずにコンテナを生成した場合、コンテナ内からローカル環境やファイルを参照することができません。

Dockerの少し詳しい概要

・Docker はクライアント・サーバ型の構造をしています。Docker クライアント は Docker デーモンに処理を依頼します。このデーモンがコンテナの構築、実行、配布という仕事をこなします。

Docker デーモン

・Docker デーモン (dockerd) は Docker API リクエストを受け付け、イメージ、コンテナ、ネットワークといった Docker オブジェクトを管理します。 docker runなどのコマンドは Docker API を利用しています。

Docker クライアント

・Docker クライアント (docker ) は Docker とのやりとりを行うために、ユーザが利用するものです。docker run のようなコマンドが実行されると、Docker クライアントは dockerd にそのコマンドを伝え、dockerd はその内容を実行します。Docker クライアントは複数のデーモンと通信することができます。

Docker レジストリ

・Docker レジストリは Docker イメージを保管する場所です。Docker はデフォルトで DockerHub (公開レジストリ) のイメージを探すよう設定されています。独自にプライベート・レジストリを運用することもできます。docker rundocker pull などのコマンドを使うと、設定されたレジストリから必要なイメージを取得します。docker push コマンドを使えば、イメージを指定したレジストリに送信します。 Reference : https://docs.docker.com/get-started/overview/

Dockerの何がいいのか?

1) 複数のPCで完全に同一の解析環境を構築できること
ユーザやPC毎にOSのバージョンやインストールされているツールが違うことがほとんどです。同じツールを利用したにも関わらずエラーが起き際に、それがツール自体のバグなのかローカル環境依存の問題なのか、判断が難しいという問題が多々あります。同じDockerイメージを使用することでこの問題を回避することができます。イメージを揃えることで、利用者の環境が原因でエラーが起きる、バージョン毎に解析結果が変わってしまうという事態を回避し、再現性を担保することができます。イメージファイルの更新は一元管理可能なので、製作者・管理者にとっても利点が大きいです。

2)ローカルの環境を汚さないこと
例えば、Linux上に複数のパッケージをインストールする際、それぞれのパッケージが要求するライブラリのバージョンが異なることが原因で、同時にインストールすることができないという問題が生じることがあります。アップグレード・ダウングレードにより既存のツールがエラーになることもよくあります。余計なものをインストールして容量を圧迫してしまうなんてこともあります。PythonやRでも同じことが言えますね。必要なツールがインストールされたイメージを利用することでこの問題を回避することができます。(自分でイメージを作成する際にはバージョンコンフリクトと戦うことになりますが...これは次回以降でまとめようと思います。)

3)環境構築が用意なこと
新しくPCを購入した際やOSを再インストールした際など、必要なツールが全くインストールされていない環境であっても、DockerHubからイメージをダウンロードすれば解析に必要な環境が整うため、毎回環境構築をやり直さなくて済みます (もちろんですが、Dockerを利用せずにローカルで解析を実施したい場合は話は別です)。

Dockerの入手

DockerHubに登録してアカウントを作成し、Docker Desktopをインストールすることで利用することができます。

Docker Desktop

・Docker Desktopは MacWindowsLinux 環境へ簡単にインストールできるアプリケーションです。コンテナを構築・共有できるようになります。Docker デスクトップに含まれるのは Docker デーモン (dockerd )、Docker クライアント (docker)、Docker Compose、Docker Content Trust、Kubernetes、 Credential Helpeです。それぞれ以下からインストールできます。

Machttps://docs.docker.com/desktop/install/mac-install/

Windowshttps://docs.docker.com/desktop/install/windows-install/

Linuxhttps://docs.docker.com/desktop/install/linux-install/

Dockerを利用する際のコマンドラインは次回まとめようと思います。

同じSingularity Imageを使用しているのに環境によってpythonパッケージのバージョンが違ったときの覚書

はじめに

とある解析ができるようにDockerfileからDocker imageを作成して、それを基にSingularity imageを作ることにしました。その解析では特定のバージョンのPythonパッケージを使用する必要があり、Dockerfile内でそのバージョンを指定してインストールしました。しかし、Singularity imageを使う環境によってなぜかPythonパッケージのバージョンが違う!という事態に遭遇しました。今回はその時に調べた事の覚書です。

具体的な状況

今回はPython3.7、numpy1.19.0、pandas0.25.3が使いたいような状況でした。なのでDockerfileには以下の様に記載してimageをbuildしました。
(※Minicondaとpipをこの前でインストールしています)

ENV PATH="/opt/conda/bin:${PATH}"
RUN /opt/conda/bin/conda install -y python=3.7
RUN pip install --only-binary :all: numpy==1.19.0
RUN conda install pandas==0.25.3

numpy==1.19.0とpandas==0.25.3を同じ行でインストールしようとするとversion conflictでエラーになってしまうのでこの形に落ち着きました。

Dockerコンテナ内でバージョンを確認

buildが完了したのでインストールが上手くいっているか確認しました。

$ docker run --rm -ti <username/repository:tag>
# python
Python 3.7.10 (default, Jun  4 2021, 14:48:32)
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> print(np.__version__)
1.19.0
>>> import pandas as pd
>>> print(pd.__version__)
0.25.3

上手くいっていることが確認できたのでこのimageをpushして、Singularity imageにすることにしました。コマンドの例は以下です。

$ docker push <username/repository:tag>
$ singularity build <XXX.sif> docker://<username/repository:tag>

XXX.sifという名前のSingularity imageが出来上がりました。
ここまでの操作はサーバーAという環境で行いました。

Singularity内でバージョンを確認

問題はここからです。
サーバーBという環境で解析したいため、念のためサーバーBでバージョンの確認を行いました。
(サーバーBではDockerが使用できない状態だと仮定してください)

$ singularity run XXX.sif
Singularity> python
Python 3.7.10 (default, Jun  4 2021, 14:48:32)
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> print(np.__version__)
1.21.6
>>> import pandas as pd
>>> print(pd.__version__)
1.3.5

Pythonは3.7ですがnumpyとpandasのバージョンが違います。これでは解析ができない...

何故バージョンのが違うのか?

という事で原因を考えてみました。
Dockerはコンテナの内外が分断された独立環境となるという特性があります。そのため確実にコンテナ何の環境が適応されます。
一方で、Singularityはホストのリソース (ファイル・ハイドウェア) を直接利用できる。ホストの$HOME配下をデフォルトでコンテナにマウントするという特性があります。
このことから、Singularity image内では別の場所のnumpyとpandasを参照してしまっているのではないか?と考えました。早速、以下のようにどこのnumpyとpandasを参照しているのか確認してみます。

$ singularity run <XXX.sif>
Singularity> python
>>> import numpy as np
>>> print(np.__file__)
/home/nagaoka/.local/lib/python3.7/site-packages/numpy/__init__.py
>>> import pandas as pd
>>> print(np.__file__)
/home/nagaoka/.local/lib/python3.7/site-packages/numpy/__init__.py

やはり、$HOME下のファイルを参照していました。
調べたところ、$HOMEPythonパッケージがインストールされている場合(例えば、pip install --userを使用してパッケージをインストールした場合など)、それらのパッケージがコンテナ内のPythonからも利用可能になってしまうようです。
同様に、Singularityはデフォルトでホストの/tmpをコンテナ内にマウントします。Pythonの一時ファイルやキャッシュがこのディレクトリに保存されている場合、それらがコンテナ内のPythonから利用可能になる可能性があります。 これは時に便利な機能ですが、今回に限っては裏目に出てしまったようです...

対応策

対策1

対応策の一つとして、Singularity imageを立ち上げる際に--no-homeというオプションを使用することでこの問題が回避できました。
--no-home$HOME配下をマウントしないようにするオプションです。

$ singularity run --no-home <XXX.sif>
Singularity> python
>>> import numpy as np
>>> print(np.__version__)
1.19.0
>>> print(np.__file__)
/opt/conda/lib/python3.7/site-packages/numpy/__init__.py
>>> import pandas as pd
>>> print(pd.__version__)
0.25.3
>>> print(pd.__file__)
/opt/conda/lib/python3.7/site-packages/pandas/__init__.py

本来であれば、/opt/conda/lib/python3.7を参照してほしかったので、これで正しい場所を参照するようになったと言えます。 しかし、この方法はホームディレクトリ全体をマウントしないため、ホームディレクトリに保存されている他の重要なデータ(例えば、ユーザー設定や作業データなど)にもアクセスできなくなる点に注意が必要です。

対策2

現状では$HOME下を参照してしまっていることが原因であり、本来使いたいPythonパッケージは/opt/conda/lib/python3.7/site-packagesにあることがわかっています。Pythonはインポートするパッケージを見つけるためにPYTHONPATHという環境変数を使います。であれば、PYTHONPATHを指定し直して、目的の場所を探すように設定すれば良いのではないか?と考えました。以下のような感じです。

$ singularity run <XXX.sif>
Singularity> export PYTHONPATH=/opt/conda/lib/python3.7/site-packages:${PYTHONPATH}
Singularity> python
Python 3.7.10 (default, Jun  4 2021, 14:48:32) 
[GCC 7.5.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy as np
>>> print(np.__version__)
1.19.0
>>> print(np.__file__)
/opt/conda/lib/python3.7/site-packages/numpy/__init__.py

上記のコマンドはシェルセッションでのみ有効です。パス設定を恒久的に行いたい場合は、~/.bashrcまたは~/.bash_profileなどのシェルの設定ファイルに追記する必要があります。これなら自分でimageを作り直せない場合でも対応できそうです。

対策3

対策2の方法はSingularity imageを起動する度に行う必要があるので、少々面倒です。(~/.bashrcなどに記載したくない場合) 自分で作成しているimageであればDockerfileを改変することができるので、以下を追記してDocker imageとSingularity imegeを作り直してみました。

ENV PYTHONPATH="/opt/conda/lib/python3.7/site-packages:${PYTHONPATH}"

新しく作成したいSIFを用いて、サーバーBにてバージョンの確認を行いました。

$ singularity run <XXX_ver2.sif>
Singularity> python
Python 3.7.10 (default, Jun  4 2021, 14:48:32)
[GCC 7.5.0] :: Anaconda, Inc. on linux
>>> import numpy as np
>>> print(np.__version__)
1.19.0
>>> print(np.__file__)
/opt/conda/lib/python3.7/site-packages/numpy/__init__.py
>>> import pandas as pd
>>> print(pd.__version__)
0.25.3
>>> print(pd.__file__)
/opt/conda/lib/python3.7/site-packages/pandas/__init__.py

上記の様に、正しいバージョンを認識していました。$HOME下をマウントしていても問題がないので、自分で作り直せる場合はこの方法が良さそうです。

Singularityとは何か?の覚書ーその3

はじめに

Singularityのイメージやインストール方法が分かったところで、今回はどうやって使うのかに関してまとめたいと思います。

Singularityの使い方

基本的にはDockerと同様にimageからコンテナを作成して実行します。
・SingularityのコンテナであるSingularity Image File (SIF)をbuildします。
・SIFコンテナに対して、アクセス(shellやrun, exec)することで使用します。
 ※SIFコンテナは読取専用ファイルでコンテナ内で編集することはできません。

SIFのbuild方法は主に5つあります。目当てのコンテナが以下の場所にあれば簡単にbuildすることができます。
1.Container Libiraryから
2.Docker Hubから
3.Singularity Hubから
4.マシン上の既存のコンテナから
5. Singularity Definition Fileから
※SIFにすると動かないDocker imageがあるようです。もう少し勉強が必要だと感じてます。

Singularityの使い方-実践

今回はRNA-seqの解析ツールであるRumBallを例にして、SIFをbuildして使用してみたいと思います。

RumBall
GitHubhttps://github.com/rnakato/RumBall  Manual: https://rumball.readthedocs.io/en/latest/ 

SIFのbuildは以下のコマンドで行います。

$ singularity build <SIF name> <インストール元>
$ singularity build rumball.sif docker://rnakato/rumball #今回の例 

今回はDocker Hub に公開されているRumBallからrumball.sifを作成しています。 rumball.sifがSIFコンテナでありRNA-seq解析に必要なツールがインストールされています。
注意点はRamBall内でインストールされているツールは使用できますが、インストールされていないものは使用できません。ツールが足りないからと言って自分でインストールしてSIFコンテナに追加することはできません。
実行は、shell, run, execで行います。

shell

コンテナ内でShellを実行する.%runscript などは実行されずShellが起動する。デフォルトのShellは Bash が起動する。--shell でShellを指定することも可能。コンテナ内で、定義されたコマンドを実行する。

$ singularity shell <SIF name>
$ singularity shell rumball.sif  #例
  Singularity> <command>

run

コンテナ内でユーザ定義のデフォルトコマンドを実行する。sifファイルの作成時に指定できる %runscript が実行される。%runscript が指定されていない場合はShellが立ち上がる。

$ singularity run <SIF name> <command>

exec

execは run の部分をexecにするだけです。違いはコンテナ内でコマンドを実行するがコンテナを作成してから run するのではなく、sifファイルに直接コマンドを投げる点です。

$ singularity exec <SIF name> <command>

個人的にはexecを使う場合が多いかと思います。
注意点ですがshell, run, execともにデフォルトは$homeがマウントされています。

$ singularity shell rumball.sif
   Singularity> pwd
   /home/nagaoka
   Singularity> exit

マウントポジションを指定する場合は--bindオプションを使います。複数のディレクトリをマウントする場合は , で続けて記載します。

$ singularity shell --bind <directory> <SIF name> #run,execも同じ

$ singularity shell --bind /work,/work2 rumball.sif #例
   Singularity> pwd
   /work/Nagaoka/rumball/worktest

また、GPUを使用してコマンドを実行したい場合は--nvオプションを使用します。

 $ singularity exec --nv --bind <directory> <SIF name> <command>

基本的な使い方は以上で、あとは<command>の用法があっていれば解析ができます。 Dockerと異なりコンテナを立ち上げては消すというような作業が不要であり、外部のディレクトリを参照しやすいため非常に使い勝手が良いです。 一方で、SIFの中身を編集することはできないためツールにバグがあっても自分で修正することができません。また、SIFの作製に使用したimageが更新された場合は都度SIFのBuildが必要になります。

Singularityとは何か?の覚書ーその2

はじめに

Singularityとは何か?は前回のまとめで大体イメージができたかと思いますので実際にインストールしてみたいと思います。
SingularityCEをネイティブに動作させるにはLinuxシステムが必要です。また、Linux, Windows, Macそれぞれインストール方法が違うため順にまとめていきます。

インストール方法-共通

Singularityのインストール手順は主に3つです。
1. Goをインストールする
2. Singularityをダウンロードする
3. Singularityのソースコードコンパイルする

※Singularity v3以上は主にGoで書かれているため、ソースからコンパイルするにはGoが必要です。Goの最新バージョンをインストールする場合は、sudo rm -r /usr/local/go で古いgo ディレクトリを削除する必要があります(違う場所にgoをインストールしている場合は適切なpathに変更してください)。既存の ディレクトリ上に新しいバージョンを展開すると、ビルドするときにエラーが発生する可能性があります。
また、最新バージョンのsingularityをインストールする場合も、古いバージョンはアンインストールする必要があります。削除は以下のコマンドで行えます。

$ sudo rm -rf \
    /usr/local/libexec/singularity \
    /usr/local/var/singularity \
    /usr/local/etc/singularity \
    /usr/local/bin/singularity \
    /usr/local/bin/run-singularity \
    /usr/local/etc/bash_completion.d/singularity

Ubuntuにインストールする方法

・初めに必要なツールをインストールします。

$ sudo apt-get update
$ sudo apt-get install -y \
    autoconf \
    automake \
    cryptsetup \
    git \
    libfuse-dev \
    libglib2.0-dev \
    libseccomp-dev \
    libtool \
    pkg-config \
    runc \
    squashfs-tools \
    squashfs-tools-ng \
    uidmap \
    wget \
    zlib1g-dev

・次に最新バージョンのGoをインストールして$PATHをセットします。
最新のバージョンはhttps://go.dev/dl/で確認して、VERSION=XXXの部分を変更してください。

#インストール
$ export VERSION=1.21.5 OS=linux ARCH=amd64 
wget -O /tmp/go${VERSION}.${OS}-${ARCH}.tar.gz \
  https://dl.google.com/go/go${VERSION}.${OS}-${ARCH}.tar.gz
sudo tar -C /usr/local -xzf /tmp/go${VERSION}.${OS}-${ARCH}.tar.gz
sudo rm /tmp/go${VERSION}.${OS}-${ARCH}.tar.gz

#PATHの設定
$ echo 'export PATH=/usr/local/go/bin:$PATH' >> ~/.bashrc && \
  source ~/.bashrc  
#バージョンの確認
$ go version

・次にSingularityCEをダウンロードします。
今回はなるべく最新バージョンをインストールするためにGitHubのRepositoryからダウンロードする方法で行います。gitが使用できない場合は、以下のコマンドでインストールしてください。

$ sudo apt-get install git-all

・最新版のsingularity repositoryのclone (versionはhttps://github.com/sylabs/singularityで確認してください) 以下のコマンドではGitHubのmain branchがcloneされます。

$ git clone --recurse-submodules https://github.com/sylabs/singularity.git
$ cd singularity

・今回 (2023/12/18時点) はv4.0.2なので以下のコマンドで確認可能できます。

$ git checkout --recurse-submodules v4.0.2

・最後にsingularityのコンパイルを行って完了です。

$ ./mconfig
make -C builddir
sudo make -C builddir install

完了したらsingularityが使用できるようになっていると思います。 以下でバージョンを確認してみてください。

$ singularity --version

Windowsにインストールする方法

この場合は何通りか方法があります。
1) Windows内にUbuntuをインストールする
2) Git for Windowsを用いる
3) VirtualBox, Vagrant, Vagrant Manager for Windowsを用いる

私自身はWindows内にUbuntuをインストールする方法を用いました。Ubuntuさえインストールできれば上述のコマンドがそのまま使用できます。後の解析を考えると恐らくこれが一番楽です。

Macにインストールする方法

・SingularityCEはVagrantで利用することができます。インストールしていなければHomebrewとともにインストールします。

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ brew install --cask virtualbox vagrant vagrant-manager

HomebrewApple(またはLinux)が提供していない必要なものをインストールすることができるもので、/Homebrewにパッケージをインストールし、それらへのシンボリックリンクを/usr/localに作成するらしい...詳しくは下記参照

Homebrew — The Missing Package Manager for macOS (or Linux)

・インストールが完了したらTerminalを起動しVagrant VM で使用するディレクトリを作成します.

$ mkdir vm-singularity-ce && \
    cd vm-singularity-ce

すでに/vm-singularity-ceを別のVMに作成して使用している場合は、VMを破棄してVagrantfileを削除する必要があります。

$ vagrant destroy && \
    rm Vagrantfile

・最後にVirtual Machineを立ち上げればsingularityが使用できるはずです。(必要に応じて、$VMに別の値を代入してください)。

$ export VM=sylabs/singularity-ce-3.8-ubuntu-bionic64 && \
    vagrant init $VM && \
    vagrant up && \
    vagrant ssh

以下のコマンドで使用できるか確認してみてください。

vagrant@vagrant:~$ singularity version

インストール方法をまとまてみましたが無事インストールできましたか?問題や解決方法があった場合は教えて頂けるとありがたいです。

マークダウン記法に関しての覚書

はじめに

NGS解析のコマンドを記事にまとめるにあたり記載方法はどうしたらいいんだろうか?という壁にぶつかりました。
今回はNGS解析やそれに関連するブログなどで良く使用されているマークダウン記法に関して簡単にまとめようと思います。

マークアップ・マークダウン記法とは?

マークアップとは、文章の論理的な構造や修飾情報に関する指定を文章とあわせてテキストファイルに記述するための言語のことです。代表的な例は「HTML (HyperText Markup Language) 」や「XML (eXtensible Markup Language)」などです。
マークアップ言語はテキストエディタを使って閲覧・編集でき、文章の一部を「タグ」と呼ばれる特定の文字列で囲むことで文書化するものです。 以下はHTMLの例です。

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>記事のタイトル</title>
<head/>
<body>

<header>ヘッダーを表示するためのタグで、サイトロゴやメニューを表示</header>
<footer>サイトの最下部に位置するタグ</footer>
<h1>「h+番号」で見出しを指定</h1>
<p>文書内に段落を作るためのタグ</p>
<div>:区分(Division)タグで、囲んだ文章をグループ化する</div>
<br>改行(Break)タグです。※閉じタグは不要
<img>…画像を挿入するためのタグです。※閉じタグは不要

</body>
</html>

上記の様にマークアップは記述や種類が多く、扱うには専門的な知識が必要です。初心者にはなかなかハードルが高いように感じます。

次にマークダウンとはHTMLなどのマークアップ言語を簡略化し、シンプルな書き方で文書構造を明示できる軽量マークアップ言語のことです。記法も少なくシンプルなため覚えれば簡単に扱うことができます。
以下に初歩的な記述例をまとめます。

1.見出し

上のような見出しを作りたい場合は、文章の前に##を入れると見出しのような表示にすることができる。 付ける個数によって大きさが変わります。

例
#見出し1
##見出し2
###見出し3
####見出し4
#####見出し5

表記

見出し1

見出し2

見出し3

見出し4

見出し5

2.改行

改行したい文章の全文の最後に半角スペースを2つ入れて改行する。改行を入れないと文章は続けて表記される。

例1:次の文章を改行したい。(半角スペース)(半角スペース) この場合は改行されない。
例2:次の文章を改行したい。(半角スペース)(半角スペース) (改行)
この場合は改行されて表示される。

表記
例1:次の文章を改行したいしたい。 この場合は改行されない。
例2:次の文章を改行したい。
この場合は改行されて表示される。

3.コードブロック

コードブロック化したい領域の前後の行を``` (バッククオート3つ)で挟む

 ```
こんな感じで挟む。(コードブロックの中で```を使用したい場合は前にスペースなどを入れると表示できる)
 ```

4.文章中のコードブロックを入れる

文章中に短いブロックを入れたい場合は文字の前後を ` (バッククオート)で挟む

例:`ブロック`にしたい文章を挟むと以下の様に表示される。

表記:ブロックにしたい文章を挟む

5.文字を強調する

文章中の文字を強調したい場合は * (アスタリスク1つ) で囲む、強く強調したい場合は** (アスタリスク2つ)で囲む。

例:この発見は特に*重要*である。
例:この発見は特に**重要**である。

この発見は特に重要である。
表記:こ発見は特に重要である。

6.水平線を引く

水平線を引いて区切りを作りたい場合はその部分にアンダーバーを3つ入力する。

例:この文章の下に水平線を引く
___

表記:この文章の下に水平線を引く


7.リンクを挿入する

参考にしたWebサイトなどのURLを挿入したい場合は、以下の複数の方法があります。
1. テキストにリンクを直接埋め込む場合は、[ ]で囲みます。
[https://www.google.com]

2.リンクを張りつつURLを表示させる場合は< >で囲みます。
<https://www.google.com>
表示 : https://www.google.com

3."Google"というテキストを表示し、クリックするとリンク先に飛ぶようにする場合は [表示させたい文字](URL)の形式で書きます。
例 : [Google](https://www.google.com)
表示 : Google

以上の様な覚え書きを随時更新していこうと思います。