Jenkins Pipeline

동균·2020년 9월 14일
1

Jenkins

목록 보기
1/1

Jenkins Pipeline

Jenkins Pipeline란 기존의 Jenkins Project 혹은 Item 들을 연속적인 배포환경을 구현하고 통합하는것을 지원해주는 플러그인들의 집합이다. (CD)
Jenkins Pipeline은 Groovy 언어를 사용하는데 문법은 크게 2가지로 나뉜다.

Declarative pipelines과 Scripted pipelines이 있다.
Scripted pipelines는 Groovy DSL을 기반으로 한 Jenkins pipeline 에서 사용하는 전통적인 방법으로 Jenkins pipeline에 처음 도입된 방식이다.
Scripted pipelines 는 처음 도입된 만큼 구조가 잘 정의되어 있지 않지만 Declarative pipelines의 경우는 구조가 잘 정의되어 있어 조금 제한적으로 보일 수 있다.

두 문법간의 차이를 간단히 설명하자면 Scripted pipelines의 경우 변수의 선언등에 대해 자유롭고 다양하게 작업을 설정 할 수 있는 반면 복잡하다는 점이고 Declarative pipelines의 경우에는 보다 쉽고 간단하게 작성하고 이해 할 수 있다.

자세한 정보는 Jenkins User Documentation 에서 확인하자.

동일한 동작을 하는 Pipeline에 대해서 두가지 문법으로 구현된 Script를 살펴 보면 아래와 같다.

Declarative pipelines

문법 생성기 위치 : <Your_Jenkins_Url>/directive-generator/

pipeline {
    agent any // 실행할 agent 선언
    stages {
        stage('Git Pull') {
            steps {
                git (
                    branch: "${YOUR_GIT_BRANCH}",
                    credentialsId: "${YOUR_CREDENTIAL_ID}",
                    url: "${YOUR_GIT_URL}"
                )
            }
        }
        stage('Build') {
            steps {
                sh 'mvn -Dmaven.test.failure.ignore=true install'
            }
        }
        stage('Test') {
            steps {
                script { // if문과 같은 scirpt를 쓰기 위해 선언
                    if (!params.TEST_SKIP) {
                        echo "start test"
                    }
                }
            }
        }
    }
    // 빌드 결과에 따른 동작 정의
    post {
        always {
            echo "Build Finish"
        }
        success {
            echo "Build Success"
        }
        failure {
            echo "Build Failure"
        }
    }
    // 환경변수 정의
    environment {
        DIR="repo"
    }
    // 파라미터 정의
    parameters {
        booleanParam(name: 'TEST_SKIP', defaultValue: true, description: '테스트 스킵 여부')
    }
    // 옵션 정의
    options {pipeline {
    agent any // 실행할 agent 선언
    stages {
        stage('Git Pull') {
            steps {
                git (
                    branch: "${YOUR_GIT_BRANCH}",
                    credentialsId: "${YOUR_CREDENTIAL_ID}",
                    url: "${YOUR_GIT_URL}"
                )
            }
        }
        stage('Build') {
            steps {
                sh 'mvn -Dmaven.test.failure.ignore=true install'
            }
        }
        stage('Test') {
            steps {
                script { // if문과 같은 scirpt를 쓰기 위해 선언
                    if (!params.TEST_SKIP) {
                        echo "start test"
                    }
                }
            }
        }
    }
    // 빌드 결과에 따른 동작 정의
    post {
        always {
            echo "Build Finish"
        }
        success {
            echo "Build Success"
        }
        failure {
            echo "Build Failure"
        }
    }
    // 환경변수 정의
    environment {
        DIR="repo"
    }
    // 파라미터 정의
    parameters {
        booleanParam(name: 'TEST_SKIP', defaultValue: true, description: '테스트 스킵 여부')
    }
    // 옵션 정의
    options {
        timestamps() //timestamp 기능
        buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '7', numToKeepStr: '5') // 오래된 빌드 삭제
    }
    // 빌드 도구 정의
    tools {
        jdk 'JDK14' // 빌드시 사용 할 JDK
        maven 'M3' // 빌드시 사용 할 maven
    }
}
        buildDiscarder logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '7', numToKeepStr: '5') // 오래된 빌드 삭제
    }
    // 빌드 도구 정의
    tools {
        jdk 'JDK14' // 빌드시 사용 할 JDK
        maven 'M3' // 빌드시 사용 할 maven
    }
}

