
Jenkins 배포 환경 : Amazon Linux, Java 17, Git, Docker, Gradle

main branch에 merge가 되면 GitHub Webhook을 통해 Jenkins에게 알린다.Jenkins는 다음과 같은 동작을 수행한다.Git clone -> Gradle로 Spring Boot 프로젝트 Build -> Docker Image화 -> GHCR (GitHub Container Registry)에 Push -> WAS 서버에 원격 접속 -> GHCR로부터 Pull -> Docker Container Run먼저 원격으로 서버에 배포를 하기 위해서는 SSH 프로토콜로 접근해야 한다.
또한 GitHub에서 Webhook을 받기 위해서 플러그인이 필요하다.
해당 작업들을 도와주는 플러그인을 설치해보자.
처음에는 Publish over SSH 플러그인을 사용하려 했으나, 보안 문제로 인해 이제는 Jenkins에서 지원을 안 해준다고 한다.
Dashboard -> Jenkins 관리 -> Plugins -> Available plusgins 순으로 들어가 SSH Agent, GitHub Integeration과 Generic Webhook Trigger를 검색하여 설치하자.

Dashboard -> {item name} -> Pipeline Syntax로 이동한 다음 Sample Step 항목에서 sshagent: SSH Agent를 선택하고 아래 +Add 버튼을 클릭하고 Jenkins를 클릭한다.

Kind : SSH Username with private key 선택Scope : Global로 선택ID : 해당 Credential을 식별할 값Username : 해당 서버에 접근할 계정명 (Amazon Linux는 ec2-user / 우분투는 ubuntu가 디폴트)Private Key Enter directly : 체크Key : ssh Private Key(.pem) 추가연결하기 전에 인바운드 규칙에 22번(SSH) 포트에 접근을 Jenkins IP도 허용해야한다!!
Jenkins에서 Gradle로 Spring Boot 프로젝트를 Build해서 배포할 계획이다.
Dashboard -> Jenkins 관리 -> Tools -> Gradle installations -> Add Gradle

name : 마음대로 설정Version : Spring Boot 프로젝트와 버전을 맞춰준다!설정이 끝나면 Save 버튼을 눌러 저장하면 된다!
Dashboard -> Jenkins 관리 -> Credentials -> System -> Global credentials (unrestricted)에서 + Add Credentials 버튼을 클릭한다.

Username : GitHub 아이디Password : GitHub Access TokenID : 해당 자격증명을 식별할 용도로써 원하는 이름을 지정해주면 된다.다 작성했으면 Create 버튼 누르기

+ 새로운 Item을 클릭해준다.

item 이름을 설정해주고 Pipeline을 선택한 후 OK를 클릭해준다.
item을 생성하면 해당 item의 Configuration로 넘어갈 것이다.
이제 Configuration을 설정해보자!

GitHub project를 체크하고, 배포하려는 GitHub Repository URL을 적어준다.

우리는 GitHub Webhook 이용할 것이기 때문에
Build Triggers에서 GitHub hook trigger for GITScm polling을 체크해준다.
아래 Pipeline 부분으로 이동해준다.

나는 Spring Boot 프로젝트 내에 Pipeline Script를 작성할 것이다.
Definition : Pipeline script from SCM SCM : Git으로 설정Repository URL : 배포하려는 GitHub Repository URLCredentials : 위에서 만든 Credential을 설정Branch Specifer : 트리거 받을려는 브랜치Script Path : .jenkinsfile 위치 (프로젝트의 루트에 위치할 경우 파일명.jenkinsfile로 설정)특정 브랜치에 대해서만 동작시키고 싶으면 여기를 확인해주세요!
프로젝트에서 Script Path에 설정한 경로에 jenkinsfile을 작성하면 된다!

