[Jenkins] 원격 Jenkins 서버로 CI/CD 환경 구현하기

2023. 2. 9. 15:42Jenkins

이번 포스팅에선 jenkins pipeline 생성 방법과 jenkinsfile script를 작성하여 애플리케이션을 배포하는 방법에 대해서 다뤄보고자 한다.

CI/CD Flow

  1. github로부터 소스코드 pull
  2. build & test
  3. 빌드된 jar 파일 배포 서버로 전송
  4. 애플리케이션 서버에 접속
  5. 전송된 jar 파일 실행하여 애플리케이션 배포

Jenkins Global Configuration 설정

JDK, Git, Gradle 등의 설정을 미리 생성해놓고 여러 Jenkins Project에서 참조하여 사용할 수 있도록 한다.

JDK 설정

JAVA_HOME 값을 출력하여 jenkins console에 등록한다.

$ echo $JAVA_HOME

Git 설정

git 커멘드 경로도 등록해준다.

$ which git

Jenkins Pipeline 생성

Jenkins Pipeline은 코드를 통해서 지속적인 배포 환경을 구축할 수 있는 Jenkins 모듈이다.

Jenkins와 Github 연동시 SSH 연동 방식을 사용하는데 Credentials에 미리 생성한 Credential을 선택해준다.

Jenkins와 Github 연동 방법은 이전 포스팅에서 다뤘다.

https://steadycode.tistory.com/87

 

[Jenkins] Jenkins Github 연동하기

이번 포스팅에선 Jenkins와 Github간 연동 방법에 대해서 다뤄 보겠다. 공개키/비밀키 생성 실행중인 젠킨스 사용자를 확인한다. ps aux | grep jenkins 현재 사용자를 jenkins로 변경하고 shell command 실행 권

steadycode.tistory.com

Jenkinsfile Script 경로 지정

jenkins 서버가 빌드시 jenkinsfile에 정의된 내용대로 동작하는데 해당 script 파일의 경로를 지정해준다.

 


민감 데이터 등록

민감 데이터는 Github에 공개되어선 안되기 때문에 Jenkins Credential에 등록하고 Script에서 참조하도록 한다.

Jenkins Credential 등록

‘Secret text’ 타입을 선택하고 key-value 형태로 민감 데이터를 credential로 등록한다.

아래 예시 처럼 Script 단에서 credential(id) 형태로 전역 변수에 할당하고 $variable 변수로 매핑한다.

pipeline {
    agent any
    environment {
        DEPLOY_SERVER_ID = credentials('deployServerId')
        DEPLOY_SERVER_PASSWORD = credentials('deployServerPassword')
    }

        stage('Send Jar') {
        steps {
            sh 'sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 rm -rf build/fire_inform-0.0.1-SNAPSHOT.jar'
            sh 'sshpass -p $DEPLOY_SERVER_PASSWORD scp -P 12308 -o StrictHostKeyChecking=no /var/lib/jenkins/workspace/pipeline/build/libs/fire_inform-0.0.1-SNAPSHOT.jar $DEPLOY_SERVER_ID@106.10.59.248:build'
        }
    }
}

Jenkinsfile 작성

본격적으로 script를 작성해보자

다음 경로에 Jenkinsfile을 생성한다.

Jenkins Pipeline Script에는 ‘Scripted Pipeline’과 ‘Declarative Pipeline’ 두 가지 syntax가 존재하는데 ‘Declarative Pipeline’를 사용했다.

Declarative Pipeline는 지원하지 않는 플러그인이 존재하여 개발자의 자유도를 낮출 수 있지만 단순하고 가독성이 높다는 특징이 있다.

