[졸업프로젝트] CI/CD 환경 구축 삽질 과정

shane·2021년 3월 25일
1
post-thumbnail

팀 이름

원래 시간순서로 따지면 하단에 작성될 역할분배부분이 먼저다. 그 이후에 팀 이름을 논의하게 되었다. 하지만 나는 작명센스가 없기에 가만히 여러 팀원들의 의견을 경청했다.
PLIM, UAU, 마라탕 등등 11가지의 의견이 나왔고, 익명 투표를 통해 팀 이름을 결정하기로 합의를 보았다.

결국 PLIM이 팀 이름이 되었다...!! PLIM은 초기 Project Leader in MJU의 약자였으나, 자체 뜻으로는 시작은 미약하지만 끝은 창대하리라라는 뜻이 있다는 것을 알고 매우 만족했다.

역할분배

처음 나는 3학년 때부터 내가 가고 싶은 직무가 Backend라는 것을 알고 있었기 때문에, 미래에 다가올 졸업프로젝트 수업인 팀프로젝트1 강의 에서 꼭 server 쪽을 맡을거라고 다짐을 했다.

4학년이 된 나는 나를 포함한 10명의 학생들이 팀을 이루게 되었다. 과거에 다짐한 것이 있기에 server 쪽을 맡고 싶었지만 다수의 팀원들도 원하던 상황이었다. 개발직무 역할은 웹, 앱, 서버, 디비(앞의 3분야와 중복) 개발자가 필요했는데, 서로 원하는 것을 다중 선택하고 하나만 선택한 사람을 우선 배정 이후 서로 의견을 조율하여 역할이 정해졌다.

내가 맡은 직무는 QA, Framework Leader, Server 팀장이다...!

이후 일주일이 지난 후, PM을 맡은 팀원이 Architect의 역할도 맡고 있었는데 졸업프로젝트 외에 동아리 활동 운영 등 다양한 활동을 진행중이어서 PM과 Architect 둘을 맡는 것이 굉장히 힘들다는 요청이 들어왔다. 모두 PM을 하지 않으려고 하는 상황에서 나에 대한 추천이 들어와, 나는 다른 팀원들도 원하면 기꺼이 PM도 맡겠다고 했다.

투표를 진행하여 다수결로 위의 3역할 외에도 PM을 맡게 되었다.

ALM 환경 구축

여기서 ALM은 Application Lifecycle Management의 약자로 전반적인 CI/CD환경을 구축하는 것이다. ALM 환경을Jira, Github, Jenkins를 이용하여 구축을 하려고 했다.

처음 나는 오픈소스인 Redmine을 이용하여 ALM을 구축하려고 했지만 Agile을 위한 최적의 환경이 초반부터 구축된 Jira가 초반 시간소모를 줄일 수 있다고 판단하여, Redmine이 아닌 Jira를 선택하게 되었다!
Jira와 Github을 엮는 것은 내가 아닌 다른 팀원이 진행하게 되었다. 그동안 나는 Jenkins, Github을 엮어야했다.

나의 최종 목표는 로컬 환경에서 git push를 하면, Github의 Webhook를 이용하여 Jenkins가 push를 알아채고 자동으로 빌드 후 원격배포를 하는 것이었다.

Jenkins

초기에는 서버를 2개를 사용하기로 했다.

  1. Jenkins Server(빌드용)
  2. Service Server(운영용)

기존에 가지고 있던 AWS 계정을 교내 학과 계정에 연동을 하여 금전적인 문제는 해결을 하였다.

Jenkins ServerServer Server 모두 CentOS 7을 ec2 인스턴스로 받아 진행하였다. t2.micro를 이용하였으며 volume은 기존 설정인 8GB가 아닌 10GB로 올렸다. 이후 ec2 인스턴스의 방화벽 포트 활성화를 위해 보안 그룹을 건들여, tcp22, http, https, 8080(spring boot), 8081(jenkins) 등을 개방하였다. ec2 CentOS의 username은 centos이다.

