toil-cwl-runner on singularity2.5.2 を試す


# [toil](https://toil.readthedocs.io/en/latest/)

toilを実行する環境を構築する方法として、公式サイトではvirtualenvを利用することを推奨しているが、ここではtoilの環境を、anacondaで構築することにしてみた。 toilは、python2.7環境を要求する。今回はcwlで書かれたワークフローをtoilを利用して、Singularity 2.5.2上で動作させることを試してみた。

#### 環境

```bash
$ singularity --version
2.5.2-dist
$ toil --version
3.16.0
$ toil-cwl-runner --version
DEBUG:rdflib:RDFLib Version: 4.2.2
3.16.0
```

### 手順

ここでは、サンプルとして実行するcwlのワークフローとして、https://github.com/hacchy1983/CWL-workflows を実行してみることにしたい。

```bash

$ conda create -n toil python=2.7 anaconda
$ source activate toil
$ pip install toil[cwl]
$ git clone https://github.com/hacchy1983/CWL-workflows
$ toil-cwl-runner Workflows/test-workflow.cwl Jobs/small.ERR034597.test-workflow.yml
```

陥った落とし穴

1. `pip install toil[cwl]`とせずに、`pip install toil`としてしまうと、cwltoolというpython libraryが入っていないのでエラーメッセージが出力される。従って、`pip install toil[cwl]`としないといけない。
2. toilはデフォルトでの実行時に、そのコア数に応じてpythonのスレッドをたくさん生成する仕様になっていて、メニーコアのマシンではかなり多くのスレッドが立つ。しかしながら、pythonでスレッドをたくさん作るとメモリ使用量が増えるので、使えるメモリが足りなくなると `thread.error: can't start new thread` というエラーメッセージが出力されて、キー入力を受け付けなくなってしまう。この場合、toilを実行するときに `--debugWorker` という引数を付けるか、そもそもメモリをたくさん詰んだマシンで実行する。


まずは、サンプルのコマンドを実行してみる。

```
=========> Failed job 'file:///~/cache/CWL-workflows/Tools/fastqc.cwl' fastqc C/j/jobSOsgEt
INFO:toil.worker:---TOIL WORKER OUTPUT LOG---
INFO:toil:Running Toil version 3.16.0-5988d51822310572dee1aa1e3cb8c81e39ba376c.
Traceback (most recent call last):
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/toil/worker.py", line 313, in workerScript
    job._runner(jobGraph=jobGraph, jobStore=jobStore, fileStore=fileStore)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/toil/job.py", line 1337, in _runner
    returnValues = self._run(jobGraph, fileStore)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/toil/job.py", line 1282, in _run
    return self.run(fileStore)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/toil/cwl/cwltoil.py", line 470, in run
    (output, status) = cwltool.main.single_job_executor(**opts)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/cwltool/main.py", line 58, in single_job_executor
    return executor(t, job_order_object, **kwargs)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/cwltool/executors.py", line 31, in __call__
    return self.execute(*args, **kwargs)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/cwltool/executors.py", line 71, in execute
    self.run_jobs(t, job_order_object, logger, **kwargs)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/cwltool/executors.py", line 107, in run_jobs
    r.run(**kwargs)
  File "~/anaconda3/envs/toil/lib/python2.7/site-packages/cwltool/job.py", line 412, in run
    "--user-space-docker-cmd.: {1}".format(container, e))
WorkflowException: Docker is not available for this tool, try --no-container to disable Docker, or install a user space Docker replacement like uDocker with --user-space-docker-cmd.: 'docker' executable not found: [Errno 2] No such file or directory: 'docker'
ERROR:toil.worker:Exiting the worker because of a failed job on host
WARNING:toil.jobGraph:Due to failure we are reducing the remaining retry count of job 'file:///~/cache/CWL-workflows/Tools/fastqc.cwl' fastqc C/j/jobSOsgEt with ID C/j/jobSOsgEt to 0
<=========
```

dockerがないマシンで実行したので、dockerがないといって怒られる。今回はdockerで動かすのではなくSingularityでコンテナを動かすことを考える。このとき、変更したいパラメータは、以下のものである。

```bash
$ toil-cwl-runner -h
  --singularity         [experimental] Use Singularity runtime for running containers. Requires Singularity v2.3.2+ and Linux with kernel version v3.18+ or with overlayfs support backported.
```

experimental であるが、--singularityのフラグを立てて実行してみた。すると、以下のエラーに見舞われた。

```bash
WARNING: Skipping user bind, non existent bind point (directory) in container: '/var/spool/cwl'
WARNING: Skipping user bind, non existent bind point (file) in container: '/var/lib/cwl/stg6bf16740-f33a-496b-9ec9-ebe8da26636c/small.ERR034597_1.fastq'
ERROR  : Could not change directory to: /var/spool/cwl
ABORT  : Retval = 255
[job fastqc.cwl] Job error:
```

エラーが吐かれてしまった。この直接の原因は、`/var/spool/cwl` というコンテナ内に存在しないフォルダを `--pwd` として指定しているため、そこにchange directoryできずにエラーを吐いたと考えられる。

この問題は、こちらのissueに書いてあった。　https://github.com/sylabs/singularity/issues/1607

ここで期待したい挙動はおそらく、Singularityのコンテナに、適当に作ったout_tmpdirを`var/spool/cwl/` のディレクトリでbindし、更にそのディレクトリをpwdとして指定したいというように見える。dockerでは類似の操作ができるが、issueによれば、どうやらsingularityではそんなことはできない（？）らしい。

toilのコードを見てみると、Singularityに投げる部分は、cwltoolのライブラリを実質的にラップしているということがわかった。つまり、cwltoolがうまく動かない限り、toil-cwl-runnerは動かないと考えられる。

*ここで、 Singularityの `--pwd` という引数を `--workDir` という引数に変更すると、とりあえずエラーを回避して次に進むことはできた。果たしてこれで問題が解決されたのかはわからない。*

しかし、またしても次に以下のようなエラーに見舞われた。

```bash

Skipping '/var/lib/cwl/stg8c52f05c-6887-4236-a266-f8f0a8a4cd47/small.ERR034597_2.fastq' which didn't exist, or couldn't be read
[job fastqc.cwl] Job error:
```

これに関連するものとして、以下のwarningが表示されている。

```
WARNING: Skipping user bind, non existent bind point (directory) in container: '/var/spool/cwl'
WARNING: Skipping user bind, non existent bind point (file) in container: '/var/lib/cwl/stg8c52f05c-6887-4236-a266-f8f0a8a4cd47/small.ERR034597_2.fastq'
```

この問題は以下に書いてある。

https://github.com/sylabs/singularity/issues/1182

Singularity 2系列のツールでは、bindする先のディレクトリにスタブ（空ファイル）がないと、bindできないということらしい。そのため、入力として使いたいfastqファイルがSingularityのコンテナにbindできず、ファイルがないというエラーを吐いているのではないかと考えられる。

現在はここまでで、toil with cwl on Singularityの試みは止まっているが、Singularityのバージョンを上げればうまく動くかもしれない。他にもし、うまくいく方法をご存じの方がいらっしゃれば、コメントいただけると助かります！