배포 자동화

Travis CI & S3 & Codedeploy

Posted by Damin on April 1, 2021

시작 전에 yml 파일 작성할 때 들여쓰기 항상 조심하자 !

CI & CD

CI : 지속적 통합

코드 버전 관리를 하는 VCS 시스템에 상호작용 (Merge, Push, etc)이 일어나면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정

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

CD : 지속적인 배포

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

Travis CI 연동하기

  1. [https://travis-ci.org] 접속 후 회원 가입
  2. 프로필 클릭 후 settings 접속
  3. 원하는 Repository 활성화

Travis CI 를 위한 프로젝트 설정

Spring boot 프로젝트에 build.gradle과 같은 위치에 .travis.yml 파일 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
language: java
jdk:
  - openjdk8

branches:
  only:
    - main
cache:
  directories:
    - '$HOME/.m2/repository'
    - '$HOME/.gradle'

before_install:
 - chmod +x gradlew

script: "./gradlew clean build"
notifications:
  email:
    recipients: 연락 받을 이메일

Travis CI & AWS S3 연동하기

War 파일을 전달하기 위해 S3 (파일 저장소)와 연동을 한다.

  1. AWS 에서 IAM 서비스 접속
  2. 왼쪽 사이드바에서 사용자 -> 사용자 추가
  3. 이름 - 원하는 이름 입력
  4. 엑세스 유형 - 프로그래밍 방식 엑세스
  5. 사용자 권한 - 기존 정책 직접 연결
  6. AmazonS3FullAccess, AWSCodeDeployFull 체크
  7. 태그는 자유롭게
  8. 검토 후 생성
  9. 엑세스 키, 비밀 엑세스 키 확인 (현재만 보여준다. 다른 페이지 넘어가면 다시 확인할 수 없으니 본인이 기록)

Travis Key 등록

  1. 프로필 클릭 후 settings
  2. Environment Variables 에 키 등록
  3. Name : AWS_ACCESS_KEY, Value : 위에서 확인한 엑세스 키
  4. Name : AWS_SECRET_KEY, Value : 위에서 확인한 비밀 엑세스 키

이를 통해 yml 파일에서 해당 Name 으로 사용할 수 있게 됐다.

S3 만드는 과정은 생략

.travis.yml 수정

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
32
33
34
35
36
37
38
39
40
41
42
43
language: java
jdk:
  - openjdk8

branches:
  only:
    - main
cache:
  directories:
    - '$HOME/.m2/repository'
    - '$HOME/.gradle'

before_install:
 - chmod +x gradlew
 
script: "./gradlew clean build"

before_deploy:
  - mkdir -p before-deploy
  - cp script/*.sh before-deploy/
  - cp appspec.yml before-deploy/
  - cp build/libs/*.war before-deploy/
  - cd before-deploy && zip -r before-deploy *
  - cd ../ && mkdir -p deploy
  - mv before-deploy/before-deploy.zip deploy/spring-nginx-CD.zip

deploy:
  - provider: s3
    access_key_id: $AWS_ACCESS_KEY
    secret_access_key: $AWS_SECRET_KEY

    bucket: springboot-build-helloworld
    region: ap-northeast-2
    skip_cleanup: true
    acl: private
    local_dir: deploy
    wait-until-deployed: true
    on:
      all_branches: true

notifications:
  email:
    recipients: 연락 받을 이메일

Travis CI & AWS S3, CodeDeploy 연동하기

  1. AWS IAM 서비스로 이동
  2. 왼쪽 사이드바 역할 - 역할 만들기
  3. 유형의 개체 - AWS 서비스
  4. 사용할 서비스 - EC2
  5. 정책 선택 - AmazonEC2RoleforAWSCodeDeploy
  6. 태그는 자유롭게
  7. 최종 검토 후 생성
  8. EC2 인스턴스로 이동
  9. 서버가 가동중인 EC2의 IAM 역할 수정 (우클릭 - 보안)
  10. 방금 만든 AWS IAM 역할 설정
  11. EC2 인스턴스 재부팅

CodeDeploy 에이전트 설치

EC2 접속 후

1
2
3
4
5
6
7
8
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2

chmod +x ./install

sudo apt install ruby
sudo ./install auto

sudo service codedeploy-agent status # 실행 상태 확인

CodeDeploy를 위한 권한 생성

  1. AWS IAM 서비스로 이동
  2. 왼쪽 사이드바 역할 - 역할 만들기
  3. 사용사례 - CodeDeploy 선택
  4. 권한은 1개밖에 없으므로 넘어가기
  5. 태그는 자유
  6. 최종 검토 후 생성

CodeDeploy 생성

  1. AWS CodeDeploy 서비스로 이동
  2. 애플리케이션 생성 (EC2)
  3. 배포 그룹 생성
  4. 서비스 역할 - 위에서 생성한 CodeDeploy 용 IAM 선택
  5. 현재 위치 (서비스가 2대 이상이면 블루/그린 선택)
  6. 환경구성 - Amazon EC2 인스턴스
  7. 배포 구성 - CodeDeployDefault.AllAtOnce (2대 이상이면 1대씩 배포, 30%, 50% 등등 선택)

본격적인 연동 시작

AWS CodeDeploy 설정은 appspec.yml 로 진행

.travis.yml 과 같은 위치에 appspec.yml 생성

1
2
3
4
5
6
version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/app/step2/zip/
    overwrite: yes

.travis.yml 에도 CodeDeploy 내용 추가

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
deploy:
   ...


- provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY
    secret_access_key: $AWS_SECRET_KEY

    bucket: springboot-build-helloworld
    key: spring-nginx-CD.zip
    bundle_type: zip
    application: springboot-nginx-cd
    deployment_group: springboot-nginx-CD-group
    region: ap-northeast-2
    wait-until-deployed: true
    on:
      all_branches: true

해당 파일을 push 한 후에 travis CI, CodeDeploy 확인을 해보면 연동이 완료된 것을 볼 수 있다.

배포 자동화 구성

.travis.yml 파일이 있는 곳에 script 디렉터리 생성

해당 디렉터리에 deploy.sh 파일 생성

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
32
#!/bin/bash

REPOSITORY=/home/ubuntu/app/step2
PROJECT_NAME=spring-nginx-CD

echo "> Build 파일 복사"

cp $REPOSITORY/zip/*.war $REPOSITORY/

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

CURRENT_PID=$(pgrep -fl helloworld | 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 "> 새 애플리케이션 배포"
WAR_NAME=$(ls -tr $REPOSITORY/*.war | tail -n 1)
echo "> WAR Name: $WAR_NAME"
echo "> $WAR_NAME 에 실행권한 추가"
chmod +x $WAR_NAME
echo "> $WAR_NAME 실행"
nohup java -jar \
       -Dspring.config.location=classpath:/application.properties,/home/ubuntu/app/application-rds.properties \
       -Dspring.profiles.active=real \
       $WAR_NAME > $REPOSITORY/nohup.out 2>&1 &

Travis 파일 수정

실제로 필요한 파일들은 jar, appspec.yml, 스크립트들 이기 때문에 모두를 압축할 필요는 없습니다.

따라서 .travis.yml 파일의 before_deploy 부분 수정

1
2
3
4
5
6
7
8
before_deploy:
  - mkdir -p before-deploy
  - cp script/*.sh before-deploy/
  - cp appspec.yml before-deploy/
  - cp build/libs/*.war before-deploy/
  - cd before-deploy && zip -r before-deploy *
  - cd ../ && mkdir -p deploy
  - mv before-deploy/before-deploy.zip deploy/spring-nginx-CD.zip

CodeDeploy 파일 수정

permission, hooks 부분 추가

1
2
3
4
5
6
7
8
9
10
11
permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu

hooks:
  ApplicationStart:
    - location: deploy.sh
      timeout: 60
      runas: root

CodeDeploy 로그 확인

/opt/codedeploy-agent/deployment-root/deployment-logs 에 있다.

전체적인 흐름도

  1. User 가 코드 변경 후 push
  2. Travis 가 Github Web Hooking
  3. Travis -> S3 War 파일 전달
  4. Travis -> AWS CodeDeploy 배포 요청
  5. S3 -> AWS CodeDeploy War 파일 전달
  6. AWS CodeDeploy -> AWS EC2 압축 해제 후 zip 파일 전달