🌥️Cloud Study🌥️/NHN

[ NHN Cloud ] 3-Tier Architecture 수동 프로비저닝-2 (Jenkins 초기 설정, 롤링 배포 및 접속 확인)

L_Chae 2024. 8. 6. 11:35

앞선 글에서 각 인스턴스별 설정들을 진행해주었다.

 

Jenkins 설정

  1. `sudo cat  /var/lib/jenkins/secrets/initialAdminPassword`로 Jenkins 초기 비밀번호를 출력, 권장 설치를 진행한다.
  2. Jenkins 관리 - Tools - Gradle 설치 (ID는 임의로 'GRADLE'로 설정)
  3. Jenkins 관리 - Plugins - Available plugins에서 SSH Agent, Pipeline: Stage View 설치
  4. Jenkins 관리  - Credentials - Github 웹 훅 토큰과 NHN Cloud에서 인스턴스 생성 시 지정한 .pem 설정
  5. 깃허브 레포지토리 - webhook의 주소를 Jenkins 인스턴스의 Public IP로 변경
    (ex: http://IP주소:8080/github-webhook/)
  6. 파이프라인 코드 입

Pipeline - Rolling 배포

AWS에서 사용했던 파이프라인 코드를 거의 그대로 사용했다.

다만 스프링 어플리케이션의 .jar 파일명이 빌드 시각에 따라 바뀌므로 해당 부분을 동적으로 추출하여 `env.JAR_NAME`에 저장하고,

이를 `deployApp` 함수에 전달하여 해당 파일명을 사용하는 방식으로 바꾸어주었다.

 

+ 빌드가 시작되기 전, 이전의 .jar 파일은 삭제하도록 설정 추가

pipeline {
    tools {
        gradle "GRADLE" // Jenkins에서 설정한 Gradle의 이름
    }

    agent any
    environment {
        JAR_NAME = '' // 빌드된 JAR 파일명을 저장할 변수
    }
    stages {
        stage('Clone') {
            steps { // main인지 master인지 확인하고 Pipeline Syntax 돌려서 이중으로 확인해보기
                git branch: 'main', url: 'https://github.com/lcl1380/KDT_Project3.git'
            }
        }

        stage('Clean Up Old Artifacts') {
            steps {
                // 기존의 .jar 파일들을 삭제
                sh 'rm -f build/custom-libs/*.jar'
            }
        }

        stage('Build') {
            steps {
                sh 'chmod +x ./gradlew'
                sh './gradlew clean build'
                script {
                    // 빌드된 JAR 파일명 추출
                    def jarFile = sh(script: "ls build/custom-libs/*.jar | head -n 1", returnStdout: true).trim()
                    env.JAR_NAME = jarFile.split('/').last()
                }
            }
        }
        
        stage('Test') {
            steps {
                script {
                    sh './gradlew test'
                }
            }
        }
        
        stage('Deploy A-Private Instance') {
            steps {
                script {
                    try {
                        // 첫 번째 인스턴스로 배포
                        deployApp('192.168.2.31', 22, env.JAR_NAME)
                        // 두 번째 인스턴스로 배포
                        // deployApp('192.168.2.32', 22, env.JAR_NAME)
                    } catch (Exception e) {
                        // 오류 발생 시 롤백
                        rollbackApp('192.168.2.31', 22)
                        // rollbackApp('192.168.2.32', 22)
                        throw e
                    }
                }
            }
        }
        
        // stage('Deploy B-Private Instance') {
        //     steps {
        //         script {
        //             try {
        //                 // 첫 번째 인스턴스로 배포
        //                 deployApp('192.168.5.31', 22, env.JAR_NAME))
        //                 // 두 번째 인스턴스로 배포
        //                 deployApp('192.168.2.32', 22, env.JAR_NAME)
        //             } catch (Exception e) {
        //                 // 오류 발생 시 롤백
        //                 rollbackApp('192.168.5.31', 22)
        //                 rollbackApp('192.168.5.32', 22)
        //                 throw e
        //             }
        //         }
        //     }
        // }
    }
    post {
        success {
            echo "배포가 성공적으로 완료되었습니다."
        }
        failure {
            echo "배포에 실패했습니다. 롤백을 수행했습니다."
        }
    }
}

def deployApp(targetServerIp, targetServerPort, jarName) {
    def deployPath = '/home/ubuntu'
    def runAppCommand = "nohup java -jar $deployPath/$jarName > nohup.log 2>&1 &"
    def checkLogCommand = "grep -q 'Started logging-sample-prj in' $deployPath/nohup.log"
    def checkProcessCommand = "pgrep -f $jarName"
        
    // 서버에 파일을 SCP로 전송
    sshagent(['KDT_Project3_NHN']) { // 이 부분에서 'KDT_Project3_NHN'는 Jenkins에 등록한 Credential ID (NHN에서 발급한 키 페어)
        // 기존 애플리케이션 프로세스 종료
        sh "ssh -o StrictHostKeyChecking=no -p $targetServerPort ubuntu@$targetServerIp 'ps -ef | grep java | grep -v grep | awk \'{print \$2}\' | sudo xargs kill -9 || echo \"No process found\"'"

        // 새로운 JAR 파일 배포 및 애플리케이션 시작
        sh "scp -o StrictHostKeyChecking=no -P $targetServerPort build/custom-libs/$jarName ubuntu@$targetServerIp:$deployPath/"
        sh "ssh -o StrictHostKeyChecking=no -p $targetServerPort ubuntu@$targetServerIp '$runAppCommand'"
    }
}

def rollbackApp(targetServerIp, targetServerPort) {
    def previousJarPath = 'build/libs/previous-logging-sample-prj-0.0.1-SNAPSHOT.jar'
    def deployPath = '/home/ubuntu'
    def runAppCommand = "nohup java -jar $deployPath/previous-inclass-spring-security-0.0.1-SNAPSHOT.jar > nohup.log 2>&1 &"
        
    // 이전 버전의 JAR 파일을 배포하고 애플리케이션을 시작
    sshagent(['KDT_Project3_NHN']) { // 이 부분에서 'KDT_Project3_NHN'는 Jenkins에 등록한 Credential ID (NHN에서 발급한 키 페어)
        // 기존 애플리케이션 프로세스 종료
        sh "ssh -o StrictHostKeyChecking=no -p $targetServerPort ubuntu@$targetServerIp 'ps -ef | grep java | grep -v grep | awk \'{print \$2}\' | sudo xargs kill -9 || echo \"No process found\"'"

        // 이전 버전 JAR 파일 배포 및 애플리케이션 시작
        sh "scp -o StrictHostKeyChecking=no -P $targetServerPort $previousJarPath ubuntu@$targetServerIp:$deployPath/"
        sh "ssh -o StrictHostKeyChecking=no -p $targetServerPort ubuntu@$targetServerIp '$runAppCommand'"
    }
}