① シナリオ界定:pip・uv・conda はいつ uv を選ぶか
判断は「解像度の単位」と「キャッシュ再利用」です。単一リポで pyproject.toml または requirements 系列を CI の正にできるなら uv が最も扱いやすいです。
| ツール | 向くケース | 跨境一括取得 | 注意 |
|---|---|---|---|
pip | レガシースクリプトのみ | 逐次が多く遅くなりがち | 並列・ロックは手動 |
| uv | プロジェクト+CI 再現性 | 並列 DL・ロック統合 | インデックス方針の文書化が必須 |
conda/mamba | 科学計算スタック全体 | チャネル設計が重い | PyPI との二重管理 |
uv を優先する条件(チェックリスト):(1)uv.lock または requirements.lock をリポジトリにコミットできる。(2)Runner が Apple Silicon/x86_64 のどちらかに固定できる。(3)社内 PyPI ミラーまたはプロキシ方針がチームで共有されている。
② 実行パラメータマトリクス(並列・タイムアウト・再試行・キャッシュ・ミラー)
デフォルト(読取 30s・再接続 10s・再試行 3)は跨境ジョブでは短めです。帯域とジョブ wall-clock を見ながら まず HTTP を伸ばし、次に並列数を上げます。
| 目的 | 環境変数/フラグ | 開始値の目安 | 備考 |
|---|---|---|---|
| 同時ダウンロード | UV_CONCURRENT_DOWNLOADS | 8〜16 | 共有 Runner ではディスク I/O と競合 |
| 展開・インストール並列 | UV_CONCURRENT_INSTALLS | 2〜4 | CPU バウンドになりやすい |
| sdist 同時ビルド | UV_CONCURRENT_BUILDS | 1〜2 | 跨境+ビルドはタイムアウトしやすい |
| HTTP 読取タイムアウト | UV_HTTP_TIMEOUT | 120〜300 | HTTP_TIMEOUT も同等 |
| 接続タイムアウト | UV_HTTP_CONNECT_TIMEOUT | 30〜60 | 高 RTT 回線で有効 |
| HTTP 再試行回数 | UV_HTTP_RETRIES | 5〜10 | 指数バックオフは uv 側 |
| キャッシュ場所 | UV_CACHE_DIR | 例: ~/Library/Caches/uv-ci | ジョブ ID をパスに含めると汚染しにくい |
| 主インデックス | UV_DEFAULT_INDEX | 公式 or ミラー URL | 古い UV_INDEX_URL も可 |
| 追加インデックス | UV_INDEX | スペース区切り | 名前付きは pyproject 推奨 |
export UV_CACHE_DIR="$HOME/Library/Caches/uv-ci/$CI_PIPELINE_ID"
export UV_DEFAULT_INDEX="https://pypi.org/simple"
export UV_HTTP_TIMEOUT=180
export UV_HTTP_CONNECT_TIMEOUT=45
export UV_HTTP_RETRIES=8
export UV_CONCURRENT_DOWNLOADS=12
export UV_CONCURRENT_INSTALLS=4
export UV_CONCURRENT_BUILDS=2
uv --version
export UV_DEFAULT_INDEX="https://mirrors.aliyun.com/pypi/simple/"
# 検証後、公式へ戻す
export UV_DEFAULT_INDEX="https://pypi.org/simple"
③ 跨境ネットワークの失敗モードと排障(TLS・証明書・プロキシ)
TLS 検査プロキシ: ブラウザは通るが uv だけ失敗 → UV_NATIVE_TLS=1 または UV_SYSTEM_CERTS=1(macOS キーチェーン)を試し、ダメなら SSL_CERT_FILE=/path/to/ca.pem。
プロキシ: HTTPS_PROXY/HTTP_PROXY と NO_PROXY(社内インデックス・localhost)を揃える。ALL_PROXY を使う場合は二重設定に注意。
ミラー遅延/不整合: 429 や欠損ファイルは公式 UV_DEFAULT_INDEX=https://pypi.org/simple に一時切替えて再現性を確認。
export HTTPS_PROXY="http://proxy.example.com:8080" export NO_PROXY="localhost,127.0.0.1,pypi.internal.example" export UV_NATIVE_TLS=1
④ requirements.lock/pyproject との整合と CI 再現ステップ
ロックは「更新 PR」と「インストールジョブ」を分離します。CI 本番は 常に frozen、バンプは開発者マシンまたはボットで uv lock だけが書き換わるようにします。
- 1. Python 版固定:
uv python pin 3.12または.python-versionをコミット。 - 2. ロック鮮度:
pyproject.toml変更はuv lock専用 PR に限定し、CI 本番はuv sync --lockedのみ(齟齬があれば失敗)。 - 3. 同期:
uv sync --locked --no-dev(本番相当)。 - 4. requirements 派生:
uv pip compile pyproject.toml -o requirements.lock→uv pip sync requirements.lock。 - 5. ログに
uv --versionとUV_DEFAULT_INDEXのホスト名のみ(認証情報は出さない)を出す。
env 例env:
UV_HTTP_TIMEOUT: "180"
UV_HTTP_RETRIES: "8"
UV_CONCURRENT_DOWNLOADS: "12"
UV_CACHE_DIR: /tmp/uv-cache-${{ github.run_id }}
⑤ FAQ(キャッシュ汚染・プラットフォーム wheel・私有インデックス併用)
キャッシュ汚染: 共有 Runner では UV_CACHE_DIR をパイプライン ID で分離。異常時のみ UV_NO_CACHE=1 で切り分け。
プラットフォーム wheel: ロック生成環境と CI の OS/アーキテクチャ/Python を一致させる。Apple Silicon リモート Mac なら arm64 前提でドキュメント化。
私有インデックス混在: UV_DEFAULT_INDEX を社内ミラーにし、公開パッケージは UV_INDEX で PyPI を追加するか、tool.uv.index で名前と URL を宣言。UV_INDEX_STRATEGY は first-index など監査に合う値に固定し、unsafe-best-match は必要最小限に。
構造化データの FAQPage と同内容を短く要約しています(検索snippet 用)。
まとめ:跨境 Python CI は「インデックス契約+ロック一本化」が最短
並列数を上げる前に UV_HTTP_TIMEOUT/UV_HTTP_RETRIES を伸ばし、UV_CACHE_DIR でキャッシュ境界を決めると、リモート Mac でも再現性とスループットの両立がしやすくなります。同系列の Rust・Cargo マトリクスや Git/Homebrew/npm プル安定性 FAQと併せて運用ルールを揃えると、パイプライン全体が安定します。
英語の関連読み物(ログイン不要):Git/Docker プル加速ガイド(英語)、Git・npm・CI キャッシュ戦略(英語)。ブログ一覧・MacPull ホームからも辿れます。料金・ヘルプはログイン不要で料金ページ・ヘルプセンターをご確認のうえ、チームの帯域と並列度に合うプランで購入ページからお試しください。
跨境でも uv sync --locked を安定させるなら、ノード位置とキャッシュ設計が鍵です
MacPull のリモート Mac(Apple Silicon)でビルド環境を揃え、低遅延回線側で wheels をまとめて取得しやすくできます。プラン比較とドキュメントはページ上でご覧いただけます。