[Spring] 스프링부트 젠킨스 + 도커로 배포하기

4 분 소요

서론

프로젝트를 진행하며, 매번 마스터 브랜치에 머지 할때마다 직접 EC2에 접속해서 배포를 수동으로 계속 하고있었습니다. 근데 이렇게 하다보니, 시간도 너무 많이 잡아먹을 뿐만 아니라, 배포중에 사람의 손이 들어가다 보니 중간에 과정 하나를 빼먹는다거나 테스트코드를 돌려보는것을 깜빡한 상태로 배포하거나 하는 일 때문에 생산성이 저하되는 걸 체감했습니다.

프로그래머로써 이러한 반복작업을 계속 하는건 너무나 비효율적이라고 생각해서 개발을 잠시 후순위로 미루고 CI/CD를 먼저 적용하기로 했습니다.

저는 현재 AWS 프리티어만을 사용해서 프로젝트를 제작 중이기에, EC2하나 만으로 이러한 CI/CD 환경을 세팅해주어야 했는데요. 생각보다 EC2하나만으로 이러한 환경을 구축한 자료가 많이 없어서 고생을 많이했는데, 혹시나 저 같이 프리티어를 사용해서 자원이 한정적인 분들을 위해서 해결한 경험을 공유해보려 합니다.

배포 방식

우선 제가 구현한 배포 과정은 이렇습니다.

image1

먼저 깃허브 마스터 브랜치에 푸쉬하면, 이를 젠킨스가 webhook으로 인식하여 해당 레포지토리를 pull한뒤 이를 그래들을 사용해 빌드합니다.

jar 파일이 완성되면, Docker는 기존 컨테이너를 종료시키고, 컨테이너와 이미지를 삭제한뒤, DokcerFile을 통해 새로운 컨테이너를 생성하여 이를 실행시켜 8080포트에 연결합니다.

보통은 젠킨스를 사용하는 EC2 인스턴스를 하나 더 두어서, 젠킨스와 도커 컨테이너가 돌아가는 인스턴스를 분리하는 방식을 많이 사용합니다. 하지만 프리티어에서는 인스턴스 하나만이 무료로 사용가능하므로 (정확히는 750시간의 사용량이 제공되기 때문에 2개의 인스턴스를 사용하면 사용량이 375시간으로 줄어들게 됩니다.) 하나의 인스턴스를 통해 이 배포과정을 구현해보도록 하겠습니다.

Docker 설치

먼저, EC2에 젠킨스 컨테이너와 서버 컨테이너를 만들어서 하나의 인스턴스로 두개의 인스턴스를 사용하는것 처럼 사용할 것이기 때문에, EC2인스턴스 접속해서 Docker를 설치해주겠습니다.

1
2
sudo yum -y upgrade
sudo yum -y install docker

위 명령으로 도커를 설치한 뒤,

1
2
docker -v
Docker version 20.10.13, build a224086

위와 같이 버젼이 확인되면 올바르게 도커가 설치된것 입니다.

젠킨스 컨테이너 설치

젠킨스 공식 이미지를 먼저 도커에 Pull 해주겠습니다.

1
docker pull jenkins/jenkins:lts

lts 버젼을 사용하면 가장 최신의 안전한 버젼을 받아옵니다.

1
2
3
4
docker run \  -p 9080:8080 \  
-v /var/run/docker.sock:/var/run/docker.sock \  
--name jenkins \ 
 getintodevops/jenkins-withdocker:lts

-v 옵션이 붙어있습니다. 무엇일까요?

사실 위 옵션 없이 하나의 인스턴스로 도커 파일을 배포하려면, 젠킨스도 컨테이너이기 때문에 젠킨스 안에서 컨테이너를 실행해야 합니다. 하지만 젠킨스 컨테이너 안에서 또 도커를 설치하여 Java안에서 또 컨테이너를 동작시킨다면, 성능이 심각하게 많이 떨어질 것입니다.

이를 해결하기 위해서 docker.sock 파일을 마운트한채로 컨테이너를 동작시켜줘야 합니다. 이렇게 하면 젠킨스 컨테이너 안의 도커가 바깥의 EC2 인스턴스의 도커와 연결되어 젠킨스 컨테이너 안에서 외부 도커에 명령을 내릴 수 있게됩니다.

혹시 접속이 안된다면 EC2 인스턴스 보안그룹의 인바운드 규칙 설정에서 9090 포트를 올바르게 열어두었는지 확인합니다. 젠킨스는 따로 아이디와 비밀번호를 설정하기 때문에 0.0.0.0으로 열어두어도 괜찮습니다.

image1

접속하면 위와 같은 창이 나오게 되는데요. 젠킨스는 초기설정으로 아이디와 비밀번호를 설정해주어야 합니다.

젠킨스 내부로 들어가서 해당 파일을 열어 초기 비밀번호를 가져오겠습니다.

아래 명령을 통해 젠킨스 컨테이너에 접근합니다.

1
docker exec -it jenkins /bin/bash

젠킨스 초기페이지에 적혀있는 위치로 가서 해당파일을 열어 초기 비밀번호를 얻어 옵니다.

1
2
cat /var/jenkins_home/secrets/initialAdminPassword
47asdu8382575878dej98989fgd

image1

