DaoCloud CI/CD 實戰
DaoCloud CI/CD 實戰:建立 Jenkinsfile
這篇文件整理 Jenkins Pipeline,目標是讓你可以在 DaoCloud 的 Jenkins 環境中,從空白檔案建立可用的
Jenkinsfile,完成「建置映像、健康檢查、推送鏡像、人工審核、GitOps 部署、通知信」全流程。
一、在 DaoCloud UI 建立 Pipeline(圖形化方式)
快速驗證流程,可先在 DaoCloud UI 以圖形化方式建立 Pipeline,再回到 Jenkinsfile 做細節微調。
1. 選擇「自定義 Pipeline」。
2. 輸入 Pipeline 名稱,設定構建參數與 Trigger(或稍後再設定)。
3. 先用 UI 編輯流水線骨架,亦可直接貼上 Jenkinsfile。
UI 編輯流水線時,常用節點說明
Add Parallel Stage:
- 將多個 Stage 並行執行
Add Stage:
- 將多個 Stage 串行執行
- 會等待前一步所有並行 Stage 完成後,再進入下一個 Stage
Add Step:
- 加入單一執行步驟,常見類型如下
1) Shell Script: 設定環境變數、執行業務邏輯
2) Git Clone: 克隆 Git Repo
3) Review: 在 DaoCloud 上進行人工審核
4) Notify: 寄送通知信
建議用法
先用 UI 畫出大致流程,確認 Stage 順序與審核節點,再回到 Jenkinsfile 進行版本化與細節微調。這樣可同時兼顧「快速建模」與「可維護性」。
也可以使用 script {} 包裝條件邏輯; 在steps 與 container('base') 內部:
steps {
container('base') {
script {
if(env.BRANCH_NAME == 'main') {
echo 'This is main branch, send email to get approval'
mail(
to: env.MAIN_APPROVAL_EMAIL,
subject: "[REVIEW REQUIRED] ${env.JOB_NAME} ${env.BUILD_DISPLAY_NAME ?: "#${env.BUILD_ID}"}",
body: approveEmailBody,
mimeType: 'text/html'
)
} else {
echo 'This is not main branch, do nothing'
}
}
}
}
二、示例 Jenkinsfile 骨架,先理解這份 Jenkinsfile 想做到甚麼效果。
-> Git Clone
-> Build Image (podman build)
-> Image Health Test (/health) or Other Unit Test
-> Push Image
-> Approve (僅 main/prod 分支需要人工審核)
-> Deploy (更新 GitOps deployment.yaml)
-> Post always (寄送結果通知 + 清理工作區)
三、前置條件(少一項都會卡)
1) Jenkins Agent 需可執行 podman / git / curl / awk
2) Jenkins 已安裝 Pipeline 與 Mail 相關能力
3) Jenkins 可連到:
- 應用程式原始碼 Repo (GIT_URL)
- GitOps Repo (GITOPS_URL)
- Container Registry (IMAGE_REGISTRY, docker.io 或私有倉庫)
4) 已建立 Credentials:
- DockerHub Token: REGISTRY_CREDENTIALS_ID
- GitOps Repo Token: GITOPS_TOKEN_CREDENTIALS_ID
四、在 DaoCloud Jenkins 建立 Pipeline Job
1. 建立一個 Pipeline 類型 Job(建議命名:pipeline-demo-prod)。
2. Pipeline Script 貼上 Jenkinsfile 內容。
3. 代理節點(Agent)使用 container('base'),可執行 Podman,進行--from-build 的方式來建置映像。
4. 審核人(input submitter)先在 DaoCloud 端建立可用帳號。
五、建立 Jenkinsfile 骨架
建立專案根目錄檔案 Jenkinsfile,先放入以下骨架:
pipeline {
agent {
node {
label 'base'
}
}
environment {
IMAGE_REGISTRY = 'docker.io'
IMAGE_TAG = ''
DOCKERFILE_PATH = 'Dockerfile'
DAOCLOUD_HOST = 'https://dc.pslab.dev'
// 其他環境變數可直接寫在 environment {},
// 也可在 DaoCloud UI 以構建參數方式設置(推薦敏感或多環境值用 UI 管理)
// GIT_URL = ''
// GIT_BRANCH = ''
// GITOPS_URL = ''
// IMAGE_REPOSITORY = ''
// REGISTRY_CREDENTIALS_ID = ''
// GITOPS_TOKEN_CREDENTIALS_ID = ''
// NOTIFICATION_EMAIL = ''
// APPROVE_EMAIL = ''
}
stages {
stage('Git Clone') {
steps {
container('base') {
sh "echo '----- Stage Git Clone End -----'"
}
}
}
stage('Build Image') {
steps {
container('base') {
sh "echo '----- Stage Build Image End -----'"
}
}
}
stage('Image Health Test (/health)') {
steps {
container('base') {
sh "echo '----- Stage Image Health Test End -----'"
}
}
}
stage('Push Image') {
steps {
container('base') {
sh "echo '----- Stage Push Image End -----'"
}
}
}
stage('Approve') {
steps {
container('base') {
script {
String pipelineReportUrl = env.JOB_NAME
? "https://dc.pslab.dev/amamba/ws/${env.JOB_NAME.tokenize('/')[0]}/pipeline/pipeline/detail/${env.JOB_BASE_NAME}/runs/${env.BUILD_ID}/running-report"
: ''
String approveEmailBody = """\
<html>
<body>
<p>請審核本次部署:</p>
<p>${pipelineReportUrl ? "<a href='${pipelineReportUrl}'>查看 Pipeline Report</a>" : '無可用連結'}</p>
</body>
</html>
""".stripIndent()
mail(
to: env.NOTIFICATION_EMAIL,
subject: "[REVIEW REQUIRED] ${env.JOB_NAME} ${env.BUILD_DISPLAY_NAME ?: "#${env.BUILD_ID}"}",
body: approveEmailBody,
mimeType: 'text/html'
)
}
input(
message: 'Please review and approve',
submitter: 'admin'
)
sh "echo '----- Stage Approve End -----'"
}
}
}
stage('Deploy') {
steps {
container('base') {
sh "echo '----- Stage Deploy End -----'"
}
}
}
}
post {
always {
echo '----- Post Always End -----'
}
}
}
接著把以下區塊補齊,才能達到實務可用:
A) Build Image:
- 以分支名稱 + commit short sha 生成 image tag
- 例:docker.io/mx/project:main-a1b2c3d4
B) Image Health Test:
- podman run 臨時容器
- 迴圈檢查 /health 回傳 {"status":"UP"}
- 失敗時輸出 podman logs 並中止
C) Push Image:
- 由 IMAGE_REPOSITORY 前段解析 registry username
- 用 Secret text token 登入 registry 推送
D) Approve:
- 目前僅 main/prod 分支要求人工審核
- 先寄審核信(含 Git 變更連結與 Pipeline report 連結)
- 再執行 input gate
E) Deploy:
- 依分支映射 deployment 路徑:
main -> main/deployment.yaml
dev -> dev/deployment.yaml
- 自動改寫 image 欄位、commit 後 push 至 GitOps repo
F) Post always:
- 寄送結果通知信(成功/失敗都寄)
- 清理 workspace,避免下次建置污染
六、環境變數建議值(對照本專案)
環境變數可用兩種方式配置:Jenkinsfile 內 environment {},或在 DaoCloud UI 的構建參數中設定。固定且不敏感的預設值可放在
environment {};需要依環境調整或避免寫死在程式碼中的值,建議使用 DaoCloud UI 構建參數管理。
environment {
IMAGE_REGISTRY = 'docker.io'
IMAGE_TAG = ''
DOCKERFILE_PATH = 'Dockerfile'
DAOCLOUD_HOST = 'https://dc.pslab.dev'
GIT_URL = 'https://github.com/---'
GITOPS_URL = 'https://github.com/---'
GITOPS_TOKEN_CREDENTIALS_ID = 'gitops-token'
GIT_BRANCH = 'main'
IMAGE_REPOSITORY = '---'
REGISTRY_CREDENTIALS_ID = 'dockerhub-token'
NOTIFICATION_EMAIL = 'xx@example.com'
APPROVE_EMAIL = 'xx@example.com'
}
七、常見錯誤與修正
1) main 分支未觸發審核
- 檢查分支字串是否為 main
- 注意 origin/main 與 refs/heads/main 需要正規化
2) Deploy 沒有更新到 image
- 目標 deployment.yaml 不存在
- 或檔案內沒有 image: 欄位
3) GitOps push 失敗
- Token 權限要有 Contents: read & write, Pull-Requests: read & write
4) /health 測試卡住
- 容器未成功啟動(先看 podman logs)
- 檢查應用是否真的 listen 在 8080
八、驗證流程(最小可行)
# 1) 推一個 commit 到 dev 分支
# 2) 觀察是否完成:Build -> Test -> Push -> Deploy
# 3) 確認 GitOps repo 的 dev/deployment.yaml image 已更新
# 4) 推一個 commit 到 main 分支
# 5) 確認是否收到審核信,且 input gate 需要人工批准
# 6) 批准後確認 main/deployment.yaml 被更新
九、Approve(人工審核)語法說明
// 只在需要人工審核的分支執行
input(
message: 'Please review and approve',
submitter: 'approval-user'
)
message:
- DaoCloud UI 顯示給審核者的提示訊息
submitter:
- 允許按下 Approve 的 DaoCloud 用戶清單(逗號分隔)
- 例如 approval-user
行為重點:
- Pipeline 會在此步驟暫停,直到授權使用者批准或中止
- 常見搭配做法:先寄審核通知信,再進入 input gate
進階示例:使用 script 發送 Approve mail 並加上審核閘門
script {
String rawBranch = env.GIT_BRANCH ?: env.BRANCH_NAME ?: ''
String normalizedBranch = rawBranch.replaceFirst(/^origin\//, '').replaceFirst(/^refs\/heads\//, '')
if (normalizedBranch != 'main') {
echo "Skip approve: branch '${normalizedBranch}' does not require approval."
return
}
String gitChangeUrl = (env.GIT_URL ?: '').replaceFirst(/\.git$/, '')
if (gitChangeUrl) {
try {
String currentSha = sh(
script: 'git -c safe.directory="$WORKSPACE" rev-parse HEAD',
returnStdout: true
).trim()
gitChangeUrl = "${gitChangeUrl}/commit/${currentSha}"
} catch (Exception e) {
echo "Unable to resolve git change URL in approve stage: ${e.message}"
}
}
String pipelineReportUrl = env.JOB_NAME
? "${env.DAOCLOUD_HOST}/amamba/ws/${env.JOB_NAME.tokenize('/')[0]}/pipeline/pipeline/detail/${env.JOB_BASE_NAME}/runs/${env.BUILD_ID}/running-report"
: ''
String approveEmailBody = """\
<html>
<body>
<p>請審核本次 main 部署:</p>
<ul>
<li><strong>Job:</strong> ${env.JOB_NAME}</li>
<li><strong>Build:</strong> ${env.BUILD_DISPLAY_NAME ?: "#${env.BUILD_ID}"}</li>
<li><strong>Build Status:</strong> ${currentBuild.currentResult ?: 'UNKNOWN'}</li>
<li><strong>Image:</strong> ${env.FULL_IMAGE ?: 'N/A'}</li>
<li><strong>Git 變更紀錄:</strong> ${gitChangeUrl ? "<a href='${gitChangeUrl}' target='_blank' rel='noopener noreferrer'>查看變更</a>" : 'N/A'}</li>
<br>
<br>
<li><strong>請登入 DaoCloud 以審核本次部署:</strong> ${pipelineReportUrl ? "<a href='${pipelineReportUrl}' target='_blank' rel='noopener noreferrer'>查看報告和審核</a>" : 'N/A'}</li>
</ul>
</body>
</html>
""".stripIndent()
mail(
to: env.APPROVE_EMAIL,
subject: "[REVIEW REQUIRED] ${env.JOB_NAME} ${env.BUILD_DISPLAY_NAME ?: "#${env.BUILD_ID}"}",
body: approveEmailBody,
mimeType: 'text/html'
)
input(message: 'Please review and approve', submitter: 'approval-user')
}
十、mail(寄送通知)語法說明
mail(
to: env.APPROVE_EMAIL,
subject: "[REVIEW REQUIRED] ${env.JOB_NAME} ${env.BUILD_DISPLAY_NAME ?: "#${env.BUILD_ID}"}",
body: approveEmailBody,
mimeType: 'text/html'
)
to:
- 收件者,可用單一地址或逗號分隔多個地址
subject:
- 郵件主旨,可帶入 Job 名稱與 Build 編號
body:
- 郵件內容字串,建議用 HTML 組出連結與欄位資訊
mimeType:
- 內容格式,text/html 代表以 HTML 顯示
行為重點:
- mail step 依賴 Jenkins 郵件相關設定
- 建議在關鍵節點(審核前、post always)寄送通知
十一、Jenkins 發送郵件配置(DaoCloud + Gmail 範例)
1) 在 DaoCloud 上找到 Jenkins Deployment
- 命名空間: amamba-system
- 工作負載: amamba-jenkins(Deployment)
2) 先完成 Gmail 端準備
- 需在 Google 帳號啟用兩步驟驗證
- 建立 App Password,Jenkins 不建議使用帳號登入密碼
3) 修改 amamba-jenkins Deployment 的環境變數(以 Gmail 為例)
- name: EMAIL_SMTP_HOST
value: smtp.gmail.com
- name: EMAIL_SMTP_PORT
value: '465'
- name: EMAIL_USE_SSL
value: 'true'
- name: EMAIL_FROM_NAME
value: <email發件者>
- name: EMAIL_FROM_ADDR
value: <發件郵件>
- name: EMAIL_FROM_PASS
value: <apppass>
4) 套用設定後注意事項
- 重啟後由 Jenkins 發信流程驗證是否可送達
- 若寄信失敗,優先檢查 SMTP 主機、埠號、SSL 與 App Password 是否正確
留言
張貼留言