사이먼's 코딩노트
[SpringBoot] 실전 서비스 배포 (4) 본문
[실전 서비스 배포]
- 저번 '실전 서비스 배포 (3)' 까지 진행하면서 docker를 통한 이미지 생성과 함께 실제 구매한 도메인 네임으로 접속까지 성공하는 실습을 진행했다.
- 이번에는 실전 서비스 배포의 마지막 단계로 젠킨스를 통해 서비스 배포 자동화를 구현해봅시다.
[젠킨스(Jenkins)란?]
- 젠킨스는 지속적 통합(Continuous Integration, CI) 및 지속적 전달(Continuous Delivery, CD)를 지원하는 오픈 소스 자동화 도구이다.
- 젠킨스는 개발자들이 소프트웨어 개발 과정에서 반복적인 작업들을 자동화하여 개발 생산성과 품질을 향상시킬 수 있도록 도와준다.
- 젠킨스는 다양한 프로그래밍 언어와 프레임워크를 지원하며, 소스 코드 컴파일, 테스트 실행, 정적 분석, 배포 등의 작업을 자동화할 수 있다.
- 개발자가 Git이나 Subversion 등에 커밋을 하면, 젠킨스는 이를 감지하고 지정된 작업들을 자동으로 실행한다.
- 젠킨스는 사용자가 웹 인터페이스를 통해 다양한 작업을 구성하고 관리할 수 있다.
- 이 작업들은 빌드 단계, 테스트 단계, 배포 단계 등으로 구성될 수 있으며, 개발자들은 작업 간의 의존성과 실행 조건을 설정할 수 있다.
- 예를 들어, 새로운 코드 커밋이 있을 때마다 자동으로 빌드하고 테스트를 실행하여 결과를 확인할 수 있다.
- 젠킨스는 다양한 플러그인을 지원하여 기능을 확장할 수 있으며, 이를 통해 젠킨스는 다양한 도구와 시스템과의 통합이 가능하며, 사용자의 요구에 맞게 유연하게 구성할 수 있다.
- CI/CD의 원칙을 따라 개발 프로세스를 자동화하고 효율적으로 관리할 수 잇는 젠킨스는 개발자 사이에서 높은 인기를 얻고있다.
[젠킨스를 사용한 간단한 예시]
- 코드 빌드 : 개발자가 코드를 커밋하면, 젠킨스는 해당 코드를 자동으로 가져와 빌드한다. 이를 통해 코드 빌드 단계에서 발생할 수 있는 문제를 빠르게 감지하고 수정할 수 있다.
- 테스트 자동화 : 빌드된 코드에 대해 자동화된 테스트를 실행하여 버그와 결함을 식별한다. 예를 들어, 단위 테스트, 통합 테스트, 성능 테스트 등을 자동으로 실행하여 코드 변경 사항의 영향을 신속하게 확인할 수 있다.
- 배포 자동화 : 코드가 테스트를 통과하면 젠킨스는 자동으로 배포를 수행할 수 있다. 이를 통해 개발된 소프트웨어를 실제 서버나 클라우드 환경으로 자동으로 배포할 수 있다. 예를 들어, 서버에 업데이트된 애플리케이션을 배포하거나, 클라우드 서비스에 새로운 가상 머신을 프로비저닝할 수 있다.
- 모니터링 및 로깅 : 젠킨스는 배포된 애플리케이션의 모니터링과 로깅을 관리할 수 있다. 예를 들어, 애플리케이션의 성능 지표를 모니터링하고 로그를 수집하여 이슈를 신속하게 파악하고 해결할 수 있다.
[젠킨스 설치]
- 먼저 docker를 통해 젠킨스를 설치해야한다.
- 아래 명령어를 SSH 클라이언트에 입력하여 젠킨스를 설치하고, 설치하기 전 먼저 기존에 젠킨스 docker 컨테이너가 있으면 삭제를 한다.
# 기존 컨테이너 삭제, 기존 디렉토리 삭제
docker rm -f jenkins_1
rm -rf /docker_projects/jenkins_1
# 젠킨스 설치
docker run \
--name jenkins_1 \
-p 8081:8080 \
-e TZ=Asia/Seoul \
-v /docker_projects/jenkins_1/var/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v /docker_projects/jenkins_1/data:/data \
-u root \
-d \
--restart unless-stopped \
jenkins/jenkins:jdk17
- 설치를 마치면 npm으로 접속해서 proxy처리를 해줘야한다.
- proxy 처리는 보안 또는 캐싱 및 성능 향상을 위해서 설정한다고 생각하면 좋다.
- 젠킨스 뿐만 아니라 실제 배포될 서버의 도메인 네임과 npm 주소도 함께 등록해야한다.
- 웹 사이트의 포트는 8080, npm의 포트는 81, 젠킨스의 포트는 8081로 추가를 해주고, 이렇게 설정을 하고 나면 기존의 보안이 떨어지는 http가 아니라 https로 접속이 가능하게 된다.
- 여기서 172.17.0.1 IP는 클라우드 플랫폼에서 VPC 생성 시 IP 주소 범위 중 하나를 택한 것이다.
- 다음은 젠킨스를 진입했을 때 필요한 초기 비밀번호를 확인하기 위해 SSH 터미널에 아래와 같은 명령어를 입력한다.
- 명령어를 입력한 후 비밀번호를 확인했다면, https://jenkins.도메인명을 입력하면 젠킨스에 접속하게 되고 초기 비밀번호를 입력하면 계정 정보를 변경할 수 있다.
- 계정을 수정하면 메인 메뉴 좌측의 새로운 Item을 선택하여 아이템을 생성한다. 그리고 이 때 Item type은 pipeline을 선택해야한다.
# 젠킨스 초기 비밀번호 확인
docker exec jenkins_1 cat /var/jenkins_home/secrets/initialAdminPassword
[깃허브 리포지터리 웹훅 추가]
- 이 다음으로는 실제 배포될 프로젝트의 깃허브 리포지터리와 젠킨스를 연결시켜 main에 push가 일어날 때마다 알림이 갈 수 있도록 설정을 해야한다.
- 아래 사진과 같이 깃허브와 젠킨스에서 모두 웹훅에 의한 호출을 허용하도록 설정해야한다.
[젠킨스 내 Docker 설치]
- 다음은 생성된 jenkins에 도커를 설치하여 HOST OS의 도커 명령어를 사용할 수 있도록 해야한다.
- 아래 명령어를 통해 jenkins bash에 접속하여 도커를 설치해봅시다.
# jenkins_1 bash 접속
docker exec -it jenkins_1 bash
# jenkins_1 bash 도커 설치
apt-get update -y
apt-get install -y ca-certificates curl gnupg lsb-release
mkdir -p /etc/apt/keyrings
rm /etc/apt/keyrings/docker.gpg
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
apt-get update
apt-get install -y docker-ce docker-ce-cli docker-compose-plugin
exit
[파이프라인 작성]
- 마지막으로 자동화를 구현하기 위해선 해당 순서를 정리하여 젠킨스 파이프라인에 작성을 해야한다.
- 파이프라인에 담겨질 내용은 간단하게 말하면 우리의 '실전 서비스 배포 (3)' 에서 진행했던 도커 이미지 삭제 후 새로 커밋한 프로젝트 pull 하기, 새로운 도커 이미지 생성과 같은 작업들을 작성한다.
- 프로젝트 내에는 Dockerfile이 존재해야되고, 여기서 말하는 Dockerfile 파일의 내용은 '실전 서비스 배포 (3)'에서 생성한 내용과 동일하게 작성하면된다.
- 아래 사진과 같이 젠킨스에서 구성으로 들어가 파이프라인을 작성하면 되고, 파이프라인 내용도 함께 참고 부탁드립니다.
- 작성된 파이프라인 내에서 market이라고 되어있는 부분은 Docker 이미지의 이름이기 때문에 사용자 임의로 변경해도상관없지만, 주의할 점은 본인 프로젝트의 깃허브 리포지터리 주소를 입력하는 것과, application-secret.yml의 내용 모두를 작성해야한다는 것이다.
pipeline {
agent any
environment {
timestamp = "${System.currentTimeMillis() / 1000L}"
}
stages {
stage('Prepare') {
steps {
script {
// Get the ID of the market:latest image
def oldImageId = sh(script: "docker images market:latest -q", returnStdout: true).trim()
env.oldImageId = oldImageId
}
git branch: 'main',
url: '깃허브 리포지터리 주소 입력'
}
post {
success {
sh 'echo "Successfully Cloned Repository"'
}
failure {
sh 'echo "Fail Cloned Repository"'
}
}
}
stage('Build Gradle') {
steps {
dir('.') {
sh """
cat <<EOF > src/main/resources/application-secret.yml -> application-secret.yml 내용이 들어가야됨
spring:
security:
oauth2:
client:
registration:
kakao:
clientId:
"""
}
dir('.') {
sh """
chmod +x gradlew
"""
}
dir('.') {
sh """
./gradlew clean build -x test
"""
}
}
post {
success {
sh 'echo "Successfully Build Gradle Test"'
}
failure {
sh 'echo "Fail Build Gradle Test"'
}
}
}
stage('Build Docker Image') {
steps {
script {
sh "docker build -t market:${timestamp} ."
}
}
}
stage('Run Docker Container') {
steps {
script {
// Check if the container is already running
def isRunning = sh(script: "docker ps -q -f name=market_1", returnStdout: true).trim()
if (isRunning) {
sh "docker rm -f market_1"
}
// Run the new container
try {
sh """
docker run \
--name=market_1 \
-p 8080:8080 \
-v /docker_projects/market_1/volumes/gen:/gen \
--restart unless-stopped \
-e TZ=Asia/Seoul \
-d \
market:${timestamp}
"""
} catch (Exception e) {
// If the container failed to run, remove it and the image
isRunning = sh(script: "docker ps -q -f name=market_1", returnStdout: true).trim()
if (isRunning) {
sh "docker rm -f market_1"
}
def imageExists = sh(script: "docker images -q market:${timestamp}", returnStdout: true).trim()
if (imageExists) {
sh "docker rmi market:${timestamp}"
}
error("Failed to run the Docker container.")
}
// If there's an existing 'latest' image, remove it
def latestExists = sh(script: "docker images -q market:latest", returnStdout: true).trim()
if (latestExists) {
sh "docker rmi market:latest"
if(!oldImageId.isEmpty()) {
sh "docker rmi ${oldImageId}"
}
}
// Tag the new image as 'latest'
sh "docker tag market:${env.timestamp} market:latest"
}
}
}
}
}
- 이렇게 파이프라인까지 작성됐다면, 실제로 배포중인 프로젝트에 main 브랜치에서 git push를 하게 되면 push와 동시에 jenkins에서 자동으로 빌드가 진행되고 배포가 진행된다.
- 아래 사진과 같이 좌측 하단에 빌드 성공 여부가 나타나는 것을 확인할 수 있다.
반응형
'Java > SpringBoot' 카테고리의 다른 글
[SpringBoot] 실전 서비스 배포 (3) (0) | 2024.07.27 |
---|---|
[SpringBoot] 실전 서비스 배포 (2) (2) | 2024.07.24 |
[SpringBoot] 실전 서비스 배포 (1) (2) | 2024.07.24 |
[SpringBoot] 결제 시스템 (0) | 2024.07.18 |
[SpringBoot] 멀티 채팅방 (3) (0) | 2024.06.19 |