Jenkins 환경변수

Jenkins Global variable

  1. env
    : env 환경변수는 다음과 같은 형식 env.VARNAME으로 참조될 수 있다. 대표적인 env의 property는 아래와 같다.
property 이름 설명
BUILD_ID 현재 빌드의 ID이며 이는 v1.597 이상에서는 BUILD_NUMBER와 같은 값을 가진다
JOB_NAME 현재 빌드중인 프로젝트의 이름으로 foo 또는 foo/bar와 같은 형식이다.
BRANCH_NAME multibranch 프로젝트인 경우 사용할 수 있으며, 현재 빌드되고 있는 브랜치명을 알려준다
CHANGE_ID multibranch 프로젝트의 change request에 대한 change ID(PR number)를 나타낸다.
CHANGE_URL multibranch 프로젝트의 change request에 대한 change URL을 나타낸다.
CHANGE_TARGET multibranch 프로젝트의 change request에 대해 merge될 base branch를 나타낸다.
CHANGE_BRANCH multibranch 프로젝트의 change request에 대해 현재 HEAD가 가리키고 있는 브랜치 명을 알려준다. 이는 BRANCH_NAME과 같을 수 있다.
BUILD_NUMBER 현재 build number를 나타낸다.
JENKINS_URL http://server:port/jenkins/와 같은 jenkins의 URL을 알려준다.
BUILD_URL http://server:port/jenkins/job/foo/15/와 같은 현재 build의 URL을 알려준다.
JOB_URL http://server:port/jenkins/job/foo/와 같은 job의 URL을 알려준다
  1. currentBuild
    : currentBuild 환경변수는 현재 빌드되고 있는 정보를 담고있다. 보통 readonly 옵션인데 일부 writable한 옵션이 존재한다. 대표적인 currentBuild의 property는 아래와 같다.
property 이름 설명
number build number를 나타낸다.
result SUCCESS, UNSTABLE, FAILURE를 가질 수 있으며, 빌드 중에는 null이 될 수 있다. writable한 옵션이다.
currentResult SUCCESS, UNSTABLE, FAILURE를 가질 수 있으며 null이 될 수 없다.
duration 빌드에 소요되고 있는 시간을 ms단위로 나타낸다.
keepLog true이면 해당 빌드에 대한 로그 파일은 지워지지 않는다. writable한 옵션이다.
displayName 보통 #123과 같으나 writable한 옵션이다.
  1. docker
    : TBD

환경변수의 사용

이들의 사용 예는 아래와 같다.

pipeline {
    agent any
    stages {
        stage('Example') {
            steps {
                echo "Running ${env.BUILD_ID} on ${env.JENKINS_URL}"
            }
        }
    }
}

: Jenkins에서 환경변수를 설정할 수 있으며 이 예는 아래와 같다.

pipeline {
    agent any
    environment { 
        CC = 'clang'
    }
    stages {
        stage('Example') {
            environment { 
                DEBUG_FLAGS = '-g'
            }
            steps {
                sh 'printenv'
            }
        }
    }
}
  • environment 지시어가 pipeline의 최 상단에 위치해 있으면, 이는 모든 step에 적용된다. 각 stage에 위치한 환경변수는 해당 stage에서만 적용된다.

pipeline-syntax/globals

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

Jenkins pipeline 이용하기

: 이번에는 GitHub 프로젝트에 Jenkinsfile을 생성하고, 여기에 기술된 작업 절차들을 Jenkins에서 수행하도록 하는 방법으로 pipeline을 사용할 수 있습니다. 이전에 Web에서 Job들을 일일이 적용하는 작업들은 매우 번거로울 뿐 아니라, Job이 추가/변경되는 경우 Website의 해당 Item에 들어가 일일이 수정해야하므로 여간 번거로운 일이 아닐 수 없습니다. 이를 Jenkinsfile에 기술해 놓으면 수정 또한 commit을 통해 할 수 있으므로 개발자 친화적인? 작업이라 할 수 있습니다. 그럼 적용하는 방법을 살펴보겠습니다.

저는 이전의 Jenkins 시작하기에서와 같이 https://github.com/JaehongParkYS/calculator_CICD 이 프로젝트를 사용하였습니다.


Manage Plugin에 들어가 위 그림처럼 Pipeline: Declarative Agent API을 설치해 줍니다.
저는 declarative 문법을 사용할 것이므로 해당 플러그인을 설치하였습니다.


New item을 선택해 줍니다.


