Jenkins Pipeline

최병훈·2024년 11월 7일
post-thumbnail

1)개요

  • 품질 점검이나 소프트웨어 인도와 같은 부분을 자동으로 수행하도록 하는 일련의 과정
  • 파이프라인은 스크립트를 연결해서 작성
  • 파이프라인을 사용했을 때 장점
    • 작업 그룹화
      • 작업들은 stage라는 단위로 그룹화
      • stage로 프로세스에 구조를 부여하며 규칙을 명확하게 정의
      • stage가 실패하면 이후 스테이지는 실행되지 않음
    • 가시성
      • 프로세스의 모든 요소를 시각화 할 수 있음
      • 실패 원인을 빠르게 분석할 수 있으며 팀원들 간의 협업이 원할해집니다.
    • 피드백
      • 문제가 발생하면 즉시 팀원들이 알 수 있고 빠르게 대응할 수 있음

2)구조

  • stage 와 step으로 구성
    트리거 -> Stage(step1, step2 ..) -> Stage(step1, step2,...) -> ... -> 알림
  • Step: 젠킨스가 수행할 것을 알려주는 단일 작업(코드 체크 아웃, 스크립트 실행 등)
  • Stage: 여러 개의 스텝을 개념적으로 분리해 그룹화한 논리적 구분
  • 여러 개의 stage를 갖는 스크립트 작성

    pipeline{
        agent any
        stages{
            stage("First Stage"){
                steps{
                    echo "Step1. Hello World"
                }
            }
    
            stage("Second Stage"){
                steps{
                    echo "Step2. Hello World"
                    echo "Step3. Hello World"
                }
            }
        }
    }

  • Jenkins에서 Pipeline Overview를 확인할 수 있다.

3)젠킨스의 작업

  • 작업을 만들 때 반드시 포함되어야 하는 지시 사항
    • 작업을 수행하는 시점(트리거)
    • 작업을 구성하는 단계별 태스크(빌드 스텝)
    • 태스크가 완료된 후 수행할 명령(포스트 빌드 액션)
  • 젠킨스의 빌드
    • 작업의 특정 실행 버전
    • 젠킨스 작업을 여러 번 실행한 경우 실행할 때 마다 고유한 빌드 번호가 부여됩니다.
    • 작업 실행 중에 생성된 아티팩트, 콘솔 로그 등 특정 실행 버전과 관련된 모든 실행 정보가 해당 빌드 번호로 저장됩니다.
  • 프리스타일 작업
    • 일반적인 형태의 빌드 작업
    • 테스트 실행 과 애플리케이션 빌드 및 패키징 그리고 보고서 전송 같은 작업을 수행할 수 있습니다.
  • 젠킨스의 작업 생성
    • 대시보드로 이동
    • 새로운 Item(New Item)을 클릭
    • 이름을 설정하고 Freestyle을 선택한 후 OK 버튼 클릭
    • 작업 구성 후 저장
    • [지금 빌드] 를 눌러 빌드를 수행해 볼 수 있다.
  • pipeline의 구문

    pipeline{
        agent any //에이전트 지정
        triggers { cron('* * * * *') } //1분마다 수행
        options { timeout(time: 5)} //5분이상 실행되면 중단
        //시작하기 전에 boolean 형 파라미터를 요청
        parameters {
            booleanParam(name: 'DEBUG_BUILD', defaultValue: true, 
            description: 'Is it the debug build')
        }
    
        stages{
            stage('Sample'){
                environment {NAME = 'RAPA'} //NAME이라는 환경 변수를 설정
                //DEBUG_BUILD 가 true 인 경우
                when { expression { return params.DEBUG_BUILD} }
                steps{
                    echo "Hello from $NAME"
                    script {
                        def browsers = ['chrome', 'firefox']
                        for(int i=0; i<browsers.size(); ++i){
                            echo "Testing the ${browsers[i]} browser"
                        }
                    }
                }
            }
        }
    
       post {always {echo "I will always say Hello again"}} //실행 중 오류 발생 여부 와 상관없이 출력
    }

    cron trigger 에 의해 분마다 수행된다.

4)pipeline의 지시어

섹션

  • Stage: 한 개 이상의 연속된 stage 지시어로 구성
  • Step: 한 개 이상의 연속된 step 명령으로 구성
  • Post
    • 파이프라인 빌드 끝에서 실행되는 한 개 이상의 step 명령으로 구성
    • 포스트는 always, success, failure 등의 조건과 함께 쓰이며 일반적으로 파이프라인 빌드가 끝날 때 알림을 보내는 용도로 사용
  • Agent: 파이프라인이나 스테이지가 어디서 실행되는지를 결정할 때 사용

