젠킨스 파이프라인 및 깃허브 연동을 설명했던 이전 포스팅에서 선언형 파이프라인과 스크립트형 파이프라인에 대해서 간단히 설명했는데, 이번에는 두 파이프라인에 대해서 설명하고 문법 및 예외처리 방법을 알아본다.
두 파이프라인 문법의 특징 및 사용되는 pipeline, node, stage 등과 같은 지시자(Directive)들을 모두 설명할 수는 없지만 주로 사용되는 지시자를 확인할 것이다.
선언형 파이프라인과 스크립트형 파이프라인
선언형 파이프라인(Declarative Pipeline)은 Jenkins DSL을 사용해서 구조화된 방식으로 파이프라인을 정의하며, 스크립트형 파이프라인(Scripted Pipeline)은 그루비(Groovy) 언어를 사용해서 파이프라인을 정의한다. 파이프라인은 자신이 사용하는 환경과 장단점을 파악해서 사용하면 된다.
선언형 파이프라인
장점
- 명확하고 구조화된 구문으로 파이프라인의 가독성이 좋다.
- 간결하고 구조화된 코드 덕분에 유지보수가 용이하다.
- 젠킨스 파이프라인에 정의된 구문을 사용하므로 학습곡선이 낮다.
단점
- 구조가 고정되어 있기 때문에 특정 상황에 맞춘 유연한 동작이 힘들 수 있다.
- 스크립트형에 비해 확장성이 떨어진다.
- 사용자가 로직을 커스터마이징해서 정의하기 어렵다.
선언형 파이프라인 문법
선언형 파이프라인에서 사용되는 지시자를 설명한다.
- pipeline: 선언형 파이프라인의 최상위 지시자로, 반드시 포함해야 한다.
- agent: 파이프라인 또는 특정 stage에서 실행될 환경을 정의한다, none, any 등의 값을 지정할 수 있다.
- stages: 여러 stage를 그룹화 한다. stage들은 연속적으로 실행된다.
- stage: 파이프라인의 개별적인 단계를 정의한다. 각 stage는 하나 이상의 step을 포함할 수 있다.
- steps: 각 stage 내에서 실행할 작업을 정의한다.
- post: 파이프라인의 실행이 완료된 후 실행될 작업을 정의한다.
always,success,failure등의 실행할 작업을 정의할 수 있다. - environment: 파이프라인이나 특정 stage에서 사용할 환경 변수를 정의한다.
- options: 파이프라인이나 특정 stage의 실행 옵션을 정의한다. 타임아웃, 재시도 횟수 등을 정의한다.
- triggers: 파이프라인을 실행하기 위한 트리거를 지정한다.
cron,pollSCM등을 사용해 정의할 수 있다. - parameters: 파이프라인 실행 시 사용자로부터 입력받을 파라미터를 정의한다.
- parallel: 여러 stage를 병렬로 실행한다.
- when: 특정 조건에 만족할 때 stage를 실행하게 한다.
- sh: 리눅스 쉘 명령을 실행하기 위해서 사용한다.
아래는 지시자들을 사용한 예제 코드다.
pipeline {
agent any
// 파라미터 정의
parameters {
string(name: "CUSTOM_PARAM", defaultValue: "spring", description: "테스트값")
}
// 환경 변수 정의
environment {
GIT_BRANCH = "main"
}
options {
retry(1) // 재시도 횟수 1번
}
triggers {
cron("H * * * *") // 매시간 정각에 실행
}
stages {
stage("Stage1") {
steps {
echo "CUSTOM_PARAM: ${params.CUSTOM_PARAM}"
echo "Environment GIT_BRANCH: ${env.GIT_BRANCH}"
sh "ls -arlth"
}
}
stage("Stage1") {
// 파라미터 값이 일치하면 실행
when {
expression {
params.CUSTOM_PARAM == "spring"
}
}
steps {
echo "CUSTOM_PARAM equals spring"
}
}
stage("Stage3") {
// 파라미터 값이 일치하지 않으면 실행
when {
expression {
params.CUSTOM_PARAM != "spring"
}
}
steps {
echo "CUSTOM_PARAM not equals spring"
}
}
// 작업을 병렬처리한다.
stage("Stage4 Parallel") {
parallel {
// 첫 번째 작업
stage("Parallel Stage 1") {
steps {
echo "First Jop Execution"
}
}
// 두 번째 작업
stage("Parallel Stage 2") {
steps {
echo "Second Jop Execution"
}
}
}
}
}
post {
// 파이프라인 빌드 끝나고 항상 실행
always {
echo "Always Run After Build"
}
// 파이프라인 빌드 성공했을 때 실행
success {
echo "Build Success"
}
// 파이프라인 빌드 실패했을 때 실행
failure {
echo "Build Fail"
}
}
}
파이프라인 코드는 이해하기 어렵지 않을 것이다. 몇 부분에는 주석으로 설명을 추가했다.
스크립트형 파이프라인
장점
- 그루비 언어의 모든 기능을 사용하므로 유연성이 높다.
- 사용자 정의 함수, 복잡한 로직을 세밀하게 작성 가능하며 확장성이 높다.
- 코드 블록들을 모듈화해서 재사용 할 수 있다.
단점
- 복잡한 로직을 처리하면 코드의 가독성이 떨어지며, 유지보수가 어려워질 수 있다.
- 문법의 자유도가 높은 만큼, 잘못된 코드로 인한 오류 가능성이 높아진다.
- 파이프라인 코드를 작성하기 위해서 젠킨스 DSL과 그루비 문법을 학습해야 한다.
스크립트형 파이프라인 문법
스크립트형 파이프라인에서 사용되는 지시자를 설명한다. 선언형 파이프라인 문법에서 설명한 지시자들은 생략한다.
- node: 스크립트형 파이프라인 최상위에 작성한다.
- env: 환경 변수를 설정한다.
- withEnv: 블록 내에서 사용할 환경 변수를 지정한다.
- parallel: 여러 작업을 병렬로 실행한다. 각 작업은 클로저로도 정의할 수 있다.
- try-catch-finally: 작업의 예외가 있을 때 처리하기 위해 사용한다.
- catchError: 오류를 잡아내고, 파이프라인 코드를 계속 실행하기 위해 사용한다.
- timeout: 특정 블록의 실행 시간을 제한하고, 시간이 초과하면 중단한다.
- retry: 특정 블록을 실패할 경우 지정된 횟수만큼 작업을 재시도한다.
- timestamp: 타임스탬프를 콘솔 출력에 추가한다.
아래는 지시자들을 사용한 예제 코드다.
node {
// 환경 변수 정의
env.GIT_BRANCH = "main"
// 파라미터 정의
properties([
parameters([
string(name: "CUSTOM_PARAM", defaultValue: "spring", description: "테스트값")
])
])
// 변수 설정
def customValue = "hello world"
// 타임스탬프를 콘솔 출력에 추가
timestamps {
stage("Timeout Stage") {
timeout(time: 5, unit: "SECONDS") {
echo "Timeout Check"
sh "sleep 2s"
//sh "sleep 10s" // 타임아웃 테스트를 위한 10초 슬립
}
}
stage("Print Stage") {
withEnv(["BLOCK_ENV=GOOD BUILD"]) {
echo "CUSTOM_PARAM: ${params.CUSTOM_PARAM}"
echo "Environment GIT_BRANCH: ${env.GIT_BRANCH}"
echo "customValue: ${customValue}"
echo "BLOCK_ENV: ${env.BLOCK_ENV}"
}
}
}
// 작업 병렬 실행
stage("Parallel Stage") {
parallel(
"Parallel First": {
echo "Parallel Job First"
},
"Parallel Second": {
echo "Parallel Job Second"
}
)
}
stage("Try Catch Stage") {
try {
echo "Try Catch First Execution"
sh "exit 1" // 고의적인 예외 발생
} catch (Exception e) {
echo "의도적인 예외가 발생했다."
}
// catchError를 사용해서 특정 스테이지에서 에러가 발생해도 전체는 성공으로 간주되도록 한다.
catchError(buildResult: "SUCCESS", stageResult: "FAILURE") {
echo "catchError Example"
sh "exit 1" // 고의적인 예외 발생
}
}
stage("Print Message") {
printMessage("메시지 출력")
}
}
// 사용자 정의 함수
def printMessage(message) {
echo "message: ${message}"
}
코드에서 선언형 파이프라인과 다른 부분들이 존재한다. 주석으로 간단히 설명했지만 부가적인 설명을 추가한다.
timestamp블록안에서 실행된 stage들은 파이프라인 콘솔에 타임스탬프가 출력된 것을 확인할 수 있다.timeout()블록안에서 실행되는 코드가 설정한 값을 초과하면 파이프라인 실행 결과가aborted가 된다.parallel블록으로 병렬처리한 것은 그루비의 클로저 문법말고 선언형 파이프라인에서 처리한 방법도 동일하게 사용 가능하다.def로 변수를 선언하거나 함수를 정의해서 사용할 수 있다.catchError를 사용할 때buildResult: "SUCCESS"는 파이프라인 전체 빌드 결과를 성공으로 설정하고,stageResult: "FAILURE는 오류가 발생한 스테이지 결과를 실패로 설정한다. 일부 스테이지의 실패를 허용하고 전체 빌드를 성공으로 처리할 때 사용한다.- 스크립트형 파이프라인에서 예외처리는
try-catch절로 처리한다.
결과를 확인하면 타임스탬프가 출력된 부분과 전체 빌드가 성공으로 처리된 것을 확인할 수 있다.