Pipeline을 선택해 주고 이름은 아무 이름이나 설정해 줍니다.



위 그림처럼 프로젝트 주소와 Git 주소를 설정해 주고 Credential은 이전에 만든 것을 동일하게 사용해 줍니다.
그리고 Script Path에 GitHub 프로젝트에 추가해 준 Jenkinsfile의 이름(저는 Jenkinsfile로 했습니다.)을 적어 줍니다.
Build할 branch는 모든 브랜치를 대상으로 할 것이므로 /으로 하였습니다.


Item을 정의하고 난 후 Build Now를 선택하면 위 그림과 같이 Pipeline 형태의 기술된 작업들이 수행되는 것을 볼 수 있습니다.


세부 항목을 선택해 해당 로그를 보면, Test 작업에서 수행한 작업들의 결과(저는 Gtest를 이용해 테스트를 수행해 보았습니다.)를 볼 수 있습니다.

제가 작성한 Jenkinsfile은

pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh '''
                echo "Start Build"
                g++ -o main main.cpp calculator.cpp -lgtest -lpthread
                '''
            }
        }
        stage('Test') {
            steps {
                sh '''
                echo "Start Test"
                ./main
                '''
            }
        }
        stage('Archive') {
            steps {
                sh '''
                echo "Start Archiving"
                mv ./main ./artifact/
                '''
                archiveArtifacts artifacts: 'artifact/*', fingerprint: true 
            }
        }
    }
}

입니다.
위 기술된 항목들에 대한 설명은 다음 페이지에서 이어나가겠습니다.

'CICD > Jenkins' 카테고리의 다른 글

Jenkins - 환경변수 사용  (0) 2021.02.24
Jenkins pipeline - Declarative pipeline 기술  (1) 2020.11.17
Jenkins - GitHub 연결(2)  (0) 2020.11.12
Jenkins - 젠킨스 설정(1)  (0) 2020.11.12

Github 프로젝트와 Jenkins 연동

해당 프로젝트를 진행하기 위하여 저는 다음의 주소에 있는 프로젝트를 사용하였습니다.

https://github.com/JaehongParkYS/calculator_CICD

 

  1. Global Tool Configuration

    : 여기서는 자신이 빌드할 프로젝트에서 필요한 환경(Maven, JDK, Gradle, Git, etc.)을 구성합니다. 저는 C/C++ 이므로 Git만 설정하면 되는데 이미 설정이 되어있어 Pass 합니다.

 

  1. Plugin 설정

    : 필요한 Plugin들을 설치합니다. Git, Github관련 Plugin들은 Install suggested plugins에 포함되어있어 추가적으로 설치할 필요는 없습니다.

저는 Docker Plugin을 설치해 주었습니다.

설치된 플러그인들은 다음의 페이지에서 확인할 수 있습니다.
http://localhost:8754/updateCenter/

 

  1. Github 설정

위 설명대로 들어온 후 해당 git에 접속할 수 있는 token을 발급해 줍니다.

본인의 의도에 맞게 token에 access 권한을 부여해 줍니다.

스크롤을 내려 GitHub 란에서 Add 버튼을 선택해 줍니다.

위 사진과 같이 설정해 주고, Secret 란에는 GitHub에서 발급한 token을 넣어줍니다.

위 사진과 같이 생성한 Credential을 선택해 주고 Connection test를 해 봅니다.

 

  1. Github 연결

위 사진과 같이 [New Item] - [Freestyle project]를 선택해 주고 아무 이름이나 넣어 줍니다.

