Jenkins와 Docker로 CI/CD pipeline 구축하기 (2)

bagt13·2023년 1월 30일
1

Project

목록 보기
14/17
post-thumbnail

이전 포스트

Jenkins와 Docker로 CI/CD pipeline 구축하기 1편


Github Public Access Token 등록

나의 경우, Git Submodule (private repo)로 설정 정보를 관리하고 있었다. 따라서 Jenkins Pipeline에서 private repository에 접근하기 위해 Jenkins에 Public Access Token을 먼저 등록해야 한다. (Github에서 Public Access Token을 미리 생성해야 한다)

  1. Jenkins 관리 -> 시스템 설정 -> Github 탭으로 이동한다.

  2. Credentials를 추가한다.

Username with Password를 선택하고, 다음 정보들을 입력한다.

  • Username (github ID)
  • Password (access token)
  • ID (script에서 사용할 변수명)


🚀 Pipeline 구축

Jenkins Item이란?

Jenkins에서 CI/CD 파이프라인은 Item을 통해 구성할 수 있다. Item을 여러개 생성해 여러개의 파이프라인을 생성할 수도 있으며, 각각의 파이프라인은 각각 작성된 pipeline script를 통해 다르게 동작하게 할 수 있다.

가장 흔하게 사용되는 Pipeline을 선택해 CI/CD 파이프라인을 구축하였다.


New Item -> Pipeline


Pipeline script 작성

pipeline script에는 단순하게 내가 생성한 파이프라인이 어떤 동작을 할 지를 적어주면 된다.

Pipeline Script

pipeline {
    agent any
    tools {
        gradle 'gradle'
    }
    stages {
        stage('Git Clone') {
            steps {
                git branch: 'dev', url: 'https://github.com/sungmingt/fly-away'
            }
        }
        stage('BE-Build') {
            steps {
                dir("./server/fly-away") {
                    sh "./gradlew clean build"
                }
            }
        }
    }
}
  • gradle 'gradle' : gradle이라는 tool을 사용한다

  • 하나의 pipeline은 각각의 stage들로 구성되며, 각각의 stage들은 steps로 이루어져있다.

  • stage('Git Clone') : 'Git Clone' 이라는 작업을 실행한다.


다음과 같은 흐름이다.

  1. url의 github 주소의 dev branch로부터 Git Clone을 실행한다.
  2. ./backend 디렉토리에서 ./gradlew clean build를 실행한다.

Git Submodule을 사용할 때의 git clone 스크립트

나는 git submodule을 사용하고 있었기 때문에, credentials를 활용해 private 레포지토리인 서브모듈에 접근하기 위해 추가 작업이 필요했다.

만일 git submodule을 사용한다면, script의 Git Clone Stage를 다음과 같이 작성해줘야 한다.

stage('Git Clone') {
	steps {
		dir('/var/jenkins_home/workspace/flyaway'){
			sh '''
				echo delete existing project file 
			'''
			deleteDir()
		}
		checkout scmGit(
			branches: [[name: '*/dev']],
			extensions: [
				submodule(
					parentCredentials: true,
					reference: '',
					trackingSubmodules: true
				)
			],
			userRemoteConfigs:[
				[
					credentialsId: 'credentialsId'
					url: 'https://github.com/sungmingt/fly-away'
				]
			]
		)
	}
}
  • dir('/var/jenkins_home/workspace/flyaway')
    : 이전에 clone 했던 프로젝트 파일이 존재한다면 삭제하고 clone 받는다.

  • checkout scmGit() : 이 부분은 pipeline script 작성란 아래에 Pipeline Syntax를 통해 작성하면 script를 자동으로 만들어준다.

    위에서 미리 생성해둔 credentialsId를 선택하고, submodule에 대한 설정을 추가적으로 해주면 된다.

    참고 자료


Script를 작성하고 지금 빌드 를 클릭하면, 수동으로 파이프라인을 실행할 수 있다.


❗️ Gradle 관련 에러

Git Clone - Gradle Build 작업을 실행하던 도중 다음과 같은 에러를 만났다.

에러 내용을 봐서는 Pipeline Script에 작성한 tools 부분의 gradle을 인식하지 못하는 것 같은데, 구글링을 해도 쉽게 원인을 찾을 수 없었다.

그렇게 삽질하던 도중 Global Tool Configuration 이라는 설정을 찾을 수 있었고, 여기에 Gradle 관련 설정이 있었다.

내 프로젝트의 Gradle 버전을 알맞게 입력 후, 'gradle'이라는 이름을 통해 인식할 수 있도록 설정하는 것 같았다.

이후 빌드에 성공할 수 있었다.



✅ 배포(CD) 구축

이제 Jenkins에서 build한 jar 파일을 운영 서버 EC2로 전달해야 한다. 이때 운영 서버로의 SSH 접속을 위해 많이 사용되는 Plugin이 Publish Over SSHSSH Agent이다.

1. SSH Agent 설치



2. AWS 접속 정보 추가 (Credentials)

이제 EC2로의 SSH 접속을 위해 설정 - Credentials로 이동해 접속 정보를 추가한다.

  • Kind : private key를 통해 SSH 접속한다.
  • ID : syntax에서 참조할 수 있는 식별자이다. 나중에 pipeline script에서 사용된다.
  • Username : 기본값인 ubuntu를 입력한다.
  • Private Key : 운영 서버(EC2) 접속에 필요한 pem키 파일 내용을 입력한다. 여기서는 -----BEGIN RSA PRIVATE KEY----- 부터 -----BEGIN RSA PRIVATE KEY----- 까지 모두 입력한다.
cat {key 이름}.pem

----BEGIN RSA PRIVATE KEY-----
{pem 내용}
-----BEGIN RSA PRIVATE KEY-----

