CI & CD

Travis CI 배포 자동화

s-jiun 2023. 2. 4. 13:05
반응형

※ 이번 포스트는 <스프링부트와 AWS로 혼자 구현하는 웹서비스> 책의 9장을 공부하면서 정리한 것입니다.

 

 

CI & CD 소개

 

● CI (Continuous Integration)

코드 버전 관리를 하는 VCS 시스템 에 코드가 PUSH 되면 자동으로 테스트 & 빌드가 수행되어 안정적인 배포 파일을 만드는 과정

● CD (Continuous Deployment)

앞선 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행하는 과정

● CI의 4가지 규칙

  1. 모든 소스코드가 살아있고(실행되고) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것
  2. 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
  3. 테스팅을 자동화하여 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것
  4. 누구나 현재 실행 파일을 얻으면 지금까지의 가장 완전한 실행파일을 얻었다는 확신을 하게 할 것

Travis CI

 

무료 CI 서비스(오픈소스 프로젝트는 무료로 이용 가능하지만 비공개 프로젝트는 유료로 이용해야 한다). Jenkins의 경우 설치형이기 때문에 배포를 위한 EC2 인스턴스를 하나 더 생성해야한다는 부담이 있지만 Travis는 그렇지 않다.

● Travis 웹사이트 초기 설정하기

  1. https://travis-ci.org/ 에서 깃허브로 로그인한다.
  2. settings에서 연동하고자하는 깃허브 저장소를 찾은 다음 상태바를 활성화시킨다.

● .travis.yml 파일 설정하기

※ YAML(.yml) : JSON에서 괄호를 제거한 형태

: "기계에서 파싱하기 쉽게, 사람이 다루기 쉽게"라는 이념으로 만들어짐

springboot 프로젝트에서, .travis.yml 파일은 프로젝트의 build.gradle과 같은 위치에 위치한다.

language: java
jdk:
    - openjdk8

branches:
    only:
        - master

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

script: "./gradlew clean build"

#CI 실행 완료 시 메일로 알람
notifications:
    email:
        recipients:
            - {본인 메일 주소}

여기까지 마친 후 마스터 브랜치에 커밋 푸시를 하면 Travis CI 저장소 페이지에서 빌드 내역을 확인할 수 있다.

 

 

AWS S3

 

AWS S3란 AWS에서 제공하는 일종의 파일 서버이다. 다양한 정적 파일을 관리하거나 배포 파일들을 관리하는 기능을 제공합니다.

실제 배포는 CodeDeploy 서비스를 이용하여 이루어지지만, CodeDeploy는 저장 기능이 없으므로 Travis CI가 빌드한 결과물을 받아 CodeDeploy가 가져갈 수 있도록 보관할 수 있는 공간을 만들고자 S3를 사용한다.

※ CodeDeploy로 빌드, 배포 모두 할 수 있지만, 이렇게 구축해놓을 경우 빌드 없이 배포만 할 때 대응하기 어렵다. 빌드와 배포가 분리되어 있으면 예전에 빌드되어 만들어진 Jar를 재사용하면 되지만, CodeDeploy가 모든 것을 할 경우 항상 빌드가 이루어져 확장성이 떨어지게 된다. 때문에 왠만하면 빌드와 배포는 분리하는 것이 좋다.

● Travis CI와 AWS S3 연동하기

  1. AWS IAM으로 사용자를 생성하여 'AmazonS3FullAccess' 권한과 'AWSCodeDeployFullAccess' 권한을 추가한다.
  2. Travis CI 설정 화면에서 환경변수로 IAM에서 발급받은 키들을 등록한다.(AWS_ACCESS_KEY, AWS_SECRET_KEY)
  3. AWS S3 버킷을 생성한다. 이때 '모든 퍼블릭 엑세스를 차단'해야한다. (Jar 파일이 퍼블릭일 경우 누구나 내려받을 수 있어 주요 설정값, 키 값 들이 탈취될 수 있기 때문!)
  4. .travis.yml 파일에 아래의 코드를 추가한다.
before_deploy:
  - zip -r freelec-springboot2-webservice *
  - mkdir -p deploy
  - mv freelec-springboot2-webservice.zip deploy/freelec-springboot2-webservice.zip

deploy:
  - provider: s3
    access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
    secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
    bucket: freelec-springboot-build # S3 버킷
    region: ap-northeast-2
    skip_cleanup: true
    acl: private # zip 파일 접근을 private으로
    local_dir: deploy # before_deploy에서 생성한 디렉토리
    wait-until-deployed: true

 

 

AWS 배포 Tool 세가지

● Code Commit

깃허브와 같은 코드 저장소이다.

● Code Build

Travis CI와 마찬가지로 빌드용 서비스이다.

● CodeDeploy

