젠킨스 빌드부터 배포 완료

 

안녕하세요. 이전 포스팅에 이어서 젠킨스로 배포하기 마무리하겠습니다.

아래 포스팅을 요약하자면 젠킨스 설치부터 플러그인 설치, Github과 deploy instance 접근 설정을 했습니다.

 

젠킨스로 CI/CD 구현하기 - (1) 설치부터 배포 ec2와 연결, plugin

젠킨스 설치부터 deploy ec2와 연결, plugin 설정 안녕하세요. 오늘은 젠킨스로 CI/CD 구축하겠습니다. 설치부터 ssh로 private repository와 연결, plugin 설치, node js 설정까지 진행하겠습니다. 목표 react와 spr

jujemu.tistory.com

 

1. 백엔드 repository item 등록

 

Dashboard에서 item 생성으로 들어갑니다.

 

Github repository의 ssh 주소를 등록합니다.

빌드가 쌓이는 것이 싫기 때문에 저는 20개만 보관하도록 설정했습니다.

 

소스 코드 관리에 Git을 선택하고 Repository URL을 등록합니다.

(1)에서 등록했던 credential로 접속이 되는 지 확인하면 아래와 같은 주의 문구가 뜰 것입니다.

안내하는 대로 아래의 명령어를 jenkins 컨테이너 안에서 실행합니다.

# jenkins host에서 실행하여 컨테이너 안으로
docker exec -it jenkins /bin/bash

# jenkins container 안의 known_hosts에 등록하는 과정입니다.
# 아래 명령어를 실행하면 찾을 수 없다는 문구가 뜰 수 있습니다.
# 하지만 credential을 none에서 다시 back으로 설정했을 때
# 아래 그림처럼 정상적으로 작동한다면 문제 없으니 진행하셔도 좋습니다.
git ls-remote -h -- git@github.com:{Github repository}.git HEAD

 

 

아래는 known_hosts에 등록한 뒤의 모습입니다. (저 역시 jenkins container에서는 레포를 찾을 수 없다고 떴습니다.)

 

브랜치를 */develop 설정합니다. 프로젝트가 아직 개발 중이기 때문에 develop 브랜치로 테스트를 하기 위함입니다.

 

이 item의 빌드 트리거를 설정하는 데에는 여러가지 방법이 있습니다.

저는 두 명의 백엔드 개발자가 같이 프로젝트를 진행하기 때문에 push가 아닌 pr, merge를 주로 활용합니다.

그리고 어떤 pr은 테스트하지 않아도 되고 같이 작업하다가 동시에 빌드를 유도하면 젠킨스 서버가 멈출 수 있습니다.

따라서 빌드 유도를 url로 진행했습니다.

아래와 같이 적당한 토큰을 등록합니다.

이 방법은 안내와 같이 URL와 설정해둔 토큰값으로 간단하게 빌드를 할 수 있습니다.

※ ec2 보안그룹에 의해서 접근할 수 있어야 빌드를 유발할 수 있다.

 

이제 빌드 내용을 작성할 시간입니다.

deploy instance가 여러 개 있고 이를 동적으로 관리해야한다면 Ansible을 이용해야하지만

지금은 하나의 EC2 인스턴스에 배포하면 되므로 간단하게 진행합니다.

 

아래 빌드를 설명하자면

스프링 부트를 그레이들로 빌드한 후에(별도의 추가 라이브러리 없이 빌드할 수 있습니다.)

날짜가 명시된 이미지와 같은 내용이 담겨있으며 배포용 이미지를 빌드하여 도커 허브에 푸쉬합니다.

저는 도커허브가 아니라 Github package를 이용하였습니다. (차이는 없습니다.)

스프링 repository에 Dockerfile이 있어야한다.

# 젠킨스 빌드 스크립트
build_part="spring"
version="${build_part}-v1.0"
docker_image_name={docker hub repository URL}
docker_version="${version}-$(date +"%y%m%d")"

echo -e "\033[1;33m # Gradle build\033[0m"
chmod +x ./gradlew
./gradlew build

echo "\n"
echo -e "\033[1;33m # Dockerfile build\033[0m"
docker build --platform linux/amd64 -t ${docker_image_name}:${docker_version} .
docker tag ${docker_image_name}:${docker_version} ${docker_image_name}:${build_part}

echo "\n"
echo -e "\033[1;33m # Docker image push on ghcr.io/jujemu\033[0m"
docker push ${docker_image_name}:${docker_version}
docker push ${docker_image_name}:${build_part}
docker rmi -f ${docker_image_name}:${docker_version} ${docker_image_name}:${build_part}
# Dockerfile
# develop profile을 추가해서 설정을 local과 다르게 진행합니다.
FROM amazoncorretto:17.0.8-alpine3.18
LABEL   "title"="spring" \
        "version"="1.0"

