[스프링 부트와 AWS로 혼자 구현하는 웹 서비스]무작정 따라하기 9일차

민지킴·2021년 5월 2일
0
post-thumbnail

*모든 내용은 책에 있는 내용을 기반으로 작성하였습니다.

9장 ----

9.1 CI & CD 소개

CI, CD란?

코드 버전 관리를 하는 VCS 시스템(Git, SVN등)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정을 CI(Continuous Integration - 지속적 통합)이라고 하며, 이 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정을 CD(Continuous Deployment - 지속적인 배포) 라고 한다.

일반적으로 CI만 구축되어 있지는 않고, CD도 함꼐 구축된 경우가 대부분이다.

CI, CD의 등장 이유

현대의 웹 서비스 개발에서는 하나의 프로젝트를 여러 개발자가 함께 개발을 진행한다. 그러다 보니 각자가 개발한 코드를 합쳐야 할 때마다 나을 지정하여 병합일을 지정하여 개발을 했다.
하지만 이런 환경에서는 코드가 통합되는 환경(CI)를 구축하였다.
개발자 각자가 웒격 저장소로 푸시가 될때마다 코드를 병합하고, 테스트 코드와 빌드를 수행하면서 자동으로 코드가 통합되어 더는 수동으로 코드를 통합할 필요가 없어졌다. -> 개발에만 집중이 가능해짐

CD역시 마찬가지이다. 한 두 대의 서버에 개발자가 수동으로 배포를 하는건 가능할 수 있지만 수백대의 서버에 배포플 해야하거나 긴박하게 당장 배포를 해야하는 상황이 오면 수동으로 배포를 할 수가 없게 되었고 이를 자동화 하게된다. -> 개발에만 집중이 가능해짐

CI에 대한 4가지 법칙 (마틴 파울러)

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

가장 중요한 것: 테스팅 자동화 -> 이 프로젝트가 완전한 상태임을 보장하기 위해서 테스트 코드가 구현 되어야 한다.

9.2 Travis 연동학

https://www.travis-ci.com/

9.2.1 travis.yml

language: java
jdk:
	-openjdk8
   
branches: //(1)
	only:
    	-master
        
#Travis CI 서버의 Home
cache: //(2)
	directories:
    - '$HOME/.m2/repository/;
    - '$HOME/.m2/gradle'
script: "./gradle clean build" //(3)

# CI 실행 완료 시 메일로 알람
notifications: //(4)
	email:
    	recipiens:
        -본인 메일 주소

9.2.1.1 branches

Travis CI를 어느 브랜치가 푸시될 때 수행할지 지정한다.
-> 현재 옵션은 오직 master branch에 push될 때만 수행한다.

9.2.1.2 cache

그레이들을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여, 같은 의존성은 다음 배포 때부터 다시 받지 않도록 설정한다.

9.2.1.3 script

master 브랜치에 푸시되었을 때 수행하는 명령어이다.
여기서는 프로젝트 내부에 둔 gradlew를 통해 clean & build를 수행한다.

9.2.1.4 notification

Travis CI 실행 완료 시 자동으로 알람이 가도록 설정한다.

9.3 Travis CI와 AWS S3 연동하기

S3란 AWS엣 제공하는 일종의 파일 서버입니다. 이미지 파일을 비롯한 정적 파일들을 간리하거나 지금 진행하는 것처럼 배포 파일들을 관리하는 등의 기능을 지원합니다. 보통의 이미지 업로드를 구현한다면 이 S3를 이용하여 구현하는 경우가 많다. S3을 비롯한 AWS 서비스와 Travis CI를 연동하게 되면 전체 구조는 다음과 같다.

GitHub -> Travis CI -> (1. jar 전달) -> AWS S3 ->(3. jar 전달) -> AWS CodeDepoy
              -> Travis CI -> (2. 배포 요청) -> AWS CodeDeploy -> (4. 배포) AWS EC2

첫번쨰로 Travis CI와 S3을 연동해야한다. 실제 배포는 AWS CodeDeploy라는 서비스를 이용한다. 하지만, S3연동이 먼저 필요한 이유는 Jar 파일을 전달하기 위해서입니다.
CodeDeploy는 저장 기능이 없습니다. 그래서 Travis CI가 빌드한 결과물을 받아서 CodeDeploy가 가져갈 수 있도록 보고나할 수 있는 공간이 필요합니다. 보통은 이럴 때 AWS S3를 이용합니다.

