AWS Graviton 向けに pixi で Bioconda コンテナを作ってみた

AWS Graviton 向けに pixi で Bioconda コンテナを作ってみた

pixi を使って Bioconda のツールを含む arm64 向け Docker イメージを作成してみました。ロックファイルの準備からマルチステージビルド、実際の動作確認まで、その手順と結果を紹介します。
2026.09.24

はじめに

pixi は prefix.dev が開発しているパッケージマネージャーです。conda と同じく bioconda チャンネルからパッケージを入れられます。前回は pixi で Bioconda のツールを入れ、conda、mamba と初回インストールの所要時間を比べました。今回は AWS Graviton で動かすことを想定して、同じ 5 つのツールを入れた arm64 向けの Docker イメージを pixi で作りました。

https://dev.classmethod.jp/articles/bioconda-install-with-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 adddocker 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-onlybuild の直後にキャッシュが効いた状態でビルドし、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-buildbowtie2samtools viewfastqcmultiqc へ続く 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 でも動くことがわかったのが収穫です。イメージの作り方はちょっと検討するとして上手い運用方法を考えてみます。

参考

この記事をシェアする

AWSのお困り事はクラスメソッドへ

関連記事