24시간 365일 운영되는 서비스에서 배포 환경 구축은 필수 과제 중 하나이다.
여러개발자의 코드가 실시간으로 병합되고, 테스트가 수행되는 환경, master브랜치가 푸시되면 배포가 자동으로 이루어지지는 환경을 구축하지 않으면 실수할 여지가 많다.
9.1 CI & CD 소개
8장에서 스프링 부트 프로젝트를 간단하게 EC2에 배포해 보았다.
스크립트를 개발자가 직접 실행함으로써 발생하는 불편을 경험했다.
그래서 CI, CD환경을 구축하여 이 과정을 개선하려한다.
CI(Continuous Integration - 지속적 통합)
코드버전 관리를 하는 VCS 시스템(Git, SVN)에 push가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정
CD(Continuous Deployment - 지속적 배포)
이 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정
일반적으로 CI만 구축되어 있지는 않고, CD도 함께 구축된 경우가 대부분
현대의 웹 서비스 개발에서는 하나의 프로젝트에 여러개발자가 함께 개발을 진행한다. 그러다 보니 각자가 개발한 코드를 합쳐야할 때마다 큰 일이었다. 그래서 매주 병합일(코드 Merge만 하는 날)을 정하여 이날은 각자가 개발한 코드를 합치는 일만 진행했다.
이런 수작업 때문에 생산성이 좋을 수가 없었으며 개발자들은 지속해서 코드가 통합되는 환경(CI)를 구축하게 됨.
개발자가 각자 원격 저장소(깃허브나 깃랩)로 push가 될 때마다 코드를 병합하고, 테스트 코드와 빌드를 수행하면서 자동으로 코드가 통합되어 더는 수동으로 코드를 통합할 필요가 없어지며 개발자들은 개발에 집중할 수 있게 되었다.
CD역시 마찬가지. 한 두대의 서버에 개발자가 수동으로 배포를 할 수 있지만, 수십대 수백대의 ㅅ버에 배포를 해야 하거나 긴박하게 당장 배포를 해야하는 상황이 오면 더는 수동으로 배포할 수가 없었다. 그래서 이것도 자동화하게 됨.
여기서 주의할 점은 단순히 CI 도구를 도입했다고 해서 CI를 하고 있는 것은 아니다.
마틴 파울러의 블로그를 참고하면 CI에 대해 다음과 같은 4가지 규칙을 이야기한다.
- 모든 소스 코드가 살아 있고(현재 실행되고) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것.
- 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
- 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것.
- 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 하게 할것.
여기서 특히 중요한 것은 테스팅 자동화이다.
지속적으로 통합하기 위해서는 무엇보다 이 프로젝트가 완전한 상태임을 보장하기 위해 테스트 코드가 구현되어 있어야만 한다.
9.2 Travis CI 연동하기
Travis CI는 깃허브에서 제공하는 무료 CI 서비스이다.
젠킨스와 같은 CI도구도 있지만 젠킨스는 설치형이기 때문에 이를 위한 EC2 인스턴스가 하나더 필요하다. 이제 시작하는 서비스에게 배포를 위한 EC2인스턴스는 부담스럽기 때문에 오픈소스 웹서비스인 Travis CI를 사용해보겠다.
Travis CI 웹 서비스 설정
Home – Travis-CI
Simple YAML configs
www.travis-ci.com
들어가서 깃헙계정으로 로그인
프로젝트 설정
Travis CI의 상세할 설정은 프로젝트에 존재하는 .travis.yml파일로 할 수 있다.
.yml
yml 파일 확장자를 YAML(야믈)이라고 한다.
아마 웹 개발을 한 독자는 JSON이 친숙할 텐데 YAML은 JSON에서 괄호를 제거한 것이다.
YAML의 이념이 "기계에서 파싱하기 쉽게, 사람이 다루기 쉽게"이다 보니 익숙하지 않은 독자라도 읽고 쓰기가 쉽다.
그러다 보니 많은 프로젝트와 서비스들이 이 YAML을 적극적으로 사용중.
language: java
jdk:
- openjdk11
branches:
only:
- main
# Travis CI 서버의 Home
cache:
directories:
- '$Home/.m2/repository'
- '$Home/.gradle'
script: "./gradlew clean build"
#CI 실행 ㅗ안료시 메일로 알람
notifications:
email:
recipients:
- lts0424@naver.com
branches
- Travis CI를 어느 브랜치가 푸시 될때 수행할지 지정
- 현재 옵션은 main 브랜치에 push될 때만 수행
cache
- 그레들을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여, 같은 의존성은 다음 배포 때부터 다시 받지 않도록 설정.
script
- main 브랜치에 푸시되었을 때 수행하는 명령어
- 여기서는 프로젝트 내부에 둔 gradlew을 통해 clean& build를 수행
notification
- Travis CI 실행 완료시 자동으로 알람이 가도록 설정.
그 후 travis CI 에서 확인.
오류발생 ! 전에 권한부여를 .yml 파일에 추가해주었다.
before_install:
- chmod +x gradlew
9.3 Travis CI와 AWS S3 연동하기
S3
AWS에서 제공하는 일종의 파일 서버.
이미지파일을 비롯한 정적 파일들을 관리하거나 지금 진행하는 것처럼 배포파일들을 관리하는 기능을 지원.
보통 이미지 업로드를 구현한다면 이 S3를 이용하여 구현하는 경우가 많다.
S3를 비롯한 AWS서비스와 Traivs CI를 연동하게 되면 전체구조는 다음과 같다.
먼저 첫 번째 단계로 Travis CI와 S3를 연동해 보겠다. 실제 배포는 AWS CodeDeploy라는 서비스를 이용한다.
하지만, S3연동이 먼저 필요한 이유는 jar 파일을 전달하기 위해서이다.
CodeDeploy는 저장기능이 없다. 그래서 Travis CI가 빌드한 결과물을 받아서 CodeDeploy가 가져갈 수 있도록 보관할 수 있는 공간이 필요하다. 보통은 이럴 때 AWS S3를 이용한다.
CodeDeploy가 빌도드 하고 배포할 수 있다. CodeDeploy에서는 github코드를 가져오는 기능을 지원하기 때문이다. 하지만 이렇게 할 때 빌드없이 배포만 필요할 때 대응하기 어렵다.
빌드와 배포가 분리되어 있을 때 장점.
만들어진 Jar를 재사용하면 됨.
CodeDeploy가 이 모든것을 하게 되면 항상 빌드를 하게 되니 확장성이 많이 떨어진다. 그래서 웬만하면 빌드와 배포는 분리하는 것을 추천.
AWS Key 발급
일반적으로 AWS 서비스에 외부 서비스가 접근할 수 없다. 그러므로 접근 가능한 권한을 가진 Key를 생성하고 사용해야한다.
AWS에서는 이러한 인증과 관련된 기능을 제공하는 서비스로 IAM(Identity and Access Management)가 있다.
IAM은 AWS에서 제공하는 서비스의 접근방식과 권한을 관리한다.
IAM을 통해 Travis CI가 AWS의 S3와 CodeDeploy에 접근할 수 있도록 해보겠다.
Travis CI에 키등록
등록한 값들은 .travis.yml파일 에서 $AWS_ACCESS_KEY, $ AWS_SECRET_KEY라는 이름으로 사용.
환경변수에 설정한다.
S3(Simple Storage Service) 버킷 생성
AWS의 S3 서비스 -> 일종의 파일서버.
순수하게 파일들을 저장하고 접근권한을 관리, 검색 등을 지원하는 파일 서버의역할
S3 -> 보통 게시글을 쓸 때 나오는 첨부파일 등록을 구현할 때 많이 이용.
Travis CI에서 생성된 Build파일을 저장하도록 구성하겠다.
S3에서 저장된 Build파일은 이후 AWS의 CodeDeploy에서 배포할 파일로 가져가도록 구성할 예정
.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
secret_access_key: $AWS_SECRET_KEY
bucket: springboot-build2
region: ap-northeast-2
skip_cleanup: true
acl: private #zip 파일 접근을 private
local_dir: deploy #before_deploy에서 생성한 디렉토리
wait-until-deployed: true
on:
branch: main #해당 라인 추가
코드 집에서 추가
Travis CI 연동 확인
S3에 업로드 성공했는지 확인
에러 발생...
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl awsspring | grep ***jar*** | awk '{print $1}')
교재에는 위의 코드 처럼 나와있는데 이렇게 하면 배포해도 update가 되지않는 문제가 있었다… 빌드는 성공하는데…..
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl awsspring | grep ***java*** | awk '{print $1}')
이코드 처럼 jar → java로 바꿔주어야지 현재 실행중인 process를 잘 죽이고 새로 update를 해준다. 찾아봤는데 jar로 하면 현재 실행중인 process를 제대로 죽이지 못해서 일어나는 에러라고는 하는데…. 링크 첨부
9.6 CodeDeploy 로그 확인
은... 책 참고 366p!
테스트, 빌드, 배포 까지 전부 자동화되었다. 이번장은 인프라 내용이 많아 어려웠다...ㅠ
이제 Main 브랜치에 푸시만 하면 자동으로 EC2에 배포가 된다.
하지만 1가지 문제가 있다.
배포하는 동안 스프링 부트 프로젝트는 종료 상태가 되어 서비스를 이용할 수 없다.
어떻게 하면 배포하는 동안에도 서비스를 계속 유지할 수 있을까?
다음 장에서는 서비스 중단 없는 배포 방법을 소개한다. 흔히 말하는 무중단 배포
정리
- CI/CD에 대한 소개
- CI 서비스인 Travis CI 에대한 소개와 프로젝트 연동 방법
- AWS의 CD 서비스인 CodeDeploy에 대한 소개와 프로젝트 연동 방법
- 수동 배포 방식에서 자동화 방식으로의 개선
'Spring > 스프링부트와 AWS로 혼자구현하는 웹 서비스' 카테고리의 다른 글
CI / CD 란? (0) | 2023.02.25 |
---|---|
섹션10. 24시간 365일 중단 없는 서비스를 만들자. (0) | 2023.02.24 |
섹션8. EC2 서버에 프로젝트를 배포해 보자. (0) | 2023.02.06 |
섹션7. AWS RDS (1) | 2023.02.05 |
섹션 6. AWS 서버 환경을 만들어보자 - AWS EC2 (0) | 2023.01.30 |