프로그래밍/Spring

[Spring] Jenkins(젠킨스)를 활용한 스프링부트 앱 간단 배포하기

Jay Tech 2019. 8. 24. 15:19

젠킨스를 활용한 스프링부트 앱 배포

젠킨스란?

젠킨스란 소프트웨어 개발 시 지속적 통합 (Continuous Integration) 서비스를 제공하는 툴이다.

젠킨스의 공식 홈페이지를 가보자. 메인화면에 젠킨스의 장점들을 설명하고 있다. 다음은 메인 화면의 장점 내용들을 간단히 번역한 내용이다.

지속적 통합과 전달

확장가능한 자동화 서버에서 젠킨스는 간단한 CI 서버 혹은 지속적 전달을 하는데 쓰인다. 여기서 말하는 지속적 전달이란 프로덕션에 릴리즈하기 위한 코드 변경이 자동으로 준비되는 개발론을 말한다. 현대 애플리케이션의 기반인 지속적 전달은 빌드 단계 이후 모든 코드 변경을 테스트 환경 및 프로덕션 환경에 배포함으로써 지속적 통합을 확장한다.

참고) https://aws.amazon.com/ko/devops/continuous-delivery/

쉬운 설치

젠킨스는 self-contained되어 있는 자바를 기반으로한 프로그램이며 Window, Mac OS X, Unix 계열과 같은 운영체제에서 실행할 수 있다.

쉬운 설정

젠킨스는 웹 인터페이스를 통해서 쉽게 설정 할 수 있으며 오류 점검 및 내장 된 도움말이 포함되어 있다.

플러그인

업데이트 센터에 엄청 나게 많은 플러그인들이 있고 지속적 통합과 전달에 있어서 유용하게 쓰인다.

확장 가능성

젠킨스는 플러그인 구조에서 매우 쉽게 확장할 수 있고 거의 무한한 가능성을 제공한다.

분산환경

젠킨스는 많은 컴퓨터들 사이에 있어서 업무를 쉽게 분산하고 빌드, 테스트, 배포를 다수의 플랫폼에서 빠르게 할 수 있다.

그렇다면 이제 젠킨스를 실제 서버에 설치를 해보고 앱을 배포해보자.

설치 시에는 직접 설치를 할 수 있고 도커를 활용해서 설치를 할 수 있다. 두 가지를 다 해보자.

설치 환경은 CentOS-7.3-64 이고 테스트를 위해 간단한 서버를 임시로 만들어보았다.

기본적으로 자바사 설치가 되어 있어야 젠킨스를 설치할 수 있다. 자바는 open jdk를 설치를 해보자.

yum install java-1.8.0-openjdk-devel.x86\_64

CentOS 기준 설치 명령어 이다. Ubuntu라면 apt-get install openjdk-8-jdk 으로 설치하는 방법이 있다.

 

젠킨스 설치 시 방법은 크게 두 가지가 있다. 직접 설치와 도커를 통한 설치. 먼저 직접설치를 알아보고 그 다음에 도커를 통한 설치를 알아볼 텐데 도커에 대한 러닝커브가 존재하기 때문에 시간이 없다면 밑의 도커를 통한 설치부분은 뛰어넘고 그냥 직접 설치를 통해서 설치해보자.

 

직접 설치 방법

 

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

rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key

yum install jenkins

systemctl enable jenkins 

systemctl start jenkins

 

이후 젠킨스가 실행되는 포트를 변경하고 싶다면,

 

/etc/sysconfig/jenkins

에 들어가서 젠킨스 포트를 찾은 뒤 원하는 포트로 변경되고 재시작 시켜주면 된다.

 

도커를 이용한 설치 방법

 

본인이 도커로 설치를 하고 싶다면 먼저 도커가 있어야 한다.

도커 설치 명령어

curl -fsSL https://get.docker.com/ | sudo sh

도커 설치 확인

 

도커 설치 후 버젼 확인을 해보자

젠킨스 도커 이미지 받아오기

