본문 바로가기

AWS

[EKS] Jenkins로 CI 수행하기 - Maven Build 및 Image ECR Push

반응형

전체적인 과정은 다음과 같다.

 

1. Git -> main 브랜치에서 Push 이벤트가 발생하면 Webhook이 발생한다.

 

2. Webhook은 Jenkins 서버에게 POST로 날린다.

 

3. Jenkins는 기 설정된 Trigger 조건(Github hook trigger for GITScm polling)에 의거하여 Trigger가 되며, Jenkins Pipeline을 수행하게 된다.

 

4. Jenkins 서버 내에서 Pipeline에 정의된 대로 작업들을 수행한다.

    1) Git Checkout (소스 코드를 받아온다.)

    2) Maven으로 Springboot 프로젝트를 Build하여 JAR 파일로 떨군다.

    3) Docker를 이용하여 Image 파일로 생성하고, ECR 컨테이너 레지스트리로 Push한다.


고로, Jenkins는 GitECR에 대한 인증, 인가를 수행할 수 있는 토큰 혹은 인증 정보를 가지고 있어야 한다.

 

=> Git에는 Username, Password(Token)을 활용할 것이며 AWS에서는 Access Key, Secret Key를 활용할 것이다.

     Access Key와 Secret Key는 ECR 관련 권한만 부여하면 된다.

 

 

전체적인 과정

 

1. GitHub 세팅 및 WebHook 설정

 

2. Plugin 세팅 및 Credentials 세팅

 

3. Pipeline project 생성 및 세팅

 

4. Jenkinsfile 생성 및 Git push 이벤트 수행 시 웹훅 → Jenkins 트리거 → CI 수행


1. GitHub 세팅 및 WebHook 설정

1. Git을 세팅한다. 해당 Git에서 SpringBoot 소스 코드 및 Jenkinsfile을 참조하게 된다.

 

2. Webhook을 설정한다.

 

처음에 Webhook 테스트를 진행할 때 실패가 떠서 IP Range를 허용해주었다.

참고 : https://api.github.com/meta

 

* Terraform 소스 코드 중 일부 (Security Group을 추가)

Jenkins 서버 내에서 tcpdump로 확인할 때 정상적으로 Webhook 테스트가 수행되는 모습

 

 

2. Plugin 세팅 및 Credentials 세팅

Jenkins 관리 → 플러그인 관리로 들어간다.

 

필요한 플러그인 목록

 

1. Amazon ECR plugin

⇒ ECR에 편리하게 접근하기 위한 Plugin이다.

URL : https://plugins.jenkins.io/amazon-ecr/

 

2. Docker pipeline

 

3. AWS Global Configuration

 

Credentials 세팅

1) Jenkins 서버가 ECR API를 사용할 수 있는 권한, 2) Jenkins 서버가 Git 레포지터리로부터 소스코드를 가져오는 권한

위의 2개가 필요하다.

Jenkins → Manage Credentials 클릭 → (global) → Add credentials 클릭

 

1. AWS Credential 생성

ECRUser 생성

 

AWS Credentials 클릭

 

ID는 추후 Jenkinsfile에서 파이프라인 내에 사용된다.

 

2. Git Credential 생성

 

GitHub Token의 경우 아래의 URL 등을 통해 방법을 확인하고 발급이 가능하다.

URL : https://hoohaha.tistory.com/37

 

Kind : username with password

Username : GitHub ID를 기입해준다.

Password : Token 값을 기입해준다.

ID : 추후 Jenkinsfile 내에 파이프라인으로 사용된다.

Description : 굳이 사용하지 않아도 된다.

 

이로 인해 Jenkins 서버가 Github 및 계정 ECR에 인증 및 인가 절차를 완료하였다.

 

 

3. Pipeline project 생성 및 세팅

 

Pipeline으로 선택한 뒤 OK를 클릭한다.

 

1. Github Project 클릭한 뒤 GitHub 레포지터리 URL 입력

2. Github hook trigger for GITScm polling

    ⇒ Git에서 Hook Trigger을 받을 수 있도록 설정

  

1. Pipeline script from SCM

    ⇒ SCM(Git)으로부터 Pipeline 스크립트를 받아올 수 있도록 함. Jenkins 내부에서 Jenkinsfile을 수정 및 설정하는 것이 아니라 Git Repo에서 관리하도록 한다.

2. Git Branch는 main 브랜치로 설정하되, 개발 혹은 다른 Branch 또한 설정이 가능하다.

 

Jenkinsfile 경로 지정한 뒤 Apply → 저장 클릭하면 초기 세팅은 완료된다.

 

 

4. Jenkinsfile 생성 및 Git push 이벤트 수행 시 웹훅 → Jenkins 트리거 → CI 수행

Jenkinsfile은 아래와 같으며, 문법 설명은 생략한다.

 

stages에는 여러 stage들이 정의되어 있으며, 보통 Git에서 소스 코드를 받아오고 빌드하고 정적 분석, 테스트 수행 후에 Docker Image를 Registry에 Push하는 과정이 주를 이루게 된다.

 