예외처리
스크립트형 파이프라인에서는 각 stage에서 예외처리를 위해 try-catch절을 사용해서 처리할 수 있을 것 같다. 하지만 선언형 파이프라인에서는 post에서 전체 빌드 결과에 대한 처리를 했는데 각 stage의 예외처리를 어떻게 할 것인지를 생각해봐야 한다.
선언형 파이프라인에서 각 stage 마다 예외처리를 하기 위해서는 script 블록 안에서 try-catch를 사용해서 예외를 처리하면 된다.
pipeline {
agent any
stages {
stage("Stage 1") {
steps {
script {
try {
echo "실행중..."
sh "exit 1" // 고의적인 예외 발생
} catch (Exception e) {
echo "예외발생: ${e.message}"
}
}
}
}
stage("Stage 2") {
steps {
script {
try {
echo "실행중..."
sh "exit 1" // 고의적인 예외 발생
} catch (Exception e) {
echo "예외발생: ${e.message}"
}
}
}
}
}
}
지금까지 선언형 파이프라인과 스크립트형 파이프라인의 문법과 예외처리에 대해서 설명했다. 이 외에도 다양한 문법들이 존재하는데 이는 파이프라인 공식문서에서 확인하고 필요한 지시자들을 사용하면 된다.
'DevOps' 카테고리의 다른 글
| 아파치 카프카 기본 설정 (0) | 2025.01.07 |
|---|---|
| 아파치 카프카 개념 정리 (0) | 2025.01.06 |
| 젠킨스 파이프라인으로 깃허브 SSH 연동 (0) | 2024.12.23 |
| 도커 젠킨스를 깃허브 SSH로 연동 (0) | 2024.12.16 |
| Jenkins Github 리포지토리 SSH 연결 에러(stderr: No ED25519 host key...) (0) | 2024.12.14 |