新建一個pipeline job
選擇Pipeline任務,然后進入配置頁面。
對於Pipeline, Definition選擇 "Pipeline script from SCM".
需要注意的是Script Path, 這里要指定項目中Jenkinsfile文件的具體位置。默認是根目錄。我這里是maven的一個子模塊,所以嵌套一層。
項目中添加Jenkinsfile
關於Jenkinsfile可以查閱w3c翻譯整理的文檔: https://www.w3cschool.cn/jenkins/jenkins-qc8a28op.html
以下是我自己的Jenkinsfile,這里用作注釋和備忘
node('slave001') {
stage('Prepare') {
echo "1.Prepare Stage"
checkout scm
pom = readMavenPom file: 'location/pom.xml'
docker_host = "docker.ryan-miao.com"
img_name = "${pom.groupId}-${pom.artifactId}"
docker_img_name = "${docker_host}/${img_name}"
echo "group: ${pom.groupId}, artifactId: ${pom.artifactId}, version: ${pom.version}"
echo "docker-img-name: ${docker_img_name}"
script {
build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
if (env.BRANCH_NAME != 'master' && env.BRANCH_NAME != null) {
build_tag = "${env.BRANCH_NAME}-${build_tag}"
}
}
}
stage('Test') {
echo "2.Test Stage"
sh "mvn test"
}
stage('Build') {
echo "3.Build Docker Image Stage"
sh "mvn package -Dmaven.test.skip=true"
sh "docker build -t ${docker_img_name}:${build_tag} " +
" --build-arg SPRING_PROFILE=prod " +
" --build-arg JAR_FILE=target/${pom.artifactId}-${pom.version}.jar " +
" ./location/"
}
stage('Push') {
echo "4.Deploy jar and Push Docker Image Stage"
sh "mvn deploy -Dmaven.test.skip=true"
sh "docker tag ${docker_img_name}:${build_tag} ${docker_img_name}:latest"
sh "docker tag ${docker_img_name}:${build_tag} ${docker_img_name}:${pom.version}"
withCredentials([usernamePassword(credentialsId: 'docker-register', passwordVariable: 'dockerPassword', usernameVariable: 'dockerUser')]) {
sh "docker login -u ${dockerUser} -p ${dockerPassword} docker.ryan-miao.com"
sh "docker push ${docker_img_name}:latest"
sh "docker push ${docker_img_name}:${pom.version}"
sh "docker push ${docker_img_name}:${build_tag}"
}
}
//stash 'complete-build'
}
if (env.BRANCH_NAME == 'master' || env.BRANCH_NAME == null) {
timeout(time: 10, unit: 'MINUTES') {
input '確認要部署線上環境嗎?'
}
}
node('slave001'){
stage('Deploy') {
//unstash 'complete-build'
echo "5. Deploy Stage"
sh "sed -i 's/<IMG_NAME>/${img_name}:${build_tag}/' location/k8s.yaml"
sh "sed -i 's/<BRANCH_NAME>/${env.BRANCH_NAME}/' location/k8s.yaml"
sh "/data/opt/kubernetes/client/bin/kubectl apply -f ${WORKSPACE}/location/k8s.yaml --record"
}
}
node('slave001') {
最外層必須是node節點,這里單獨制定運行的jenkins節點,通常不用指定,由jenkins master分配任務即可。這種寫法屬於Scripted Pipeline。stage('Prepare') {}
stage是一個階段的語法,括號里階段名稱。腳本從node開始,按順序向下執行。遇到的第一個stage就是第一個階段。- 使用
echo xxxx
來輸出文字,給出進度信息。 checkout scm
是Jenkins固定獲取代碼的方法,會輸出Check out from version control。pom = readMavenPom file: 'location/pom.xml'
是讀取workspace下相對目錄的pom文件。這個需要Jenkins 安裝Pipeline Utility Steps插件。通過${pom.groupId}-${pom.artifactId}
來獲取pom信息. 我的pom在子module location里。docker_host = "docker.ryan-miao.com"
聲明一個全局的變量,如果只想在方法體{}
中使用,可以加def
。${docker_host}
變量可以通過這樣類似shell的方式獲取。build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
用來獲取git的commit id- Build階段執行docker命令打包,把我們的變量傳遞到Dockerfile. 我的Dockerfile同樣在子module location下。
withCredentials
可以調用存儲在Jenkins里的憑證。這個需要安裝Credentials Binding Plugin.input
會產生一個交互式的按鈕,需要手動點擊通過才會繼續,否則暫停。這個只是暫停下一步,線程還在運行。所以,需要單獨提出node之外,再添加一個超時設置。參見“input” step blocks executorstash
暫存文件,參見官方文檔. 主要用來把這次build過程中的某個文件給暫存,只在本次build有效。本次不需要。timeout
主要用來設置超時,參見官方文檔, 時間單位有:NANOSECONDS, MICROSECONDS, MILLISECONDS, SECONDS, MINUTES, HOURS, DAYS
。這里等待用戶確認是否繼續,若超過10分鍾還沒有確認,則停止。
看起來,似乎完美的從代碼編譯,打包,構建docker鏡像,推送到倉庫,設置觸發了部署。但離真正生產方案還有距離。因為你不可能編譯結束就直接上生產。真實的流程應該是: checkout->build->test-> 部署到測試環境 -> 對測試環境的自動化測試 -> 部署到生產環境。
如何做到build once, deploy many
我這里的pipeline步驟里沒有多環境串聯部署。這里部署到測試環境了,如果測試通過之后,想要部署生產環境應該怎么下一步呢?想要手動點一下某個按鈕,就可以將部署在測試環境的這個版本的鏡像部署到prod。input顯然不滿足需求。
第一,記錄當前測試環境的鏡像id;第二,提供一個生產prod job,可以手動輸入鏡像id進行部署.