場景與瓶頸
先選邊:同時打 rubygems.org 與 GitHub/GitLab :git 源,瓶頸多在連線/TLS與Git 連線池。lock 漂移(未提交 lock、CI 未 --frozen)會讓線上樹與預期脫鉤。共享 Runner 上 BUNDLE_JOBS 過高易觸發四二九/連線重設。請在 Runbook 寫死「目標還原時間」再回推併發。
並行與連線池參數
BUNDLE_JOBS 為同時 worker 數;頻寬或 NAT 緊時建議四至六。BUNDLE_RETRY 建議三至五,並可寫入 bundle install --retry=。共享池同機多 Pipeline 時請下調或串列。
# CI/遠端 shell(數值依 CPU、頻寬、同機 job 數微調)
export BUNDLE_JOBS=4
export BUNDLE_RETRY=5
export BUNDLE_FROZEN=true
# 弱網 Git 拉取可選(單位:位元組/秒、秒)
export GIT_HTTP_LOW_SPEED_LIMIT=1000
export GIT_HTTP_LOW_SPEED_TIME=600
bundle install --path vendor/bundle --jobs="${BUNDLE_JOBS}" --retry="${BUNDLE_RETRY}" --frozen
跨境鏡像與 Git 源策略
下表為可執行決策矩陣(網域請換核准端點);Git 源請確認 git@ 或 https+Token 政策。
| 鏡像/源類型 | BUNDLE_JOBS/BUNDLE_RETRY 建議 | vendor/cache 與 CI 快取鍵思路 | 失敗重試閾值(流程級) |
|---|---|---|---|
| 直連 rubygems.org | _jobs 四、_retry 四;共享 Runner 再降 | 快取路徑含 vendor/bundle;鍵:lock 雜湊+RUBY_VERSION | 最多三次,退避二/四/八秒,總等待約六十秒內 |
| 區域/企業 RubyGems 鏡像 | _jobs 可至六;仍觀察四二九 | 同上;另快取 vendor/cache(見 bundle package) | 同上;第二次失敗改查鏡像健康狀態 |
| GitHub/GitLab :git gem | _jobs二至四(Git 連線成本高) | 鍵須含 lock 與私有源指紋(避免跨 repo 汙染) | Git 逾時單次可拉長;流程重試不超過三次 |
| 離線/準離線(vendor/cache) | _jobs 一即可;以磁碟 IO 為主 | 鍵:Gemfile.lock 雜湊+package 目錄存在與否 | 缺包直接失敗不重試,改觸發補包流水線 |
# 將官方索引與下載改走鏡像(URL 請替換)
bundle config set mirror.https://rubygems.org https://gems.example-mirror.local/
# GitHub HTTPS 私有 gem:雙底線主機名變數(Token 放 CI 密文)
export BUNDLE_GITHUB__COM="x-access-token:${GITHUB_TOKEN}"
# GitLab.com 私有 gem 類推(依實際主機名調整雙底線段)
# export BUNDLE_GITLAB__COM="oauth2:${GITLAB_TOKEN}"
# 產生 vendor/cache 供準離線或加速還原
bundle package --all
lockfile 漂移與快取鍵
CI 請用 --frozen 或 --deployment(依版本擇一)避免改 lock。快取鍵須含 lock 雜湊與 Ruby 次版本,以免原生擴充殘留。
- 主線分支已提交 lock;與目標 Ruby、Bundler 版本區間文件一致。
- CI 使用
--frozen/--deployment;失敗日誌可定位到哪一顆 gem。 - 快取鍵=
sha256sum Gemfile.lock片段+RUBY_VERSION;vendor/bundle路徑固定。 - 若用
bundle package,發版分支上vendor/cache與 lock同步更新。
# 例:以專案相對路徑安裝,便於快取整個 vendor/bundle
export BUNDLE_PATH="$CI_PROJECT_DIR/vendor/bundle"
bundle config set path "$BUNDLE_PATH"
# GitLab CI 快取鍵片段(YAML 思路,請合併至你的設定)
# key: "${CI_COMMIT_REF_SLUG}-ruby-${RUBY_VERSION}-${HASH_OF_GEMFILE_LOCK}"
# paths: [ vendor/bundle/, vendor/cache/ ]
FAQ
bundle install 頻繁逾時或 reset by peer?
降 BUNDLE_JOBS、升 BUNDLE_RETRY;加鏡像或拉長 Git 逾時;流程三次後改備援或 vendor/cache。
GitHub 私有 repo 的 gem 拉不下來?
確認 BUNDLE_GITHUB__COM 或 git config url.insteadOf 使用有效 Token;企業代理需放行 github.com 與 codeload.github.com。
為何 CI 與本機解析結果不同?
對齊 Ruby 次版本與 Bundler 版本;清掉混用鏡像的快取目錄;確保同一個 Gemfile.lock 入庫且 CI 下 --frozen。