FireDrago

[배포] jenkins 사용하여 배포 자동화 하기 본문

프로그래밍/배포

[배포] jenkins 사용하여 배포 자동화 하기

화이용 2024. 7. 27. 13:14

jenkins 뭐하는 건데?

Jenkins를 사용하면 Github 리포지토리에서 코드를 다운로드하고,

자동으로 빌드하여 생성된 jar 파일을 서버에 전달하고 실행할 수 있다.

이 모든 작업이 버튼 한 번으로 가능해진다.

  1. Github 코드 다운로드
  2. Build: jar 파일 생성
  3. 백엔드 서버에 jar 전달
  4. jar 파일 실행

또한, Github webhook 설정을 추가하면 Github에 코드가 push될 때 이 작업을 자동으로 실행할 수도 있다.

webhook 설정에 대한 자세한 내용은 다음 포스트에서 알아보자

 

1. 리눅스 서버에 Docker 와 jenkins 설치하기

먼저 vultr 인스턴스를 하나 생성했다. os는 RockyLinux 9버전을 사용했다. jenkins를 사용하기 위한 서버다.

 

1. 리눅스 업데이트 :

시스템의 패키지 관리자(dnf)를 사용하여 설치된 모든 패키지를 최신 버전으로 업데이트하는 명령

시스템이 안정적이고 안전하게 동작하도록 보장하기 위해 실행한다.

sudo dnf update -y 

 

2. 도커 설치: 도커를 설치하고 젠킨스 이미지를 설치하는 이유는 설치가 간편하고, 여러 서버에서 일관된 환경을 제공한다

sudo dnf install dnf-plugins-core -y
   - DNF의 기능을 확장하여 추가적인 명령어나 옵션을 사용할 수 있게 해준다.

sudo dnf confing-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo 
   - Docker 패키지를 설치할 때 Docker의 공식 저장소에서 최신 버전의 Docker를 다운로드할 수 있도록 한다.

sudo dnf install docker-ce docker-ce-cli containerd.io -y
   - docker-ce (Community Edition): Docker의 오픈 소스 버전을 의미한다.
   - docker-ce-cli: Docker 명령줄 인터페이스(CLI)
   - containerd.io: 컨테이너 런타임 Docker의 핵심 컴포넌트 중 하나로, 컨테이너를 생성하고 관리한다.

 

3. 도커 서비스 시작 :

sudo systemctl start docker 
    - 도커를 실행한다.
sudo systemctl enable docker
    - 시스템 부팅시 도커가 자동으로 시작되도록 한다.

 

4. jenkins 도커 이미지를 pull & 컨테이너 시작 : Docker 컨테이너에서 Jenkins를 실행

sudo docker run -d -p 8080:8080 -p 50000:50000 --name jenkins --restart=always
-v jenkins_home:/var/jenkins_home jenkins/jenkins:lts

    - '-p 8080:8080' : 호스트의 포트 8080을 컨테이너의 포트 8080에 매핑, jenkins 웹 인터페이스 접속 포트
    - '-p 50000:50000' : 호스트의 포트 50000을 컨테이너의 포트 50000에 매핑,  Jenkins 에이전트와 통신 포트
    - ' --name jenkins' : 생성되는 컨테이너의 이름을 jenkins로 지정, 컨테이너를 쉽게 식별하고 관리
    - ' --restart=always ' : Docker 데몬이 시작될 때, 컨테이너가 중지되었을 때 자동으로 재시작하도록 설정
    - ' -v jenkins_home:/var/jenkins_home ' : Jenkins의 데이터(설정, 빌드 로그, 플러그인 등)를 영구적으로 저장
    - ' jenkins/jenkins:lts' : Jenkins의 LTS(Long Term Support) 버전 이미지를 사용, (안정적인 버전)

jenkins 환경설정

5. 서버ip주소:8080 => 젠킨스 접속

6. 젠킨스 초기 비밀번호를 확인하고 접속할때 입력해준다.

sudo docker exec jenkins cat /var/jenkins_home/secrets/initialAdminPassword
    - 젠킨스 초기 비밀번호를 확인하고 접속할 때 입력해준다.

 

7. 'install suggested plugins' 눌러 플러그인 설치한다. 젠킨스 계정을 생성한다.

8. new item -> Pipeline 생성한다.

9. 파이프 라인 스크립트를 작성한다.

