티스토리 뷰

(1편!) https://sedangdang.tistory.com/272?category=1011928 

 

Travis CI를 이용한 CI/CD 환경 구성 실습 (1)

* Travis CI는 유료로 전환되었다! 회원가입 하면 한달 무료 체험을 할 수 있게 해주니 한달 안에 최대한 많은 것을 해보자 * <스프링 부트와 AWS로 혼자 구현하는 웹 서비스> 책을 굉장히 많이 참고

sedangdang.tistory.com

 

1편에서 내 깃허브 리포지토리랑 Travis CI를 연동하고, Travis CI에서 빌드된 파일을 AWS S3에 옮기는 것 까지 해봤다.

 

그 다음으로는 S3에 옮겨진 파일을 EC2로 다시 옮겨서 jar 파일을 실행(배포)하는 것 까지 마무리 해보자!!

 

 

# 1. CodeDelpoy 연결

CodeDeploy는 AWS에서 만든 CI/CD 툴이다. 

그럼 굳이 Travis CI랑 S3 필요 없이 CodeDeploy 하나로 다 해결 가능한거 아닌가요?

-> 빌드 과정(Travis CI)과 배포 과정(CodeDeploy)은 분리되어 있는 것이 좋다

 

로컬 --> 깃허브 --> Travis CI --> S3 --> CodeDeploy 흐름인데,

 

이렇게 CI랑 CD가 서로 떨어져 있으면, 필요에 따라 S3 이전 과정을 싹 치우고 (CI 과정을 건너뛰고)

 

S3 --> CodeDeploy 와 같이 이전에 만들어둔 jar 파일을 재사용 시켜 유연한 운영이 가능하게 해준다.

 

 

# 1-1. IAM 역할 생성

AWS S3을 연동할 때 IAM에서 사용자를 추가했었는데, 이번에는 역할을 생성한다.

사용자와 역할의 차이가 뭘까?

 

IAM (Identity and Access Management)

- AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스.

- IAM을 사용하여 리소스를 사용하도록 인증하고, 권한이 부여된 대상을 관리한다.

- 쉽게 말해 접근 권한을 관리한다.

 

IAM 정책 (IAM Policy)

- 대상이 어떤 작업을 할 수 있는 지에 대한 권한 설정 모음

 

IAM 사용자 (IAM User)

- AWS와 상호 작용하는 사람 또는 서비스(애플리케이션)

--> Travis CI가 AWS S3과 상호 작용 하기 위해서 IAM 사용자를 생성했던 것이 이것 때문.

- 액세스 키를 이용해 인증한다.

- IAM 사용자들을 묶어서 그룹으로 관리할 수도 있다 (IAM Groups) -> 공통 권한을 부여해야 할 때 유용.

 

IAM 역할 (IAM Role)

- 리소스에 대한 액세스 권한이 없는 사용자 또는 서비스에게 일시적으로 권한을 위임하는 것

- 여러 정책들을 묶어서 역할을 만들어놓고, 여러 사용자들이 이 역할을 위임받아 리소스에 접근할 수 있다.

- IAM 사용자와 달리 액세스 키가 따로 없다.

- 그렇다고 역할을 아무나 위임받을 수 있는것은 아니고, 신뢰할 수 있는 엔티티여야 한다.

(IAM 사용자, AWS 내부 서비스, 인증된 외부 사용자 등..)

-> 각 사용자마다 따로따로 권한 일일히 설정해주는건 번거로우니까 그냥 신뢰할 수 있는 사용자라면 같이 돌려쓸 수 있도록 공용 정책 모음을 따로 만들어둔 느낌이다.

 

<참고>

(1) - IAM 개념 원리 & IAM 계정 · 정책 생성하기

(2) - https://docs.aws.amazon.com/ko_kr/IAM/latest/UserGuide/introduction.html 

 

 

IAM > 역할 > 역할 만들기

신뢰할 수 있는 엔티티로 AWS 서비스 - EC2 선택

 

 

AmazonEC2RoleforAWSCodeDeploy 권한 추가

 

이제 EC2가 CodeDeploy에 접근할 수 있는 역할이 만들어졌다.

이 역할을 여러 EC2가 공용으로 돌려쓸 수 있다. EC2는 신뢰할 수 있는 엔티티니까!

아까 위에서 용어 정리할 때는 뭔소린가 싶었는데 만들고 나니까 이해가 뭔소린지 이제야 좀 알겠다.

 

이제 AWS EC2에 해당 역할을 연결해주면 된다.

 

 

 

역할 업데이트 이후에는 EC2를 재부팅 해줘야한다!

만약 Elastic IP를 지정해두지 않았다면 재부팅 시에 IP가 변경되게 되니 유의하면서 진행하자.

 

