Jenkins CI/CD 구축하기

쭈·2023년 3월 4일
0

✅ 기본흐름

  1. 로컬에서 작업 후 git에 push 한다.
  2. main branch로 pr요청 후 merge되면 git에서 webhook이 발생한다.
  3. jenkins에서 webhook이 발생 된 걸 감지하고 빌드 시작한다.
    3-1. 빌드 결과를 discord로 보내준다. (생략가능)
    3-2. 빌드 성공 시 jar 파일이 생성된다.
  4. 젠킨스 서버에서 ssh를 통해 원격 서버로 jar파일을 전송한다.
    원격서버 에 저장된 배포스크립트 (deploy.sh)가 실행된다.
    4-1. 배포스크립트 내용에 따라 현재 실행 중인 스프링부트가 있으면 종료시키고 새로운 jar파일을 실행시킨다.

✅ springboot 서버 구축

1. ec2 인스턴스 생성 및 연결

1-1. 인스턴스 생성

프리티어로 인스턴스를 생성하는 방법은 이미 너무 많아 생략한다.

AMI로 리눅스2 사용했고 인스턴스에 하나의 탄력적 ip(Elastic Ip)는 무료이기 때문에 추가했다.

❗️ 주의할 점은 ip와 인스턴스가 연결되어 있지 않으면 요금이 청구되므로 인스턴스를 삭제하거나 중지할 때 탄력적 ip도 같이 삭제 할 것. !!

1-2. 인스턴스 접속

  • SSH를 이용하여 Linux 인스턴스에 접속하는 방법 (1)
ssh -i "본인pemkey명.pem" instance-user-name@instance-public-dns-name

