현대 오토에버 SW 스쿨 - 클라우드/버전관리_Jenkins

[Jenkins] - 프로젝트와 jenkins 연결

yongyongMom 2024. 11. 11. 17:49
SMALL

1. 프로젝트와 Jenkins 연결 - git hub

1) Spring Boot Project 생성

2) git hub 에 repository 만들어서 연결

3) Jenkins Server 에서 Code Checkout ( 코드를 다운로드 받아오는 것)

  • 하나는 직접 스크립트를 작성해야 받아올 수 있고 다른 하나는 git 과 연결해서 코드를 받아올 수 있음
  • Item 을 Pipeline 으로 생성하고 Script 부분에서 SCM 으로 수정하고 repository 를 설정
    • 프로젝트에 Jenkinsfile 을 추가하고 빌드

2. 단위 테스트

class 만 있으면 가능함

1) 테스트 전에 컴파일이나 빌드가 먼저

  • 컴파일 :: 운영체제나 VM 이 인식할 수 있는 코드 생성 - 테스트하기 위해서 수행 (java -> class :: 문법 테스트만)
  • 빌드 : 실행 가능한 코드를 생성 - 배포하기 전에 수행, 운영체제에 맞는 startup 코드를 추가
  • java -> class (유닛테스트) -> binary file (통합테스트)
  • 단위 테스트를 수행하기 위한 코드를 추가
    public class JenkinsService {
       public int  hap(int n){
           int result = 0;
           for(int i=1; i<=n; i++){
               result += i;
           }
           return result;
       }
    }

  • 스크립트 파일에 추가 : 에러가 발생하면 문법 에러 OR 접근 권한에 관련된 에러
    • 윈도우즈는 읽기와 쓰기 권한만 부여 
    • MAC 과 LINUX 는 실행권한이 별도로 주어짐
    • 윈도우즈에서 작성할 실행 파일은 MAC 이나 LINUX 에서 가져가서 실행하고자 하면 실행권한 오류 발생
      pipeline{
         agent any
         stages{
             stage("Permission"){
                 steps{
                     sh "chmod +x ./gradlew"
                 }
             }
      
             stage("Compile"){
                 steps{
                     sh "./gradlew compileJava"
                 }
             }
         }
      }

2) 단위 테스트

  • 단위 테스트를 위한 코드를 작성 : test 디렉터리의 패키지에 클래스를 생성
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class Jenkins1111Test {

   //테스트할 메서드를 가진 클래스를 가져오기
   private JenkinsService service = new JenkinsService();

   @Test
   public void testService(){
       assertEquals(55, service.hap(10));
   }
}
  • 테스트 수행 : ./gradlew test
  • 스크립트에 스테이지 추가
stage("Unit Test"){
   steps{
       sh "./gradlew test"
   }
}

 

3) Code Coverage

  • 개요
    • 코드 전체를 대상으로 테스트를 진행하고 검증이 완료된 부분을 식별하는 작업
    • 일정 부분 테스트를 진행하지 않은 경우 빌드를 중단
  • build.gradle 파일에 의존성을 설정하고 기본 설정을 추가
    • 20% 이상 코드를 테스트하지 않은 경우 빌드 실패
plugins {
   id 'java'
   id 'org.springframework.boot' version '3.3.5'
   id 'io.spring.dependency-management' version '1.1.6'
  
   id 'jacoco'
}

jacocoTestCoverageVerification{
   violationRules{
       rule{
           limit{
               minimum = 0.2
           }
       }
   }
  • 수행
./gradlew test jacoco TestCoverageVerification
  • 보고서 생성 (build/reports 디렉터리에 생성)
./gradlew test jacoco TestReport
  • 스테이지에 추가
stage("Code Coverage"){
steps{
   sh "./gradlew jacocoTestCoverageVerification"
   sh "./gradlew jacocoTestReport"
   publishHTML(target: [
   reportDir: 'build/reports/jacoco/test/html',
   reportFiles: 'index.html',
   reportName: 'Jacoco Report'
   ])
}
  • HTML Publisher 플러그인을 설치하고 수행
  • 성공 -> 프로젝트 이름 누름 -> HTML 링크가 보임

 

4) 정적 코드 분석

  • 개요
    • 컴파일이나 실행과는 관련없는 코드를 작성할 때 서로 간에 암묵적으로 정한 규칙을 확인하는 작업
    • Checkstyle 인 Sonarqube 를 많이 이용
  • Checkstyle 을 이용한 정적 코드 분석
    • build.gradle 파일에 의존성 라이브러리와 기본 환경 코드를 추가 
    • plugins { id 'java' id 'org.springframework.boot' version '3.3.5' id 'io.spring.dependency-management' version '1.1.6' id 'jacoco' id 'checkstyle' } checkstyle { maxWarnings = 0 configFile = file("${rootDir}/config/checkstyle.xml") configProperties = ["suppressionFile":"${rootDir}/config/checkstyle-suppressions.xml"] toolVersion = "8.42" }
    • 루트 디렉터리에 config 디렉터리를 생성하고 checkstyle.xml 파일을 만들어서 작성:
      https://checkstyle.sourceforge.io/config.html 에서 파일을 다운로드 받아서 참고해서 작성
      <?xml version="1.0" ?>
      <!DOCTYPE module PUBLIC
             "-//Checkstyle//DTD Checkstyle Configuration 1.3//EN"
             "https://checkstyle.org/dtds/configuration_1_3.dtd">
      <module name="Checker">
         <module name="TreeWalker">
             <module name="ConstantName" />
         </module>
      </module>

    • 실행 : ./gradlew checkstyleMain
    • 스테이지에 추가
      stage("Static Code Analysis"){
        steps{
            sh "./gradlew checkstyleMain"
                publishHTML(target: [
                            reportDir: 'build/reports/checkstyle/',
                            reportFiles: 'main.html',
                            reportName: 'Checkstyle Report'
                ])
        }
      }

    • checkstyle 보다 sonarqube 가 더 많이 사용되므로 sonarqube 로 사용을 해보는 것이 좋음

 

3. 트리거

1) 주기적인 수행

  • 스케줄 작성 방법은 Linux 와 Crontab 과 동일
  • Build periodically: commit 여부에 상관없이 무조건 빌드를 다시 수행
  • Poll SCM : 변경 사항이 있을 때만 빌드를 다시 수행

 

