michaelfeil/infinity の ARM64 CUDA イメージのビルド、動作確認を行ったのでその作業を記録する。
なお、この作業記録は Codex が自身の作業を記録したものである。
なお成果物は mikoto2000/infinity at for_dgx_spark に置いた。
目的
DGX Spark 上で、 Infinity を使いたかったので、 ARM 用の Docker イメージを作成したい。
実行環境
- 作業日: 2026-09-14
- リポジトリ: Windows
F:\project\infinity/ WSL/mnt/f/project/infinity - WSL2:
Ubuntu-24.04、ユーザーmikoto、ホストlinux/amd64 - ホスト Docker Engine: 29.6.1
- DinD 内 Docker Engine: 29.8.0
- 専用 DinD コンテナ:
infinity-spark-dind - Docker データボリューム:
infinity-spark-dind-data - ソースは DinD の
/workspaceに読み取り専用でマウントする。 - PowerShell のサンドボックスから通常権限では WSL の列挙が
Wsl/EnumerateDistros/Service/E_ACCESSDENIEDになったが、昇格実行で利用可能と確認した。 前の回答の「Docker がない」は Windows の PATH の確認に限られていた。
参照した仕様
- NVIDIA Spark 対応表: CUDA Toolkit 13.0 以降。
- Spark
の公式 PyTorch 手順:
nvcr.io/nvidia/pytorch:25.11-py3を使用。 - PyTorch 25.11 リリースノート: Ubuntu 24.04、Python 3.12、CUDA 13.0.2、NVIDIA ビルドの PyTorch 2.10.0a0。
DinD の準備 (WSL2 のシェルで実行)
cd /mnt/f/project/infinity
docker run -d --name infinity-spark-dind --privileged \
--mount type=volume,source=infinity-spark-dind-data,target=/var/lib/docker \
--mount type=bind,source=/mnt/f/project/infinity,target=/workspace,readonly \
--workdir /workspace \
docker:29-dind dockerd --host=unix:///var/run/docker.sock
docker exec infinity-spark-dind docker info
docker exec infinity-spark-dind docker run --privileged --rm tonistiigi/binfmt --install arm64
docker exec infinity-spark-dind docker buildx create \
--name infinity-spark-builder --driver docker-container --use --bootstrap
docker exec infinity-spark-dind docker pull --platform linux/arm64 nvcr.io/nvidia/pytorch:25.11-py3進行状況
- DinD の作成と ARM64 エミュレーション確認: 成功。
defaultビルダー (docker driver / BuildKit v0.33.0) もlinux/arm64に対応していた。 以降は取得済みイメージを共有できる--builder defaultを使用する。- Poetry エクスポートと
infinity_emb-0.0.77-py3-none-any.whl作成: 成功。 - CPU 用の既存テスト4件、Spark 依存関係変換2件、環境分離2件: WSL2 上で合計8件成功。
- ARM64 依存インストール: 成功 (309.9 秒)。
- Infinity 本体
0.0.77のインストール: 成功。 - 環境分離後の
python -m pip check:No broken requirements found.(終了コード0)。 - ARM64 スモークテスト: 成功 (初回の読み込みを含め 824.1 秒)。 torch の CPU 演算、torchvision の NMS、小規模 BERT forward、Infinity サーバー構築を確認。
infinity_emb v2 --help: 成功 (終了コード0)。- ARM64 production イメージ: ビルド・DinD 内への保存に成功 (終了コード0)。
追加した構成
libs/infinity_emb/Dockerfile.spark: Spark 専用。既存の Jinja 生成対象とは別に直接編集する。libs/infinity_emb/docker_spark_prepare.py: GPU 関連パッケージを NVIDIA ベースのバージョンで制約し、その他は既存 Poetry ロックを使用する。libs/infinity_emb/docker_spark_isolate.py: インストール後、アプリ依存と NVIDIA の torch/torchvision/Triton のみを仮想環境から参照できるようにする。libs/infinity_emb/tests/docker/smoke_spark.py: GPU 不要の import、CPU テンソル演算、小規模 BERT forward、サーバー構築確認。libs/infinity_emb/tests/docker/test_spark_prepare.py: NVIDIA パッケージの保持と不適切なベースイメージの拒否を検証。
依存エクスポート、ARM64 wheel のダウンロード、純 Python wheel 作成は
BUILDPLATFORM (amd64) で実行し、production
の依存インストールと 動作確認は ARM64/QEMU で実行する。 ダウンロードは
Python 3.12 / CPython / ARM64 の manylinux タグを明示する。
GPUtil のみソース配布なので、ネイティブ側で
py3-none-any wheel を作る。 wheelhouse
はビルド時だけマウントし、最終イメージには含めない。 Python 仮想環境
/opt/infinity はインストール時のみ NVIDIA ベースの system
site-packages を参照する。
venv --without-pip --system-site-packages と
python -m pip を組み合わせ、 ベース付属の pip 25.3
を利用する。通常の venv は QEMU 上の ensurepip に
3分以上かかったため、初回ビルドを中断してこの方式に変更した。
変更後の仮想環境作成は 3.4 秒で完了した。初回ログは
spark-build-initial.log。 次の試行では QEMU 内のオンライン
pip 解決・インストールに時間がかかり、 1,328
秒時点でもインストール途中だったため中断した
(spark-build-online-install.log)。 ARM64 wheel
をネイティブ側で事前取得する処理は 23.2 秒で成功した。 ARM64 側では
--no-index --find-links /wheelhouse --no-compile
を使用する。 バイトコードの事前生成を省くだけで、ARM64
のネイティブ拡張インストールと実行確認は省略しない。
インストール後、必要なベース由来の Python パッケージと dist-info
を仮想環境へ
シンボリックリンクし、include-system-site-packages = false
にする。 これにより NVIDIA の CUDA バイナリを再利用しつつ、NGC
の学習・開発用ツールが
アプリの依存解決に混ざることを防ぐ。ベースの実ファイルは削除・変更しない。
追加の x86_64 用 Flash Attention wheel はインストールしない。
既定エンジンは torch、BetterTransformer は無効とする。
ビルドコマンド (WSL2)
set -o pipefail
docker exec infinity-spark-dind docker buildx build \
--builder default --platform linux/arm64 --target production \
--progress plain -f libs/infinity_emb/Dockerfile.spark \
-t infinity:spark-arm64 --load libs/infinity_emb \
2>&1 | tee /mnt/f/project/infinity/spark-build.logログは spark-build.log と
spark-requirements-build.log に保存する (*.log
は Git 管理対象外)。 イメージは DinD 内
にロードされる。ホストの docker images には現れない。
取得した NVIDIA ベースのマニフェスト:
- マルチアーキテクチャ:
sha256:417cbf33f87b5378849df37983552cd1f8bc8b62fe1ceabe004de816a55dff21 - ARM64:
sha256:4a85d8cf6fb3a943280960b8948cf4e9b6eca77b4414c68c9b2c7bb863f79b70
厳密に同じベースを使用する場合は、ビルドに以下を追加する。
--build-arg SPARK_BASE_IMAGE=nvcr.io/nvidia/pytorch:25.11-py3@sha256:4a85d8cf6fb3a943280960b8948cf4e9b6eca77b4414c68c9b2c7bb863f79b70ビルド後の確認コマンド (WSL2)
docker exec infinity-spark-dind docker image inspect infinity:spark-arm64 \
--format '{{.Os}}/{{.Architecture}} {{.Id}}'
docker exec infinity-spark-dind docker run --rm --platform linux/arm64 \
--entrypoint python infinity:spark-arm64 /app/smoke_spark.py
docker exec infinity-spark-dind docker run --rm --platform linux/arm64 \
infinity:spark-arm64 v2 --helpDGX Spark への転送・GPU 確認の手順
WSL2 側でイメージをエクスポートし、gzip 圧縮した tar を Spark に転送する。 大きいイメージなので、出力先の空き容量を確保する。
set -o pipefail
docker exec infinity-spark-dind docker save infinity:spark-arm64 | gzip -1 > infinity.tar.gzSpark 上で実行する。
docker load -i infinity.tar.gz
docker run --rm --gpus all --entrypoint python infinity:spark-arm64 \
-c 'import torch; print(torch.__version__, torch.version.cuda); print(torch.cuda.get_device_name(0)); x = torch.ones(4, device="cuda"); print(x + 1)'
docker run --rm --gpus all -p 7997:7997 \
-v infinity-spark-models:/app/.cache/huggingface \
infinity:spark-arm64 v2 --model-id BAAI/bge-small-en-v1.5 --engine torch --device cuda --port 7997最後のコマンドはモデルをダウンロードして API を起動する。 GPU 演算・実モデル推論・性能・Flash Attention・TensorRT・CTranslate2 の GPU 実行は今回の確認範囲に含まれない。
ベースイメージの依存チェック
docker exec infinity-spark-dind docker run --rm --platform linux/arm64 \
--entrypoint python nvcr.io/nvidia/pytorch:25.11-py3 -m pip checkInfinity 追加前から以下の1件が存在した (終了コード1)。
nvidia-resiliency-ext 0.4.1+cuda13 requires pynvml, which is not installed.
ログ: spark-base-pip-check.log。
さらに pip inspect のメタデータ
(spark-base-inspect.log) とアプリのロックを比較し、
以下の衝突を確認した。これらの開発用パッケージをアプリ環境から分離する理由となった。
| ベース内のパッケージ | 要求 | アプリのロック |
|---|---|---|
| tyro | typing-extensions >= 4.13 | 4.12.2 |
| typeguard | typing-extensions >= 4.14 | 4.12.2 |
| torchtitan | datasets >= 2.21 | 2.14.4 |
| lightning-thunder | networkx >= 3.3 | 3.2.1 |
| lightning-thunder | dill >= 0.3.8 | 0.3.7 |
実インストール時には、NGC の httpcore 1.0.9 とアプリ側の
h11 0.14.0 の 衝突も検出された。httpcore
はアプリの実行依存ではないため、同じ分離処理で解消した。 一時的に system
site-packages を共有しているインストール途中のログにはこれらの
依存警告が出るが、最終環境では pip check
により不整合がないことを確認した。
GPU スタックを新しい PyPI torch で置き換えたり、アプリのロック全体を更新する処理は行わない。
ARM64 スモークテストの実測結果
architecture: aarch64
torch: 2.10.0a0+b558c986e8.nv25.11
torchvision: 0.25.0a0+7a13ad0f
cuda_build: 13.0
sentence_transformers: 3.3.1
onnxruntime: 1.19.2
gpu_execution_tested: False
torch.backends.cuda.is_built()
も真であることを確認した。 GPU を必要とする演算は実行していない。
初回スモークテストは QEMU
上で多数のモジュールを読み込むため約14分かかった。 途中で生成される
.pyc とロード済み ARM64
共有ライブラリを確認し、停止ではなく
初期化が進行していることを確認した。 既存コードの
torch.backends.*.allow_tf32 に PyTorch 2.10
の非推奨警告が出たが、 演算とスモークテストは成功した。TF32 設定 API
の更新は今回の変更に含めない。 スモークテストと別プロセスでの CLI
ヘルプ確認を合わせたステージは 1,145.3 秒だった。 この実測は amd64 上の
QEMU であり、DGX Spark ネイティブ実行の性能を表すものではない。
完成したイメージ
- タグ:
infinity:spark-arm64 - 保存先: WSL2 の
infinity-spark-dindコンテナ内の Docker - OS / Architecture:
linux/arm64(docker image inspectで確認) - Docker が報告したイメージ ID:
sha256:578dd3cebf7b75a06cf017428ec55ecfdc1534b66dc2d153e66c57819c3cde1c - ARM64 イメージマニフェスト:
sha256:94b2018bb094a357afe043e0ab415ba7f78b303ebb13d3c2232185af66ea0199 docker image inspectの Size:9725644356bytes- 作成時刻:
2026-09-14T08:42:26.723536977Z(日本時間 17:42) - ENTRYPOINT:
["infinity_emb"] - インストール一覧: イメージ内
/app/installed-packages.txt。 完成イメージから取り出した一覧をspark-installed-packages.logに保存した。pip freeze出力なので、NVIDIA パッケージにはビルド元のローカル wheel URL が含まれる。 再インストール用 requirements としてではなく構成記録として使用する。
ビルド中にスモークテストと CLI の成功を確認したため、完成後に同じ重いテストは 繰り返さず、イメージ属性と保存済みパッケージ一覧を確認した。
DinD コンテナと専用データボリュームは再利用できるよう残している。 WSL2 再起動などで停止した場合は、以下で再開できる。
docker start infinity-spark-dind
docker exec infinity-spark-dind docker image inspect infinity:spark-arm64Docker Hub / NGC などへのイメージ push は行っていない。Spark への転送結果は末尾に記載。
gzip 圧縮したイメージの保存 (2026-09-14 実施済み)
ユーザーの指定により infinity:spark-arm64 を
docker save で書き出した。 WSL2 の Bash
内で以下を実行し、Windows PowerShell
のバイナリパイプを経由せずに保存した。
set -o pipefail
set -o noclobber
docker exec infinity-spark-dind docker save infinity:spark-arm64 \
| gzip -1 > /mnt/f/project/infinity/infinity.tar.gz.partial
gzip -t /mnt/f/project/infinity/infinity.tar.gz.partial両コマンドの終了コードが 0
であることを確認後、一時ファイルを同じディレクトリの
infinity.tar.gz にリネームした。
- 保存先:
F:\project\infinity\infinity.tar.gz - ファイルサイズ:
9679762352bytes (約 9.68 GB / 9.02 GiB) - 検証:
gzip -tによる圧縮ファイル全体の整合性チェック成功 docker save単体の出力は.tar。今回は gzip 圧縮したため、指定の.tar.gzが正しい。- Spark での読み込み:
docker load -i infinity.tar.gz
DGX Spark への SCP 転送 (2026-09-14 実施済み)
ユーザーの指定により Windows OpenSSH の scp
で転送した。
scp -o BatchMode=yes -o ConnectTimeout=15 F:/project/infinity/infinity.tar.gz mikoto@gx10-707e.local:~/infinity.tar.gz
ssh -o BatchMode=yes -o ConnectTimeout=15 mikoto@gx10-707e.local 'stat -c "%s %n" ~/infinity.tar.gz'scp は終了コード 0。転送先
/home/mikoto/infinity.tar.gz のサイズが
9679762352 bytes
であり、転送元と一致することを確認した。
(筆者追記)DGX Spark での GPU 実行確認
Codex にイメージファイルの転送までしてもらったので、それ以降の動作確認は自分で行った。
DGX Spark 上で、gzip 圧縮したイメージをロードし、GPU を使用して Infinity サーバーを起動した。
docker load -i ./infinity.tar.gz
docker run -it --rm \
--gpus all \
-p 8081:8081 \
-v models:/app/.cache
infinity:spark-arm64 v2 \
--model-id BAAI/bge-m3 \
--model-id BAAI/bge-reranker-v2-m3 \
--engine torch \
--device cuda \
--port 8081curl でモデル一覧取得 API を呼び出し、サーバーが正しく起動していることを確認した。
curl http://localhost:8081/models以上。
0 件のコメント:
コメントを投稿