pipeline {
    agent any

    tools {
        gradle 'Gradle'
    }

    environment {
        JASYPT_PASSWORD = credentials('jasypt-password-id')  // JASYPT 암호화 비밀번호를 환경 변수로 설정
        SERVER_IP = '***.***.***.'  // 배포할 서버의 IP 주소
        DEPLOY_PATH = '/root'  // 서버의 배포 경로
        JAR_FILE = 'build/libs/bobzip-0.0.1-SNAPSHOT.jar'  // 빌드된 JAR 파일 경로
        LOG_FILE = 'app.log'  // 애플리케이션 로그 파일 이름
        RUN_APP_COMMAND = "nohup java -Dspring.profiles.active=prod -Djasypt.encryptor.password=${JASYPT_PASSWORD} -jar $DEPLOY_PATH/bobzip-0.0.1-SNAPSHOT.jar > $DEPLOY_PATH/$LOG_FILE 2>&1 &"  // 애플리케이션 실행 명령
        CHECK_LOG_COMMAND = "grep -q 'Started BobzipApplication in' $DEPLOY_PATH/$LOG_FILE"  // 로그에서 애플리케이션 시작 확인 명령
        STOP_APP_COMMAND = """
            pgrep -f 'bobzip-0.0.1-SNAPSHOT.jar' && \
            pkill -f 'bobzip-0.0.1-SNAPSHOT.jar' || \
            echo "No process found"
        """  // 애플리케이션 종료 명령
    }

    stages {
        stage('Checkout') {
            steps {
                git url: 'https://github.com/Firedrago95/project_bobzip', branch: 'main' // Git 저장소에서 코드 체크아웃
            }
        }

        stage('Prepare') {
            steps {
                script {
                    sh 'chmod +x ./gradlew'  // gradlew 파일에 실행 권한 추가
                }
            }
        }

        stage('Build') {
            steps {
                script {
                    sh "./gradlew clean build -x test -Pjasypt.encryptor.password=${JASYPT_PASSWORD}"  // Gradle을 사용하여 빌드 수행, 테스트 제외
                }
            }
        }

        stage('Deploy') {
            steps {
                script {
                    sshagent(['deploy_ssh_key']) {
                        // 기존 애플리케이션 종료
                        sh script: "ssh root@$SERVER_IP '${STOP_APP_COMMAND}'", returnStatus: true

                        // JAR 파일을 원격 서버로 복사
                        sh "scp -o StrictHostKeyChecking=no $JAR_FILE root@$SERVER_IP:$DEPLOY_PATH/"

                        // 원격 서버에서 애플리케이션을 백그라운드에서 실행
                        sh """
                        ssh -o StrictHostKeyChecking=no root@$SERVER_IP '
                            echo "Starting new application..."
                            $RUN_APP_COMMAND
                        '
                        """

                        // 애플리케이션이 시작될 시간을 주기 위해 30초 대기
                        sleep 30

                        // 로그 파일에서 애플리케이션 시작 메시지를 확인
                        def result = sh(script: "ssh -o StrictHostKeyChecking=no root@$SERVER_IP '$CHECK_LOG_COMMAND'", returnStatus: true)
                        if (result == 0) {
                            echo 'Deployment was successful.'  // 배포 성공 메시지 출력
                        } else {
                            error 'Deployment failed.'  // 배포 실패 메시지 출력
                        }
                    }
                }
            }
        }
    }
    
    post {
        success {
            echo 'Pipeline completed successfully.'  // 파이프라인 성공 메시지 출력
        }
        failure {
            echo 'Pipeline failed'  // 파이프라인 실패 메시지 출력
        }
    }    
}

 

10. 파이프라인 스크립트에서 Gradle 사용하기 위해 젠킨스 관리페이지 > Tools > Gradle installations name 'Gradle'

11. 개인키 공개키 설정

docker ps -q 
    - 컨테이너 id 확인
docker exec -it [컨테이너id] /bin/bash
    - bash 설정 파일로 들어온다.
ssh-keygen -t rsa -b 4096 
    - 개인키 / 공개키 쌍 생성
cat /var/jenkins_home/.ssh/id_rsa.pub 
    - 공개키 복사

---------------------------------- 애플리케이션 설치된 서버로 이동 ----------------------------
vi ~/.ssh/authorized_keys
    - 입력 'i'로 편집모드 진입 => 복사한 공개키 붙여넣기

서버의 방화벽 설정, 자바버전 설치

---------------------------------- jenkins 웹 인터페이스 --------------------------------------------
jenkins 관리 > 플러그인 > ssh agent 플러그인 설치
jenkins 관리 > credentials > add credentials > SSHUsername with private key
             id = 'deploy_ssh_key',   username = jenkins
             private key는 "cat /var/jenkins_home/.ssh/id_rsa" 실행 붙여넣기 (----start-----, -----END---- 포함) 

 

 

< jenkins 배포된 이후, 계속 실행중인 경우>

- 애플리케이션 설치된 서버에서 'ps -aux | grep java' : 'java' 이름을 가진 실행중인 프로세스를 검색

- kill -15 [프로세스 id] : 애플리케이션을 종료

- 파이프라인 수정 : 'nohub' 사용으로 특정 로그 있으면 성공, 실패 출력하도록 변경

nohup java -Dspring.profiles.active=prod -Djasypt.encryptor.password=${JASYPT_PASSWORD} -jar $DEPLOY_PATH/bobzip-0.0.1-SNAPSHOT.jar

'지금 빌드' 누르면 빌드가 잘 실행되는것을 볼 수 있다.