(인스턴스 대시보드 > '연결' > SSH 클라이언트'에 접속하면 편하게 명령어 복사할 수 있도록 되어있다!)

  • SSH를 이용하여 Linux 인스턴스에 접속하는 방법 (2)

매번 ssh -i "본인pemkey명.pem" instance-user-name@instance-public-dns-name 를 입력하는 건 너무 귀찮은 일이다.

간편하게 ssh 호스트명로 접속할 수 있도록 설정해보자!

  1. pem 파일을 ssh 내부에 복사
$ cp pem키명.pem ~/.ssh/
  1. pem 권한 수정
$ chmod 600  pem키명.pem
  1. config파일에 설정넣기

나처럼 기존의 aws 계정 config파일이 존재하면 기존 config파일 밑에 작성하면 된다. 없으면 config파일 생성하여 하단에 있는 정보 작성하기

$ vi config

Host {호스트명 설정}
User ec2-user // 리눅스로 이미지를 만들었을 경우 
HostName {퍼블릭 IPv4 주소|탄력적 IP 주소}
IdentityFile {pem키 파일 위치}

2. 인스턴스에 java와 git 설치하기

ec2는 AWS에서 제공해주는 가상의 컴퓨터이기 때문에 필요한 소프트웨어들을 설치해야한다. 나는 스프링 프로젝트를 배포할 예정이기 때문에 java와 git을 설치했다.

2-1. java 설치

인스턴스에 사용하는 java 버전과 프로젝트 버전이 일치하는 것이 좋기 때문에 11 버전을 설치했다.

  • 설치
sudo amazon-linux-extras install -y java-openjdk11
  • 설치된 버전 확인
java -version

2-2 git 설치

  • 설치
sudo yum install git
  • 설치된 버전 확인
git --version

3. 인스턴스에 스프링 프로젝트 빌드 및 배포하기

처음부터 jenkins로 빌드 및 배포해도 되지만 프로젝트 배포는 처음이기 때문에 cicd 구축 전에 해당 인스턴스에 연습삼아 빌드 및 배포를 해봤다.

3-1. git으로부터 프로젝트 clone하기

나는 팀원 깃허브에 생성된 레포를 fork해서 작업할 예정인데 ec2인스턴스에 프로젝트를 배포하는 경우 일반적으로 원본 레포지토리 주소를 사용해야하므로 팀원의 주소를 복사해서 사용했다.

git clone https://github.com/[]/[].git

3-2. 빌드테스트

  • yml 파일 추가

yml파일은 보안상 git에 직접 올리는 것을 지양하기 때문에 직접 인스턴스에 yml 파일을 넣으면 된다.

vim application-deploy.yml
  • 빌드 테스트
./gradlew test

빌드테스트에서 실패했다.

해당 오류를 찾아보니 @SpringBootTest 주석처리 혹은 테스트 경로에 설정 파일 만들어주면 된다고 한다.

우선 주석처리하고 main에 merge한 후 인스턴스에 프로젝트가 존재하는 경로에서 변경 사항이 있는 깃 내용을 pull 받는다.

$ git pull

그 후에 다시 빌드 테스트했더니 성공

3-3. 프로젝트 빌드

$ ./gradlew clean build

빌드 성공 시, 프로젝트 폴더에 build/lib 내부에 들어가면 jar파일이 만들어져 있다.

3-4. 프로젝트 배포

$ nohup java -jar todoit-0.0.1-SNAPSHOT.jar

$ vim nohup.out 을 통해 로그를 볼 수 있다.
(오류 발생 시 오류내용도 볼 수 있다.)

4. 배포된 파일 실행

http:// [탄력적ip주소] : 8080

✅ jenkins 서버 CI/CD 구축

1️⃣ CI 부분을 구축해보자

1. ec2 인스턴스 생성 및 연결

위의 과정과 동일

2. 인스턴스에 jenkins 설치

2-1. git과 java 설치

위의 과정과 동일하게 git과 java도 인스턴스에 같이 설치해주자!

2-2. jenkins 설치 및 실행

  • jenkins 설치
sudo wget -O /etc/yum.repos.d/jenkins.repo http://pkg.jenkins-ci.org/redhat/jenkins.repo

sudo rpm --import http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key
sudo yum install jenkins

  • jenkins 서버 실행 및 설정
$ sudo service jenkins start

![](https://velog.velcdn.com/images/dlfrlwk![](https://velog.velcdn.com/images/dlfrlwkd/post/4222c345-82ba-4225-aef8-28f73322a3ab/image.png)
d/post/7a06ffe7-4580-4c8b-8430-1c6e039e0d98/image.png)

  • jenkins 웹 컨테이너 접속

http://[퍼블릭ip주소]:8080/

  • 초기 비밀번호
$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword

  • 플러그인 설치 (좌측 선택하면 편해용)

플러그인 설치하고 회원가입까지 해주면 완료!

3. jenkins에 item 등록하기

3-1. github 프로젝트와 jenkins 연동하기

1. github token 발행
`깃허브 settings > developer settings > personal access token`에서 발행 
2. jenkis에 깃허브 정보 등록하기
`dashboard > Jenkins관리 > Configure System > github` 

credentials 선택 > kind: secret text 선택 > secret창에 발행한 깃허브 토큰을 입력

test connection으로 정상 동작하는 거 확인 후 저장

3-2. jenkins에서 item 생성

item 생성 시 freestyle과 파이프라인을 선택해서 구축할 수 있다. 파이프라인으로 생성할 경우 빌드 배포 단계 등을 다양하게 커스텀할 수 있지만 배포가 이번이 처음이기 때문에 편하게 구축할 수 있는 freestyle로 선택했다.

  1. new item > Free style project > General > Github Project Url 입력
    (ex. https://github.com/[본인깃허브계정]/[레포명])

  2. 하단 소스코드 관리 > Git 선택 > Repository URL 입력
    (ex. https://github.com.[본인깃허브계정]/[레포명].git)

  1. Credentials 추가

username은 자유롭게 작성하면 된다.
id와 password는 깃허브 아이디와 비밀번호를 입력해야한다.

❗️Branches to build에서 master로 되어있는 값을 main으로 바꿔야한다.
이부분 생각 못했다가 계속 빌드 실패해서 쓸데없는 시간 보냈다 ㅜㅜ


빌드 성공!

4. git webhook 설정

깃에서 일어나는 특정 이벤트들을 (ex. push) jenkins에서 감지할 수 있도록 webhook을 설치한다.
(jenkins에서 감지 후 알아서 빌드해준다.)

4-1. github에서 webhook 설정

  1. github settihgs > webhook > payload url 입력

[jenkins 주소]/github-webhook/

❗️자동리다이렉트 주소라 마지막 슬래쉬 까먹지 말고 꼭 붙일 것

  1. github settihgs > webhook > content type

application/json 선택

나머지는 default로 선택된 값 그대로 냅뒀다.

4-2. jenkins 설정

  1. Jenkins 관리 > 플러그인 관리 > Github Integration 설치
  2. Jenkins 해당 프로젝트 item > Configure(구성) > 빌드 유발 > GitHub hook triger for GTSScm polling 선택

깃으로 push하고 main에 merge했을 경우 자동 빌드 성공!

5. Jenkins Discord Notification

(생략가능)

추가로 빌드 결과를 디스코드에 보내주기 위해 jenkins 플러그인에서 Discord Notifier을 설치한다.

Discord에서 채널 서버의 settings > Webhooks 링크를 복사한 후 하단 jenkins url에 넣어주기만 하면 된다.

6. jenkins 빌드 설정

지금까지의 빌드 성공은 일종의 빌드 테스트라고 보면 된다.

실제 배포를 위한 빌드단계를 추가적으로 jenkins에서 설정해줘야한다.

실제 빌드를 진행하게 되면 gradle 폴더가 생기고 내부에 jar파일이 생기게 된다.

  • gradle plugin 설치

나는 gradle로 build하기 때문에 gradle 플러그인을 따로 설치해줬다.

  • use gradle wrapper 선택

CI 구축이 끝났다.

이제 생성된 jar파일을 SSH를 통해 원격 서버 (스프링부트 인스턴스)에 보내주면 된다.

2️⃣ CD 부분을 구축해보자

7. SSH 설치 및 설정

7-1. Publish Over SSH 설치 및 설정

❗️ 스프링프로젝트 서버 aws 보안규칙 > 인바운드규칙에 jenkins server도 추가하는거 잊지말기

1. SSH, Publish Over SSH 플러그인 설치
2. SSH Key 생성

jenkins ssh에 접속하여 SSH Key를 생성한다.

id_rsa와 id_rsa.pub가 생겼다.
(pub = public 즉, 공개키)

3. jenkins에서 ssh 설정하기

3-1. Jenkins 관리 > 시스템 설정 > Publish Over SSH 접속

$ cat id_rsa을 통해 출력할 수 있다. id_rsa값을 복사해서 key 부분에 붙여넣는다.

3-2. add SSH Servers

name: 사용할 ssh server name (자유롭게 설정)
hostname: 원격 서버 ip
username: 원격 서버 user name
Remote Directory: 원격서버에서 접속하여 작업할 디렉토리 (하위 디렉토리는 item 설정에서 사용할 수 있어 나는 기본 디렉토리만 적어놨다.

test configuration 눌러서 success 뜨면 된다.

4. item 설정하기
  • Source File

따로 경로를 바꾸지 않았으면 jenkins 설치되어 있는 인스턴스 내부에서 /var/lib/jenkins/workspace 경로에 내 스프링 프로젝트가 있다.
(Jenkins 관리 > 시스템설정에서 홈디렉토리 확인 가능)

해당 경로가 기본 경로로 잡혀 있기 때문에 jar파일이 생성되는 하위 디렉토리만 작성해주면 된다.

  • Remote directory

젠킨스에서 접속한 원격 SSH에서 소스파일을 업로드 할 경로를 지정한다.

  • Exec command

파일 전송 후 실행할 명령어 (배포스크립트)

8. 배포스크립트 작성

스프링프로젝트 인스턴스 내부에 넣어줬다.

#/bin/bash

REPOSITORY=/home/ec2-user/app/deploy

echo "Start Spring Boot Application!"
CURRENT_PID=$(pgrep -f todoit.*.jar)
echo "$CURRENT_PID"

 if [ -z $CURRENT_PID ]; then
echo ">현재 구동중인 어플리케이션이 없으므로 종료하지 않습니다."

else
echo "> kill -15 $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
 echo ">새 어플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/ | grep jar | tail -n 1)
nohup java -jar $REPOSITORY/$JAR_NAME 2>&1 &

nohup: 터미널 세션이 끊겨도 프로세스가 종료되지 않도록 해줌
& : 백그라운드 실행

  • ssh 인증 오류로 에러 발생

    ERROR: Exception when publishing, exception message [Failed to connect and initialize SSH connection. Message: [Failed to connect session for config [aws-jenkins]. Message [Auth fail]]]

다시 ssh 설정부분 들어가보니 해당 오류가 떠있다.

jenkins.plugins.publish_over.BapPublisherException: Failed to connect and initialize SSH connection. Message: [Failed to connect session for config [aws-jenkins]. Message [Auth fail]]

분명 아까 test success 였는데 ㅜㅜ

  1. jenkins에서 발급받은 id_rsa.pub를 원격서버 ssh에 접속하여 존재하는 aurthorized_keys 폴더 하단에 추가해줬다.

  2. chmod 600 ~/.ssh/authorized_keys 600

블로그를 통해 해결했다 휴우

로그 보면 빌드 성공 후 실행 중인 스프링을 kill한 후 새로운 jar필드를 구동시키는 걸 확인할 수 있다.

ssh 타임아웃 에러

근데 어떤 오류발생으로 cicd 성공과 별개로 jenkins 상태가 unstable하다.

ERROR: Exception when publishing, exception message [Exec timed out or was interrupted after 120,000 ms]
Build step 'Send build artifacts over SSH' changed build result to UNSTABLE

배포스크립트 하단에 >/dev/null를 추가해줬다.

> : 리다이렉션의 의미로써 화면에 출력되는 내용을 > 우측에 있는 파일로 전송

2>&1 : 파일디스크립터에서 0은 표준입력, 1은 표준출력, 2는 표준에러를 의미한다. 표준에러를 표준출력으로 즉, 화면에 표시한다는 의미

> /dev/null 2>&1: 표준출력이 현재 화면에서 /dev/null(로그파일)로 바꼈으므로 에러내용을 화면에 출력하지 않고 로그파일 (/dev/null)로 보낸다는 의미

내 첫 빌드 배포 구축기 끝 !!


+) 회고 및 앞으로 수정할 내용

jenkins credential을 깃허브 계정(아이디, 비번)으로 했는데 이렇게 할 경우 보안상의 문제가 있을 수 있다고 들었다. ssh에서 비밀키 생성 후 수정할 것

현재 젠킨스 아이뎀을 freestyle로 구축했는데 pipeline학습 후 pipeline으로 구축해보기

현재 pr후 merge한 프로젝트 (main)을 젠킨스가 보고있는데 만약에 빌드 할 때 오류가 나면 다시 로컬에서 수정하고 push하고 main으로 merge한 후 빌드 결과를 기다려야한다. main으로 통합하기 전에 pr보낸거에 대한 빌드결과를 보고 성공시 merge할 수 있도록 수정하기.
(github pullrequest builder hook)

publish over ssh 플러그인 종료가 됐음에도 불구하고 처음 도전하는 cicd 구축이기에 현재 레퍼런스가 제일 많아 사용하게 됐다. 해당 플러그인 사용하지 않고 구축해보기

리눅스명령어.. 공부의 필요성을 느꼈다 !


🙇🏻‍♀️ 참고

https://docs.aws.amazon.com/ko_kr/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html

https://jojoldu.tistory.com/263

https://bcp0109.tistory.com/356

https://velog.io/@hmyanghm/AWS-EC2%EC%97%90-Jenkins-%EC%84%9C%EB%B2%84-%EA%B5%AC%EC%B6%95#---%ED%94%84%EB%A6%AC%ED%8B%B0%EC%96%B4-ec2-%EC%8A%A4%EC%99%91-%ED%8C%8C%ED%8B%B0%EC%85%98-%EC%83%9D%EC%84%B1

https://genie247.tistory.com/entry/jenkins-server-연동-오류-해결
https://blogger.pe.kr/369

profile
🌱

0개의 댓글