Tổng quan
Pipeline là kiểu job mới trên Jenkins 2.x, cho phép chúng ta sử dụng code để thực thi một complex CI build (Pipeline as Code). Nó được xây dựng dựa trên ngôn ngữ Groovy với một DSL (Domain-specific language) syntax riêng. Đọc thêm về Pipeline documentation để làm quen với nó. Bài viết này sẽ ghi chép lại một số chú ý quan trọng khi làm việc với Pipeline.
Một template chung cho việc bắt đầu viết một pipeline script có thể như sau:
node('pipeline') { // Run on slave with label 'pipeline'
timestamps { // show timestamps in console output
ansiColor('xterm') { // support for ANSI color in console output
try {
// Do main works in stages
stage('Stage 1') {
// Execute Pipeline steps here
sh 'printenv | sort'
if (something is wrong) {
// Signal an error and pipeline execution will be stopped here
error 'Something is wrong. Stopping pipeline execution...'
}
}
stage('Stage 2') {
}
} catch (ex) {
// Handle errors in this stage
stage('Error Handling') {
echo "ERROR: ${ex.message}"
currentBuild.result = 'FAILURE'
}
} finally {
// Execute post-build actions in this stage
stage('Post-build actions') {
cleanWs notFailBuild: true
}
}
}
}
}
Chú ý là chúng ta đang sử dụng Scripted Pipeline thay cho Declarative Pipeline vì nó linh hoạt và phù hợp hơn với complex workflow.
Trong template script trên, có vài điểm lưu ý sau:
- Các stage trong
tryblock sẽ là các main stage trong CI build. Nó sẽ thực hiện những công việc chính là chạy build và test. - Nếu có lỗi xảy ra trong
tryblock (từ một trong số các stage), thì nó sẽ được xử lí ởcatchblock, trong stageError Handling. Các lỗi có thể phát sinh do các build script, build step hoặc từerrorstep. - Cuối cùng, trong stage
Post-build actions(luôn luôn được chạy), chúng ta sẽ chạy các bước như cleanup, send mail, archive actifacts, v.v.
Các biến global
Trong suốt quá trình build, Jenkins cung cấp sẵn cho pipeline script một vài biến global. Những biến này có thể được xem tại JENKINS_URL/pipeline-syntax/globals (ví dụ localhost:8080/jenkins/pipeline-syntax/globals). Các biến sau đây là thông dụng:
currentBuild: Một object có kiểuRunWrapper, cho phép chúng ta truy vấn một số thông tin của build đang chạy, cũng như thay đổi một số thuộc tính của nó, chẳng hạn kết quả build.env: Cho phép truy vấn và lưu trữ các biến môi trường trong suốt quá trình build.params: Chứa các tham số của build đang chạy.
Pipeline steps
Một step là một việc cụ thể nào đó mà chúng ta muốn làm, ví dụ như đọc một file, gửi mail, lưu artifact, v.v. Có rất nhiều step được cung cấp trong Jenkins Pipeline, một số có sẵn, một số được cung cấp qua các plugin. Tuy nhiên một số step sau đây là thông dụng:
Basic steps
echo: In một message ra console output.echo "Some build information."
dir: Thay đổi thư mục hiện hành trong quá trình build. Mặc định trong quá trình build, mọi thứ sẽ được diễn ra trong thư mụcWORKSPACE. Ví dụ:dir("${WORKSPACE}/somedir") { // Any step inside this block will use ${WORKSPACE}/somedir as current directory }Nếu chúng ta không cung cấp full path, ví dụ
dir('somdir') {...}, thì mặc định nó sẽ hiểu đây là relative path với thư mục hiện hành.-
pwd: Cho biết thư mục hiện hành.dir("${WORKSPACE}/somedir") { echo "${pwd()}" } deleteDir: Xóa thư mục hiện hành, mà mặc định làWORKSPACE. Sử dụngdirstep nếu muốn xóa một thư mục khác.dir("${WORKSPACE}/somedir") { deleteDir() }readFile: Đọc một file và trả về nội dung của file như là một GroovyString.def content = readFile(file: "${WORKSPACE}/file.txt", encoding: 'UTF-8') echo "${content}"writeFile: Ghi một GroovyStringvào một file.writeFile(file: "${WORKSPACE}/file.txt", text: 'some content', encoding: 'UTF-8')
Tương tự như dir step, nếu chúng ta không cung cấp full path cho file, nó sẽ hiểu là relative path với thư mục hiện hành. Điều này được áp dụng tương tự như các step read và write dưới đây.
Utility steps
Để có thể sử dụng các step sau đây, chúng ta cần cài đặt plugin sau:
https://wiki.jenkins.io/display/JENKINS/Pipeline+Utility+Steps+Plugin
readProperties: Đọc một properties file hoặc mộtStringcó định dạng của một propeties file (key=value) và trả về một GroovyMapvới các key là GroovyString.def props = readProperties(file: "${WORKSPACE}/file.prop") props.each { k, v -> echo "${k}=${v}" }readJSON: Tương tựreadPropertiesstep nhưng với định dạng JSON.readYaml: Tương tựreadPropertiesstep nhưng với định dạng YAML và kiểu trả về có thể làList,String,Long,Boolean, v.v.readCSV: Tương tựreadPropertiesstep nhưng với định dạng CSV và trả về kiểu danh sách của các object có kiểuCSVRecord.writeJSON: Ghi một GroovyMapobject vào một JSON file.writeYaml: Ghi một GroovyObject(có thể làString,List,Long,Boolean, v.v) vào một YAML file.writeCSV: Ghi một danh sách cácCSVRecordvào một CSV file.
Các step khác
-
sh: Chạy một shell script.sh '''#!/bin/bash printenv | sort '''
shstep có hai option quan trọng đó làreturnStatusvàreturnStdout.int status = sh(returnStatus: true, script: '''#!/bin/bash exit 1''') if (status != 0) { error "A meaningful error message" }String output = sh(returnStdout: true, script: '''#!/bin/bash somescript 2> /dev/null''').trim() // do some stuff with output
build: Build một job khác.def b = build(job: 'Demo', parameter: [ string(name: 'PARAM', value: 'VALUE') ], propagate: false) if (b.currentResult == 'FAILURE') { error "'Demo' build failed." }Kết quả trả về của
buildstep là mộtRunWrapperobject (giống nhưcurrentBuild).-
checkout: Kéo source code về từ một version control system, ví dụ như Git. Step này có khá nhiều option và thông thường chúng ta sẽ dùng Snippet Generator của Jenkins để viết step này.checkout( poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[ credentialsId: 'admin', url: 'git@github.com:testdrivenio/django-on-docker.git' ]] ]) git: Một shortcut củacheckoutstep.git(url: 'git@github.com:testdrivenio/django-on-docker.git', branch: 'master', credentialsId: 'admin' )archiveArtifacts: Lưu trữ những artifact sau khi build, ví dụ một file.jar, một file.tar.gzchứa các log file. Những artifact này sẽ được lưu tại thư mụcJENKINS_HOME/jobs/JOB_NAME/builds/BUILD_NUMBER/archive/. Đây là một post-build action.archiveArtifacts artifacts: 'build_logs.tar.gz', fingerprint: true
emailext: Step này dùng để gửi mail. Đây là một post-build action.emailext(body: 'Something went wrong, check build log!', subject: 'Build failed', to: 'someone@example.com')
TL;DR
Trên đây là một vài ghi chú ngắn gọn về Jenkins Pipeline với các tính năng cơ bản và thông dụng của nó. Ngoài ra còn khá nhiều khía cạnh liên quan đến Pipeline đã được đề cập khá chi tiết ở documentation như:
- Jenkins Shared Pipeline Libraries: Một cơ chế để tránh duplicate code trong nhiều pipeline script.
- Handling Credentials: Cách để chúng ta handle crendentials trên Jenkins một cách an toàn và hiệu quả.
- Parallel execution: Một step đặc biệt trong Scripted Pipeline cho phép chạy song song nhiều step, stage hay build cùng một lúc.
- Script Security: Một vài security concern với Groovy script trên Jenkins. (xem thêm tại đây và đây).