生物套件執行系統 Galaxy Project

linnil1
10 min readNov 27, 2021

--

繼上次介紹整個架構,這次來講講為什麼 Galaxy 是個不錯的生物資訊平台,我們這次以整合生物資訊套件的觀點出發,畢竟這是最核心的部分。

上次講ㄉ Galaxy part1

Galaxy 之所以厲害,就是因為它整合了很多套件。但整合套件的前提是有一個架構很簡單的可以讓開發者開發各式各樣的需求,而且不會常常出 bug

我們從兩個層面出發

  1. 套件: 使用 conda 安裝並包裝從 source code 來的東西
  2. 工具: 也就是呈現在 galaxy 工具的網頁頁面,以及輸入參數執行該套件

套件安裝 (Conda)

因為 galaxy 是有點古老的系統,所以比較不支援 docker 之類的 container 操作,所以是使用 conda 進行套件的安裝。conda 也是一個套件管理系統,厲害的是很多 system packages 也一起處理了,所以不容易碰到 xxx not found 或是需要 libxx.so 的 bug。在生物資訊,有一個生態圈叫 bioconda ,專門放置生物資訊的套件。

conda 的 recipes 有多好寫呢,可以看看我覺得簡單的例子https://github.com/bioconda/bioconda-recipes/tree/master/recipes/lastz

裡面有兩個最重要的檔案 meta.ymlbuild.shbuild.sh 其實沒什麼好說,就是寫怎麼執行 make (通常開發者會寫在 README ),然後再把東西搬到正確位置($PREFIX/bin)。meta.yml的重要部分如下:

source:
url: http://www.bx.psu.edu/~rsharris/lastz/newer/lastz-{{ version }}.tar.gz
sha256: b251080534dd67c25a9d751af464ffff9b2752d6834e75feb3860404174ea40c
requirements:
build:
- make
- {{ compiler('c') }}
run:
test:
commands:
- lastz --version 2>&1 | grep {{ version }} > /dev/null
  • 前兩行是下載 source code
  • 第三行告訴我們安裝時需要那些套件(比如說 gcc, make),下面一行告訴我們執行時需要那些套件(這裡寫不需要,因為他是個不需要 external library 的 binary 檔)
  • 最後是簡單的 testing 確定有安裝成功
  • 就這樣,詳細設定可以看 conda 文件

Conda 唯一的缺點是他跟很久以前的 npm 一樣,install 要很久,我開發的等 testing 也等很久。做好且發 PR 接受後,我們就可以用 conda search 看到那個套件,然後也可以用 conda install 就把他安裝好

注意 conda 的 version 是該開發者自己的版本號(比如說 lastz 在他的原始碼中版本號就是 1.04.15),build 是在 version 固定的情況下的版本號,通常會跟更新上游的 requirement 有關,格式是 {hash}_{build_id}

conda 還有一個功能是會解析 dependency ,所以安裝不同工具在同一個環境的時候會確認底層會不會衝到。真正的使用情境,就會像等等要說的工具安裝一樣,把很多個工具包在一個環境裡,conda create --name mull-test hisat2=2.1.0 samtools=1.11 ,然後要執行的時候在進入那個環境 conda activate mull-test 。如下圖三個工具都被放在一個 _conda/envs/mulled-xxx 的環境裡

總而言之,只要把你的軟體包成 conda,對於一個一般使用者而言,最簡單 conda install xxx就能解決很多問題了

工具安裝 (Galaxy ToolShed)

講完套件的安裝了,再來講怎麼整合進入 Galaxy,其實也意外的簡單,每個 tool 基本上就是一個 wrapper 把所有需要的套件與執行參數包進去,剩下的 galaxy 會幫你。

以這個例子 https://github.com/galaxyproject/tools-iuc/tree/master/tools/lastz 來說,幾乎所有設定都放在 lastz.xml ,裡面有幾個重要的地方

1. 需要安裝的 conda 套件

<requirements>
<requirement type="package" version="1.04.15">lastz</requirement>
<requirement type="package" version="1.7">samtools</requirement>
<requirement type="package" version="3.4.2">r-base</requirement>
<requirement type="package" version="1.0.6">bzip2</requirement>
</requirements>

這些 dependency 會在 admin 介面要安裝 tools 的時候 進行安裝(下圖 按下 Install 後的青藍色按鈕),會安裝到剛剛說的一個 conda 環境(_conda/envs/mulled-xxx)。每個 job 開始跑後,會直接連到(activate)那個環境,所以執行時不會卡下載或安裝時間。

注意,Galaxy 的 tool 版本號跟原工具的版本號一樣,如果是 galaxy 這邊有新的版本,比如說新增輸入參數,會放在 +galaxy{N} 這裡