docker hub의 jenkins image

 

도커 허브에 가보면 젠킨스의 공식 이미지가 있다. 주의할 것은 어떤 jenkins 이미지를 받아오느냐이다. 처음에 official image를 받았는데 jdk 8 환경에서 설치 후 젠킨스 환경 설정이 제대로 되지 않았다. 여러번 삽질 끝에 그 밑에 있는 open source 버젼을 받았다. 이름은 jenkins/jenkins이고 업데이트 날짜를 확인해보라. latest TAG는 무려 글쓴 시간 기준 3 Hours ago 이고 offcial image는 latest가 1 year ago 이다. 아마 jenkins/jenkins 라는 이미지가 계속 해서 업데이트되고 있는 듯 하다.

 

이미지를 pull 을 해보자.

docker pull jenkins/jenkins

 

docker image 당겨오기

사실 도커이미지를 받을 때 TAG 버젼을 명시하는 것이 좋다. 계속 해서 업데이트 되므로 업데이트가 되었을 시 본인이 최초로 설정한 base 환경에 맞을지 안맞을지 모르기 때문이다. 하지만 지금은 설치법을 보여주는 글이기 때문에 그냥 TAG를 붙이지 않았다. TAG를 붙이지 않고 이미지를 pull 하게 되면 자동으로 제일 최신 버전의 이미지를 가져오게 된다 (latest TAG)

혹시 도커가 실행이 되지 않는다면?

systemctl status docker

status를 확인하고 inactive 상태라면

 

systemctl start docker

 

다음과 같이 도커를 시작해준다.

 

systemctl enable docker

 

도커 데몬이 부팅시에 자동으로 실행될 수 있도록 하는 설정도 넣어 줄 수 있다.

 

이미지 확인

docker images

 

도커 이미지

이미지를 통해서 container를 띄워보자.

한 가지 유의 점은 도커 컨테이너와 볼륨을 공유할지에 대한 설정을 설정할 수 있다는 것이다. 즉 컨테이너 안의 파일과 호스트의 파일을 공유하는 것이다. 공유를 하고 싶다면 볼륨을 명시해 주어야 한다.

docker run -d -p 8080:8080 -v /jenkins:/var/jenkins_home --name jenkins -u root jenkins/jenkins

-d : 이 옵션은 백그라운드에서 실행하겠다라는 의미이다.

 

-p : 포트 옵션은 도커 컨테이너 내부 포트와의 매핑을 설정하는 것인데 왼쪽에 있는 포트 번호가 외부 포트번호이다. 만약에 9090:8080 이렇게 쓴다면 내 서버 아이피의 9090 포트로 접근을 하게되면 컨테이너 내부 포트 8080 (젠킨스 컨테이너) 와 매핑을 시키겠다는 의미이다.

 

-v: 볼륨 옵션은 위에서 언급한 호스트와 볼륨을 공유하는 설정이다. 콜론 왼쪽이 내 호스트 서버의 루트경로를 잡아온다. 저렇게 쓰게되면 루트에 jenkins라는 폴더가 생길 것이다. 그리고 그 폴더를 실제 컨테이너 내부의 젠킨스 폴더인 /var/jnkeins_home이라는 폴더와 매핑이 된다. 젠킨스가 나중에 빌드하고 난 결과물들을 직접 호스트에서 공유할 수 있다.

 

--name: 컨테이너 이름을 설정한다. 그리고 pull받은 이미지인 jenkins/jenkins를 넣어준다.

 

또 다른 예시) 단순히 9090포트에 매핑시킬 때

docker run -d -p 9090:8080 -p jenkins/jenkins

이제 본인이 설정한 포트를 통해 젠킨스에 접속해보자.

 

젠킨스 준비중

 

아주 설레는 접속화면이다. 나를 위한 인상좋은 비서가 손에 수건을 두르고 준비중이다. 무슨 일을 시켜먹을까 행복한 고민을 하면서 기다리길 바란다.

 