물론 Jenkinsfile 내부에는 보통 Private한 Git 혹은 SCM에 저장되기야 하겠지만 소스 코드는 언제 어디서든 유출될 가능성이 있기 때문에 안전하게 인증 정보 및 토큰 등을 저장하는 과정이 필수적이다.

 

그래서 ECR Credential과 Git Credential을 Global Credentials를 통해 저장하였으며, 여기서는 ID 값으로 가져와서 사용할 수 있다.

 

고로 Git 플러그인 혹은 ECR 플러그인 등을 활용할 때 기 설정한 ID 값을 활용하여 인증 및 인가를 수행할 수 있다.

pipeline {
    agent any

    tools {
      // Jenkins 'Global Tool Configuration' 에 설정한 버전과 연동
      maven 'apache-maven-3.8.1'
    }

    environment {
        ECR_PATH = '{YOUR-ACCOUNT-NUMBER}.dkr.ecr.ap-northeast-2.amazonaws.com'
        ECR_IMAGE = 'demo-maven-springboot'
        REGION = 'ap-northeast-2'
        ACCOUNT_ID='{YOUR-ACCOUNT-NUMBER}'
    }

    stages {
        stage('Git Clone from gitSCM') {
            steps {
                script {
                    try {
                        git branch: 'main', 
                            credentialsId: 'GitCredential',
                            url: 'https://github.com/pingping95/demo-springboot'
                        sh "ls -lat"
                        sh "sudo rm -rf ./.git"
                        env.cloneResult=true
                        
                    } catch (error) {
                        print(error)
                        env.cloneResult=false
                        currentBuild.result = 'FAILURE'
                    }
                }
            }
        }
        stage("Build JAR with Maven") {
            when {
                expression {
                    return env.cloneResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
                }                
            }
            steps {
                script{
                    try {
                        sh """
                        rm -rf deploy
                        mkdir deploy
                        mvn --version
                        java -version
                        """
                        sh "sed -i 's/  version:.*/  version: \${VERSION:v${env.BUILD_NUMBER}}/g' /var/lib/jenkins/workspace/${env.JOB_NAME}/src/main/resources/application.yaml"
                        sh "cat /var/lib/jenkins/workspace/${env.JOB_NAME}/src/main/resources/application.yaml"
                        sh 'mvn -e -Dmaven.test.failure.ignore=true clean install'
                        sh """
                        cd deploy
                        cp /var/lib/jenkins/workspace/${env.JOB_NAME}/target/*.jar ./${ECR_IMAGE}.jar
                        """
                        env.mavenBuildResult=true
                    } catch (error) {
                        print(error)
                        echo 'Remove Deploy Files'
                        sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*"
                        env.mavenBuildResult=false
                        currentBuild.result = 'FAILURE'
                    }
                }
            }
        }
        stage('Docker Build and Push to ECR'){
            when {
                expression {
                    return env.mavenBuildResult ==~ /(?i)(Y|YES|T|TRUE|ON|RUN)/
                }
            }
            steps {
                script{
                    try {
                        sh"""
                        #!/bin/bash
                        cat>Dockerfile<<-EOF
FROM openjdk:11-jre-slim
ENV JAVA_OPTS="-XX:InitialRAMPercentage=40.0 -XX:MaxRAMPercentage=80.0"
ADD ./deploy/${ECR_IMAGE}.jar /home/${ECR_IMAGE}.jar
CMD nohup java -jar /home/${ECR_IMAGE}.jar 1> /dev/null 2>&1
EXPOSE 8080
EOF"""
                        docker.withRegistry("https://${ECR_PATH}", "ecr:${REGION}:AWSCredentials") {
                            def image = docker.build("${ECR_PATH}/${ECR_IMAGE}:${env.BUILD_NUMBER}")
                            image.push()
                        }
                        
                        echo 'Remove Deploy Files'
                        sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*"
                        env.dockerBuildResult=true
                    } catch (error) {
                        print(error)
                        echo 'Remove Deploy Files'
                        sh "sudo rm -rf /var/lib/jenkins/workspace/${env.JOB_NAME}/*"
                        env.dockerBuildResult=false
                        currentBuild.result = 'FAILURE'
                    }
                }
            }
        }
    }
}

 

Git Push

 

Git → Jenkins로 웹훅을 보내 Trigger 유발

 

CI 수행된 것 확인

 

Log에서 정상적으로 수행된 것을 확인할 수 있다.

 

ECR에 Docker Image가 Push 된 것을 확인

 

그 다음의 작업으로 CI가 완료되면 자동으로 KubeAPI에게 배포하도록 CD 과정을 추가할 수 있다.

 

이는 ArgoCD로 Sync를 맞추며 CI 과정이 완료되면 CD가 수행될 수 있도록 할 것이다.

 

 

 

 

 

Ref

https://aws-diary.tistory.com/53?category=753093

 

 

 

반응형