Credential이 aws_key라는 이름으로 생성된 것을 확인할 수 있다.



Pipeline script에 Deploy stage 추가

stage('Deploy') {
	steps {
    	sshagent(credentials: ['aws_key']) {
			sh '''
				ssh -o StrictHostKeyChecking=no ubuntu@{Private 또는 Public IP}
                scp /var/jenkins_home/workspace/{프로젝트명}/backend/build/libs/{프로젝트명}-0.0.1-SNAPSHOT.jar ubuntu@{Private 또는 Public IP}:/home/ubuntu/{폴더명}
                ssh -tt ubuntu@{Private IP} sh ./deploy.sh
            '''
		}
	}
}
  • sshagent(credentials: ['aws_key']) : 생성한 credential를 토대로 sshagent를 통해 운영 서버에 접속한다.

  • ssh -o StrictHostKeyChecking=no ubuntu@{Private 또는 Public IP} : EC2 접속 시, Host Key Checking을 생략하도록 한다.

    Host Key Cheking이란?

    터미널에서 ssh 접속시 Are you sure you want to continue connecting (yes/no)? 와 같은 메시지를 띄워 접속을 확인하는 것


  • scp ... : Jenkins 프로젝트 내에 저장된 빌드 파일을 운영 서버로 전송시킨다. 프로젝트명은 docker를 사용하는 경우, 컨테이너 내에 접속해 /var/jenkins_home/workspace에서 확인할 수 있다.

    또한 폴더명은 운영 서버에서 jar파일을 위치시킬 폴더명이며, 당연히 미리 생성되어 있어야 한다.

  • ssh -tt ... : 운영 서버로 접속해 운영 서버의 ./deploy.sh 파일을 실행시킨다. 해당 script 파일에는 운영 서버에 기존의 spring boot 서버를 kill 시키고, 새로 전달된 jar 파일을 실행시키는 명령어가 포함되어 있다.



deploy.sh

pid=$(pgrep -f jenkins | pgrep java)
if [ -n "${pid}" ]
then
        sudo kill -9 ${pid}
        echo kill process ${pid}
        sleep 10
else
        echo no process
fi

echo "Deployment Start..."

JAR_PATH=$(ls -t /home/ubuntu/flyaway/*.jar | head -1)
sudo chmod +x ${JAR_PATH}
sudo nohup java -jar -DSpring.profiles.active=prod ${JAR_PATH} >> /home/ubuntu/flyaway/application.log &

sleep 10

echo "Done!!"
  • 실행 중인 애플리케이션 process가 존재한다면 kill 한다.
  • Jenkins Pipeline으로 전달받은 jar파일을 prod 환경(profile)으로 실행한다.

최종 Pipeline Script

pipeline {
    agent any
    tools {
        gradle 'gradle'
    }
    stages {
        stage('Git Clone') {
            steps {
                dir('/var/jenkins_home/workspace/flyaway'){
                    sh '''
                       echo delete existing project file 
                    '''
                    deleteDir()
                }
                checkout scmGit(
                    branches: [[name: '*/dev']],
                    extensions: [
                        submodule(
                            parentCredentials: true,
                            reference: '',
                            trackingSubmodules: true
                            )
                    ],
                    userRemoteConfigs:[
                        [
                            credentialsId: 'credentialsId',
                            url: 'https://github.com/sungmingt/fly-away'
                        ]
                    ]
                )
            }
        }
        stage('BE-Build') {
            steps {
                dir("./server/fly-away") {
                    sh "chmod 777 gradlew"
                    sh "./gradlew clean build"
                }
            }
        }
        stage('Deploy') {
	        steps {
    	        sshagent(credentials: ['aws_key']) {
			        sh '''
						ssh -o StrictHostKeyChecking=no ubuntu@{Private 또는 Public IP}
                		scp /var/jenkins_home/workspace/{프로젝트명}/backend/build/libs/{프로젝트명}-0.0.1-SNAPSHOT.jar ubuntu@{Private 또는 Public IP}:/home/ubuntu/{폴더명}
                		ssh -tt ubuntu@{Private IP} sh ./deploy.sh
            		'''
		        }
			}
		}
	}
}

❗️SSH 접속 에러

처음 Deploy 단계 실행 시 pipeline script에 ssh -t 옵션을 주었고, 위 에러를 만났다. 이런 경우 ssh -tt 또는 ssh -t -t 옵션을 추가로 주면 된다.



✅ Webhook 등록

지금까지는 Jenkins GUI에서 지금 빌드를 통해 파이프라인을 실행해왔지만(수동 배포), 이제 Github에 push를 trigger로 파이프라인이 실행(CD)되도록 하자


1. Github hook trigger for GITScm polling 활성화

생성한 파이프라인 -> 구성에서 Github hook trigger for GITScm polling을 활성화시킨다. Github으로부터 webhook이 들어오면 자동으로 파이프라인이 실행된다.

2. Github Repository에서 Webhook 생성

Repository -> Settings -> Webhooks으로 이동하여 Add webhook으로 webhook을 생성한다.

  • Payload URL : https://{Jenkins 접속 주소}/github-webhook/를 입력한다.

  • Content type : application/json 을 선택한다.

  • 다음으로는 어떤 event를 통해 webhook을 실행할 것인지를 선택할 수 있으며, push를 통해 실행되도록 하였다.

이제 dev branch로의 push가 일어나면, 자동으로 파이프라인이 실행되어야 한다.



✅ Webhook 동작 테스트

1. dev branch로 PR


2. webhook 동작 확인

Github의 dev branch로의 push를 trigger로 파이프라인이 정상적으로 실행된다!


📃 References

profile
주니어 백엔드 개발자입니다😄

0개의 댓글