젠킨스 접속 화면

요 언락 화면이 나올텐데 초기 접속화면은 비밀번호를 입력해야 한다 (최초 한번). 도커로 설치 했을 경우, 컨테이너의 로그를 확인하면 비밀번호를 얻을 수 있다. (일반 설치의 경우 /var/jenkins_home/secrets/initialAdminPassword 를 관리자 권한으로 열면 비밀번호가 들어있다)

 

컨테이너를 먼저 확인해보자.

docker container ls

 

컨테이너 상태

컨테이너 로그 확인하기

docker logs [컨테이너 id]

컨테이너 로그의 확인

 

이렇게 비밀번호를 얻을 수 있다. 저 번호를 웹에다가 입력하자. (참고로 글 작성을 위한 서버를 임시로 만든 것이어서 그냥 가리지 않았다. 글 작성 이후 바로 서버 terminate 하였다)

 

저 비밀번호를 입력하면 설치화면이 나오게 된다. 첫 번째 버튼을 누르고 넘어가자.

 

젠킨스 설치화면 - 2

설치가 완료되면 아이디와 비밀번호를 설정하는 화면이 나오는데 적절히 설정해주자.

초기화면에서 환경설정을 해보자.

필자가 생각하는 젠킨스를 활용한 구성도이다. 물론 젠킨스가 설치된 서버에서 앱을 배포할 수 있지만 그렇게된다면 별로 쓰는 의미가 없을듯하여 다른서버와 ssh 연결을 통한 배포를 진행해 보겠다.

 

젠킨스 활용 구상도

소스코드를 깃허브를 참조하여 가져온다. (브랜치 별로 명시할 수 있는데 밑에서 자세히 설명하겠다) 그리고 직접 빌드 및 테스트를 한다. 물론 이 과정에서 jar 파일이 만들어진다. (정확히 말하자면 2번후 3번이 아니라 2번과정에서 3번이 만들어 지는 것) 그리고 그 jar 파일을 ssh 연결을 통해서 보내려는 서버에 전송한다. 전송 이후 그 서버에 존재하는 스크립트를 실행한다.

 

참고로 best practice가 아니기 때문에 본인에 맞는 구성을 만들면 된다. 예를들어 개발/운영 서버의 스크립트를 직접 만들지 않고 젠킨스 내부에서 스크립트를 작성할 수 있다. 가능한 방법은 서두에서 언급한 것처럼 엄청나게 많으므로 본인의 프로젝트에 맞게 커스텀 하길 바란다.

 

 

플러그인 설치

 

ssh 연결을 하려면 플러그인이 필요하다. 플러그인을 먼저 설치해보자.

 

플러그인의 설치

검색창에 ssh 라고 치면 Publish Over SSH 라는 플러그인이 보일 것이다. 저것을 선택하고 Download now and install after restart를 눌러주고 설치하자. 그러면 젠킨스가 재시작될 것이다. 이 플러그인을 설치하는 이유는 다른 서버에 ssh 연결을 통해서 작업을 시키기 위해서이다.

 

그 이후 해야할 일은 젠킨스 서버와 연결할 서버를 등록해 주는 것이다. 친구맺기라고 가정하자.

 

젠킨스 환경설정

 

왼쪽 탭의 Manage Jenkins를 들어가서 Configure System 톱니바퀴 모양을 눌러보자.

 

그 이후 스크롤을 밑으로 쭉 내리면 Pulish Over SSH 라는 탭이 보일 것이다.

 

그곳에서 서버 이름과 주소를 등록해주어야 친구가 맺어진다. 

 

서버 등록 과정

Advanced 탭을 누르면 체크 박스부터 밑으로 쭉 펼쳐지는데 그곳에서 서버를 등록해준다. 필자는 Ubuntu 서버를 pem 키를 통해 등록했는데 pem 키를 cat 해서 열어보면 RSA 키가 나오는데 그것을 Key에 등록해준다. 혹은 비밀번호로 서버에 접속한다면 키 등록 말고 비밀번호 등록으로 해도 된다.

 