2. 使用者輸入參數

放在 lastz.xml 的 inputs 部分,某種程度很像 --help 直接搬過來,但是這樣的優點是使用者可以在網頁上操作,而且是邊看 help 邊填,甚至直接寫好讓你用選的。

下圖這個例子,不僅幫你把參數按照種類分類分好(section),還有一些巧妙的設計,比如說按下 Yes/No 的 Yes 後才會跑出某些參數讓你填(filter, when)。詳細的設計可以看文件

Note: 我把 Help 拿掉了,因為呈現起來很長

3. 塞入執行參數

在執行階段,Galaxy 已經幫我們把環境開好,資料夾設定好,甚至 pbs 的部份也做好了,我們唯一要定義的事情是如何執行。

我們在開發上這個執行程式是非常自由的,只要寫一個 template 就好了,這裡 Galaxy 用的語法 Cheetah 而不是最近大家常用的 jinja ,如下圖,這是 lastz.xml 的 command 的部分,output_format.out.format 是使用者在網頁上所選的,然後我們的 template 用一堆 if 來決定 argument 要塞哪個,甚至可以加 pipe | 或者是 繼續加執行的東西 && (像下面 用了 | samtools sort把所有的 sam 都弄成 bam 這種更標準的格式後,才會存到 galaxy 的 objects 裡)

#if str( $output_format.out.format ) == "bam":
'--format=${output_format.out.bam_options}'
#elif str( $output_format.out.format ) == "general_def":
--format=general-
#elif str( $output_format.out.format ) == "maf":
'--format=${output_format.out.maf_type}'
#elif str( $output_format.out.format ) == "blastn":
--format=BLASTN-
#elif str( $output_format.out.format ) == "general_full":
'--format=general-:${output_format.out.fields}'
#elif str( $output_format.out.format ) == "differences":
'--format=differences'
#end if
--action:target=multiple
$output_format.rplot
#if str( $output_format.out.format ) == "bam":
| samtools sort -@\${GALAXY_SLOTS:-2} -T "\${TMPDIR:-.}" -O bam -o '${output}'
#else:
> '${output}'
#end if
#if $output_format.rplot:
&&
Rscript $r_plot > /dev/null 2>&1
#end if

總而言之,在工具安裝上,我們就只是把 command line 再包一層而已,雖然只要工具越多參數,這方面會稍微麻煩一點,但也是不得不的。而對於使用者,只要滑鼠隨便點一點,就能執行了,至少不會還要停下來研究要輸入哪個。以 paired-end 的 fastq 檔為例,有 read1.fq read2.fq , -1 read1.fq -2 read2.fq ,-r read1.fq.gz -r read2.fq.gz ,read1.fq out1.fq read2.fq out2.fq 這麼多種寫法在不同工具上,實在很頭痛

總結

把新的工具放進 Galaxy 就這兩個步驟,寫 conda recipe 跟 寫 ToolShed 。對於生物資訊軟體開法者而言,conda 部分只是某種把 building 標準化的流程而已(而且比 docker build 嚴謹一點),而 ToolShed 則是很像 我們在寫 argparse 的邏輯,且執行程式的組合非常自由,不至於要太大的阻礙。

有了 version 版本號 跟 galaxy 版本號,只要 source code 一更動,或者是 dependency 變動,可以用 bot 去監測並自動更新(目前會有機器人自動 PR),所以 galaxy 跟 bioconda 都能持續地走在最新版本。

這是為什麼 galaxy 能容納這麼多各式各樣的生物資訊工具,也是 galaxy 是一個很不錯的平台的其中一個原因。

雖然我是這麼稱讚 Galaxy,但除了沒有使用 docker 以外(畢竟使用了 conda 管理了),還有很重要的事情是 resource 分配的問題。Galaxy 的工具並沒有定義最低的 resource ,resource 的定義是 admin 手動寫在 job_conf.xml,所以如果該工具如果有特殊需求,比如說 Assembler 需要比較大的 memory,admin 要自己手動調整要給這個工具多少資源,這蠻煩的。

另外大家應該有發現我一直舉某個軟體當例子,原因我們的 NTU galaxy user 有需求,我特別研究一下的結果,然後順手丟了兩個 PR

https://github.com/bioconda/bioconda-recipes/pull/31727

https://github.com/galaxyproject/tools-iuc/pull/4251

覺得這篇也幫助的話,請多按旁邊的 claps 支持作者ㄅ

--

--

linnil1

目前做生物資訊與演算法,過去做過 Machine Vision(Deep learning),維護伺服器(k8s, docker),部分IOT(rpi, arduino)