Jenkins에서 환경 변수를 사용하고 싶으면 Dashboard -> Jenkins 관리 -> System로 이동한 다음 Global properties에서 Environment variables를 체크하여 환경 변수를 추가하면 된다.
pipeline {
agent any
environment {
VERSION = sh(script: 'git rev-parse --short HEAD', returnStdout: true).trim()
DOCKER_IMAGE = "${DOCKER_REGISTRY}/test:${VERSION}"
}
stages {
stage ('Git clone') {
steps {
git branch: 'main', credentialsId: 'github-access-token',
url: ${GITHUB_REPO}
}
}
stage ('Gradle Build') {
steps {
sh '''
chmod +x gradlew
./gradlew clean bootJar
'''
}
}
stage ('Docker Image Build') {
steps {
sh '''
docker rmi -f \$(docker images -q) || true
docker build -t test .
docker tag test ${DOCKER_IMAGE}
export CR_PAT=${GITHUB_TOKEN}
echo \$CR_PAT | docker login ghcr.io -u ${GITHUB_ID} --password-stdin
docker push ${DOCKER_IMAGE}
'''
}
}
stage ('Deploy') {
steps {
sshagent (credentials: ['위에서_만든_SSH_Credential_ID']) {
sh '''
ssh -o StrictHostKeyChecking=no ${API_SERVER_USER}@${API_SERVER_IP} "docker login ghcr.io -u ${GITHUB_ID} --password ${GITHUB_TOKEN}"
ssh -o StrictHostKeyChecking=no ${API_SERVER_USER}@${API_SERVER_IP} "docker pull ${DOCKER_IMAGE}"
ssh -o StrictHostKeyChecking=no ${API_SERVER_USER}@${API_SERVER_IP} "docker stop test || true"
ssh -o StrictHostKeyChecking=no ${API_SERVER_USER}@${API_SERVER_IP} "docker rm test || true"
ssh -o StrictHostKeyChecking=no ${API_SERVER_USER}@${API_SERVER_IP} "docker rm test || true"
ssh -o StrictHostKeyChecking=no ${API_SERVER_USER}@${API_SERVER_IP} "docker run -d --name test -p 8080:8080 ${DOCKER_IMAGE}"
'''
}
}
}
}
}
이제 GitHub Repository의 main 브랜치가 변경될 때마다 자동으로 배포가 될 수 있게 만들어보자!
GitHub 로그인 후 본인 계정 페이지에서
Settings -> Developer settings -> Personal access tokens -> Tokens (classic) -> Generate new token -> Generate new token (classic)
순서대로 들어가 토큰을 생성한다.

Note : Token의 이름 (마음대로 짓기)repo와 admin:repo_hook은 꼭 체크하기!!생성된 토큰값은 해당 페이지를 나가면 다시 볼 수 없으므로 다른 곳에 저장해두길 바란다.
Webhook을 받을려는 GitHub Repository -> Settings -> Webhooks -> Add webhook

Payload URL : http://{Jenkins 서버 IP}:{Jenkins Port}/github-webhook/ (/ 빠지면 안됨!!)Content type : application/jsonSecret : 발급 받은 GitHub Access TokenSSL verification : Jenkins 서버가 HTTPS가 적용되었다면 Enable로 해주고 Payload URL도 https로 변경해주면 된다!Push Event만 Trigger로 받을 것이다!나는 테스트 용도로만 하는 것이기에 HTTPS를 적용하지 않았다.
아마 별다른 보안 그룹을 설정하지 않았으면 ping 요청부터 실패했을 것이다.
아래 링크를 통해 Jenkins 서버의 보안 그룹을 수정하자!
GitHub Webhook 실패 시 참고!
Dashboard -> Jenkins 관리 -> System

Add GitHub Server를 클린한 다음 GitHub Server를 클릭하자.

+Add를 클릭한 다음 Jenkins를 클릭하면 아래와 같은 창이 나온다.

Kind : Secret Text로 설정Secret : 위에서 발급 받은 GitHub TokenID : 해당 자격증명을 식별할 용도로써 원하는 이름을 지정다 작성했으면 Add 버튼을 눌러 추가하고, 이전 창의 Credentials을 방금 만든 ID로 설정하고 저장하면 된다!



Spring Boot 서버로 접속하면 페이지가 뜨는 것을 확인할 수 있었다!
처음에는 Jenkins를 Docker Image로 받아서 사용했는데, Docker 컨테이너 내부에서 Docker 명령어를 사용할 수 없어서 로컬에 다시 설치해서 해결했다...
그 외에도 Linux 명령어를 잘 모르고, Pipeline도 처음 작성하다 보니까 수많은 에러를 많이 만난 것 같다.
확실히 설계까지의 과정이 오래 걸리긴 하지만, GitHub에 Push만 하면 자동으로 배포해줘서 진짜 편리하다.
Jenkins/Nginx로 무중단 배포 하기 1편 | HYK
[DevOps] Jenkins를 통한 CI/CD 구축기 2편 (Backend CI/CD 구축) | Seongwon.dev
[CI/CD] Jenkins와 GitHub 연동하기 | rungoat.log
Jenkins pipeline + Docker SpringBoot프로젝트 SSHAgent로 배포하기(+Slack Notification) | devdo
[AWS] EC2 Jenkins -(2) Github와 연동, 자동 빌드 적용하기 | yunSeok
docker image를 삭제하는 다양한 방법들 | soonbee