세미나
Jenkins Pipeline - Basic
nineDeveloper
2019. 10. 22. 21:18
728x90
Hello World
Job 생성
- Jenkins > New Item > Pipeline
node {
stage('Stage 1') {
echo 'Hello World'
}
stage('Stage 2') {
echo 'Stage 2'
}
}
Node, Stage, Step
- pipeline 스크립트는 node, stage, step 으로 구성된다.
- node (Required)
- 실행 머신
- stage (Optional)
- 관련 동작들 grouping 용도
- Step
- UI Job에서 설정했던 동작들
- git checkout
- execute shell script
- junit report
- archive, ...
실행 결과 (console output)
Started by user 신현일 Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] node Running on Jenkins in /data/jenkins/workspace/pipeline_training/hello world
[Pipeline] {
[Pipeline] stage
[Pipeline] { (Stage 1)
[Pipeline] echo Hello World
[Pipeline] }
[Pipeline] // stage
[Pipeline] stage
[Pipeline] { (Stage 2)
[Pipeline] echo Stage 2
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
Stage View
Step 별 실행 결과
Pipeline 기본 Flow
자유롭게 구성할 수 있다.
node {
stage("build") {
step step ...
}
stage("report") {
step step ...
}
}
node를 여러 개 사용할 수 있다.
stage("1") {
node ("nodeA") {
step step ...
}
}
stage("2") {
node ("nodeB") {
step step ...
}
}
Step 문법 외울 필요 없다 (코드 자동 생성 기능)
- GUI 이용하여 코드 자동 생성
Example: git checkout
Generate Pipeline Script
기본 Steps
https://jenkins.io/doc/pipeline/steps/
sh (리눅스)
- shell 명령어 실행
node {
stage('Stage 1') {
sh 'pwd'
sh 'java -version'
}
}
sh: return value
- returnStdout
- output을 반환
node {
stage('s') {
def output = sh(encoding: 'UTF-8', returnStdout: true, script: 'java -version')
echo output
}
}
- returnStatus
- status code 반환
node {
stage('s') {
def output = sh(encoding: 'UTF-8', returnStatus: true, script: 'java -version')
echo output.toString()
}
}
sh: label
human-readable 제목 붙이기
node {
stage('s') {
def output = sh(encoding: 'UTF-8',
label: 'print java version', //set label
returnStatus: true, script: 'java -version')
echo output.toString()
}
}
dir
node {
stage('s') {
sh 'mkdir -p hello'
sh 'pwd'
dir('hello') {
sh 'pwd'
}
}
}
실행 결과
[Pipeline] sh
+ mkdir -p hello
[Pipeline] sh
+ pwd /home1/irteam/apps/jenkins/jenkins_home/jobs/pipeline_training/jobs/sample/workspace
[Pipeline] dir Running in /home1/irteam/apps/jenkins/jenkins_home/jobs/pipeline_training/jobs/sample/workspace/hello
[Pipeline] {
[Pipeline] sh
+ pwd /home1/irteam/apps/jenkins/jenkins_home/jobs/pipeline_training/jobs/sample/workspace/hello
[Pipeline] }
[Pipeline] // dir
실습 01. Pipeline job 만들기
개인 폴더 > Pipeline job 생성
git checkout 후에 shell script 실행
- git
- url: https://github.com/hyunil-shin/JenkinsPipelineTraining
- credentials: hyunil-shin
- shell script 파일
- shell_scripts/script1.sh
- git
sh returnStdout, returnStatus 적용
dir 활용
node() {
stage('git') {
}
stage('execute a script') {
}
}
stash, unstash
- 빌드 내에서 파일 저장/불러오기 (임시 저장)
- 빌드 결과에 저장되지는 않음
archiveArtifacts
- 파일 보관
node {
deleteDir()
stage('stash') {
dir('hello') {
sh 'echo "hey" > file1.txt'
stash includes: 'file1.txt', name: 'file1'
}
} // other steps
stage('unstash') {
unstash 'file1'
sh 'find ./'
sh 'cat file1.txt'
}
}
build a job
node {
build 'build\_job\_target'
}
- options
- Wait for completion
- Job 빌드 종료를 기다릴 것인가?
- Propagate errors
- if true, Job 빌드 실패 시 build step도 실패이다.
- Wait for completion
More Steps
- https://jenkins.io/doc/pipeline/steps/workflow-basic-steps/
- deleteDir
- retry
- sleep
- timeout
Input Step
- 빌드 중 사용자 입력을 받을 수 있다.
- 참고
echo "build"
input message: 'Confirm?', ok: '확인'
echo "confirmed"
빌드 성공, 실패
- 일반적인 스크립트와 동일하게 실패하는 부분에서 중지한다.
- 빌드 성공/실패를 스크립트에서 결정할 수 있다.
- 변수명: currentBuild.result
- values
- SUCCESS, UNSTABLE, FAILURE, ABORTED
- 참고
Tip. 복잡한 Pipeline 구성 시 빌드 실패 테스트가 필요하다. 강제로 특정 Step을 실패하도록 만들어 원하는 결과가 나타나는지 확인하는 것이 좋다.
빌드 실패
- step이 실패하면 빌드가 중지된다.
- 이 후 step들은 실행되지 않는다.
- 빌드 결과 (currentBuild.result): FAILURE
- 이 후 step들은 실행되지 않는다.
node {
sh 'echo "hello"'
echo "RESULT: ${currentBuild.result}"
// do something that fails
sh "exit 1"
echo "RESULT: ${currentBuild.result}"
}
실행 결과
sh "exit 1"
에서 실패가 발생하고 pipeline 실행이 중지된다.
+ echo hello
hello
[Pipeline] echo RESULT: null
[Pipeline] sh
+ exit 1
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
ERROR: script returned exit code 1 Finished: FAILURE
try - catch
- try-catch로 빌드 실패를 막을 수 있다.
node {
try {
// do something that fails
sh "exit 1"
} catch (Exception err) {
}
}
실행 결과
Running on Jenkins in /data/jenkins/workspace/pipeline_training/try-catch
[Pipeline] {
[Pipeline] sh
+ exit 1
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: SUCCESS
강제 실패
currentBuild.result = 'FAILURE'
node {
try {
// do something that fails
sh "exit 1"
} catch (Exception err) {
// post actions
currentBuild.result = 'FAILURE'
}
echo "after try-catch"
}
실행 결과: currentBuild.result=FAILURE
[Pipeline] sh
+ exit 1
[Pipeline] echo after try-catch
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
Finished: FAILURE
강제 실패
error step 사용
node() {
stage("s1") {
sh 'ls -al'
}
def aa stage("s2") {
aa = sh script: 'exit 1', returnStatus: true
if(aa != 0) {
error "hello" // <=== 여기서 실행이 중지된다.
}
}
stage("s3") {
sh 'ls -al'
}
}
특정 Stage 실패
- warnError, unstable step으로 stage 실패를 구분할 수 있다.
- Blue Ocean에서만 지원된다. Stage View에서는 아직 지원되지 않는다.
node() {
stage("s1") {
sh 'ls -al'
}
stage("s2") {
sh 'ls -al'
// https://jenkins.io/blog/2019/07/05/jenkins-pipeline-stage-result-visualization-improvements/
// required: Blue Ocean
warnError('script error') {
sh script: 'exit 1'
}
}
stage("s3") {
sh 'ls -al'
}
}
실습 02. 빌드 실패
- A. stage 여러개 만들고, step 실패가 있으면 빌드를 중지시킨다.
- B. stage 여러개 만들고, step 실패가 있더라도 계속 진행한다.
- 빌드 최종 결과 = unstable
- C. stage 여러개 만들고, step 실패가 있더라도 계속 진행한다.
- 빌드 최종 결과 = failure
- currentBuild = "UNSTABLE", "FAILURE"
- steps: error, unstable, warnError
실패하는 step 예 sh 'exit 10'
종합
maven + junit
- flow
- git checkout -> mvn clean test -> junit, jacoco report
properties([parameters([string(defaultValue: 'test', description: 'test or verify', name: 'testType', trim: false)])
])
node {
stage("git") {
git 'https://github.com/hyunil-shin/java-maven-junit-helloworld.git'
}
stage('build') {
//withEnv(["PATH+MAVEN=${tool 'mvn-3.3.9'}/bin"]) {
//withEnv(["PATH+MAVEN=${tool 'mvn-3.6.2'}/bin"]) {
withEnv(["PATH+MAVEN=${tool 'mvn-3.6.0'}/bin"]) {
sh 'mvn --version'
sh "mvn clean ${params.testType}"
}
}
stage('report') {
junit 'target/surefire-reports/*.xml'
jacoco execPattern: 'target/**.exec'
}
}
properties
properties([parameters([string(defaultValue: 'test', description: 'test or verify', name: 'testType', trim: false)])])
- 빌드 속성 정의
- Pipeline Syntax 사용하여 자동 생성 가능
- 매개변수 접근
params.[매개변수명]
withEnv
- 환경 변수 추가
- PATH+WHATEVER=/something
- PATH=/something:$PATH 와 동일한 의미
- 참고. 도구 설정
- maven
- Jenkins 관리 > Global Tool Configuration > Maven installations
- maven
도구 선택
//tool [tool name] => tool path 반환
withEnv(["PATH+MAVEN=${tool 'apache-maven-3.6.0'}/bin"]) {
}
mvn 빌드
withEnv(["PATH+MAVEN=${tool 'apache-maven-3.6.0'}/bin"]) {
sh 'mvn --version'
sh "mvn clean ${params.testType}"
}
junit, jacoco
stage('report') {
junit 'target/surefire-reports/*.xml'
jacoco execPattern: 'target/**.exec'
}
테스트 실패
- mvn test가 실패하면 sh step이 실패하여 이후 코드들이 실행되지 않는다.
- try-catch 또는
maven.test.failure.ignore=true
사용
...
stage('build') {
withEnv(["PATH+MAVEN=${tool 'apache-maven-3.6.0'}/bin"]) {
sh 'mvn --version'
sh "mvn clean ${params.testType} -Dmaven.test.failure.ignore=true"
}
}
stage('report') {
junit 'target/surefire-reports/*.xml'
jacoco execPattern: 'target/**.exec'
}
}
실습 03. mvn
- maven + junit pipeline 스크립트 작성
- git fork (개인 repository 생성)
- https://github.com/hyunil-shin/java-maven-junit-helloworld
- 개인 repository collaborators에 hyunil-shin 추가
- 사용해야 할 steps
- mvn test
- junit
- jacoco
- 빌드 결과를 메일로 전달받기
- emailext step
- archiveArtifacts
- junit xml
- 확장
- 빌드 매개변수
- properties step
- 브랜치 선택
- 다른 JDK 버전 사용
- withEnv step
- 사용 가능한 버전: openjdk8, openjdk9, openjdk10
- 다른 maven 버전 사용
- 사용 가능한 버전: mvn-3.6.2, mvn-3.6.0, mvn-3.3.9
- 빌드 매개변수
Pipeline 스크립트
Pipeline Step + Groovy + Jenkins API
Groovy Syntax
- for
- if
- array, map
- 참고
Groovy - String Interpolation
def username = 'Jenkins'
echo 'Hello Mr. ${username}'
echo "I said, Hello Mr. ${username}"
실행 결과
Hello Mr. ${username} I said, Hello Mr. Jenkins
Parsing Json data
def body = """ { "f1": "b?", "f2": "c" }"""
def parser = new groovy.json.JsonSlurper()
def data = parser.parseText(body)
echo data.f1
echo data.f2
Jenkins API
- 강력한 기능
- Jenkins 모든 데이터에 접근 가능
- 보안 때문에 Jenkins admin 승인 필요
Example: 특정 Job의 git 정보 조회
@NonCPS
def getGitInfo(String jobName) {
def map1 = jenkins.model.Jenkins.instance.getItemMap()
def project
if(jobName.contains('/') == true) {
// folder를 사용하는 경우
def tmp = jobName.split('/')
project = map1.get(tmp[0]).getJob(tmp[1])
} else {
project = map1.get(jobName)
}
def giturl = project.scm.getUserRemoteConfigs()[0].getUrl().toString()
def credential = project.scm.getUserRemoteConfigs()[0].getCredentialsId().toString()
println giturl
println credential
return [giturl, credential]
}
Global Variable Reference
- http://[your_jenkins]/pipeline-syntax/globals
- env
- params
- currentBuild
- manager
env (환경 변수)
env.[환경변수명]
(env. 없이도 사용 가능)
echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
env.MYTOOL_VERSION = '1.33'
node {
echo JOB_NAME
sh "echo $MYTOOL_VERSION"
sh "echo ${env.MYTOOL_VERSION}"
sh 'echo $MYTOOL_VERSION'
}
currentBuild
- 현재 빌드 상태를 나타냄
- currentBuild.result, currentBuild.displayName, ...
- Example) 빌드 Trigger 알아내기
import groovy.json.*
// Get all Causes for the current build
def causes = currentBuild.getBuildCauses()
// Get a specific Cause type (in this case the user who kicked off the build),
// if present.
def specificCause = currentBuild.getBuildCauses('hudson.model.Cause$UserIdCause')
echo specificCause[0].userId echo specificCause.toString()
728x90