본문 바로가기
기술/Spring-Boot

[Ubuntu/Travis-CI/CodeDeploy] SpringBoot 환경 배포 자동화 환경 구축

by Zabee52 2022. 1. 4.

CI/CD

하루종일 travis와 싸웠다. travis 사이트도 말썽을 부려댔고, 깃헙도 잠깐 터졌고, 티스토리도 잘 안 되는 데다가, 시스템 구축이 감이 통 잡히지 않아 나를 괴롭게 했다. 이런 나를 이끌었던건 다른 사람들은 했는데 라는 생각이었다. 남들이 하는 걸 내가 못 할 리가 없다. 이 마음 하나로 계속해서 붙들고 늘어졌다. 그리고 마참내 나는 해냈다.

세팅값이 미묘.... 하게 달라 어딜 바꿔야 할 지 찾기 쉽지 않았다. 아마 내가 세팅한 값도 누군가에겐 미묘할 것이다. 그런 사람들은 나와 같은 방식으로 구현한 다른 작성자들과 비교해가면서 풀어나간다면 비교적 수월하게 해낼 수 있을 것이다.

정보를 참고한 사이트는 여기 있다.

 

[SpringBoot] 웹서비스 출시하기 - 4. TravisCI & AWS CodeDeploy로 배포 자동화 구축하기

해당 글은 '우아한 형제들'의 개발자이신 jojoldu님의 블로그와 책(스프링 부트와 AWS로 혼자 구현하는 웹서비스)을 참고하여 작성하였습니다. 이전 글에서 AWS EC2에 개발한 프로젝트를 배포하였

dev-jwblog.tistory.com

 

why?

본문이 꽤나 길다. 그래서 먼저 대략적인 CI/CD 후보 선정 사유와 흐름을 먼저 한 번 간략하게 잡아보려고 한다.

 

먼저 CI/CD에 있어서 사용하고자 정했던 후보는 Travis CI와 Jenkins였다. 이후 GitHub Actions라는게 존재한다는 건 알았는데, 후보를 선정할 때 그 존재조차 몰랐기 때문에 후보군에 오르지 못했다. 그래서 둘 중에 무엇을 쓸까 고민하던 중, 두 가지 사유로 Travis CI를 고르게 되었다.

 

1. 당장 적용 가능하다

- 프로젝트 기간이 그다지 짧은 것은 아니다. 하지만 우리는 배포자동화에 들이는 시간보다 기능 개발, 성능 개선에 더욱 많은 코스트를 투자하고자 했고, 이에 따라 당장 적용할 수 있는, 세팅이 더욱 간편한 것으로 골라야 했다.

- 우선 중요한 것은 UI였다. 짧은 시간에 적용하려면 UI가 단순하고 명확해야 했다. 기능을 학습하는데 많은 시간이 투자되지 않아야 했다. 이런 부분에서 봤을 때, 많은 기능들이 화면 왼쪽에 다닥 다닥 붙어있는 Jenkins보다 branch 표시, 대시보드 출력이 끝인 Travis CI가 매력적으로 다가왔다.

- Jenkins는 그 역사가 긴 만큼 플러그인도 많이 지원하고 그만큼 강력한 기능을 자랑하지만, 우선 우리는 이 프로젝트에서 그 플러그인들을 사용할 것도 아니고, 플러그인이 많다는 것은 그만큼 매뉴얼한 세팅이 많다는 뜻이고, 그만큼 세팅에 더 많은 비용을 투자해야 한다는 뜻이었기 때문에 선택이 망설여질 수밖에 없었다.

- 반면 Travis CI는 GitHub에서 개발하는 만큼 비교적 간단한 세팅으로 GitHub과의 연동이 가능했고, 연동하는 것만으로 자체적으로 Build까지 수행해줬기 때문에 이용이 간편했다.

 

2. 현재 환경에서 적용 가능하다

- docker 위에 Jenkins를 올렸던 한 동기의 증언에 따르면 배포는 성공적으로 되었지만, t2.micro 에서 메모리 부족으로 계속해서 서버가 중단되는 경험을 했다고 한다. 이 상황을 해결하기 위해선 EC2의 메모리 사양을 높여야 했다고 했는데, 내 생각으론 서버의 부하가 아닌 배포때문에 메모리 사양을 키우는 것은 맞지 않다고 생각했기 때문에 결국 최종 후보에서 Jenkins를 제외하게 되었고, 그럼에 따라 자연스럽게 Travis CI로 선택하게 되었다.

 

 

CI/CD 흐름은 다음과 같다.

 

1. 개발자         : git push

2. Travis CI       : 감지 후 Build

3. Travis CI       : Build 결과물 S3에 업로드