AWS의 배포 서비스이다. 오토 스케일링 그룹 배포, 블루 그린 배포, 롤링 배포, EC2 단독 배포 등 많은 기능을 지원한다.

 

 

Travis CI, AWS S3, CodeDeploy 연동하기

 

  1. EC2에 IAM 역할을 추가한다. (AmazonEC2RoleforAWS-CodeDeploy)
  2. EC2인스턴스 > 인스턴스 설정 > IAM 역할 연결/바꾸기를 선택하여 방금 생성한 역할을 선택하고 인스턴스를 재부팅한다.
  3. EC2에서 다음 명령을 차례로 입력한다.
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install .--region ap-northeast-2 #1)
chmod +x ./insall                                                                    #2)
sudo ./install auto                                                                  #3)
sudo service codedeploy-agent status                                                 #4) Agent가 잘 실행되고 있는지 확인

※ 만약 설치 중 '/usr/bin/env: ruby: No such file or directory' 에러가 날 경우 sudo yum install ruby로 루비를 설치해주면 된다

4. IAM 역할을 생성하여 CodeDeploy를 위한 권한을 생성한다.

5. CodeDeploy 서비스로 이동하여 애플리케이션을 생성한다. 이때 컴퓨팅 플랫폼은 EC2/온프레미스를 선택하면 된다.

6. 배포 그룹을 생성한다. 이때 서비스 역할은 방금 생성한 CodeDeploy용 IAM 역할을 선택한다. 배포 유형의 경우 2대 이상의 서버에 배포한다면 '블루/그린'을, 그렇지 않다면 '현재 위치'를 선택하면 된다.

※ 이때 '배포 구성'을 선택하게 되는데, 배포 구성이란 한 번 배포할 때 몇 대의 서버에 배포할 것인지 결정하는 것이다. 2대 이상이라면 한 대씩 배포할지, 30% 나 50%로 나눠서 배포할지 옵션을 선택하면 되고 1대의 서버라면 전체 배포하는 옵션으로 선택하면 된다.

7. EC2 인스턴스에 접속하여 다음 명령을 입력한다.

mkdir ~/app/step2 && mkdir ~/app/step2/zip

8. 프로젝트에 appspec.yml을 생성한다. 코드는 다음과 같다.

version: 0.0
os: linux
files:
  - source:  /
    destination: /home/ec2-user/app/step3/zip/
    overwrite: yes

9. travis.yml 파일의 deply 부분에 다음 코드를 추가한다.

 - provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
    secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
    bucket: freelec-springboot-build # S3 버킷
    key: freelec-springboot2-webservice.zip # 빌드 파일을 압축해서 전달
    bundle_type: zip
    application: freelec-springboot2-webservice # 웹 콘솔에서 등록한 CodeDeploy 어플리케이션
    deployment_group: freelec-springboot2-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
    region: ap-northeast-2
    wait-until-deployed: true

10. 프로젝트를 커밋 푸시한다.

 

 

배포 자동화 구성

 

  1. 프로젝트에 deploy.sh 파일을 생성한다. 코드는 다음과 같다
#!/bin/bash

REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=freelec-springboot2-webservice

echo "> Build 파일 복사"

cp $REPOSITORY/zip/*.jar $REPOSITORY/

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

CURRENT_PID=$(pgrep -fl freelec-springboot2-webservice | grep jar | 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 | tail -n 1)

echo "> JAR Name: $JAR_NAME"

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

chmod +x $JAR_NAME

echo "> $JAR_NAME 실행"

nohup java -jar \
    -Dspring.config.location=classpath:/application.properties,classpath:/application-real.properties,/home/ec2-user/app/application-oauth.properties,/home/ec2-user/app/application-real-db.properties \
    -Dspring.profiles.active=real \
    $JAR_NAME > $REPOSITORY/nohup.out 2>&1 &

2. travis.yml 파일의 before_deploy 부분을 다음과 같이 수정한다.

before_deploy:
  - mkdir -p before-deploy # zip에 포함시킬 파일들을 담을 디렉토리 생성
  - cp scripts/*.sh before-deploy/
  - cp appspec.yml before-deploy/
  - cp build/libs/*.jar before-deploy/
  - cd before-deploy && zip -r before-deploy * # before-deploy로 이동후 전체 압축
  - cd ../ && mkdir -p deploy # 상위 디렉토리로 이동후 deploy 디렉토리 생성
  - mv before-deploy/before-deploy.zip deploy/freelec-springboot2-webservice.zip # deploy로 zip파일 이동

3. appspec.yml 파일에 다음 코드를 추가한다.

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

hooks:
  ApplicationStart:
    - location: start.sh # 엔진엑스와 연결되어 있지 않은 Port로 새 버전의 스프링 부트를 시작합니다.
      timeout: 60
      runas: ec2-user
반응형

 

반응형