그리고 중요한 점이 Remote Directory설정이다. 이것을 기준으로 이따가 파일을 전송하게 될 텐데 잘 기억해 놓자. /home/ubuntu 까지 등록해 놓았다.

 

그리고 하단의 Test Configuration을 눌러본다. 

 

Test Configuration

저 버튼을 누르게 되면 연결할 서버를 한 번 TCP 를 통해서 찔러보게 된다. 

잠깐의 로딩 끝에 바로 Success 가 나오면 성공이다. 계속 로딩이 된다면 연결할 서버의 22 번 포트가 젠킨스 배포 서버 ip가 허용이 되어 있는지 확인해 보자. 

 

이 설치가 끝났다면 메인화면이 띄워질 텐데 바로 메인화면에서 새로운 ITEM을 생성하기 버튼을 누른다.

 

New Item

이름 지정후 Freestyle Project 를 선택을 한다.

General

 

General 설정

일반 환경설정에서 GitHub Project를 선택하고 url을 입력한다.

Source Code Mangement

 

Source Code Management

Git을 선택하고 url을 한 번 더 입력 후 Credential을 등록한다. 저것은 자신의 깃허브 아이디를 등록하면 되는데 Advanced를 눌러서 아이디 비밀번호를 입력하고 셀렉트 박스를 눌러서 선택하면 등록할 수 있다. 그리고 빌드할 브랜치를 명시한다. 사진은 개발용 서버로 쓸 예정이니 develop 브랜치로 잡아보았다.

Build

빌드 항목은 하단의 셀렉트 박스를 통해 빌드 시 할 수 있는 작업을 정의해 놓는다.

 

Build 시 선택할 수 있는 작업들

 

여기서 지금 써보려고 하는 것은 Invoke Gradle scriptSend files or execute commands over SSH 이 두 가지 설정이다. SSH 관련 설정은 디폴트에선 없고 아까 위에서 말했던 플러그인을 통한 설치를 해야 저 항목이 보일 것이다.

 

먼저 Invoke Gradle script 설정이다. 사실 젠킨스 통합 환경 설정에서 Global Tool Configuration에서 Gradle을 다운받아 전역적으로 사용할 수 있다. 하지만 Gradle wrapper를 통해서 Gradle 설치 없이 진행할 수 있다. (이것은 스프링부트에서 gradle 로 프로젝트를 만들어 Github에 push 할 때 wrapper 까지 push가 되었다면 따로 설정할 필요가 없다)

 

Build 관련 설정 - 1

 

그렇기 때문에 Use Gradle Wrapper를 선택하고 Tasks를 정의한다. 여기서는 클린 후 빌드를 해보자. 참고로 build명령어 시 test도 수행되게 하려면 스프링부트 앱의 설정에서 build.gradle 에 다음과 같은 설정을 추가해야한다.

 

test {  
  useJUnitPlatform()  
}

혹여나 test를 스킵 하고 싶다면 build 명령어 뒤에 -x test를 붙이면 된다.

 

다음은 다른 서버로 빌드된 jar 파일을 던질 때 해야 하는 설정이다.

이 부분이 제일 중요한데 자칫 하다 삽질 지점이 될 수 있다.

 

Build 관련 설정 - 2

 

Source files: 내가 전송할 파일의 위치를 적는다. 젠킨스의 workspace 기준으로 적게 되는데 git pull 로 당겨 온 스프링 부트 앱의 루트 경로라고 생각해도 된다. 그렇게 되면 (gradle build 시) jar 파일의 위치는 build/libs 안에 들어가 있다. 그 곳에 jar 파일이라고 명시를 해준다.

 