4. CodeDeploy  : S3에 업로드 된 자료 EC2에 업로드

5. CodeDeploy  : EC2에 업로드된 .jar 자동 실행

 

대략적으로 보자면 이렇다. 근데 이 과정이 꽤나 험난하다. 그래도 따라하기만 하면 되도록 되어 있으니 다행이다. 이런 것도 나중엔 많이 쉬워졌으면 좋겠다. 그럼이제출발출출발출출출출발렛츠고

 

 

Travis-CI 설정

 

Homepage | Travis CI – Start building today!

Travis CI is a continuous integration tool that test and deploy your projects with ease. Sync your build projects with Travis CI in minutes!

www.travis-ci.com

 

시작은 당연히 Travis CI의 계정을 만드는데서 시작한다. 계정은 알아서 잘 만들리라 믿는다. 깃헙으로 로그인 하면 된다.

 

중요한 점은, 위와 같은 화면이 나오면 인내심 있게 좀 기다려줘야 한다. 사이트가 원체 느리다. 유튜브 영상이라도 하나 보면서 다음 화면으로 넘어가길 기다리자.

 

다음 화면으로 넘어간다면 본격적으로 계정 세팅에 들어간다.

 

처음 해야하는 작업은 계정의 플랜 세팅이다. 

 

 

세팅에 들어가면 Plan을 눌러 Free Plan을 구매해야한다. 이놈의 사이트는 프리 플랜이라면서 1달러 뜯어간다. 돈 드는 무료라니, 뼈 조심해야하는 명순튀같은 소리다.

 

여기서 명심할 점! Organizations는 별도의 플랜으로 결제를 해야한다. Organization을 위한 할당량은 따로 존재하는 것이다. 덕분에 나는 1달러 한 번 더 썼다. 입 안이 썼다. 입 안을 새콤달콤하게 만들어줄 새콤달콤을 살 수 있는 돈이 빠져나갔다.....

 

다음으로 해줘야하는 것은 Repository 세팅이다. 센스 있는 문화시민이라면 이것저것 버튼을 눌러가며 잘 추가 할 수 있도록 시스템이 되어 있다. 리포 전부 불러와서 이상한 에러메세지 보지 말고 필요한 리포만 골라서 딱딱 가지고 오자.

 

처음 보게 될 화면은 이 화면이다. 빌드 상태는 unknown, 휑한 화면. 뭐 어쩌라고 싶은 그런 화면이다. 이제 초기 세팅을 들어가줘야 한다.

 

이제 본격적인 세팅에 들어간다. 처음엔 .travis.yml 파일을 만들어줘야 한다. 생성 위치는 build.gradle이 존재하는 곳과 같은 레벨의 디렉터리에 생성하면 된다. 최상위라는 뜻이다.

 

language: java
jdk:
  - openjdk8

# Git Push할 Branch
branches:
  only:
    - travis-deploy # 여기 바꿔도 됨!

# gradlew 권한 추가
before_install:
  - chmod +x gradlew

# Travis CI 서버의 Home
cache:
  directories:
    - '$HOME/.m2/repository'
    - '$HOME/.gradle'

script: "./gradlew clean build"

# CI 실행 완료시 메일로 알람
notifications:
  email:
    recipients:
      - zabeee52@gmail.com # 여기 바꿔도 됨!

내용은 다음과 같다. 튜닝 요소는 branches의 only 쪽이다. 원하는 branch명으로 설정해주면 된다.나는 별도로 배포해주는 branch를 배치해주고 싶어서 이렇게 설정해 주었다.

before_install같은 경우 travis ci가 빌드하는 과정에서 gradle 실행 권한이 없다는 에러메세지를 출력할 수 있는데, 이를 해결해줄 수 있는 코드다.

나머지는 그냥 붙여넣으면 된다.

 

이렇게 하고 나서 branches에 명시된 branch로 push를 수행했다면 이제 본격적인 시작이다.

 

 

참고로 build passing 클릭하면 상태 정보를 체크할 수 있는 마크다운 주소를 제공해준다. readme에 넣고싶다면 가져다 쓰자.

이렇게 장식이 가능해진다!

 

사용자 설정

 

가장 먼저 해줘야 하는 일은 배포 작업을 수행해줄 사용자를 만드는 것이다. 사용자를 만드는 작업은 AWS IAM에서 수행한다.

 

먼저 AWS에서 IAM을 검색한 뒤 해당 기능으로 이동한다.

AmazonS3FullAccess

AWSCodeDeployFullAccess

차례대로 검색 후 둘 다 체크하고 다음으로 간다.

 

태그에서는 볼 것 없다. 그냥 다음 누른다.

 

권한 제대로 체크했는지 확인하고 만들기 누른다.

 