지시어

  • Triggers
    • 파이프라인을 자동으로 시작하는 방법을 정의
    • cron으로 시간별 일정에 따라 실행하거나 pollSCM으로 레포지토리 변경에 따라 시작하도록 할 수 있음
  • Options: 파이프라인에서만 사용하는 옵션을 정의

  • Environment: 빌드에서 사용하는 환경 변수를 Key-Value 형태로 정의

  • Parameters: 파이프라인을 시작할 때 제공되는 사용자 파라미터 정의

  • Stage: step을 논리적으로 그룹화

  • When: 스테이지가 어떤 조건에 실행되어야 하는지를 정의

  • Tools: 설치할 도구를 정의하고 PATH에 추가

  • Input: 매개변수 입력

  • Parallel: 병렬로 실행할 스테이지를 지정

  • Matrix: 특정 스테이지에서 병렬로 실행할 매개변수의 조합을 지정

스텝

  • sh: 쉘 명령
  • custom: 젠킨스에서 제공하는 명령으로 sh의 래퍼
  • script: 시나리오를 이용

5)Commit Pipeline

  • 가장 기본적인 지속적 통합 프로세스가 Commit Pipeline
  • Repository로 Commit 이나 Push를 한 후 빌드 결과를 보고하는 파이프라인
  • 코드가 변경될 때 마다 파이프라인이 실행되기 때문에 빌드 시간은 5분을 넘지 않도록 해야 하고 리소스 사용도 합리적이어야 합니다
  • 커밋이 CD의 시작점이며 개발 프로세스에서 가장 중요한 피드백 사이트 정보를 제공
  • 과정
    체크 아웃: 레포지토리에서 소스 코드를 다운로드 받는 단계
    컴파일: 소스 코드를 컴파일하는 단계
    단위 테스트: 단위 테스트를 수행하는 단계

체크아웃

  • 파이프라인을 만들고 스크립트를 작성
    pipeline{
        agent any
        stages{
            stage("Checkout"){
                steps{
                    git url:'https://github.com/yachae1101/jenkins-test.git', branch:'main'
                }
            }
        }
    }
  • Build를 수행

    GitHub 레포지토리에 접근해서 코드를 clone 한 후, main으로 checkout 하는 것을 확인할 수 있다.

compile

  • 인간이 알아보는 코드를 운영체제나 vm이 알아볼 수 있는 코드로 변경하는 것
  • 자바에서는 javac 파일명으로 컴파일을 하지만 gradle에서는 ./gradlew compileJava
  • IntelliJ에서 웹 프로젝트를 생성
  • 소스 코드를 GitHub에 푸시
    • calculator 라는 레포지토리를 생성
      : https://github.com/yachae1101/calculator.git
    • IntelliJ에서 소스 코드를 GitHub에 push
      git init
      git add .
      git commit -m "init"
      git branch -M main
      git remote add origin https://github.com/yachae1101/calculator.git
      git push origin main
  • pipeline 스크립트 수정
    pipeline{
        agent any
        stages{
            stage("Checkout"){
                steps{
                    git url:'https://github.com/yachae1101/calculator.git', branch:'main'
                }
            }
            stage("Compile"){
                steps{
                    sh "chmod +x ./gradlew"
                    sh "./gradlew compileJava"
                }
            }
        }
    }
  • Build를 수행
  • 컴파일을 하고 난 후 단위 테스트를 수행

    • JUnit 을 이용해서 수행: .gradlew test

    • 실행: .gradlew bootRun

    • 프로젝트에 Service 클래스를 추가하고 작성(Calculator)

      import org.springframework.stereotype.Service;
      
      @Service
      public class Calculator {
         public int sum(int a, int b){
             return a + b;
         }
      }
    • Controller 클래스를 만들어서 사용자의 요청을 처리하는 메서드를 작성(CalculatorController)

      import lombok.RequiredArgsConstructor;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      @RequiredArgsConstructor
      public class CalculatorController {
         private final Calculator calculator;
      
         @RequestMapping("/sum")
         String sum(@RequestParam("a") Integer a,
                    @RequestParam("b") Integer b){
             return String.valueOf(calculator.sum(a, b));
         }
      }
    • 실행 한 후 브라우저에서 입력: http://localhost:8080/sum?a=10&b=20
      10 + 20 의 결과값인 30 이 출력된다.

    • test 디렉토리에 테스트를 위한 클래스를 추가하고 작성(CalculatorTest)

      import org.junit.Test;
      import static org.junit.Assert.assertEquals;
      
      public class CalculatorTest {
         private Calculator calculator = new Calculator();
         @Test
         public void testSum(){
             assertEquals(5, calculator.sum(2, 3));
         }
      }
    • build.gradle의 dependencies 부분에 라이브러리 의존성 추가하고 리빌드 버튼을 클릭

      testImplementation 'junit:junit:4.13.2'
    • ./gradlew test 명령으로 테스트를 수행

    • jenkins script 파일에 Test stage를 추가

      pipeline{
          agent any
          stages{
              stage("Checkout"){
                  steps{
                      git url:'https://github.com/yachae1101/calculator.git', branch:'main'
                  }
              }
              stage("Compile"){
                  steps{
                      sh "chmod +x ./gradlew"
                      sh "./gradlew compileJava"
                  }
              }
              stage("Test"){
                  steps{
                      sh "./gradlew test"
                  }
              }
          }
      }
    • IntelliJ에서 git push 를 진행

    • Build를 수행
      Checkout을 하고, Compile을 하고 Test Stage에서 JUnit을 이용해서 단위 테스트까지 수행한 것을 확인할 수 있다.

