제육's 휘발성 코딩
반응형

CI & CD

  • CI (Continuous Integration) - 지속적 통합
  • CI를 통해 운영 서버에 무중단 배포까지 진행되는 과정을 CD (Continuous Deployment) - 지속적 배포라고 한다.
  • CI,CD 를 이용하여 코드 병합, 배포를 자동화하여 생산성을 높일 수 있다.

CI 4원칙

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

Travis CI 연동

  • GitHub에서 제공하는 무료 CI 서비스 (젠킨스는 설치형으로 인스턴스가 하나 더 필요)
  • https://travis-ci.com/ 에서 깃허브 계정으로 로그인

image

  • 계정 - Settings -레포지토리 activate - 해당 화면이 나오면 설정 끝

프로젝트 설정

image

  • .travis.yml 생성
language: java
jdk:
  - openjdk8

branches:
  only:
    - master

before_install:
  - chmod +x gradlew

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

script: "./gradlew clean build"

# CI 실행 완료시 메일로 알람
notifications:
  email:
    recipients:
      - sasca37@naver.com
  • .travis.yml에 메일정보 입력

image

  • 커밋 성공시 해당 화면과 성공메일을 확인할 수 있다.

Travis CI 와 AWS S3 연동

  • S3는 AWS에서 제공하는 파일 서버이다.
  • 이미지 같은 정적 파일이나 배포 파일 등을 관리하는 기능 지원

image

  • 다음과 같은 구조를 갖는다.
  • 실제 배포는 AWS Code Deploy라는 서비스를 이용
  • Code Deploy는 저장 기능이 없기 때문에 jar를 보관할 수 있는 S3 이용
  • S3 없이 Code Deploy로 빌드와 배포를 할 수 있지만 모두 해야하므로 확장성이 떨어진다.

AWS Key 발급

  • 일반적으로 AWS 서비스에 외부 서비스가 접근 할 수 없다.
  • 접근 가능한 권한을 가진 Key를 생성하자. (IAM 서비스 : Identity and Access Management)

image

  • IAM에 접속하여 사용자를 추가하자.

image

  • 사용자이름, 프로그래밍 방식 엑세스 선택
  • 기존 정책 직접 연결 - S3FullAccess 와 CodeDeployFullAccess 체크
  • 태그 추가 (선택)

image

  • 최종 설정 화면 - 다음 화면에서 키와 비밀 액세스키가 발급 된다.

Travis CI 키 등록

image

  • Travis CI - Settings - Environment Variables 에 발급 받은 키값들을 넣는다.
  • 이 키 값들은 .travis.yml에서 $AWS_ACCESS_KEY 와 같이 사용할 수 있다.

S3 버킷 생성

image

  • s3 검색 - 버킷 만들기

image

  • 퍼블릭 액세스를 모두 차단한다.
  • 실제 서비스의 경우 Jar 파일이 퍼블릭일 경우 누구나 내려받을 수 있어서 보안상 위험하다.

.travis.yml 추가

language: java
jdk:
  - openjdk8

branches:
  only:
    - master

before_install:
  - chmod +x gradlew

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

script: "./gradlew clean build"

before_deploy:
  - zip -r crawler-web * # 현재 위치의 모든 파일을 해당이름으로 압축
  - mkdir -p deploy
  - mv crawler-web.zip deploy/crawler-web.zip

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

# CI 실행 완료시 메일로 알람
notifications:
  email:
    recipients:
      - sasca37@naver.com
  • before_deploy, deploy를 추가 후 깃 푸쉬

image

  • Travis CI 에서 위와 같은 로그가 나오면 정상 실행

image

  • S3 버킷도 정상 생성된 것을 확인

Travis CI, S3, CodeDeploy 연동

EC2 IAM 추가

  • CodeDeploy를 이용하기 전에 EC2가 CodeDeploy를 연동 받을 수 잇게 IAM 역할 생성
  • IAM - 액세스 관리 - 역할 - 역할 만들기 (역할은 AWS 서비스에서만 할당할 수 있는 권한(EC2, CodeDeploy, SQS 등)을 말한다.)

image

  • AWS 서비스 - EC2 선택

image

  • EC2RoleforAWSCodeDeploy 정책 선택

image

  • 태그는 자유롭게 지정

image

  • 최종 결과 화면

image

  • EC2 이동 - 인스턴스 - 보안 - IAM 역할 수정 및 저장- 적용을 위해 재부팅

CodeDeploy 에이전트 설치

wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x ./install
sudo yum install ruby
sudo ./install auto
sudo service codedeploy-agent status
  • EC2에 접속한 후 다음 명령어를 입력

image

  • 해당 결과가 출력되면 정상 동작

CodeDeploy 권한 생성

image

  • IAM - 역할 생성 - CodeDeploy 선택

image

  • 자유롭게 태그 생성 (선택)

image

  • 최종 선택 화면