그럼 이제 EC2가 CodeDeploy에 접근할 수 있게 되었다! (EC2 -> CodeDeploy)

 

근데 이 반대로 CodeDeploy가 EC2에도 접근할 수 있어야 한다;; (CodeDeploy -> EC2)

아까랑 똑같은데 AWS 서비스 중에서 CodeDeploy를 선택하면 된다. 권한은 어차피 딱 하나밖에 없다.

 

 

 

# 1-2. CodeDeploy 설정

난생 처음 들어본 IAM 설정하느라 벌써 진이 다 빠지지만 이제 다 왔다.

 

CodeDeploy -> 애플리케이션 ->  애플리케이션 생성

 

 

 

애플리케이션 생성 이후 배포 그룹 탭에서 배포 그룹 생성

배포 그룹은 어디서 해당 애플리케이션을 배포할 것인지? 를 뜻하는 것 같다.

 

 

 

* 로드 밸런서는 비활성화 한다

 

 

# 1-3. 코드 작성

EC2에 들어가서 먼저 CodeDeploy 에이전트를 설치해야한다.

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

 

그 다음 프로젝트로 이동해서 설정파일을 작성한다.

<.travis.yml>

language: java
jdk:
  - openjdk11

# 어느 브랜치에 push될 때 수행할 것인지?
branches:
  only:
    - main # main branch에 push 될 때만 CI를 수행해라

# CI를 통해 빌드할때마다 gradle || maven 을 통한 의존 라이브러리를 전부 빌드하는 것은 꽤 비효율적이다
# 그래서 Travis가 내부적으로 캐싱을 해두도록 설정할 수 있다.
cache:
  directories:
    - '$HOME/.m2/repository' # maven 사용하는 경우
    - '$HOME/.gradle' # gradle 사용하는 경우

# main branch에 push 되었을 때 수행할 명령어
script: "./gradlew clean build"