만들고나서 정말 중요한 건, CSV 다운로드 반드시 해줘야한다. 이후 작업 액세스에 쓰이는 키값들이 보관되어있는 파일인데, 사용자 생성시에만 다운로드 받을 수 있으므로 지금 못 받아놓으면 사용자 다시 만들어야 한다. 귀찮다.

 

남의사진 잠깐 빌려 씁니다... 고맙습니다...

위 사진 출처)

 

[매뉴얼][초보자를 위한 AWS 웹구축] 2. IAM 유저 및 MFA 생성하기

IAM 이란? IAM(AWS Identity and Access Management)은 AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스입니다. IAM을 사용하여 리소스를 사용하도록 인증 및 권한 부여된 대상을 제어합니다.

tech.cloud.nongshim.co.kr

 

 

배포용 S3 버킷 생성

AWS에서 S3를 검색하고 해당 페이지로 이동한다.

1. 버킷 이름 : 나중에 써먹는다. 알아서 잘 짓자.

2. 리전 : 일치해야 안 피곤하다. 리전을 다른걸로 하면 나중에 쓸 데 없이 수정해야하는 부분이 많아진다. 그만큼 실수할 가능성도 커지고.

3. ACL 활성화됨 : 버킷은 오픈마인드가 중요한거다.

4. 모든 퍼블릭 액세스 차단 체크 해제 : 오픈마인드.

5. 퍼블릭 상태가 될 수 있음을 알고 있음 : 오픈마인드!

6. 버킷 만들기

 

이렇게 보안에 취약한 나약해 빠진 S3 Bucket을 만드는데 성공했다. 걱정하지마라. 어차피 연습이니까. 전문가라면 알아서 잘 써주자.

 

 

CodeDeploy 설정

이제 S3에 배포된 파일을 EC2에 올려줄 CodeDeploy의 설정을 해줘야 한다.

먼저 해줘야 하는 것은 역할을 생성하는 것이다. CodeDeploy를 이용해 EC2에 배포를 진행해 줄 역할이다.

AWS에 IAM 검색 -> 역할 진입

역할 이름 지정해주고, 정책 잘 들어갔는지 확인해주고 역할 만들기 누르면 된다.

 

EC2로 되돌아가 인스턴스 우클릭 후 작업을 시행한다.

 

저장해주면 EC2가 CodeDeploy를 받아들일 준비가 절반은 끝난 것이다.

 

역할을 설정했다면 인스턴스를 재부팅하자.

참고로 재부팅하면 저장되지 않은 iptables 정보가 초기화 되니, 포트포워딩 같은 것을 설정해뒀다면 다시 해줘야 한다.

재부팅하면 다음의 명령어를 입력해주면 된다. CodeDeploy를 시행할 사용자를 지정해주는 영역이다.

sudo apt-get update
sudo apt-get install awscli

설치 다 하면 다음의 작업을 수행하자.

mkdir /home/ec2-users/
cd /home/ec2-users
sudo aws configure

aws configure까지 입력하고 나면 총 4개의 값을 입력해야 한다.

- Access-Key

- Secrey-Access-Key

- Default region name

- Default output format

 

여기서 사용자를 생성할 때 저장해뒀던 csv가 활용된다.

 

이 두 개의 정보를 입력하면 된다.

.csv 파일의 위 두 개 정보를 입력하면 된다. 다음 두 개는

Default region name : ap-northeast-2
Default output format : json

입력을 순차적으로 해주면 된다. region name의 경우 S3 버킷 정도에서 말했지만, 맞춰주지 않았을 경우 자신에게 맞게 잘 입력해줘야 한다.

 

이제 CodeDeploy CLI 설치를 해준다. 그 전에 먼저 ruby가 설치가 안 되어 있다면 ruby를 설치해줘야한다.

sudo apt-get install ruby

설치가 다 되면 본격적으로 세팅을 한다.

sudo aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2
sudo chmod +x install
sudo ./install auto

놀라울 정도로 간단하다. 참고로 첫 줄의 리전, 다르면.. 아시죠?

 

입력을 다 하고나면 서비스가 잘 설치되었는지 확인해보자.

 

active (running) 상태인지만 보면 된다.

이번엔 선택사항인데, 시스템 재부팅 시 자동으로 서비스를 올리도록 설정해주면 좋다.

sudo vim /etc/init.d/codedeploy-startup.sh

입력하면 웬 입력창이 나올 것이다. 여기서 영문자 i를 누르면 입력모드로 전환되는데, 아래의 내용을 복사해서 붙여넣기(마우스 가운데 클릭) 하면 된다.

#!/bin/bash

echo 'Starting codedeploy-agent'
sudo service codedeploy-agent start