Remote Directory: 파일을 전송할 원격 서버의 디렉터리를 명시하는 부분이다. 이 부분에서 조심해야 할게 아까 젠킨스의 서버 친구 맺기에서 설정한 폴더 기준으로 적어야 한다. 그 쪽에서 /home/ubuntu 라고 적어줬기 때문에 그 밑의 경로를 적는다. 사진에서는 /zzazan/deploy 라고 되어 있다. zzazan은 애플리케이션 이름이고 deploy라는 폴더는 jar 파일을 넣어놓기 위한 폴더로 사용하려고 만들어 놓았다. 미리 서버에 들어가서 저 폴더를 만들어 놓자.

 

그 전에 사진으로 한 번 더 어떤 상황인지 자세히보자. 경로를 맞춰주지 않으면 파일이 갈 수 가 없기 때문에 끝없는 삽질이 이어질 수 있다.

 

 

원격 서버의 폴더 구조

원격 서버의 폴더 구조이다. 우리가 전송할 경로는 ubuntu/[앱의이름에 해당하는폴더]/deploy 이다.

 

자세한 구상도

 

Exec command: 파일 전송 후 실행할 명령어를 입력한다. 절대 경로로 ubunut의 루트 부터 적어 보았다. 그렇다면 전송할 서버에 미리 저 스크립트 파일이 있어야 하겠다.

 

스크립트의 내용을 보자.

echo "> 현재 구동중인 짜잔스타그램 pid 확인"
​ CURRENT_PID=$(ps -ef | grep java | grep zzazan* | awk '{print $2}')
echo "$CURRENT_PID"
​ if [ -z $CURRENT_PID ]; then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -9 $CURRENT_PID"
kill -9 $CURRENT_PID
sleep 10
fi
​ echo "> 새 짜잔 애플리케이션 배포 합니다 짜장면!!"
nohup java -jar /home/ubuntu/zzazan/deploy/zzazanstagram-0.0.1-SNAPSHOT.jar >> /home/ubuntu/zzazan/logs/zzazanSys.log &

간단하게 떠 있는 앱을 grep으로 찾아서 죽이고 새로운 앱을 배포한다. 출력은 logs폴더에 넣어서 nohup 에 해당하는 산출물을 저장한다. (다음 게시물에서는 배포 환경별 로그 파일 관리에 대해서 다룬다)

 

왼쪽 탭

 

Build Now를 누르자

 

그리고 그 작업에 들어가보면,

 

작업

Console Output이 있을텐데 눌러보면 로그를 확인할 수 있다. Fail 된다면 로그를 통해서 확인하자. 

삽질하면서 주로 Fail 이 떴던 경우는, 

 

SSH 연결이 서로 되어 있지 않는 경우 (즉 원격 서버쪽에서 젠킨스 서버와의 22번 포트를 통한 TCP 연결이 허용되어 있지 않은 경우)

 

File send 시 디렉터리가 제대로 맞지 않는 경우

 

스크립트를 실행할 권한이 없는 경우 (스크립트 파일에 chmod 755를 주었던 것 같다 <- 이부분은 확실하지 않음)

 

jar 파일이 전송이 안되는 경우 (먼저 젠킨스의 workspace를 확인해서 jar파일이 제대로 생성되었는지 부터 확인하자)

 

로 나누어볼 수 있겠다. 그 외의 오류들은 로그를 확인하면서 살펴보자.

 

젠킨스의 console output

스프링부트 앱을 빌드를 하고 jar파일을 생성해 개발서버에 던져놓고 스크립트 까지 실행하는 모습이다. 

 

젠킨스는 정말 많은 일들을 해준다. 빌드와 배포과정을 간단히 해 놓음으로써 애플리케이션 개발에 좀 더 집중할 수 있고 여러 사람들이 들어와서 배포 상황들을 확인할 수 있는 장점들이 있다. 

 

프로젝트에 적용하지 않았다면 꼭 한번 해보길 바란다. 프로젝트 진행 시간을 많이 단축시킬 수 있을 것이다.

 

다음 게시물은 개발/운영 서버 별로 환경설정을 다르게 가져가 젠킨스를 통해 배포하고 환경 별 Log를 쌓는 방법에 대해서 포스팅 해보려고 한다.