그럼 위와같이 플러그인을 설치하는 화면이 나오는데요. sugeested 플러그인을 설치하는게 가장 간편합니다.

image1

해당 플러그인을 모두 설치 후,

image1

아이디와 비밀번호를 설정해주면 젠킨스 초기 설정이 완료됩니다.

젠킨스 빌드 설정하기

image1

메인 화면에서 왼쪽에 있는 새로운 Item을 눌러 새로운 프로젝트를 만들어줍니다.

image1

설정은 Freestyle project로 해줍니다.

저는 메인서버에 푸쉬하기전 테스트 하는 develop 서버를 하나 만들려고 하기 때문에, 이름을 jamong-develop으로 설정하겠습니다.

image1
소스코드에 Git을 선택하고 현재 배포에 필요한 레포지토리의 주소를 적어줍니다. Branch Specifier에는 푸쉬됐을때 배포할 브랜치를 입력합니다. 저는 develop 브랜치 서버 배포를 위해서 develop으로 만들어주겠습니다.

이제 Credential을 설정해야 합니다. 간단하게 개인서버라면 깃허브 아이디와 비밀번호로도 설정할 수는 있지만, 보안을 위해서는 ssh연동 방식을 사용하는것이 안전합니다.

다시 젠킨스로 가서 ssh키를 발급 받겠습니다.

1
sudo -u jenkins /bin/bash

전환이 됐다면 ssh키가 들어갈 수 있는 폴더를 만들어주고 이동한 뒤, ssh키를 하나 생성하도록 하겠습니다.

1
2
mkdir /var/lib/jenkins/.ssh
cd /var/lib/jenkins/.ssh
1
ssh-keygen -t rsa -f /var/lib/jenkins/.ssh/github_ansible-in-action

image1
비밀 번호는 모두 입력하지 않고 Enter로 스킵해줍니다.

ls -al 을 사용해서 비밀키와 공개키가 잘 생성되었는지 확인해 줍니다.

image1

이제 GitHub로 가서 Deploy Key를 등록해줍시다.
image1

Add deploy Key를 눌러 ssh키를 설정해 줍시다. 저는 이미 발급받은 키를 등록해 놓은 상태입니다.

image1

젠킨스에서 아까 만들어준 공개키를 받아와 입력해줍시다. 아래의 명령어로 공개키를 확인 할 수 있습니다.

1
cat /var/lib/jenkins/.ssh/github_ansible-in-action.pub

image1
image1

다시 젠킨스 관리로 가서 Jenkins 관리 - Manage Credentials로 이동해줍니다.

image1

Stores scoped to Jenkins에 있는 global을 눌러 이동합니다.

image1
Add Credenials를 눌러 키를 추가해 줍니다.

image1

Kind를 SSH Username with private Key로 바꾸고 privateKey의 Enter directly를 활성화한뒤 Add를 통해 이번에는 젠킨스의 비밀키를 추가해줍시다.

1
cat /var/lib/jenkins/.ssh/github_ansible-in-action

image1

비밀키를 복사해주고 저장해줍니다. Username은 원하는 이름으로 설정해주면 됩니다. 저는 deploy key로 정하겠습니다.

image1

이제 아까 Credentials에 아까 만들어준 ssh키를 설정해줍니다.

빌드 유발에는 깃허브 webhook 설정을 위해 GitHub hook trigger for GITScm polling을 체크해줍니다.

이제 Build 설정을 해주겠습니다. Build 항목에서 Execute shell을 선택해주고 Github에 푸쉬가 되었을때 어떻게 작동할지를 적어주도록 하겠습니다.

1
2
3
4
5
6
7
8
./gradlew clean build
sudo docker rmi lmj938/jamong-serverdevelop

sudo docker build --no-cache=true -t lmj938/jamong-serverdevelop .      

sudo docker rm jamong-serverdevelop 

sudo docker run -d -p 8081:8080 --name jamong-serverdevelop lmj938/jamong-servertest

이대로 돌리게 되면 sudo를 사용할 수 없다는 에러가 뜹니다. root 계정이 아니면 sudo를 사용할 수가 없기 때문입니다. 이를 해결하기 위해 젠킨스 계정이 sudo를 사용할 수 있도록 설정 해주어야 합니다.

1
2
cd /etc
vim sudoers

vim 에디터로 sudoers 파일을 열어줍시다.

1
jenkins ALL=(ALL) NOPASSWD: ALL

위 명령어를 추가합니다. jenkins에게 sudo 접근권한을 주는 명령어입니다.

image1

완료 됐으면 저장합니다.

깃 Webhook 설정하기

레포지토리의 세팅에 들어가 Webhooks를 선택해줍니다.

image1

payload URL에 해당 젠킨스 주소를 적어주고, Content type을 application/json으로 설정해주면 됩니다.

이때, 꼭 보안그룹의 인바운드 규칙에 젠킨스 포트를 0.0.0.0으로 퍼블릭으로 열어두어야 깃허브가 보낸 Webhook 요청을 받을 수 있습니다.

이제 푸쉬요청을 보내면, 젠킨스가 알아서 깃에서 푸쉬된 내용을 가져와 파일을 빌드하고 이를 도커 컨테이너로 빌드하여 실행하는 것을 확인할 수 있습니다.

카테고리:

업데이트:

댓글남기기