Scripted pipelines

문법 생성기 위치 : <Your_Jenkins_Url>/pipeline-syntax/

node {
    // 환경변수 정의
    def DIR="repo"

    // 빌드 도구 정의    
    def jdk = tool name: 'JDK14', type: 'jdk'
    def maven = tool name: 'maven3.5', type: 'maven'
    env.JAVA_HOME = "${jdk}"
    env.MAVEN_HOME = "${maven}"
    
    //timestamp 기능
    timestamps {
        // 빌드 결과에 따른 동작 정의
        try {
            stage('Git Pull') {
                git (
                    branch: "${YOUR_GIT_BRANCH}",
                    credentialsId: "${YOUR_CREDENTIAL_ID}",
                    url: "${YOUR_GIT_URL}"
                )
            }
            stage('Build') {
                sh 'mvn -Dmaven.test.failure.ignore=true install'
            }
            stage('Test') {
                if (!params.TEST_SKIP) {
                    echo "start test"
                }
            }
            echo "Build Success"
        } catch (e) {
            echo "Build Failure"
            throw e

        } finally  {
            echo "Build Finish"
        }
    }
    properties([
        buildDiscarder(logRotator(artifactDaysToKeepStr: '', artifactNumToKeepStr: '', daysToKeepStr: '7', numToKeepStr: '5')), // 오래된 빌드 삭제
        parameters([booleanParam(name: 'TEST_SKIP', defaultValue: true, description: '테스트 스킵 여부')]) // 파라미터 정의
    ])
}

비교

두가지 방식에 차이점에 대해 자세히 살펴 보자.

먼저 첫번째, pipeline 시작시 유효성 검사의 유무 이다.
Declarative Pipelines 의 경우 실행시 유효성 검사를 통해 빌드를 하게 되는데 이때 오류가 발생하게 되면 어떠한 단계도 실행하지 않고 실패를 하게 된다. 반면 Scripted pipelines의 경우 각 단계를 실행 하다 오류가 발생하게 되고 이전 단계는 이미 실행이 된 상태로 실패를 하게 된다.

두번째, 특정 stage에서 다시 시작을 할 수 있는 기능이다.
Declarative Pipelines의 경우 특정 stage에서 다시 시작을 할 수 있는데 반해 Scripted pipelines의 경우 특정 stage에서 다시 시작을 할 수 있는 기능 자체가 없다.

세번째, when 기능이다.
stage 내에

script { // if문과 같은 scirpt를 쓰기 위해 선언
    if (!params.TEST_SKIP) {
        echo "start test"
    }
}

대신

when {
	expression { params.TEST_SKIP }
}

을 사용하게 되면 TEST_SKIP 이 true 일 경우 Test stage 자체를 건너 뛰게 된다.
하지만 if문을 사용하게 되면 if문 내에 명령을 실행 하지 않을 뿐이지 Test stage가 실행 되지 않는것은 아니다.

마지막으로 Option 기능이다.
Declarative Pipelines 의 경우 Option 영역을 따로 잡아두고 선언을 통해 관리를 하는 반만 Scripted pipelines 경우는 별도 Option을 선언하는 영역을 가지고 있지 않다.
그로 인해서 오래된 빌드 삭제를 위한 기능은 별도 properties에 추가하고 timestamp를 찍는 기능은 별도 영역을 추가하는 등 복잡성이 증가하게 된다.

결론

둘 중에 어떤 방식이 더 좋은가는 구현하고자 하는 방식에 따라 다르다.

Declarative Pipelines의 경우는 엄격하고 사전 정의된 구조로 사용자에게 제한을 하지만 이는 보다 단순한 지속적인 배포 방식에 조금 더 이상적이고

Scripted pipelines의 경우는 Groovy에 의해 정의되는 구조와 구문에 제한이 적어 복잡한 요구사항을 가진 사용자에게 이상적이다.

profile
내가 볼려고 끄적끄적 적는 개발 블로그

0개의 댓글