이후 다음의 순서로 빠져나오면 된다.

ESC -> :wq! 또는 :ZZ     // 콜론까지 입력해줘야 한다. 둘다 저장 후 빠져나오겠다는 의미다.

 

여기까지 잘 되었다면 이제 이 EC2는 본격적으로 자동 배포되는 코드를 받아들이고, CodeDeploy의 작업 명령을 이행할 준비가 된 것이다. 이제 본격적으로 스프링부트 환경에서 travis 세팅을 시작하면 된다.

 

 

까지 설명을 했고, 이후 내용은 최상단의 링크와 최소한의 튜닝 요소를 빼면 정확하게 일치하기 때문에 작성에 의미가 없는 것으로 생각된다. 이후는 링크의 6. .travis.yml & appspec.yml 설정하기 부터 따라 하면 될 것이다.

 

 

[SpringBoot] 웹서비스 출시하기 - 4. TravisCI & AWS CodeDeploy로 배포 자동화 구축하기

해당 글은 '우아한 형제들'의 개발자이신 jojoldu님의 블로그와 책(스프링 부트와 AWS로 혼자 구현하는 웹서비스)을 참고하여 작성하였습니다. 이전 글에서 AWS EC2에 개발한 프로젝트를 배포하였

dev-jwblog.tistory.com

 

다만, 위 링크에서 7. CodeDeploy로 스크립트 실행 부분에 설명이 부족한 부분이 두 가지 있어 추가한다.

 

1. deploy.sh에서 PROJECT_NAME이 무엇인가.. 라는 궁금증이 들 텐데, 이건 build했을 때 나타나는 프로젝트의 이름이다. 이 이름을 기반으로 프로세스를 검색, 프로세스가 존재할 경우 kill 하는 원리로 구성되어 있다.

 

2. CodeDeploy로 배포를 하는데, 아마 application.properties 또는 yml은 .gitignore에 등록했을 것이다. 그렇기 때문에 위 링크 그대로 작업을 하면 제대로 동작하지 않는다. 이 문제를 해결하기 위해 아래의 작업을 추가한다. 참고로 보안이고 뭐고 생각 안 한 방법이니 더 제대로 하고 싶다면 application.properties를 암호화해서 보관하는 방법을 수행하면 될 것이다.

 

1. application.properties 또는 yml를 EC2로 이전한다.

2. application 파일을 실행하기 좋은 자리로 옮긴다.

3. 그리고 deploy.sh의 아래 구문을 다음과 같이 수정한다.

 

nohup java -jar \
        -Dspring.config.location=file://[application 파일의 경로] \
        -Dspring.profiles.active=real \
        $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &

언제나 그렇지만 경로는 절대경로가 안전하다. 절대경로로 지정해주자.

추가로 PROJECT_NAME을 선언했지만 사용을 하지 않고 상수로 값을 넣은 부분이 있는데, 이 부분을 수정해준다.

CURRENT_PID=$(pgrep -fl $PROJECT_NAME | awk '{print $1}')

 

 

이렇게 수정된 전체 내용은 다음과 같다.

 

#!/bin/bash

REPOSITORY=/home/ec2-user/app/travis
PROJECT_NAME=backend-0.0.1-SNAPSHOT.jar

echo "> Build 파일 복사"

cp $REPOSITORY/build/build/libs/*.jar $REPOSITORY/jar

echo "> 현재 구동중인 애플리케이션 pid 확인"

CURRENT_PID=$(pgrep -fl $PROJECT_NAME | awk '{print $1}')

echo "현재 구동중인 어플리케이션 pid: $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/jar/*.jar | tail -n 1)

echo "> JAR Name: $JAR_NAME"

echo "> $JAR_NAME 에 실행권한 추가"

chmod +x $JAR_NAME

echo "> $JAR_NAME 실행"

nohup java -jar \
        -Dspring.config.location=file://[application 파일의 경로] \
        -Dspring.profiles.active=real \
        $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &

 

이 부분까지 되고 나서 다음 작업을 계속 따라가면 배포가 잘 될 것이다. 건승하길 바란다. 화이팅!

 

 

무중단 배포는 다음 게시글에서 이어진다.

 

[Ubuntu/nginx] 스프링 부트 및 우분투 환경에서 nginx 이용한 무중단배포 구현

CI/CD [Ubuntu/Travis-CI/CodeDeploy] SpringBoot 환경 배포 자동화 환경 구축 CI/CD 하루종일 travis와 싸웠다. travis 사이트도 말썽을 부려댔고, 깃헙도 잠깐 터졌고, 티스토리도 잘 안 되는 데다가, 시스템 구..

dazbee.tistory.com

 

댓글