COPY build/libs/*.jar app.jar
ENTRYPOINT ["java","-jar","app.jar", "--spring.profiles.active=dev"]

 

이제 위 빌드가 성공적으로 이루어지면

deploy EC2 instance에서 배포가 되도록 설정해야합니다.

(1)에서 설정했던 Publish over ssh를 이용합니다.

빌드 후 조치에서 Send build artifacts over SSH 선택 후

Exec command에 배포 인스턴스에서 실행할 명령어를 입력합니다.

저는 원래 있던 백엔드 이미지를 지우고 docker-compose up -d을 진행했습니다.

2. 프론트엔드 repository item 등록

 

저는 백엔드 담당이기 때문에 프론트엔드 빌드에서 좀 애먹었습니다.

npm이 아니라 pnpm으로 빌드하는 과정에서 겪는 어려움이 있었는데

저는 아래와 같이 해결했습니다.

 

item 생성할 때, 처음에는 back과 똑같이 진행합니다.

다만 하나 다른 것은 별다른 설정 없이도 front private repository에 접근이 가능하다는 것입니다.

 

또한, 프론트엔드는 한 명에서 작업하기 때문에 push로 빌드 유발해도 괜찮습니다.

 

2-1. Github webhook 설정하기

잠시 Github으로 와서 webhook 설정을 하겠습니다.

 

private repository -> Settings -> Webhooks 들어갑니다.

아래처럼 jenkins instance의 탄력적 IP(public ip)와 8080 port 그리고 /github-webhook/을 입력합니다.

※ /github-webhook/ 마지막 / 을 입력하지 않아 고생한 팀도 있으니 꼭 붙이길 바란다.

 

Update webhook 후에 아래 그림처럼 초록색 체크표시를 확인합니다.

만약 아무 반응이 없다면 플로그인을 제대로 설치되지 않은 것입니다.

 

다시 돌아와서 마저 프론트엔드 아이템 설정을 마치겠습니다.

Jenkins 관리 -> Tools에서 설정했던 NodeJS 세팅값을 불러옵니다.

세팅값을 정확히 입력했다면 pnpm으로도 빌드할 수 있습니다 :>

 

이제 빌드 스크립트를 작성합니다.

저는 백엔드와 비슷하게 작성했습니다.

pnpm을 설치하기 위한 script를 추가했습니다.

# 젠킨스 빌드 스크립트
build_part="nginx_react"
version="${build_part}-v1.0"
docker_image_name={docker hub repository}
docker_version="${version}-$(date +"%y%m%d")"

echo -e "\033[1;33m # React build\033[0m"
corepack prepare pnpm@latest-8 --activate
wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
. /root/.shrc
npm install
pnpm run build

echo "\n"
echo -e "\033[1;33m # Dockerfile build\033[0m"
docker build --platform linux/amd64 -t ${docker_image_name}:${docker_version} .
docker tag ${docker_image_name}:${docker_version} ${docker_image_name}:${build_part}

echo "\n"
echo -e "\033[1;33m # Docker image push on ghcr.io/jujemu\033[0m"
docker push ${docker_image_name}:${docker_version}
docker push ${docker_image_name}:${build_part}
docker rmi -f ${docker_image_name}:${docker_version} ${docker_image_name}:${build_part}
# Dockerfile
# nginx와 react를 하나의 이미지로 빌드합니다.
FROM nginx:stable-alpine3.17-slim
LABEL   "title"="nginx-and-react" \
        "version"="1.0"

EXPOSE 80 443

COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./nginx/conf.d /etc/nginx/conf.d
COPY ./dist /usr/share/nginx/html

CMD ["nginx", "-g", "daemon off;"]

 

빌드가 완료되면 역시 deploy 인스턴스에 배포하기 위해서 원격 명령어를 실행합니다.

역시 기존에 있던 프론트엔드 이미지를 지우고 docker-compose up -d 합니다.

3. 지금 빌드로 테스트해보기

 

젠킨스 Dashboard에서 각 아이템에 들어가서 지금 빌드로 동작하는 지 테스트해봅니다.

 

성공적으로 빌드된 것을 확인할 수 있습니다.

deploy 서버에도 들어가서 docker ps -a로 확인합니다.

이상으로 스프링과 리액트로 구현하는 프로젝트를 젠킨스와 도커로 CI/CD를 구축했습니다.