シナリオとボトルネック
リモート Mac プールでは xcodebuild・派生データ・OCI blob キャッシュが同一 NVMeに積み上がりやすく、越境ではマニフェスト往復とレイヤ並列が RTT に敏感です。429は帯域より同時クライアント本数に寄りがちで、digest 固定とチェックサムがゲートの主戦場になります。
本稿はGit shallow/Webhook/単一パッケージマネージャ一覧と重ねず、Registry 上の汎用成果物レイヤの取得・キャッシュ・検証に限定します。コンテナ実行中心なら GHCR/Registry の越境 pull 決定表を併読ください。
- レイヤ並列過多:
--concurrencyとジョブ内の同時アーティファクト本数を先に下げる。 - キャッシュとビルドのディスク競合:
ORAS_CACHEをDerivedData/ビルド出力と別ボリュームへ。 - 検証漏れ:descriptor digest に加え、展開後ファイルの SHA-256 をリポジトリに固定する。
ORAS と従来の成果物配布(対照・選定)
ORAS は OCI Distribution 上の非イメージ成果物を、docker と同型の認証・レイヤ転送で扱う CLI です。
| 方式 | 強み | 弱み/コスト | 向くケース |
|---|---|---|---|
| OCI + ORAS | digest 固定・レイヤ再利用・Registry 運用と同居 | CLI/マニフェストの学習 | SDK tarball・検証束・重みの版固定 |
| 汎用 Artifact リポ | 審査経路・ACL 実績 | OCI 外 API が増える | レガシー審査のみ |
| S3+プリサイン | 実装が単純 | dedup 弱く再転送増 | 単発巨大オブジェクト |
選定の早引き:Helm OCI やコンテナを同一 Registry に載せているならORAS 一本化が運用コスト最小です。
リモート Mac 上のキャッシュディレクトリとディスク水位
ORAS_CACHE はレイヤ一時領域として膨らみ、ビルド出力と同一ディスクだと Xcode リンクと書き込み競合で await が悪化しやすいです。
| 階層 | 推奨パス例(macOS) | 役割 | 備考 |
|---|---|---|---|
ORAS_CACHE | $HOME/Library/Caches/oras-ci/$CI_JOB_ID | レイヤ再利用・再開 | ジョブ毎サブディレクトリで汚染隔離 |
| pull 出力 | $CI_WORKSPACE/.ci/oras-out | 展開後の検証対象 | ビルドステップからは読み取り専用扱い推奨 |
| 大容量共有キャッシュ | 別 APFS ボリューム/外付け(運用許可時) | プール横断ヒット | 並列 pull とディスク FAQの閾値と併用 |
ディスク水位:使用率 80/85/90% で警告・キュー・延期+クリーン。空き25→12→6 GB の三段も併用すると運用しやすいです。
越境帯域とリトライパラメータ(コピペ)
以下は初期値。P95 と 429 で ±1 段階。
並列・環境変数(シェル断片)
# 越境向け初期値(同一リージョンなら ORAS_CONCURRENCY=4〜6 まで試験的に上げる)
export ORAS_CACHE="${ORAS_CACHE:-$HOME/Library/Caches/oras-ci/$CI_JOB_ID}"
export ORAS_CONCURRENCY="${ORAS_CONCURRENCY:-3}" # oras pull の --concurrency に渡す前提
mkdir -p "$ORAS_CACHE" "${ORAS_OUT:-./.ci/oras-out}"
# 認証(Registry はプレースホルダ)
printf '%s' "${REGISTRY_TOKEN_PLACEHOLDER}" | oras login "${REGISTRY_HOST_PLACEHOLDER}" -u "${REGISTRY_USER_PLACEHOLDER}" --password-stdin
# 取得(失敗時 4→12→30→90 秒 + 並列一段下げ)
for i in 1 2 3 4 5; do
oras pull "${ORAS_REF_PLACEHOLDER}" -o "${ORAS_OUT:-./.ci/oras-out}" --concurrency "${ORAS_CONCURRENCY}" && break
case "$i" in
1) sleep "${B1:-4}";;
2) sleep "${B2:-12}"; ORAS_CONCURRENCY=$(( ORAS_CONCURRENCY > 1 ? ORAS_CONCURRENCY - 1 : 1 ));;
3) sleep "${B3:-30}";;
4) sleep "${B4:-90}";;
*) echo "oras pull 打ち切り"; exit 1;;
esac
done
| レバー | キー/フラグ | 越境の推奨初期値 | 上げる/下げる条件 |
|---|---|---|---|
| レイヤ並列 | oras pull … --concurrency | 2〜3 | 429 なし・await 良好なら +1。429 多発なら 1 まで段階的に |
| ジョブ内の同時アーティファクト | ワークフロー直列化/セマフォ | 1〜2 本 | IO 飽和なら 1 本固定 |
| HTTP 429/5xx 退避(秒) | B1…B4 または sleep 直書き | 4 → 12 → 30 → 90(最大 120 でクリップ可) | 2 回目以降は ORAS_CONCURRENCY を必ず −1 |
CI ゲート受入(descriptor・チェックサムチェックリスト)
マニフェスト digest とファイルハッシュの二層で締めます。
検証コマンド断片(コピペ)
# descriptor の digest(jq 例。jq なしなら次行の go-template へ)
test "$(oras manifest fetch "${ORAS_REF_PLACEHOLDER}" --descriptor | jq -r '.digest')" \
= "${EXPECTED_DESCRIPTOR_DIGEST_PLACEHOLDER}"
# test "$(oras manifest fetch "${ORAS_REF_PLACEHOLDER}" --format go-template --template '{{ .digest }}')" = "${EXPECTED_DESCRIPTOR_DIGEST_PLACEHOLDER}"
# 展開後ファイル — expected.sha256 は「ハッシュ 相対パス」形式(shasum -a 256 出力をそのまま貼る)
shasum -a 256 -c expected.sha256
| ゲート項目 | 合格基準 | 失敗時の典型原因 |
|---|---|---|
| digest | 期待値と完全一致 | 可変タグ・ミラー遅延 |
| artifactType | 許可リスト内 | 誤リポジトリ混入 |
| SHA-256 | shasum -a 256 -c 成功 | 再圧縮・改行差 |
| リトライログ | 429 時の秒数と並列変化 | 無限リトライ |
FAQ
Q. oras pull と docker pull はどう分担する?
A. 実行イメージは docker/containerd 系。バイナリ束・検証データを digest で固定配布するなら ORAS。同一ホストでもキャッシュディレクトリは分離してください。
Q. descriptor は合うが shasum が落ちる
A. gzip レベル差や CRLF 変換を疑い、期待ハッシュを同一条件で再生成して固定し直す。
Q. 429 が続く
A. --concurrency を一段下げ、並列アーティファクトを 1〜2、退避 4→12→30→90。効かなければレプリカまたはジョブ分散。
まとめと次の一手(購入・資料)
越境では並列・キャッシュ階層・退避秒・チェックサム二層を同時に決めるのが安定の近道です。OCI 化した成果物は Registry 運用と一本化できる一方、Mac ローカル NVMeの水位を軽視すると逆に遅くなります。