2) 외부에서 Code Repository 에 이벤트가 발생했을 때 수행

  • git hub 에서 token 을 발급 
    • 레포지토리에 대한 권한과 workflow 에 대한 권한은 반드시 설정
  • git hub 의 레포지토리에서 web-hook 을 등록
    • payload-url 설정 : http://jenkins URL/github-webhook
  • jenkins server 에서 credential 을 생성
    • Dash board 메뉴에서 configure credential 을 선택 -> global 부분 클릭해서 생성
    • kind 부분을 secret text 로 수정 -> password 부분에 토큰 값을 대입
  • jenkins item 에서 구성 부분을 클릭해서 액션을 수정 
    • GitHub hook trigger for GITScm polling 에 체크

 

3) 빌드 자동화

  • 주기적인 자동화 
    • 빌드한느데 시간이 오래 걸리는데 push 가 자주 발생하는 경우
    • push event 가 발생했을 때 빌드 : 빌드하는데 시간이 짧게 걸리는 경우

 

4. 이미지 빌드 및 업로드

1) 코드를 수정

  • Service 클래스를 수정
import org.springframework.stereotype.Service;

@Service
public class JenkinsService {

   public int  hap(int n){
       int result = 0;
       for(int i=1; i<=n; i++){
           result += i;
       }
       return result;
   }
}
  • Controller 클래스를 추가
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
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 JenkinsController {
   private final JenkinsService jenkinsService;

  
   @RequestMapping("/")
   public String index(@RequestParam("data") int data) {
       return String.valueOf(jenkinsService.hap(data));
   }
}

 

2) 실행하고 테스트

  • http://localhost:8080?data=10

3) gradle 프로젝트 빌드

  • 빌드는 실행 가능한 상태로 만들어주는 작업
  • 빌드 도구에 따라 빌드하는 명령어는 다름
    • gradle 의 경우 : ./gradlew clean build
    • maven 의 경우 : ./mvnw clean build
  • 빌드 결과는 build 라는 디렉터리에 저장
    • 실행할 애플리케이션이 build 디렉터리에 존재

4) 이미지 빌드

  • Dockerfile 을 프로젝트 디렉터리에 생성하고 작성
FROM bellsoft/liberica-openjdk-alpine:17

ARG JAR_FILE=build/libs/*.jar

COPY ${JAR_FILE} app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]
  • 이미지 빌드
docker build -t 이미지이름 .

 

5) 빌드 내용을 stage 에 추가

  • Gradel Build: Jenkinsfile 에 추가하고 push
stage("Gradle Build"){
  steps{
      sh "./gradlew clean build"
  }
}
  • Docker Image Build
stage("Docker Image Build"){
  steps{
      sh "docker build -t jenkins1111 ."
  }
}
  • Docker Image Build 단계에서 실패하면 Jenkins 에서 Docker 를 사용할 떄는 Docke pulugin 을 설치해야 함

 

6) 컨테이너로 생성해서 테스트 진행

  • 컨테이너 생성
docker run -d --name 컨테이너이름 -p 외부포트번호:내부포트번호 이미지이름
  • 확인
curl http://locahost:외부포트번호?data=정수

 

7) 도커 허브에 push

  • 도커 허브에 레포지토리를 생성
  • 도커 허브의 레포지토리에 업로드 할 수 있게 도커 이미지 태그를 변경
docker tage 이미지이름 tpdms0159/jenkins1111:latest
  • 도커 푸시
docker push 이미지이름

 

8) jenkins 에서 도커 허브에 푸시

  • credential 추가
  • 변수를 추가하는 stage 추가
stage("Set Variables"){
   steps{
       echo "SetVariables"

       script{
           DOCKER_HUB_URL = 'registry.hub.docker.com'
           DOCKER_HUB_FULL_URL = 'https://' + DOCKER_HUB_URL
           DOCKER_HUB_CREDENTIAL_ID = 'docker-hub'
       }
   }
}
  • GIT 과 외부 계정을 이용할 때 토큰 값을 코드에 직접 입력하면 GIT 또는 외부 계정이 잠김
  • 직접 입력한 코드를 삭제하더라도 기록이 남아서 계정은 잠김
반응형
LIST