9.3.1 AWS Key 발급

일반적으로 AWS서비스에 외부 서비스가 접근할 수 없다. 그러므로 접근 가능한 권한을 가진 Key를 생성해서 사용해야한다. AWS에서는 이러한 인증과 관련된 기능을 제공하는 서비스로 IAM(Identity and Access Management)이 있다.
IAM은 AWS에서 제공하는 서비스의 접근 방식과 권한을 관리한다. 이 IAM을 통해 Travi CI가 AWS의 S3와 CodeDeploy에 접근할 수 있도록 해야한다.

책보고 진행...

9.3.2 S3 버킷 생성

S3(Simple Storeage Service) : 일종의 파일 서버이다. 순수하게 파일들을 저장하고 접근 권한을 관리, 검색 등을 지원하는 파일 서버의 역할
보통 게시글을 쓸 때 나오는 첨부파일 등록을 구현할 때 많이 이용한다.
Travis CI에서 생성된 Build 파일을 저장한다.

책보고 진행...

9.3.3 .travis.yml

9.2의 yml에 추가한다.

...
before_deploy: //(1)
    - zip -r freelec-springboo2-webservice * //(2)
    - mkdir -p deploy //(3)
    - mv freelec-springboot2-webservice.zip deploy/freelec-springboot2-webservice.zip //(4)
    
deploy: //(5)
    - 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: privae # zip 파일 접근을 private으로
      local_dir: deploy # before_deploy에서 생성한 디렉토리 //(6)
      wait-until-deployed: true

9.3.3.1 before_deploy

deploy 명령어가 실행되기 전에 수행되며, CodeDeploy는 Jar파일은 인식하지 못하므로 Jar+기타 설정 파일들을 모아 압축한다.

9.3.3.2 zip -r freelec-springboo2-webservice

현재 위치의 모든 파일을 해당 이름으로 압축하여야하며, 명령어의 마지막 위치는 자신의 프로젝트 이름이여야 한다.

9.3.3.3 mkdir -p deploy

deploy라는 디렉토리를 Travis CI가 실행중인 위치에서 생헌한다.

9.3.3.4 mv freelec-springboot2-webservice.zip deploy/freelec-springboot2-webservice.zip

freelec-springboot2-webservice.zip 파일ㅇ르 deploy/freelect-springboot2-webservice.zip

9.3.3.5 deploy

S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언합니다.

9.3.3.6 local_dir: deploy

앞에서 생성한 deploy 디렉토리르 지정, 해당 위치의 파일들만 S3로 전송한다.

완료하고 push

9.4 Travis CI와 AWS S3, CodeDeploy 연동하기

책보고 진행...

9.4.1 CodeDeploy 에이전트 설치

EC2에 접속해서 다음 명령어 입력

aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install .--region ap-northeast-2

install 파일에 실행권한 추가

chmod +x ./install

install 파일로 설치를 진행

sudo ./install auto

설치가 끝났으면 Agent가 정상적으로 실행되고 있는지 상태 검사를 한다.

sudo service codedeploy-agent status

9.4.2 CodeDeploy 생성

  • Code Commit
    • 깃허브와 같은 코드 저장소 역할
    • 프라비잇 기능을 지원하지만, 깃허브에서 무료로 지원하고 있어서 거의 사용 안함
  • Code Build

    • Travis와 마찬가지로 빌드용 서비스이다.
    • 멀티 모듈을 배포해야하는 경우는 사용해볼만 하지만 큰 규모 서비스에서는 사용하지 않는다.
  • CodeDeploy

    • 대체제가 없는 AWS의 배포 서비스이다.

9.4.3 Travis CI, S3, CodeDeploy 연동

먼저 S3에서 넘겨줄 zip 파일을 저장할 디렉토리를 하나 생성한다. EC2 서버에 접속해서 다음과 같이 디렉토리를 생성한다.

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

Travis CI의 Build가 끝나면 S3에 zip 파일이 전송되고, 이 zip 파일은 /home/ec2-user/app/step2/zip으로 복사되어 압축을 푼다.

