환경
- Ubuntu 20.04 Server
순서
- 스프링부트 프로젝트를 Github에 Commit
- Github의 Webhook 기능을 이용해 Jenkins에 자동으로 trigger 유발
- trigger된 Jenkins에서 Github Clone후 Build를 통해 jar파일 생성
- jar파일을 Publish Over SSH를 이용해 다중 서버로 배포 후 배포
전체적인 흐름을 설명하기 위한 글이며 각각의 흐름 중 모르는게 있다면 따로 찾아보시길 추천합니다.
반대로 흐름을 까먹으셨다면 다시 이 글로 돌아와서 어느 부분을 연동시켜야 되는지 찾으시길 추천합니다.
Jenkins에서 Github 연동
위와 같이 Github에 Commit이되면 자동으로 Jenkins에 설정한 명령들이 실행될 수 있도록 Jenkins와 Github을 연결시켜줘야 합니다.(이것을 Github의 WebHook이라고 합니다.)
첫번째로 Jenkins에서 Github을 연결해줘야 합니다.
Jenkins 관리 > Manage Credentials에 들어가줍니다.
초기 화면은 위와 같습니다. (global)부분의 화살표를 눌러 인증 정보를 추가 해줍시다.
- Username - Github 아이디를 입력해줍니다.
- Password - 비밀번호를 입력해줍니다. 토큰 연동 방식을 사용할 수 있지만 여기서는 간단하게 설명하기 위해 비밀번호를 입력하겠습니다.
- ID - ID는 앞으로 젠킨스에서 사용하게 될 값이라고 보면 됩니다. 젠킨스에서 사용할 Github 변수라고 생각하면 됩니다.
- Description - Description에도 본인이 식별할 값을 적어주세요. 앞으로 Credentials에 등록될 키나 인증 정보가 많기 때문에 Description을 적어줘야 추후에 관리가 용이 합니다.
Github에서 Jenkins 연동
두번째로는 역으로 Github에서도 Jenkins를 연결해줘야 합니다.
본인의 Repository에서 Settings > Webhooks를 들어가 Payload URL 부분에 본인의 Jenkins 주소를 적어주면 됩니다.
끝 부분에 github-webhook이라고 적어줍니다.
사진에서는 예시를 위해 내부 IP를 적어줬지만 github에서는 당연히 우리의 젠킨스 서버의 내부 IP를 알질 못하니 포트포워딩을 통해 외부 IP를 연결해줘야 합니다.
Jenkins에서 Pipeline 생성
이제 젠킨스와 Github 연동은 마쳤습니다.
이제 실제 CI & CD를 구축할 차례입니다.
젠킨스 메인 화면에서 좌측에 새로운 Item을 눌러서 Job을 생성하겠습니다.
Jenkins에서는 여러 종류의 Job을 만들 수 있습니다.
가장 전통적인 방식은 FreeStyle Project이지만 최근에는 코드 하나로 모든 CI & CD가 구현이 되는 Pipeline을 이용해서 구축하겠습니다.
적절한 이름으로 생성을 마쳤다면 바로 왼쪽에 '구성'버튼을 눌러 설정을 시작하도록 하겠습니다.
첫번째로는 Build Triggers 부분에 Github의 Webhook 기능이 활성화 될 수 있도록 체크해주세요.
그리고 하단에 코드를 입력하는 창이 있습니다.
코드의 문법으로는 Declarative Pipeline, Scripted Pipeline 2가지를 사용할 수 있습니다.
2가지를 혼용해서 사용할 수는 없습니다. 1가지만 선택해서 사용해야 합니다.
다만 Declarative Pipeline이 Scripted Pipeline보다 문법이 더 간단하며 권장되는 방식입니다.
또 Declarative Pipeline을 사용하면 Scripted Pipeline도 작성할 수 있는 기능이 있기 때문에 Declarative Pipeline을 이용해서 구축해보겠습니다.
참고 - Declarative Pipeline은 Blue Ocean에서 사용할 수 있습니다. Scripted Pipeline은 Blue Ocean 통합을 지원하지 않습니다. 파이프라인 문법 중에서도 대부분의 경우 Declarative 방식을 사용하시는 것을 추천합니다. 초보를 위해 편집 UI도 제공하기 때문에 정의하기가 편리합니다.
아래와 같이 양식을 맞춰주세요. credetialsId에는 위에서 Github 연동을 설정했을 때 ID값을 적어주면 됩니다.
pipeline {
agent any
stages {
stage('github Clone') {
steps {
git credentialsId: 'stir084', url: 'https://github.com/stir084/JenkinsStudy.git'
}
}
}
}
그리고 저장을 눌러서 메인에서 '지금 빌드'를 눌러주세요.
github Clone이 정상적으로 됐다면 우측 아래에 초록색으로 영역표시가 되며 성공했다는 알림이 뜹니다.
참고 - 위의 소스 코드를 JenkinsFile이라고 부릅니다.
실제 Clone이 잘되었는지 확인해봅시다.
저는 젠킨스를 Docker 내에 설치하지 않았기 때문에 Docker 내에 설치 하셨다면 위의 경로가 다를 수가 있습니다.
또 On-Premise 환경처럼 실제 서버에 구축 했기 때문에 클라우드를 이용하시는 분들과 환경 설정이 조금 다를 수 있습니다.
젠킨스 Workspace의 경로로 가면 본인이 설정한 Pipeline 이름으로 Clone된 폴더를 확인할 수 있습니다.
이제는 빌드를 해봅시다.
pipeline {
agent any
stages {
stage('github Clone') {
steps {
git credentialsId: 'stir084', url: 'https://github.com/stir084/JenkinsStudy.git'
}
}
stage('build') {
steps {
sh '''
echo 'start bootJar'
chmod +x gradlew
./gradlew clean bootJar
'''
}
}
}
}
Pipeline에서는 직접 서버에 명령을 전달할 수 있습니다.
따옴표 3개를 앞뒤로 묶으면 여러줄을 작성할 수 있고 1개를 적으면 1줄을 작성할 수 있습니다.
위의 코드를 이용해 jar파일을 만들어봅시다.
build/libs 경로에 jar파일이 잘 들어간걸 볼 수 있습니다.
Publish Over SSH 플러그인을 통해 서버에 배포하기
서버에 이미 jar파일이 있으니 단일 서버로 운영할 것이라면 위에서 java -jar 혹은 ./gradlew bootrun을 위의 Pipeline에 추가만 하면 됩니다.
하지만 jar파일을 다른 서버에서 실행 하고 싶거나 다중 서버를 운용할 때는 jar파일을 해당 서버에 전달해서 실행시켜야 합니다. 그 기능을 Publish Over SSH가 도와줍니다.
올해 초인 2022년 1~2월 쯤에 Publish Over SSH의 취약점 문제로 사용이 중지 됐었으나 바로 해결이 되어 지금은 사용이 가능합니다.
Publish Over SSH 플러그인을 설치했다면 SSH 연동을 해줘야합니다.
일단 연결될 서버에서 아래 명령어를 입력 해줍니다.
ssh-keygen -t rsa -b 4096 -m PEM
그리고 아래 경로로 들어갑니다.
cd ~/.ssh
그러면 개인키인 id_rsa 파일과 공개키인 id_rsa.pub 파일이 생성되어있습니다.
일단은 공개키인 id_rsa.pub 파일의 내용을 복사해서 authorized_keys 파일을 만들어서 안에 그대로 붙여넣어줍니다.
그래야 Publish Over SSH가 해당 파일을 바라보며 연동이 됩니다.
그리고 id_rsa 개인키 내용을 복사합니다.
Jenkins로 돌아가서 Jenkins 관리 > 시스템 설정을 들어가서
제일 하단으로 가면 Publish Over SSH 설정 부분이 있습니다.
제일 상단에는 복사한 id_rsa 키 값을 입력해줍니다.
- Name - 아무 이름이나 식별할 수 있는 이름으로 설정해줍니다.
- Hostname - SSH로 배포될 외부 아이피를 설정해줍니다. SSH로 연결되니 22번 포트가 당연히 포트포워딩을 통해 열려 있어야 합니다.
- Username - 연결될 서버의 Username을 적어줍니다.
- Remote Directory - jar가 배포될 경로를 설정해줍니다. 해당 폴더는 미리 만들어져 있어야 합니다.
Publish over SSH 파이프라인 작성하기
pipeline {
agent any
stages {
stage('github Clone') {
steps {
git credentialsId: 'stir084', url: 'https://github.com/stir084/JenkinsStudy.git'
}
}
stage('build') {
steps {
sh '''
echo 'start bootJar'
chmod +x gradlew
./gradlew clean bootJar
'''
}
}
stage('deploy'){
steps {
sshPublisher(
publishers:
[
sshPublisherDesc(
configName: 'ssh',
transfers: [sshTransfer(
cleanRemote: false,
excludes: '',
execCommand: 'sh /deploy/test.sh',
execTimeout: 120000, flatten: false,
makeEmptyDirs: false,
noDefaultExcludes: false,
patternSeparator: '[, ]+',
remoteDirectory: '/',
remoteDirectorySDF: false,
removePrefix: 'build/libs',
sourceFiles: 'build/libs/*.jar'
)],
usePromotionTimestamp: false,
useWorkspaceInPromotion: false,
verbose: true
)
]
)
}
}
}
}
파이프라인의 마지막 단계는 위의 코드를 추가해주면 됩니다.
갑자기 코드량이 너무 많아져서 어떻게 작성해야 될 지 감이 안옵니다.
이렇게 길고 복잡할 때는 젠킨스에서 도와주는 기능이 있습니다.
아래 Pipeline Syntax를 눌러줍니다.
그리고 sshPublisher: send build artifact over SSH를 설정해줍니다.
- SSH Server에는 시스템 설정에서 설정해놨던 SSH Server 이름을 선택합니다.
- Source files - 전달할 source file의 경로를 작성합니다.
- Remove prefix - 전달할 때 경로까지 다 포함해서 파일 이름이 전달될 필요가 없으므로 경로는 지웁니다.
- Remote Directory - 파일이 전달될 폴더를 지정합니다. 시스템 설정에서 /deploy 폴더를 설정했으니 해당 경로로 전달이 됩니다.
- Exec Command - 파일이 전달되고 나서 실행될 쉘스크립트를 지정합니다.
양식을 맞춰서 넣어줬다면 하단에 Generate 버튼을 누르면 적절한 코드가 생성이 됩니다. 해당 코드를 위와 같이 파이프라인에 붙여서 사용하면 됩니다. 여러 대를 배포한다면 Deploy에 해당하는 코드를 여러개 쓰면 되겠죠?
쉘스크립트 내용은 실행되고 있는 애플리케이션이 있다면 종료하고 다시 배포하는 형식이며 아래 내용이 궁금하다면 하나하나 검색해보면서 공부해보길 추천합니다.
echo "> JenkinsStudy pid 확인"
CURRENT_PID=$(ps -ef | grep java | grep JenkinsStudy | grep -v nohup | awk '{print $2}')
echo "$CURRENT_PID"
if [ -z ${CURRENT_PID} ] ;then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> sudo kill -9 $CURRENT_PID"
sudo kill -9 $CURRENT_PID
sleep 10
fi
echo "> JenkinsStudy 배포"
JAR_PATH=$(ls -t /deploy/*.jar | head -1)
sudo nohup java -jar -DServer.port=8080 -Dspring:profiles.active=dev ${JAR_PATH} > /deploy/nohup.out 2>&1 &
참고 - nohup 사용시 output인 nohup.out을 적어주지 않으면 Publish Over SSH의 기본 제한시간 120초로 인해 120초 뒤 배포 상태가 Unstable 상태가 됩니다. 이럴 땐 제한시간을 0초로 해주거나 nohup.out을 설정해줘야 합니다.
모든 설정이 제대로 완료되었다면 3개의 Stage가 잘 통과됐을 것이며 아래와 같이 자동으로 배포가 성공되게 됩니다.
'🛠️ CI & CD' 카테고리의 다른 글
Harbor 용량 관리 및 트러블 슈팅 (0) | 2023.12.21 |
---|---|
스프링부트 + Github + Jenkins + Docker / CI & CD 연습하기 (2) (0) | 2022.10.03 |
Jenkins Blue Ocean 소개 및 주관적인 단점 3가지 (1) | 2022.09.26 |
Jenkins 에서 SSH 접속 시 sudo 권한 사용 (0) | 2022.09.26 |
도커에 젠킨스를 설치하는 것에 대한 장점과 단점 (0) | 2022.09.22 |