6)Jenkinsfile을 프로젝트에 포함

  • 루트 디렉토리에 Jenkinsfile을 만들어서 스크립트를 작성해서 사용
    • 이 경우에는 Repository에서 다운로드 받는 코드를 사용하지 않음
    • IntelliJ에서 루트 디렉토리에 Jenkinsfile을 추가하고 작성
      pipeline{
         agent any
         stages {
            stage("Permission"){
                 steps{
                     sh "chmod +x ./gradlew"
                 }
             }
             stage("Compile"){
                 steps{
                     sh "./gradlew compileJava"
                 }
             }
             stage("Test"){
                 steps{
                     sh "./gradlew test"
                 }
             }
         }
      }
  • Definition을 Pipeline script에서 Pipeline script from SCM으로 수정
  • SCM에서 git을 선택
  • Repository URL에 git hub URL을 설정
  • Branch 설정하고 저장
  • IntelliJ에서 git push 를 진행
  • Build를 수행
    GitHub에 있는 Jenkinsfile 의 명령대로 Build 작업을 수행하였다.

7)코드-품질 스테이지

  • 코드 커버리지
    • 여러 개발자가 개발을 하는데 특정 개발자 또는 모든 개발자가 단위 테스트를 수행하지 않는 경우 빌드가 될 수 는 있지만 코드가 안전하게 동작할지는 알 수 없음
    • 이런 경우에는 코드 전체를 대상으로 테스트를 진행하고 검증이 완료된 부분을 식별하는 코드 커버리지 도구를 추가해서 해결
    • 이를 이용하게 되면 테스트가 수행되지 않은 부분에 대한 보고서를 받을 수 있고 테스트 미수행 영역이 많으면 아예 빌드를 실패한 것으로 간주
    • Java의 경우는 이러한 도구로 JaCoCo 나 오픈 클로버, 코버추라다 등이 있습니다.
  • JaCoCo를 이용한 코드 커버리지 과정

    • JaCoCo 를 그래들 구성에 추가
      : build.gradle 파일의 plugins 부분에 id 'jacoco'

    • 빌드 중단 조건을 설정하고자 하는 경우에는 build.gradle에 설정을 추가

      jacocoTestCoverageVerification{
         violationRules {
             rule{
                 limit{
                     minimum = 0.2
                 }
             }
         }
      }

    • 터미널에서 실행

      ./gradlew test jacocoTestCoverageVerification

    • 보고서 만들기

      ./gradlew test jacocoTestReport
    • 보고서 확인: build/reports/jacoco/test/html/index.html

    • code coverage 스테이지를 Jenkinsfile의 파이프라인에 추가 후 push

      pipeline{
         agent any
         stages {
            stage("Permission"){
                 steps{
                     sh "chmod +x ./gradlew"
                 }
             }
             stage("Compile"){
                 steps{
                     sh "./gradlew compileJava"
                 }
             }
             stage("Test"){
                 steps{
                     sh "./gradlew test"
                 }
             }
             stage("Code Coverage"){
                steps{
                    sh "./gradlew jacocoTestCoverageVerification"
                    sh "./gradlew jacocoTestReport"
                }
             }
         }
      }
    • Jenkins에서 Build
      추가된 Code Coverage Stage까지 수행하고 build가 완료되었다.

0개의 댓글