실제 사용은 PuTTYgen을 이용하여 .pem 키를 .ppk로 변환하여, PuTTY에 Jenkins Server IP, Auth메뉴에 가서 .ppk 키를 등록하여 ec2에 접속한다!

Docker Image - Jenkins

CentOS에서 Jenkins를 직접 다운받아 실행하는 방법도 있었지만 여러 불편함을 해소하기 위해, docker를 설치하여 진행하였다. 다음의 명령어를 입력하여 docker를 설치하면 된다.
docker를 설치하기 전에 root권한을 획득하기 위해 다음의 명령어를 먼저 입력한 후, docker 설치 명령어를 입력하자.

sudo su
yum install -y docker

이후 docker를 실행하기 위해 다음의 명령어를 입력한다.

systemctl start docker

Jenkins 도커이미지를 필요로 하기 때문에 다음의 명령어를 이용하여 이미지를 받자.

docker pull jenkins/jenkins

다운받은 도커이미지를 통해 컨테이너로 만들어 젠킨스를 실행하자.

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

-d 옵션은 백그라운드 실행을 의미한다.
--privileged를 입력해야 aws ec2 환경에서 -v 옵션을 사용할 수 있다.
-p 옵션은 로컬의 포트와 컨테이너의 포트를 연결하는 것이다. Local Port:Container Port의 형식이다.
--name은 컨테이너의 이름을 지정하는 옵션이다.
-v는 로컬과 컨테이너의 volume을 연결하는 옵션이다. Local Directory:Container Directory의 형식이다.
마지막에 적은 jenkins/jenkins는 컨테이너 실행을 위한 도커이미지 이름이다.

이후 Jenkins Server IP:8081을 입력하면 Jenkins 접속이 가능하다...!

접속이후 credential 입력을 요구로 하게 되는데, ec2에서 다음의 명령어를 입력하여 credential을 찾고 옮겨서 입력하자.

docker logs jenkins

기본값으로 젠킨스 플러그인 설치를 이어서 하면 설치가 끝나게 된다.

Jenkins - 설정 및 Build Error

Jenkins - Gradle

초기 Server를 spring boot를 이용하게 되었는데, 빌드를 Gradle로 하여 진행하였다. 그러나...

엿같은 오류가 계속하여 발생하였다.

  1. ~ can't cd to ~ : 해결 못함.

이틀 가까이 Gradle로 시도하다가 포기했다. 이후 Maven으로 빌드툴을 바꿨다.

Jenkins - Maven

초기설정을 Maven에 맞춰 바꿨다.
Jenkins관리 → Global Tool Configuration으로 이동하여 다음과 같이 입력 후 저장한다.

Jenkins관리 → 플러그인 관리로 이동하여 다음의 플러그인을 설치후 Jenkins를 재시작한다.

Jenkins관리 → 시스템 설정으로 이동하여 제일 밑으로 내려서 다음과 같이 작성한다.

Key에는 Service Server의 .pem키를 메모장으로 열어 복사 후 붙여넣기한다.
Name은 SSH Server 구별용 이름이니 아무거나 작성하자.
Hostname은 Service Server 즉, Jenkins Server에서 빌드된 Jar파일을 받을 서버의 IP를 입력한다.
Username은 초기에 ec2에 입장할 때 사용하는 것을 입력한다. ec2 CentOS의 경우 centos를 입력한다.
Remote Directory는 ec2의 경로를 입력한다. 여기서 작성한 경로를 기준으로 Jar파일의 경로가 결정이 될 것이니 신중히 작성하자.

이후 새로운 Item을 클릭하여 이름을 입력하고, Freestyle Project를 선택한다.
Github URL을 입력한다.

하단으로 내려가서 Github URL과 함께 Add를 클릭하여 본인의 Github계정 아이디와 비밀번호를 입력하여 추가한다.

git push를 trigger로 하여 빌드를 유발하기 위해 다음과 같이 선택한다.

빌드 탭으로 이동하여 Invoke top-level Maven project를 클릭하여 다음과 같이 입력하자.

