yNagaokaのブログ

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

ローカルの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できない問題は解決できていません。どなたか解決方法をご存じでしたら教えて頂ければ幸いです。