pipeline {
    agent any
    environment {
        DEPLOY_SERVER_ID = credentials("deployServerId")
        DEPLOY_SERVER_PASSWORD = credentials("deployServerPassword")
        SECRET_KEY = credentials('SECRET_KEY')
        DB_USERNAME = credentials('DB_USERNAME')
        DB_PASSWORD = credentials('DB_PASSWORD')
        DB_URL = credentials('DB_URL')
        DB_PORT = credentials('DB_PORT')
    }

    stages {
        stage("Clean Up") {
            steps {
                sh "pwd"
                sh "rm -rf *"
            }
        }

        stage("Checkout") {
            steps {
                git url: "<https://github.com/f-lab-edu/ChatBot.git>", branch: "main",
                credentialsId: "cbf50f14-c18f-4bc0-a792-668780641040"
            }
        }

        stage("Build") {
            steps {
                sh "./gradlew clean build"
            }
        }

        stage("Send Jar") {
            steps {
                sh 'sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 rm -rf build/fire_inform-0.0.1-SNAPSHOT.jar'
                sh 'sshpass -p $DEPLOY_SERVER_PASSWORD scp -P 12308 -o StrictHostKeyChecking=no /var/lib/jenkins/workspace/pipeline/build/libs/fire_inform-0.0.1-SNAPSHOT.jar $DEPLOY_SERVER_ID@106.10.59.248:build'
            }
        }

        stage("Send Shell Script") {
            steps {
                sh 'sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 rm -rf build/deploy.sh'
                sh 'sshpass -p $DEPLOY_SERVER_PASSWORD scp -P 12308 -o StrictHostKeyChecking=no /var/lib/jenkins/workspace/pipeline/deploy.sh $DEPLOY_SERVER_ID@106.10.59.248:build'
            }
        }

        stage("Connect Deploy Server") {
            steps {
                sh 'sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 sh build/deploy.sh'
            }
        }
    }
}

1. Clean Up 단계

소스코드를 clone 받기 전에 비워주는 단계

2. Checkout 단계

Github Repository에서 소스코드를 clone 받는 단계이다.

credentialsId에 Github 연동 암호키 정보를 담은 Credential의 ID값을 입력해준다.

2. Build 단계

gradle wrapper를 이용해서 빌드한다.

3. Send Jar 단계

필자는 jenkins 서버와 애플리케이션 서버를 별도로 배포했기 때문에 빌드된 jar 파일을 애플리케이션 서버로 전송한다.

Checkout 단계에서 생성된 jar의 파일 경로는 /var/lib/jenkins/workspace/flab/build/libs/fire\_inform-0.0.1-SNAPSHOT.jar 이다.

sshpass 는 원격 컴퓨터에 보안 접속할 때 사용하는 명령어이다.

sshpass -p 'ssh접속비밀번호' ssh 'ssh접속계정'@'ssh접속주소' '명령어'

파일 전송시 SCP 프로토콜을 이용한다.

SCP(Secure Copy)는 원격 호스트 간에 파일을 전송하는 프로토콜이며 SSH기반이다.

  • scp로 전송할 배포 서버 경로
    • -P : 호스트 포트 번호
    • build : 디렉토리명
    • -o StrictHostKeyChecking=no : 호스트간 키 인증 과정 스킵
# 이전 파일 삭제
sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 rm -rf build/fire_inform-0.0.1-SNAPSHOT.jar

# jar 파일 애플리케이션 서버로 전송
sshpass -p $DEPLOY_SERVER_PASSWORD scp -P 12308 -o StrictHostKeyChecking=no /var/lib/jenkins/workspace/pipeline/build/libs/fire_inform-0.0.1-SNAPSHOT.jar $DEPLOY_SERVER_ID@106.10.59.248:build

4. Send Shell Script 단계

애플리케이션 서버에서 실행할 동작을 정의해 놓은 Shell 스크립트를 전송한다.

# 이전 파일 삭제
sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 rm -rf build/deploy.sh

# deploy.sh script 파일 전송
sshpass -p $DEPLOY_SERVER_PASSWORD scp -P 12308 -o StrictHostKeyChecking=no /var/lib/jenkins/workspace/pipeline/deploy.sh $DEPLOY_SERVER_ID@106.10.59.248:build

전송할 script의 내용은 아래와 같다.

  1. java 이름으로 동작하는 프로세스의 pid를 찾고 있다면 해당 프로세스를 종료한다.
  2. 백그라운 스레드로 애플리케이션을 실행한다.
#!/bin/sh

pid=`pgrep -f java`
if [ $pid ]
then
    kill -9 $pid;
    echo '$pid process kill complete'
else
    echo 'pid is empty'
fi

sleep 5

nohup java -jar build/fire_inform-0.0.1-SNAPSHOT.jar &

5. Connect Deploy Server 단계

sh : .sh 확장자의 파일 실행

sshpass -p $DEPLOY_SERVER_PASSWORD ssh -p 12308 $DEPLOY_SERVER_ID@106.10.59.248 sh build/deploy.sh

정리

Jenkins를 통해 소스 코드를 빌드하고 원격 서버에서 애플리케이션을 배포하는 방법에 대해서 알아보았다.

github actions 를 이용하면 git merge 시 자동으로 테스트 및 배포하는 기능도 지원하는데 추후 학습해보겠다.

소스 코드

https://github.com/KIM-KYOUNG-OH/ChatBot

Reference