다음 그림과 같이 GitHub project란에 프로젝트 명(https://github.com/JaehongParkYS/calculator_CICD)을%EC%9D%84) 넣어주고, Source Code Management란에 git 주소(https://github.com/JaehongParkYS/calculator_CICD.git)를%EB%A5%BC) 넣어줍니다. 그리고 Credential 란에는

ssh-keygen -t rsa -f 파일명 명령으로 ssh 키를 만들어, .pub 확장자가 없는 파일(private 키)의 내용을 넣어 줍니다.

그 후, 다음과 같이 Build 절차와 Post-build action을 정의해 줍니다.
저는 C/C++ 프로젝트이어서 간단하게 작성하였습니다. 저장을 눌러주면 다음과 같이 Item이 생성되었습니다.

다시 GitHub의 프로젝트로 넘어와서,

위에서 ssh-keygen -t rsa -f 파일명 명령으로 만든 public key를 위 사진과 같이 GitHub 계정에 등록시켜 줍니다. 이를 통해 Jenkins와 GitHub이 사전에 정의된 키를 이용해 통신을 가능하게 합니다.

GitHub 프로젝트의 [Settings] - [Webhooks]로 넘어가 [Add webhook]을 선택한 뒤 위와 같이${Jenkins의 주소}/github-webhook/을 넣어줍니다. 저는 public 주소가 없으므로 추후 ngrok을 이용해 수정해 줄 것입니다.

 

  1. Host(Windows10)와 Guest(Ubuntu-VirtualBox)를 포트포워딩 시키기

    제 PC는 Windows10이 설치되어있어, 개발 편의를 위해 VirtualBox에 Ubuntu20.04를 설치하였고, 이 Ubuntu에 모든 개발환경(Jenkins 포함)을 설정하였습니다.

    따라서 Jenkins 특성상 외부에서 제가 설정한 Jenkins 서버에 접속하여야 하므로, Host(Windows10)와 Guest(Ubuntu)의 특정 포트(8754)를 포트포워딩 시켰습니다.

다음 그림과 같이 HostPC의 loopback 주소(127.0.0.1)의 8754 포트를 GuestPC의 IP주소:8754 포트에 포트 포워딩 시켰습니다.


Ubuntu에서 IP 주소를 확인하기 위해서는 ifconfig 명령을 사용하면 되는데요, VirtualBox에서 설치하였다면 10.0.2.15로 고정되어 있습니다.

 

  1. ngrok을 이용해 Host PC의 특정 포트를 외부에서 접근가능하도록 public 주소 만들기

    ngrok은 다음의 주소에서 설치할 수 있습니다.

ngrok.com/download

 

ngrok - download

Running this command will add your authtoken to your ngrok.yml file. Connecting an account will list your open tunnels in the dashboard, give you longer tunnel timeouts, and more. Visit the dashboard to get your auth token.

ngrok.com

설치가 끝난 후, 저는 8754 포트를 Jenkins 접속 포트로 사용하고 있기 때문에 다음과 같이 ngrok에 명령어를 실행시켜주면


외부에서 접근할 수 있는 주소가 나타납니다.
한번 접속해 볼까요?


네, Jenkins로 포트포워딩 되어 접속이 잘 되네요.

 

그렇다면 위 GitHub 프로젝트의 [Settings] - [Webhooks]로 넘어가 [Add webhook] 다시 올바른 주소를 설정해 주도록 합시다. 그리고 나서 PR을 발생시켜보면,

위 그림과 같이 Jenkins의 Job이 생기고, PR에도 Jenkins 관련 내용이 보입니다. ^^

 

7. Build 결과물(artifact) 확인

Build 결과물은 jenkins 설치 경로에 따라서 다르므로 설치경로를 확인하는게 좋습니다.

default 경로는 /var/lib/jenkins/ 이므로 참고하시고, 해당 경로로 들어가보면 다음과 같이 빌드 결과물과, 해당 artifact를 실행해 볼 수 있습니다.

 

Jenkins 설치 (Ubuntu 20.04)

  1. JDK 설치

    apt-get update
    sudo apt-get install openjdk-8-jdk
  2. Jenkins 저장소 key 다운로드 후 sources.list에 다운로드 경로 추가 & Jenkins 다운로드

    wget -q -O - https://pkg.jenkins.io/debian/jenkins.io.key | sudo apt-key add -
    
    echo deb http://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list
    
    sudo apt-get update
    
    sudo apt-get install jenkins
  3. Jenkins 서비스 시작

    sudo service jenkins restart

이 후 Jenkins의 HTTP PORT로 설정되어있는 포트(기본 8080)에 웹 브라우저를 이용해 접속합니다.

  • http://localhost:8080
    Jenkins의 HTTP PORT는 다음의 파일을 수정하여 바꿀수 있습니다.
  • /etc/default/jenkinsHTTP_PORT=8080

페이지에 접속 후 비밀번호를 입력하는 페이지가 나오는데 비밀번호는 아래의 명령어로 확인할 수 있습니다.

  • sudo cat /var/lib/jenkins/secrets/initialAdminPassword

Install suggested plugins 을 선택하여 플러그인을 설치합니다

관리자 계정을 생성합니다.

Jenkins 접속 URL을 설정합니다.

설정을 성공적으로 끝마치면 다음과 같은 페이지를 볼 수 있습니다.

+ Recent posts