CodeDeploy 생성

  • AWS 배포 삼형제
    • Code Commit : 깃허브와 같은 코드 저장소 역할 - GitHub 대체
    • Code Build : Travis CI와 같은 빌드용 서비스 - Travis CI 대체
    • CodeDeploy : 배포용 서비스 (대체재가 없다.)

image

  • CodeDeploy 검색 후 어플리케이션 생성 선택

image

  • 생성 화면

image

  • 해당 설정을 하고 마지막에 로드 밸런싱 활성화를 꺼주고 배포 그룹을 생성한다.
  • 배포 구성은 몇 퍼센트씩 나눠서 배포할지 여부지만 1대를 사용하므로 기본값으로 가져가면 된다.

CI, S3, CodeDeploy 연동

mkdir ~/app/step2 && mkdir ~/app/step2/zip
  • EC2 서버에 디렉토리 생성
  • Travis CI에서 빌드가 끝나면 S3에 zip파일이 전송되고, 이 zip은 app/step2/zip으로 복사되어 압축을 푼다.
  • Travis CI 설정은 .travis.yml로 진행
  • CodeDeploy 설정은 appspec.yml로 진행
version: 0.0
os: linux
files:
  - source:   /
    destination: /home/ec2-user/app/step2/zip/
    overwrite: yes
  • appspec.yml 정보
  • version : 프로젝트 버전이 아니므로 0.0 버전 사용
  • source : 지정된 파일을 받을 위치 , 이후 jar 실행하는 동안에는 destination에서 옮긴 파일들로 진행
  • overwrite : 기존 파일 덮어씀
language: java
jdk:
  - openjdk8

branches:
  only:
    - master

before_install:
  - chmod +x gradlew

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

script: "./gradlew clean build"

before_deploy:
  - zip -r crawler-web * # 현재 위치의 모든 파일을 해당이름으로 압축
  - mkdir -p deploy
  - mv crawler-web.zip deploy/crawler-web.zip

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

  - provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
    secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
    bucket: crawler-springboot-build
    key: crawler-web.zip
    bundle_type: zip
    application: crawler-webservice
    deployment_group: crawler-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
    region: ap-northeast-2
    wait-until-deployed: true

# CI 실행 완료시 메일로 알람
notifications:
  email:
    recipients:
      - sasca37@naver.com
  • .travis.yml 수정 (오타나면 골치 아프다.. )

image

  • Travis CI 성공 화면

image

  • CodeDeploy 배포 성공 화면
  • EC2에서 cd /home/ec2-user/app/step2/zip 으로 프로젝트 최상단 파일이 있는지도 확인해주자.

배포 자동화

image

  • step2 환경에서 실행될 deploy.sh 를 해당 경로에 생성
#!/bin/bash

REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=crawler-web

echo "> Build 파일 복사"

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

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

CURRENT_PID=$(pgrep -fl crawler-service | grep java | 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 &
  • deploy.sh
language: java
jdk:
  - openjdk8

branches:
  only:
    - master

before_install:
  - chmod +x gradlew

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

script: "./gradlew clean build"

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/crawler-web.zip # deploy로 zip파일 이동

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

  - provider: codedeploy
    access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
    secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
    bucket: crawler-springboot-build
    key: crawler-web.zip
    bundle_type: zip
    application: crawler-webservice
    deployment_group: crawler-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
    region: ap-northeast-2
    wait-until-deployed: true

# CI 실행 완료시 메일로 알람
notifications:
  email:
    recipients:
      - sasca37@naver.com
  • .travis.yml 에 before_deploy 수정
  • 배포에 필요한 파일들만 설정
version: 0.0
os: linux
files:
  - source:   /
    destination: /home/ec2-user/app/step2/zip/
    overwrite:  yes

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

hooks:
  ApplicationStart:
    - location: deploy.sh # 엔진엑스와 연결되어 있지 않은 Port로 새 버전의 스프링 부트를 시작합니다.
      timeout: 60
      runas: ec2-user
  • appspec.yml 파일 수정

image

  • 깃 푸쉬 후 Travis CI 정상 실행 화면

image

  • CodeDeploy 에서도 정상 배포 확인

image

  • nohup.out 파일에서 정상 실행 확인 (여기까지 성공 시 배포자동화 완료)

테스트 방법

  • IDE의 build.gradle, 화면 수정 -> 깃 푸쉬 -> Travis CI 정상 실행 확인 -> CodeDeploy 정상 배포 확인 -> 배포 자동화 화면 확인
  • CodeDeploy에서 배포파일은 만들었지만 자동화 무반응 또는 whitelabel 발생 시
    • CodeDeploy 로그 찾는 방법 : cd /opt/codedeploy-agent/deployment-root 로 찾아가서 오류 내용 확인

본 포스팅은 프리렉-이동욱님의 '스프링 부트와 AWS로 혼자 구현하는 웹 서비스' 책을 참고하였습니다.

반응형
profile

제육's 휘발성 코딩

@sasca37

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요! 맞구독은 언제나 환영입니다^^