Jenkins Pipeline 故障排查:Credentials 類型不匹配(SSH Key vs StringCredentials)融合演化版 v8¶
文檔資訊
- 分類: debugging
- 難度: intermediate
- 預估閱讀時間: 12 分鐘
- 標籤:
jenkins,credentials,pipeline,shared-library,ssh,secret-text,ci-cd,gitlab-token,private-token,oauth2
摘要¶
Jenkins BuildServer Pipeline 失敗的完整排查與修復流程。根因是 AutoBuildSiteDeploy 觸發子任務時載入了 common@feat/shallow-fetch 分支,該分支對 credential 類型的期望從 SSH Key 變成 StringCredentials。修復分兩層:(1) BuildServer 端改回 common@main 並換用 Secret Text credential;(2) AutoBuildSiteDeploy 的 checkout stage 需要同步改用 PRIVATE-TOKEN header 方式而非 oauth2 URL 嵌入(oauth2 方式導致約 109 秒連線延遲)。Build #570 實測驗證 oauth2 延遲問題,Build #571 確認 PRIVATE-TOKEN header 修法有效。
關鍵學習¶
-
Jenkins shared library 的分支版本是隱性風險:
common@feat/shallow-fetch對 credential 類型的期望與main分支不同,Pipeline 代碼本身完全沒有改變,卻因 library 引用分支切換導致 credential 類型不符錯誤 -
credentials() 參數若指定具體 credentialType(如 BasicSSHUserPrivateKey),實際類型不符時直接報錯;改用
credentialType: 'Any'可解除限制 -
Secret Text credential 用法:
withCredentials([string(...)])搭配http.extraHeader=PRIVATE-TOKEN: ${GIT_TOKEN},比 oauth2 URL 嵌入方式更安全且無連線延遲 -
oauth2:TOKEN@URL方式在此環境下實測導致約 109 秒連線等待後被中斷(Build #570 實測:04:03:26 → 04:05:15 abort) -
AutoBuildSiteDeploy 的 checkout stage 是獨立的 credential 設定,不會因 BuildServer 的 gitlabAccount 參數更換而自動更新,必須分開修改
-
Jenkins 原生 checkout() SCM 步驟直接以 SSH 方式 clone,不支援 Secret Text 類型的 credential,必須改成手動 git 指令
-
AutoBuildSiteDeploy 中 gitlabAccount 環境變數來自 Jenkins Job 的 Environment Variables 設定,不在 Jenkinsfile 的 parameters block 內
技術細節¶
錯誤訊息¶
ERROR: Credentials 'Make-Wish-Gitlab-Lupin' is of type 'SSH Username with private key'
where 'org.jenkinsci.plugins.plaincredentials.StringCredentials' was expected
根因分析¶
Build #566(成功) vs Build #567(失敗) 的關鍵差異:
- Build #566:AutoBuildSiteDeploy 載入
library 'common@main'(revision62530a8c) - Build #567:AutoBuildSiteDeploy 載入
library 'common@feat/shallow-fetch'(revision36d83889)
feat/shallow-fetch 分支在 git.shallowFetch() 函數內部改用了 withCredentials([string(...)]) 方式讀取 credential,期望 StringCredentials,但 Make-Wish-Gitlab-Lupin 實際是 SSH Key 類型。Pipeline 代碼本身沒有改變,只有 library 分支改變,導致難以從表面診斷。
Credential 類型對照¶
| Credential ID | 類型 | 適用場景 |
|---|---|---|
Make-Wish-Gitlab-Lupin |
SSH Username with private key | git clone via SSH |
cheng-csp-gitlab-token |
Secret Text (StringCredentials) | git clone via HTTPS with token |
Build #569 新問題:credential not found¶
Environment Variables 改為 cheng-csp-gitlab-token 後,Build #569 日誌顯示:
Warning: CredentialId "cheng-csp-gitlab-token" could not be found.
ERROR: Error cloning remote repo 'origin'
原因:AutoBuildSiteDeploy 的 Checkout stage 使用的是 Jenkins 原生 checkout() SCM 步驟,該步驟直接以 SSH 方式 clone,不支援 Secret Text 類型的 credential。
Build #570 oauth2 延遲問題(實測)¶
改用 oauth2:TOKEN@URL 方式後,實測 Build #570 出現約 **109 秒**連線等待:
[04:03:26] + git clone --branch main http://oauth2:****@[IP]:17080/pocketstore/genglobalsetting.git .
[04:03:26] Cloning into '.'
[04:05:15] Sending interrupt signal to process ← 被手動中斷
原本正常應在 **18 秒**內完成,oauth2 URL 嵌入方式在此環境下存在嚴重的連線延遲問題。
What Changed¶
第一層修復:BuildServer Jenkinsfile¶
// 修改前
credentials(
name: 'gitlabAccount',
defaultValue: 'Make-Wish-Gitlab-Lupin',
credentialType: 'com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey'
)
// 修改後
credentials(
name: 'gitlabAccount',
defaultValue: 'cheng-csp-gitlab-token',
credentialType: 'Any' // 不鎖定類型,相容 Secret Text
)
第二層修復:AutoBuildSiteDeploy¶
Jenkins Job 的 Environment Variables 中 gitlabAccount 改為 cheng-csp-gitlab-token。
Checkout stage 從 Jenkins 原生 SSH checkout 改為手動 git + PRIVATE-TOKEN header:
// 修改後(正確方式)
withCredentials([string(credentialsId: "${gitlabAccount}", variable: 'GIT_TOKEN')]) {
sh '''
git checkout -b main
git -c "http.extraHeader=PRIVATE-TOKEN: ${GIT_TOKEN}" fetch origin
git pull --rebase=false origin main --prune --verbose
'''
}
實測驗證過程¶
- Build #570 實測確認
oauth2:TOKEN@URL方式導致約 **109 秒**連線延遲(後被手動中斷) - Build #571 實測確認
PRIVATE-TOKENheader 方式成功,整體流程恢復正常 - 釐清 Build #569 失敗原因:Jenkins 原生
checkout()SCM 不支援 Secret Text credential,必須改用手動 git 指令
So What¶
Jenkins shared library 的分支版本管理是**高度隱性的風險**。Pipeline 代碼本身完全沒有改變,只是 library 引用的分支從 main 切換到 feat/shallow-fetch,就能導致看似無辜的失敗,且錯誤訊息指向的是 credential 類型,而非 library 版本。
此外,從 SSH Key 遷移到 Secret Text token 時,有兩個重要的連帶效應需要處理:
- Jenkins 原生
checkout()SCM 步驟**不相容** Secret Text credential,必須改成手動 git 指令 oauth2:TOKEN@URL方式**在此環境下有嚴重連線延遲問題**(實測 109 秒),必須改用PRIVATE-TOKENheader
Trade-offs¶
credentialType: 'Any'vs 鎖定具體類型:Any 靈活但失去類型安全保護,鎖定類型能在 pipeline 觸發時就報錯而非 runtime 才發現- SSH Key vs Secret Text Token:SSH 不需要嵌入 URL、安全性較高;Token 方式 HTTPS 連線更通用,但 Jenkins 原生 checkout() SCM 不支援 Secret Text
oauth2:TOKEN@URLvsPRIVATE-TOKENheader:前者語法簡單,但實測在此環境下導致約 109 秒連線延遲;後者語法稍複雜,但穩定且安全(token 不暴露在 URL 中)- library
@mainvs@feat/xxx:功能分支引入不穩定風險,生產環境建議只使用穩定 tag 或 main
Try It Fast¶
// BuildServer Jenkinsfile - credentials 參數修正
parameters {
credentials(
name: 'gitlabAccount',
defaultValue: 'cheng-csp-gitlab-token',
description: 'GitLab Token',
credentialType: 'Any' // 不鎖定類型,相容 Secret Text
)
}
// AutoBuildSiteDeploy - Checkout stage 正確用法(Secret Text)
// ✅ 推薦:PRIVATE-TOKEN header(不將 token 暴露在 URL,無連線延遲)
withCredentials([string(credentialsId: "${gitlabAccount}", variable: 'GIT_TOKEN')]) {
sh '''
git checkout -b main
git -c "http.extraHeader=PRIVATE-TOKEN: ${GIT_TOKEN}" fetch origin
git pull --rebase=false origin main --prune --verbose
'''
}
// ❌ 避免:oauth2 URL 嵌入(Build #570 實測導致約 109 秒連線延遲)
// withCredentials([string(credentialsId: gitlabAccount, variable: 'GIT_TOKEN')]) {
// sh 'git clone http://oauth2:${GIT_TOKEN}@host/repo.git .'
// }
// ❌ 避免:Jenkins 原生 checkout() SCM 不支援 Secret Text credential
// checkout([$class: 'GitSCM', userRemoteConfigs: [[credentialsId: gitlabAccount, url: gitURL]]])
Recommendation¶
- 已完成:BuildServer Jenkinsfile 的
credentialType改為'Any',defaultValue改為'cheng-csp-gitlab-token' - 已完成:AutoBuildSiteDeploy Jenkins Job 的 Environment Variables 中
gitlabAccount改為cheng-csp-gitlab-token - 已完成:AutoBuildSiteDeploy Checkout stage 改用
PRIVATE-TOKENheader 方式,已通過 Build #571 驗證 - 短期:確認
common@feat/shallow-fetch分支在合併至 main 前,不在任何生產 pipeline 中引用 - 長期:建立 shared library 版本管理策略,生產 pipeline 只使用 main 或穩定 tag,功能分支僅在測試環境使用
- 長期:在
feat/shallow-fetch合併後,確認所有使用git.shallowFetch()的 pipeline 都已統一使用 Secret Text credential