Travis CI의 설정은 .travis.yml로 진행
AWS CodeDeploy는 appspec.yml로 진행한다.

9.4.4. appspec.yml

version: 0.0   //(1)
os: linux
files:
   -source: /  //(2)
    destination: /home/ec2-user/app/step2/zip/.  //(3)
    overwrite: yes //(4)

9.4.4.1 version: 0.0

  • CodeDeploy의 버전을 이야기한다.
  • 프로젝트 버전이 아니므로 0.0 외에 다른 버전을 사용하면 오류가 발생한다.

9.4.4.2 source

  • CodeDeploy에서 전달해준 파일 중 destination으로 이동시킬 대상을 지정한다.
  • 루트 경로(/)를 지정하면 전체 파일을 이야기한다.

9.4.4.3 destination

  • source에서 지정된 파일을 받을 위치이다.
  • 이후 Jar를 실행하는 등은 destination에서 옮긴 파일들로 진행된다.

9.4.4.4 overwrite

  • 기존에 파일들이 있으면 덮어쓸지를 결정한다.
  • 현재 yes라고 했으니 파일들을 덮어쓰게 된다.

9.4.5 .travis.yml 에 추가하기

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

git에 푸쉬를 하면 자동으로 배포가 수행된다.

cd /home/ec2-user/app/step2/zip

파일 목록을 확인.

ll

9.5 배포 자동화 구성

9.5.1 deploy.sh 파일 추가

step2에 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}') //(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   //(2)

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 &  //(3)

9.5.1.1 CURRENT_PID

  • 현재 수행 중인 스프링 부트 애플리케이션의 프로세스 ID를 찾는다.
  • 실행 중이면 종료하기 위해서이다.
  • 스프링 부트 애플리케이션 이름으로 된 다른 프로그램들이 있을 수 있어 같은 이름으로 된 jar 프로세스를 찾은 뒤 id를 찾는다.

9.5.1.2 chmod +x $JAR_NAME

  • Jar 파일은 실행 권한이 없는 상태이다.
  • nohup으로 실행할 수 있게 실행 권한을 부여한다.

9.5.1.3 $JAR_NAME> $REPOSITORY/nohup.out 2>1 &

  • nohup 실행시 CodeDeploy는 무한대기한다.
  • 이 이슈를 해결하기 위해 nohup 파일을 표준 입출력용으로 별도로 사용한다.
  • 이렇게 하지 않으면 nohup 파일이 생기지 않고, CodeDeploy 로그에 표준 입출력이 출력된다.
  • nohup이 끝나기 전까지 CodeDeploy도 끝나지 않게 되므로 반드시 이렇게 해야만 한다.

9.5.2 .trivis.yml 수정

현재는 프로젝트의 모든 파일을 zip으로 만드는데, 실제로 필요한 파일들은 Jar, appspec.yml, 배포를 위한 스크립트들이다. 이 외 나머지는 배포에 필요하지 않으니 포함하지 않는다.

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

9.5.2.1 Travis CI는 S3로 특정 파일만 업로드가 안된다.

  • 디렉토리 단위로만 업로드할 수 있기 때문에 before-deploy 디렉토리는 항상 생성 한다.

9.5.2.2 before-deploy 에는 zip 파일에 포함시킬 파일들을 저장한다.

9.5.2.3 zip -r 명령어를 통해 before-deploy 디렉토리 전체 파일을 압축한다.

9.5.3 appspec.yml 수정

permissions: //(1)
	- object: /
    	  pattern: "**"
          owner: ec2-user
          group: ec2-user
          
hooks: //(2)
   ApplicationStart:
   -location: deploy.sh
    timeout: 60
    runas: ec2-user

9.5.3.1 permissions

  • CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 한다.

9.5.3.2 hooks

  • CodeDeploy 배포 단계에서 실행할 명령어를 지정한다.
  • ApplicationStart라는 단계에서 deploy.sh를 ec2-user 권한으로 실행한다.
  • timeout: 60으로 스크립트 실행 60초 이상 수행되면 실패가 된다. (무한정 기다릴수 없으니 시간 제한을 두어야한다.)
profile
하루하루는 성실하게 인생 전체는 되는대로

0개의 댓글