여기서 Maven Version은 초기 설정에서 받은 Maven을 선택해주면 되고, Goals는 Maven을 이용하여 진행할 task를 입력해주면 된다.

Send files ~ over SSH를 선택하여 다음과 같이 입력한다.

SSH Server의 name은 초기에 설정한 SSH Server이름이 적히게 된다.
Source files는 빌드 후의 소스파일의 위치를 입력한다.
Remove prefix는 Source files에서 입력한 것에서 파일만 남게 되도록 파일의 앞부분 디렉토리를 입력해준다.
Remote directory는 아까 초반에 SSH Server 설정시에 말한 것처럼 초기 입력한 디렉토리를 기준으로 그 다음 디렉토리를 입력하는 것이다. 위 사진을 예시로 보면 /home/centos/plim/deploy에 소스파일이 저장될 것이다.
Exec command는 소스파일을 옮긴 후에 실행한 커맨드를 입력한다. 나의 경우 Service Server에서 사용하는 배포 스크립트를 실행하게 해두었다.

Jenkins - Build error(해결)

다행히도 바로 빌드에 성공했다!!! 그러나... SSH에서 문제가 발생했다.

위의 사진으로 봤을 때는 도대체 어떤 부분에서 permission이 거절된 것인지 알 수가 없었다.
자세히 알기 위해 다음의 설정을 건들였다.

빌드탭의 SSH Server에서 고급을 눌러 Verbose output in console을 선택한다. 그러면 다음과 같이 자세한 과정이 나열된다.

기록을 보니 Jenkins의 빌드를 통해 생성된 산출물인 jar파일이 Service Server로 집어넣으려고 할 때, Permission이 거절되고 있었다.
Google 신의 힘을 빌려 해결하려고 하였으나 동일한 증상을 찾아볼 수 없었다. 그렇게 시작된 시간낭비... 3시간을 넘게 검색을 하다가 결국은 방법을 찾아냈다. 정확하게는 동일한 증상은 아니지만 의심이 가는 부분을 찾아서 유사한 문제의 해결방안을 한번 따라해보았다.

그렇다! 문제의 원인은 jar파일이 들어갈 폴더의 owner가 centos가 아닌 root였다!
폴더의 owner를 변경하기 위해 jar파일이 들어갈 폴더의 상위 폴더로 이동하여 다음의 명령어를 입력했다.

chown -R centos:centos /home/centos/plim/

위와 같이 입력하면 뒤의 디렉토리를 포함한 자식들이 모두 centos의 소유로 바뀌게 된다.

그렇게 완벽하게 성공을 했다!

Jenkins - Github 연동

간단하다. Webhook 설정을 하면 된다.
가장 먼저 Jenkins의 메인에서 Jenkins관리 → 시스템 설정으로 이동하여 Jenkins Location을 설정한다. IP가 아닌 localhost로 되어있으면, 외부의 접속을 위해 IP로 변경해주자.

Github으로 이동하여 연동을 하려고 하는 레포지토리의 Settings로 간다.
Webhooks 메뉴로 가서, Add webhook를 클릭하여 진행한다.

Payload URL에 젠킨스의 ip:port/github-webhook/을 입력해주자. 여기서 주의점은 끝에 /를 꼭 넣어주자.
Add webhook을 클릭하여 설정을 끝내자.
이제 git push하면 젠킨스가 스스로 빌드를 진행한다!!!


후기

결국은 구축에 성공했다.
이렇게 되면 master 브랜치로의 git push가 일어나면 trigger를 통해 젠킨스의 빌드가 발생하게 되며, 이후 SSH Server를 이용하여 Service Server로의 원격배포 및 실행이 끝나게 된다.
과거 저학년 때 심심풀이로 알게 되어 시도를 해봤지만, 결국은 실패했었지만 4학년이 되어 3일 가까이를 끈기를 가지고 노력했더니 성공하게 되었다.
이런 뿌듯함으로 개발자를 하는가 보다.

profile
개발 관련 소통을 좋아하는 백엔드 개발자입니다.

0개의 댓글