# Travis CI에서 Build한 Jar 파일을 S3에 올리는 과정
before_deploy:
  - mkdir -p before-deploy # 디렉토리 생성 (Travis는 디렉토리 단위로만 업로드 가능)
  - cp build/libs/*.jar before-deploy/ # 배포에 필요한 파일만 꼽아서 복사 (스크립트 + appspec.yml + executable jar)
  - cp scripts/*.sh before-deploy/
  - cp appspec.yml before-deploy/
  - cd before-deploy && zip -r smartnotice * # 위치 이동 후 내부 파일 전체 압축
  - cd ../ && mkdir -p deploy # 상위 디렉토리로 이동 후 deploy 디렉토리 생성
  - mv before-deploy/smartnotice.zip deploy/smartnotice.zip # 파일 위치 옮기기

deploy:
  - provider: s3
    access_key_id: $AWS_ACCESS_KEY # Travis 웹에서 설정한 환경변수 사용
    secret_access_key: $AWS_SECRET_KEY
    bucket: my-springboot-build
    region: ap-northeast-2
    skip_cleanup: true
    acl: private
    local_dir: deploy # 해당 위치의 파일들만 s3으로 전송한다
    wait-until-deployed: true
    on:
      branch: main # main branch 허용

  - provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY # Travis 웹에서 설정한 환경변수 사용
    secret_access_key: $AWS_SECRET_KEY
    bucket: my-springboot-build
    key: smartnotice.zip
    bundle_type: zip
    application: smartnotice
    deployment_group: smartnotice-group
    region: ap-northeast-2
    wait-until-deployed: true
    on:
      branch: main # main branch 허용

# CI 완료 시 메일로 알람
notifications:
  email:
    recipients:
      - [이메일]

 

< appspec.yml > 파일 새로 추가 (동일한 위치)

# CodeDeploy Version
version: 0.0
os: linux
files:
  - source: / # CodeDeploy에서 전달해준 파일 중 destination으로 이동시킬 대상 지정 (/ = 루트, 전체 파일)
    destination: /home/ec2-user/app/smartnotice_build/zip # source에서 지정된 파일을 받을 위치. 이후 Jar은 destination에서 옮겨진 파일들로 진행.
    overwrite: yes

 

* destination 옵션에 있는 경로에다가 디렉토리를 미리 만들어 놔야한다.

그럼 CodeDeploy S3 버킷의 / (루트) 경로에 있는 파일을 EC2의 해당 destination에 옮겨놓는다.

 

이제 설레는 마음으로 commit & push를 해 본다면???

아래와 같이 배포 내역에 성공이라고 뜨는 것을 확인할 수 있다!!

 

 

배포 성공 이후에 EC2의 해당 destination에 들어가보면?

 

 

내가 아까 압축했던 jar 파일과 yml 설정 파일이 잘 들어가 있는 것을 확인할 수 있다.

이제 저 jar 파일을 실행만 시킬 수 있다면 완벽할 것 같다.

 

 

# 2. jar 파일 실행을 위한 스크립트 작성

< deploy.sh > 스크립트 작성

#!/bin/bash

# 로컬 환경 변수 세팅
REPOSITORY=/home/ec2-user/app/smartnotice_build
PROJECT_NAME=smartnotice

echo "> Build 파일 복사"

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

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

CURRENT_PID=$(pgrep -fl springwebservice | grep jar | awk '{pring $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 실행"

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

* 스크립트 맨 앞에 #!bin/bash는 무슨 뜻일까

-> 해당 스크립트 파일을 bash 쉘으로 실행시키겠다는 뜻이라고 한다. 맨 처음의 "#"은 주석이 아니다

 

되게 복잡해보이는데 까고보면 그냥 아까 EC2의 destination에 있던 jar 파일을 zip 상위 디렉토리로 복사한 다음에 실행시키는 과정이다.

중간에 권한 부여 하는것과 현재 애플리케이션이 실행중인지를 확인하는 로직이 들어가서 복잡해 보이는 것 뿐이다.

 

JAR_NAME 뽑는 곳에서 사용된 코드는 알아둘만 한데

 

ls

-t: 파일이 수정된 순서대로 출력

-r: reverse, 역순으로 출력

=> 가장 마지막에 수정된 파일이 가장 마지막에 오도록 출력

 

의 결과를 파이프라인 ( | ) 으로 넘겨서

 

tail: 파일 내용을 뒤에서부터 출력

-n 1 : 뒤에서부터 1줄을 출력

=> 가장 최근에 수정된 jar 파일의 이름을 딱 찝는다!!

 

이외에 pgrep 명령어는 ps + grep 명령어의 결합으로 PID를 쉽게 뽑아낼 수 있도록 만들어진 명령어다

 

 

< .travis.yml > 파일 내용 추가

# Travis CI에서 Build한 Jar 파일을 S3에 올리는 과정
before_deploy:
  - mkdir -p before-deploy # 디렉토리 생성 (Travis는 디렉토리 단위로만 업로드 가능)
  - cp build/libs/*.jar before-deploy/ # 배포에 필요한 파일만 꼽아서 복사 (스크립트 + appspec.yml + executable jar)
  ###### 변경 부분 #####
  - cp scripts/*.sh before-deploy/
  ######################
  - cp appspec.yml before-deploy/
  - cd before-deploy && zip -r smartnotice * # 위치 이동 후 내부 파일 전체 압축
  - cd ../ && mkdir -p deploy # 상위 디렉토리로 이동 후 deploy 디렉토리 생성
  - mv before-deploy/smartnotice.zip deploy/smartnotice.zip # 파일 위치 옮기기

 

< appspec.yml > 파일 내용 추가

# CodeDeploy에서 EC2 서버로 넘겨준 파일들 모두 ec2-user 권한을 갖도록 한다
permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user

ApplicationStart: # deploy.sh 파일을 ec2-user 권한으로 실행해라 (중단 배포)
  - location: deploy.sh
    timeout: 60
    runas: ec2-user

 

이제 로컬에서 commit & push 하게 되면

-> Github에 업로드 

-> Travis CI가 받아서 빌드

-> 빌드 파일과 설정 파일, 스크립트를 묶어 단일 zip파일로 만들고 AWS S3 버킷에 업로드

-> CodeDeploy가 S3 버킷에서 zip 파일을 꺼내 EC2의 destination에다가 옮긴 다음에 deploy.sh 스크립트를 실행시킨다

-> 애플리케이션 자동 실행

 

이것이 바로 말로만 듣던 CI/CD인 것이다!!!!

대체 CI/CD가 뭐야? 설명을 봐도 뭔가 와닿지 않았는데 직접 실습해보고 나니 이제서야 체득이 된다

 

 

한가지 딱 아쉬운 점이 있다면, 배포를 할 때 기존에 동작중인 애플리케이션을 중단한 다음에 새로운 애플리케이션을 실행시키는 "중단 배포"를 하게 된다는 점이다.

 

우리가 매일 쓰는 구글, 유튜브, 네이버 등등. 사이트 수정 사항이 있다고 서버를 내렸다가 다시 올리지 않는 것처럼 "무중단 배포"를 하는 것이 실제 서비스를 운영하는 현장에서는 필수적이다.

 

 

다음에는 애플리케이션을 무중단 배포하는 방법을 알아보도록 하자!

 

투 비 컨티뉴..

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함