AWS Graviton 向けに pixi で Bioconda コンテナを作ってみた
はじめに
pixi は prefix.dev が開発しているパッケージマネージャーです。conda と同じく bioconda チャンネルからパッケージを入れられます。前回は pixi で Bioconda のツールを入れ、conda、mamba と初回インストールの所要時間を比べました。今回は AWS Graviton で動かすことを想定して、同じ 5 つのツールを入れた arm64 向けの Docker イメージを pixi で作りました。
確認結果
確認は Mac(arm64)の Docker 29.5.3 で行いました。pixi 公式ドキュメントのコンテナの例に沿って作りました。
- 公式の例はビルドで
pixi install --lockedを使うので、ロックファイルを先に作っておく必要がある - 公式の例はマルチステージビルドで pixi 本体を実行イメージに持ち込まない
- ただし差は 390 MB ほどで、ツールが重たい Bioconda のイメージではそれほど気にするサイズではなかった
検証環境
| 項目 | 値 |
|---|---|
| ホスト | Mac(arm64)、Rancher Desktop |
| Docker エンジン | 29.5.3 |
| プラットフォーム | linux/arm64(ネイティブビルド) |
| ビルドステージ | ghcr.io/prefix-dev/pixi:0.81.0 |
| 実行ステージ | ubuntu:26.04 |
| 対象ツール | seqkit 2.13.0、bowtie2 2.5.5、samtools 1.24、fastqc 0.12.1、multiqc 1.35 |
| 検証日 | 2026/09/20 |
ビルド前にロックファイルを作る
公式ドキュメントの例に合わせて、ビルドではロックファイルを使う pixi install --locked で環境を作ります。そのため先にロックファイルを用意します。ホストに pixi を入れずに済むよう、生成は pixi コンテナで行います。マウント先のディレクトリ名がそのままワークスペース名になるため、/bioinfo にマウントしています。
docker run --rm --platform linux/arm64 -v "$PWD":/bioinfo -w /bioinfo \
ghcr.io/prefix-dev/pixi:0.81.0 \
pixi init --channel conda-forge --channel bioconda --platform linux-aarch64 .
今回テストで使う fastqc など 5 つのツールを追加します。ここで欲しいのはロックファイルだけなので、--no-install を付けて依存関係の解決で止め、インストールはしません。
docker run --rm --platform linux/arm64 -v "$PWD":/bioinfo -w /bioinfo \
ghcr.io/prefix-dev/pixi:0.81.0 \
pixi add --no-install seqkit bowtie2 samtools fastqc multiqc
pixi add は docker run の起動を含めて約 2 秒で完了しました。インストールしないぶん、かなり速く終わります。生成された pixi.toml は次の内容です。
[workspace]
channels = ["conda-forge", "bioconda"]
name = "bioinfo"
platforms = ["linux-aarch64"]
version = "0.1.0"
[tasks]
[dependencies]
seqkit = ">=2.13.0,<3"
bowtie2 = ">=2.5.5,<3"
samtools = ">=1.24,<2"
fastqc = ">=0.12.1,<0.13"
multiqc = ">=1.35,<2"
生成された pixi.lock には conda パッケージが 157 個含まれていました。ロックファイル内の URL のディレクトリ名から、5 つのツールが linux-aarch64 向けか noarch かを判別できます。
grep -oE "(bioconda|conda-forge)/(linux-aarch64|noarch)/(seqkit|bowtie2|samtools|fastqc|multiqc)-[^ ]*" pixi.lock | sort -u
seqkit、bowtie2、samtools は aarch64 ネイティブビルドで、fastqc と multiqc は noarch でした。
bioconda/linux-aarch64/bowtie2-2.5.5-h54003ff_1.conda
bioconda/linux-aarch64/samtools-1.24-h391949c_1.conda
bioconda/linux-aarch64/seqkit-2.13.0-h8865c2f_0.conda
bioconda/noarch/fastqc-0.12.1-hdfd78af_0.tar.bz2
bioconda/noarch/multiqc-1.35-pyhdfd78af_1.conda
マルチステージビルドの Dockerfile を作る
マルチステージビルドを使い、pixi 本体を実行イメージから除外します。ビルドステージで環境を構築し、実行ステージへ環境ディレクトリのみをコピーします。
pixi 公式ドキュメントの例は、pixi shell-hook の出力を ENTRYPOINT で実行してアクティベーションします。私の事情なのですが、AWS ParallelCluster でこのイメージを動かす場合は、コンテナの実行には同梱されている NVIDIA Pyxis を使う予定でいます。Pyxis は既定で ENTRYPOINT を実行しません。ENTRYPOINT に任せるとツールに PATH が通らないため、ENTRYPOINT は使いません。pixi がツールを入れたディレクトリ /app/.pixi/envs/default/bin を Dockerfile の ENV で PATH に追加します。
FROM ghcr.io/prefix-dev/pixi:0.81.0 AS build
WORKDIR /app
COPY pixi.toml pixi.lock ./
# --locked で pixi.lock がマニフェストと合致しているかを確認してから作る
RUN pixi install --locked
FROM ubuntu:26.04 AS path-only
WORKDIR /app
COPY --from=build /app/.pixi/envs/default /app/.pixi/envs/default
ENV PATH=/app/.pixi/envs/default/bin:$PATH
実行イメージをビルドする
作成した Dockerfile から 2 つのターゲットをビルドします。サイズを比べるため、ビルドステージも pixi-bio:build としてビルドしています。
docker build --platform linux/arm64 --target build -t pixi-bio:build .
docker build --platform linux/arm64 --target path-only -t pixi-bio:path-only .
計測では build ターゲットに --no-cache を付けました。キャッシュにヒットすると pixi install --locked の層が実行されないためです。所要時間はベースイメージの取得を除いて 45 秒で、うち pixi install --locked が 32.7 秒でした。path-only は build の直後にキャッシュが効いた状態でビルドし、1 秒以内で完了しました。
for i in pixi-bio:build pixi-bio:path-only ghcr.io/prefix-dev/pixi:0.81.0 ubuntu:26.04; do
docker image inspect -f '{{.Size}}' "$i" \
| awk -v n="$i" '{printf "%-34s %8.1f MB\n", n, $1/1024/1024}'
done
pixi-bio:build 2040.2 MB
pixi-bio:path-only 1653.6 MB
ghcr.io/prefix-dev/pixi:0.81.0 164.5 MB
ubuntu:26.04 114.5 MB
実行イメージは、pixi 本体を含むビルドステージより約 387 MB 小さくなりました。ベースの ubuntu:26.04 は 114.5 MB なので、残りの約 1.5 GB は pixi が入れた環境です。インストールするツールが大きいので、差はそれほど大きくなりませんでした。
テストデータと実行スクリプトを用意する
バージョン表示ではなく、テストデータを通した処理で動作を確認します。data/ を作り、次のスクリプトで 1,000 塩基のリファレンス配列 ref.fa と、50 塩基 20 本のリード reads.fq を生成します。ランダムですが固定シードなので、同じ Python(今回は 3.14.7)なら何度実行しても同じファイルになります。
mkdir -p data
python3 - <<'PY'
import random
random.seed(20260919)
ref = "".join(random.choice("ACGT") for _ in range(1000))
with open("data/ref.fa", "w") as f:
f.write(">chr_test\n")
for i in range(0, len(ref), 60):
f.write(ref[i:i+60] + "\n")
with open("data/reads.fq", "w") as f:
for n in range(20):
s = random.randint(0, len(ref) - 50)
seq = ref[s:s+50]
f.write("@read%02d\n%s\n+\n%s\n" % (n, seq, "I" * len(seq)))
print("ref.fa / reads.fq created")
PY
続いてテストスクリプト data/chain.sh を用意します。seqkit stats から bowtie2-build、bowtie2、samtools view、fastqc、multiqc へ続く 6 ステップを通します。各ステップは終了コードが 0 なら OK、それ以外なら FAIL として 1 行ずつ出力します。成否は終了コードだけで判定しており、アライメント結果やレポートなど出力の中身は確認していません。
chain.sh の全文
#!/bin/bash
set -u
WORK=/work
OUT=/tmp/out
mkdir -p "$OUT"
echo "user: $(id -u):$(id -g) HOME=${HOME:-(unset)} writable_home=$(test -w "${HOME:-/nonexistent}" && echo yes || echo no)"
echo "java_home=${JAVA_HOME:-(unset)}"
step() {
local name="$1"; shift
local rc
"$@" > "$OUT/$name.log" 2>&1
rc=$?
if [ "$rc" -eq 0 ]; then
printf ' OK %s\n' "$name"
else
printf ' FAIL %s (exit=%s) %s\n' "$name" "$rc" "$(sed -n '1p' "$OUT/$name.log" 2>/dev/null)"
fi
}
step seqkit seqkit stats "$WORK/ref.fa"
step bowtie2-build bowtie2-build "$WORK/ref.fa" "$OUT/idx"
step bowtie2 bowtie2 -x "$OUT/idx" -U "$WORK/reads.fq" -S "$OUT/aln.sam"
step samtools samtools view -bS "$OUT/aln.sam" -o "$OUT/aln.bam"
step fastqc fastqc "$WORK/reads.fq" -o "$OUT"
step multiqc multiqc "$OUT" -o "$OUT"
PATH の設定しておけば大丈夫だった
path-only イメージで単体コマンドを動かします。num_seqs が 1、sum_len が 1,000 になっていれば、ツールがデータを読めています。
docker run --rm --platform linux/arm64 -v "$PWD/data":/work:ro \
pixi-bio:path-only seqkit stats /work/ref.fa
file format type num_seqs sum_len min_len avg_len max_len
/work/ref.fa FASTA DNA 1 1,000 1,000 1,000 1,000
続いて chain.sh で 6 ステップを通します。
docker run --rm --platform linux/arm64 -v "$PWD/data":/work:ro \
pixi-bio:path-only bash /work/chain.sh
6 ステップすべてが終了コード 0 で終わりました。
OK seqkit
OK bowtie2-build
OK bowtie2
OK samtools
OK fastqc
OK multiqc
まとめ
pixi 公式ドキュメントのコンテナの例に沿って、Bioconda の 5 つのツールを入れた arm64 向けの Docker イメージを作りました。公式の例はビルドで pixi install --locked を使うので、ロックファイルを先に用意しておきます。マルチステージビルドで pixi 本体は実行イメージから外れますが、差は 390 MB ほどです。ツールが重たい Bioconda のイメージでは、それほど気にするサイズではありません。
おわりに
ParallelCluster で実行するときもコンテナがよいのか、コンピュートノードにインストールするのがいいのか検討していました。pixi ベースでコンテナイメージ作れる&ARM でも動くことがわかったのが収穫です。イメージの作り方はちょっと検討するとして上手い運用方法を考えてみます。








