CICD/Jenkins

Jenkins pipeline - Declarative pipeline 기술

Jayyy.H 2020. 11. 17. 22:05

Pipeline이란?

: Jenkins Pipeline은 CD(Continuous Delevery)를 지원하는 플러그인의 집합이다. 이 과정에서 소프트웨어를 빌드하고 여러 단계의 테스트, 배포를 진행한다. Pipeline은 Pipelie Domina Specific Language라는 문법을 통해 마치 코드를 작성하는 것과 같이 해당 기능을 제공한다. Pipeline을 사용하면 다음과 같은 이점이 있다.

  • 모든 Pull Request에 대해 Pipeline build process를 자동으로 제공한다.
  • Pipeline 선언을 코드로써 관리하여 프로젝트의 여러 구성원이 함께 보고 이해하며 편집할 수 있다.

이러한 Pipeline을 작성하는 데에는 크게 두 가지, Declarative 방식, Scripted 방식이 있으며, Declarative 방식은 Scripted방식보다 풍부한 구문 기능을 제공하며, 간편하게 작성할 수 있으며, 이해하기 쉬운 구조로 구성되어 있다.

Declarative Pipeline 기본 구조

기본 구조는 아래와 같다.

// Jenkinsfile

pipeline { // 최 상단 element로 정의되어 있어야 한다.
    agent any // pipeline 블록 내 최 상단에 정의되어야 하며, 말 그대로 실행할 Agent가 할당된다. 여기서 'any'는 사용가능한 어떠한 agent로도 실행해도 된다는 걸 나타낸다. 이는 pipeline 아래 위치해도 되고 각 stage 블록에 위치해도 된다.
    options {
        skipStagesAfterUnstable()
    }
    stages {
        stage('Build') { // stage는 Pipeline의 단계를 나타낸다.
            steps { // 해당 stage에서 실행할 명령을 기술하는 부분이다.
                sh 'make' // 주어진 shell 명령을 수행한다.
            }
        }
        stage('Test'){
            steps {
                sh 'make check'
                junit 'reports/**/*.xml' // junit 플러그인을 통해 제공하는 기능으로, 테스트 보고서를 집계한다.
            }
        }
        stage('Deploy') {
            steps {
                sh 'make publish'
            }
        }
    }
}

여기서 agent에 들어올 수 있는 parameter에 대해 자세히 알아보자.

agent type 설명
any 사용가능한 어떠한 agent를 써도 좋다 agent any
none pipeline 블록에 선언된 경우, 전체 파이프라인을 실행하는 동안 어떠한 global agent도 할당되지 않는다.
이 때, 각 stage 블록에 agent가 선언되어야 한다.
agent none
label 제공된 label을 이용해 파이프라인을 실행한다. agent { label 'my-defined-label' }
agent { label 'my-label1 && my-label2' }
agent { label 'my-label1 || my-label2' }
node agent { node { label 'labelName' } }agent { label 'labelName' }와 동일한 의미를 가진다.
하지만 customWorkspace와 같은 추가적인 옵션을 가질 수 있다.
agent { node { label 'labelName' } }
docker 도커 기반 파이프라인을 제공한다. docker는 아래에서 자세히 다루어 보자. -

docker

: 제공된 컨테이너를 이용해 도커 기반의 파이프라인 실행을 제공한다. 이는 args 파라미터를 이용하여 docker run 호출 시 제공할 파라미터를 줄 수 있다. 또한 alwaysPull 옵션은 이미지가 이미 존재하더라도 docker pull을 강제로 수행하도록 한다.

  • agent { docker 'maven:3-alpine' }
agent {
    docker {
        image 'maven:3-alpine'
        label 'my-defined-label'
        args  '-v /tmp:/tmp'
    }
}

: docker는 추가적으로 registryUrl, registryCredentialsId 옵션을 통해 Docker Registry와 이에 필요한 Credential을 명시할 수 있도록 지원한다. registryCredentialsId 는 도커허브의 private repository를 위한 기능이다.

agent {
    docker {
        image 'myregistry.com/node'
        label 'my-defined-label'
        registryUrl '<https://myregistry.com/>'
        registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
}

dockerfile

: source repository(GitHub?)에 존재하는 Dockerfile을 이용해 pipeline을 실행한다. 이를 위해서는 JenkinsfileMultibranch pipeline 또는 Pipeline from SCM을 이용해 로딩되어야 한다. Dockerfile의 최 상단에는 agent { dockerfile true }이 정의되어 있어야 한다. dir 옵션을 통해 Dockerfile의 경로를 지정할 수 있다. filename을 통해 Dockerfile의 이름(Dockerfile이 아닌 경우)을 지정할 수 있다. additionalBuildArgs 옵션을 통해 docker build 명령에 들어가는 추가적인 인자를 지정할 수 있다.

agent {
    // Equivalent to "docker build -f Dockerfile.build --build-arg version=1.0.2 ./build/
    dockerfile {
        filename 'Dockerfile.build'
        dir 'build'
        label 'my-defined-label'
        additionalBuildArgs  '--build-arg version=1.0.2'
        args '-v /tmp:/tmp'
    }
}

dockerfile 또한 docker와 마찬가지로 registryUrl, registryCredentialsId 옵션을 사용할 수 있다.

agent {
    dockerfile {
        filename 'Dockerfile.build'
        dir 'build'
        label 'my-defined-label'
        registryUrl '<https://myregistry.com/>'
        registryCredentialsId 'myPredefinedCredentialsInJenkins'
    }
}

Jenkinsfile 사용하기

: Jenkinsfile을 편집할 때 groovy 문법을 지원하는 에디터를 사용하면 편집에 편리하다. 그냥 파일명에 Jenkinsfile.groovy를 사용해도 무방하다. Jenkinsfile은 Make, CMake, Gradle, Maven과 같은 빌드도구가 아닌 빌드 및 테스팅을 간편하게 도와주는 중간 layer라고 이해하면 된다. 아래에서 sh 명령어는 Unix/Linux 기반 시스템에서, bat 명령어는 Window기반 시스템에서 사용하면 명령어 호출 예약어이다.
: 다음은 간단한 Jenkinsfile 의 예제이다.

// Declarative Jenkinsfile

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh 'make' 
                archiveArtifacts artifacts: '**/target/*.jar', fingerprint: true
            }
        }
        stage('Test') {
            steps {
                /* `make check` returns non-zero on test failures,
                * using `true` to allow the Pipeline to continue nonetheless
                */
                sh 'make check || true' 
                junit '**/target/*.xml' 
            }
        }
        stage('Deploy') {
            when {
              expression {
                currentBuild.result == null || currentBuild.result == 'SUCCESS' 
              }
            }
            steps {
                sh 'make publish'
            }
        }
    }
}
  • archiveArtifacts는 이후에 기술된 */target/*.jar과 패턴 매칭되는 파일들을 찾아 이들을 나중에 찾아볼 수 있도록 Jenkins controller 에 저장한다.
  • currentBuild.result 변수는 파이프 라인이 테스트 실패했는지 성공했는지를 알 수 있다. fail 시의 값은 UNSTABLE이다.

Jenkins 환경 변수

: TBD
https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#using-environment-variables

참고 링크
Jenkins pipeline
Jenkinsfile
Jenkins pipeline syntax