[ EnjoyDelivery ] 이슈 4. 다중 서버에서의 CI / CD : Jenkins Pipeline

Dayeon myeong·2021년 12월 4일
0

Enjoy Delivery

목록 보기
4/4
post-custom-banner

프로젝트 코드를 develop 브랜치에 합치면서 통합 오류로 인해 자주 버그를 수정하곤 했습니다. 또한 여러 대의 서버에 배포를 수작업으로 진행하면서 매번 build하고 jar를 수행하고 이러한 과정을 했습니다. 이는 매우 불필요한 시간 낭비라고 생각이 들었습니다. 이를 해결하기 위해 CI / CD를 적용했습니다.

CI / CD

redhat 이미지

CI란 지속적인 통합(Continuous Integration) 으로 프로젝트를 진행하며 코드를 "통합"하면서 자동화된 테스트와 빌드를 수행합니다. 이렇게 함으로써 오류를 빨리 찾을 수 있게 됩니다. 오류를 빨리 찾는다는 것은 그만큼 빠르게 버그 수정이 가능하게 됩니다.

CD란 지속적인 전달 Continuous Delivery, 지속적인 배포 Countinuos Deploy 두가지 의미로 혼용해서 사용합니다.

지속적인 배포(Continuous Deploy)는 자동화된 배포를 계속 지원합니다. 예를 들어 개발자가 코드를 변경하면 Git 레포지토리에서부터 프로덕션용 서버까지 바로 자동으로 "배포"되도록 하는 것을 말합니다.

지속적인 전달 (Continuous Delivery)은 코드의 변경사항이 버그 테스트를 거쳐 리포지토리(Github 과 같은 곳)에 자동으로 "업로드"되는 것을 뜻하며, 배포는 수동으로 진행합니다.

Jenkins Pipeline

젠킨스 파이프라인은 젠킨스에서 CI / CD 모든 과정을(통합, 빌드, 테스트 , 배포) 자동화하도록 지원하는 기술입니다. Jenkinsfile을 작성함으로써 파이프라인이 코드로 구현될 수 있습니다.

Jenkins를 이용한 CI / CD 과정

젠킨스 파이프라인을 만들고 백엔드에 배포되기까지 다음과 같은 과정을 거칩니다.

  1. 개발자가 Github에 수정한 코드를 push한다.
  2. Github webhook은 이를 감지하고 Jenkins에 push hook을 보낸다.
  3. Jenkins에서는 push hook을 받으면 코드를 가져온다.
  4. Jenkins에서 테스트, 빌드를 진행하고, 설정된 여러개의 서버에 각각 배포한다.

Jenkinsfile

def ssh_publisher(SERVER_CONFIG) {
    sshPublisher(
        continueOnError: false,
        failOnError: true,
        publishers:[
            sshPublisherDesc(
                configName: "${SERVER_CONFIG}",
                verbose: true,
                transfers: [
                    sshTransfer(
                        sourceFiles: "build/libs/enjoy-delivery.jar, deploy.sh",
                        remoteDirectory: "project"
                    )
                ]
            )
        ]
    )
}

pipeline {
    agent any
    tools {
      gradle 'Gradle 7.2'
    }
    options {
        timeout(time: 1, unit: 'HOURS')
    }
    environment {
        SOURCECODE_JENKINS_CREDENTIAL_ID = '...'
        SOURCE_CODE_URL = 'https://github.com/f-lab-edu/enjoy-delivery/'
        RELEASE_BRANCH = 'develop'
        SERVER_LIST = 'server1,server2'
    }
    stages {
        stage('clone') {
            steps {
                git url: "$SOURCE_CODE_URL",
                    branch: "$RELEASE_BRANCH",
                    credentialsId: "$SOURCECODE_JENKINS_CREDENTIAL_ID"
                sh "ls -al"
            }
        }


        stage('backend build') {
            steps {
                sh "pwd"
                sh "gradle clean test"
                echo "build.."
                sh "gradle build -s"
            }
        }

        stage('server deploy') {
            steps {
              echo "deploy"
              echo "${SERVER_LIST}"

              script {
                SERVER_LIST.tokenize(',').each {
                  echo "SERVER: ${it}"
                  ssh_publisher("${it}")
                  sh "chmod +x ./deploy.sh"
                  sh "./deploy.sh"
                }
              }
            }
        }
    }
}

작성한 젠킨스 파이프라인입니다. 다음과 같은 과정을 거칩니다.

  • stage clone : 깃에서 코드를 가져옴
  • stage backend build : gradle을 이용해 테스트 빌드하여 enjoy-delivery.jar 파일을 생성한다.
  • stage server deploy : ssh_publisher함수를 호출하여 jar 파일과 deploy.sh를 각 서버의 project 폴더에 보낸다. 그리고 deploy.sh를 실행하여 배포를 진행한다.

(public over SSH 플러그인을 사용해 원격 서버 2개를 server1, server2로 미리 등록했습니다.)

deploy.sh

#!/bin/bash

REPOSITORY=build/libs
PROJECT_NAME=enjoy-delivery

echo "> 현재 구동중인 애플리케이션 pid 확인"

CURRENT_PID=$(pgrep -f ${PROJECT_NAME}*.jar)

echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID"

if [ -z "$CURRENT_PID" ]; then
   echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
else
   echo "> kill -15 $CURRENT_PID"
   kill -15 $CURRENT_PID
   sleep 5
fi

echo "> 새 애플리케이션 배포"

JAR_NAME=$(ls $REPOSITORY | grep ${PROJECT_NAME} | tail -n 1)

echo "> JAR Name: $JAR_NAME"

nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &

deploy.sh은 현재 구동중인 어플리케이션이 있으면 종료하고, 새로운 애플리케이션을 백그라운드로 배포합니다.

결과 및 사용 후기

실행 결과 이미지

실제로 사용해본 결과 코드를 합칠 때 오류를 빨리 알아챌 수 있어서 편리하고, 자동 배포가 가능해서 매우 편리했습니다. 번거로운 통합 오류를 찾거나 배포 과정을 거치지 않게 되어 문제를 해결할 수 있게 되었습니다.

참고 문헌

마틴파울러 - CI

마틴파울러 - CD

Jenkins Pipeline

Redhat : What is CI/CD?

Webhook을 이용하여 CI CD 구성하기

profile
부족함을 당당히 마주하는 용기
post-custom-banner

0개의 댓글