배경
현재 참여 중인 프로젝트는 Github action을 통해 CI/CD를 구축했습니다. 하지만 Github action을 사용하는 것에 대해 2가지 단점이 있었습니다.
첫 번째 단점은 빌드 시간이 오래 걸린다는 점입니다. 로컬에서 React 프로젝트 빌드 시간이 약 30초였는데, action에서는 약 3분이 걸리며 빌드 시간이 약 6배 증가했습니다. 깃허브 액션이 실행되는 서버가 매번 변경되어 workflow를 실행할 때마다 React 프로젝트 내 필요한 라이브러리를 설치하는데 시간이 소요됩니다.
두 번째 단점은 workflow가 실행되는 서버가 동적이라는 점입니다. 배포 서버는 인바운드 규칙이 있고 action이 실행되는 서버 IP는 매번 바뀝니다. 이에 배포 서버에서 ssh 접근을 허용하는 데 어려움이 있었습니다.
위 2가지 단점을 해결하고자 고정 서버에서 배포를 진행하는 Jenkins를 이용하여 서비스 배포를 시도했습니다.
Jenkins 도입
Jenkins를 설치하는 방법은 [MAC] 젠킨스 설치하기 글을 참고해 주세요😀
Macbook local에 Jenkins를 설치하여 진행했습니다.
사내 jenkins 가 설치된 서버에서 실행해 봤지만,, 낮은 스펙으로 인해 뻗어 버렸습니다.
1. 젠킨스 접속 후 아이템 생성
2. 아이템 이름을 작성하고 파이프라인 선택
3. 세부사항 설정
(저는 별도로 필요한 설정이 없어서 스크립트 파일만 작성했습니다.)
3-2. 스크립트 파일 작성
- 빌드에 필요한 세부사항 설정
- agent : 파이프라인 또는 스테이지를 실행할 위치를 설정
- tools : Jenkins에서 관리하는 특정 도구를 파이프라인에서 사용하도록 설정
- Jenkins 관리 > Tools에서 등록할 수 있고 등록 시 작성한 이름과 동일하게 사용 가능합니다.
- options : 파이프라인이나 특정 스테이지의 실행 동작을 제어하기 위한 다양한 옵션을 설정
- timeout : 파이프라인의 최대 실행 시간을 설정합니다.
- environment : 파이프라인 실행 시 사용할 환경 변수를 설정
pipeline {
agent any
tools {
nodejs "NodeJS-22"
jdk 'java-11'
}
options {
timeout(time: 10, unit: 'MINUTES')
}
environment {
GIT_CREDENTIALS = 'Github-user'
FRONT_END_BUILD_SHELL_SCRIPT = 'build-front-view.sh'
DOCKER_IMAGE_NAME = 'project-docker-image'
REPO_URL = '../kea-rems-web.git'
BRANCH = 'develop'
DOCKERHUB_CREDENTIALS = credentials('DOCKER_HUB_ADMIN')
SSH_NAME = 'hz_sudo'
}
}
- Git repository에서 프로젝트 코드 클론
- Jenkins 관리 > Cridentials 페이지에서 Git 인증 정보 등록 필요
stages {
stage('GitHub Repository Clone') {
steps {
checkout([
$class: 'GitSCM',
branches: [[name: "${BRANCH}"]],
userRemoteConfigs: [[
credentialsId: "${GIT_CREDENTIALS}",
url: "${REPO_URL}"
]]
])
script {
env.GIT_COMMIT = sh(
script: "git rev-parse HEAD",
returnStdout: true
).trim()
// Git 커밋 해시가 제대로 설정되었는지 확인
if (!env.GIT_COMMIT || env.GIT_COMMIT.isEmpty()) {
error "Failed to retrieve GIT_COMMIT. Exiting build."
} else {
echo "Successfully retrieved GIT_COMMIT: ${env.GIT_COMMIT}"
}
}
}
}
- REACT 빌드 스크립트 실행
stage('Frontend Build') {
options {
retry(1)
}
steps {
sh 'chmod +x ${WORKSPACE}/${FRONT_END_BUILD_SHELL_SCRIPT}'
sh "${WORKSPACE}/${FRONT_END_BUILD_SHELL_SCRIPT}"
}
}
- Spring 프로젝트 빌드 실행
stage('Backend Build') {
options {
retry(2)
}
steps {
sh 'java --version'
sh 'chmod +x gradlew'
sh './gradlew clean build -x test'
}
}
- Docker Hub 로그인 및 도커 이미지 생성
- Github와 동일하게 Docker hub 인증 정보도 Jenkins 관리 > Cridentials에서 등록 필요
stage('Docker Hub Login'){
steps{
sh "echo ${DOCKERHUB_CREDENTIALS_PSW} | docker login -u $DOCKERHUB_CREDENTIALS_USR --password-stdin"
}
}
stage('Docker Image Build and Push') {
options {
retry(1)
}
steps{
sh "docker build --platform linux/amd64 -t ${DOCKERHUB_CREDENTIALS_USR}/test-web:dev-${env.GIT_COMMIT} ." // docker build
sh "docker push ${DOCKERHUB_CREDENTIALS_USR}/test-web:dev-${env.GIT_COMMIT}"//docker push
}
}
- 도커 이미지 배포
- 배포 서버에 SSH로 접근하고 도커 허브에 올린 이미지를 pull 받아서 컨테이너 실행
stage('Docker Image Pull and Deploy') {
options {
retry(1)
}
steps {
script {
def DOCKER_IMAGE_TAG = "${DOCKERHUB_CREDENTIALS_USR}/test-web:dev-${env.GIT_COMMIT}"
def EXEC_COMMAND = """
OLD_IMAGE_ID=\$(sudo docker inspect --format='{{.Image}}' test-web);
sudo docker stop kea-rems-web;
sudo docker rm test-web;
sudo docker rmi \${OLD_IMAGE_ID};
sudo docker pull ${DOCKER_IMAGE_TAG};
sudo docker run -d -p 9091:8080 --name test-web --net=test-network ${DOCKER_IMAGE_TAG}
"""
sshPublisher(
failOnError: true,
publishers: [
sshPublisherDesc(
configName: "${SSH_NAME}",
verbose: true,
transfers: [
sshTransfer(
execCommand: "${EXEC_COMMAND}"
)
]
)
]
)
}
}
}
결과
React 빌드 시간은 180s(3분) > 30s로 약 83% 감소했지만, Docker 이미지 생성 단계에서 약 3분 정도 소요되어 Github action과 비교하여 오랜 시간이 걸렸습니다. 그 결과, CI/CD 전체 실행 시간을 비교하면 약 30초 정도 단축했습니다.
React (FE) 빌드 | 도커 이미지 생성 | 전체 | |
Github action 소요시간 | 3분 7초 | 38초 | 5분 57초 |
Jenkins 소요시간 | 20초 | 4분 10초 | 5분 25초 |
도커 이미지를 생성하는 데 오래 걸린 이유 (예측)
1. 이미지 플랫폼 문제
: Github action은 우분투에서 --platform linux/amd64 타입의 이미지를 만들고 Jenkins는 macbook local 환경에서 실행했기 때문에 arm머신에서 x86 이미지를 빌드한다. 그 결과 이미지를 생성하는 데 오래 걸릴 수 있다.
실제로 도커 이미지를 실행할 플랫폼을 별도로 지정하지 않고 실행했을 때 약 1분가량 시간을 단축할 수 있었다.
2. 리소스 부족
: Github action은 워크플로우를 실행하는 전용 서버로 돌리지만, Jenkins는 로컬 환경에서 시스템 리소스를 공유해서 사용하기 때문에 속도가 느리지 않았을까 생각했습니다.
* github action의 self-hosted runners라는 기능을 발견했습니다. 간단하게 자기 소유의 서버로 Github action을 실행하는 것입니다. 다음에 CI/CD를 설계하면 사용해 보겠습니다.
'Devops' 카테고리의 다른 글
[MAC] 젠킨스 설치하기 (1) | 2024.10.16 |
---|