교재 8장 EC2 서버에서 프로젝트를 배포한 상태까지 완료했다는 가정하에 진행하겠습니다.
지금까지 쉘 스크립트로 작성된 deploy.sh로 직접 스크립트를 실행하여 푸시된 코드를 배포했습니다. 이러한 과정을 자동으로 만들기 위해 CI/CD 환경을 구축하고, Github에 푸시된 코드를 자동으로 배포하는 과정을 구현하겠습니다.
✅ CI & CD란?
CI(Continuous Integration - 지속적인 통합)
- 코드 버전 관리를 하는 VCS 시스템(Git, SVN 등)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정
- 코드 레벨의 테스트까지 자동화
- 어플리케이션에 대한 새로운 코드 변경 사항이 정기적으로 빌드 & 테스트되어 공유 저장소에 통합, 여러 명의 개발자가 동시에 작업할 경우, 서로 충돌할 수 있는 문제를 해결할 수 있습니다.
CD(Continuous Deployment - 지속적인 배포)
- 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정
- 시스템 테스트 및 배포 등 실행 환경과 릴리즈까지 자동화
- 개발팀과 비즈니스팀 간의 가시성, 커뮤니케이션 부족 문제를 해결할 수 있습니다.
📢 참고사항
CI에 대한 4가지 규칙
1. 모든 소스 코드가 살아있고(현재 실행되고) 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것
2. 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
3. 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것
4. 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 주는 것
위 4가지 규칙 중 가장 중요한 것은 테스팅 자동화입니다. 테스트 코드를 통과했다는 것은 결국, 해당 프로젝트가 완전한 상태임을 입증하기 때문입니다.
✅ Travis CI 연동하기
웹 사이트 설정
Travis CI는 Github에서 제공하는 무료 CI서비스입니다. 먼저, https://travis-ci.com/에서 Github계정으로 로그인한 뒤, [계정] -> [Settings]에서 원하는 저장소를 활성화 시켜줍니다.
프로젝트 설정
이어서 Travis의 상세한 설정은 .travis.yml로 진행합니다. build.gradle과 같은 위치에서 아래 코드를 작성합니다.
language: java
jdk:
- openjdk8
branches:
only:
- master
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
script: "./gradlew clean build"
notifications:
email:
recipients:
- frtt0608@naver.com
이 상태에서 코드를 커밋/푸쉬한 후, Travis CI 저장소 페이지를 확인합니다. 만약, 빌드에 실패하여 ./gradlew의 권한이 없다는 에러가 뜨는 경우, 아래 코드를 .travis.yml에 추가합니다.
before_install:
- chmod +x ./gradlew
✅ Travis CI와 AWS 연동하기
해당 부분은 AWS에서 설정할 부분이 많습니다.
- AWS S3 - 버킷생성
- AWS IAM - 사용자(인증) 추가
- AWS EC2에 IAM 역할 추가
- AWS에서 CodeDeploy 생성
- Travis CI, S3, CodeDeploy 연동
- 배포 자동화를 위한 스크립트 작성
대략 위와 같은 과정에 따라 진행되기 때문에 최대한 간략하게 작성하겠습니다. 자세한 설명과 이미지를 참고하며 진행하길 원하시는 분들은 해당 교재를 참고하시기 바랍니다.
Travis CI와 AWS S3 연동
AWS S3는 일종의 파일 서버입니다. 정적 파일이나 배포 파일들을 관리하는 기능을 지원하며, 보통 이미지 업로드를 구현한다면 이 S3를 이용하여 구현하는 경우가 많습니다.
전체적인 구조는 다음과 같습니다.
위 구조를 보면 실제 배포는 AWS CodeDeploy라는 서비스를 이용합니다. 하지만, CodeDeploy는 저장 기능이 없기 때문에 jar파일을 전달하기 위해서 S3 연동이 필요합니다. 즉, Travis CI가 빌드한 결과물을 CodeDeploy가 가져갈 수 있도록 보관하는 역할로 AWS S3를 이용합니다.
📢 참고사항
물론, CodeDeploy는 빌드 & 배포가 가능합니다. 다만, 빌드 없이 배포만 필요한 경우 대응하기 어렵습니다. 배포만 필요할 때는 이전에 만들어진 jar를 재사용하며 배포하기 위해 빌드와 배포를 분리하여 진행합니다.
AWS Key 발급
일반적으로 AWS 서비스에 외부 서비스가 접근할 수 없습니다. 그래서 접근 가능한 권한을 가진 Key를 만들기 위해 AWS에서 제공하는 IAM(Identity and Access Management)이 있습니다.
IAM은 접근 방식과 권한을 관리하는 서비스로 Travis CI가 AWS S3와 CodeDeploy에 접근할 수 있게 만들어줍니다.
📢 AWS Key 발급의 진행과정은 교재 329p ~ 334p에 있습니다.
S3 버킷 생성
AWS S3는 앞에서 언급했듯이 일종의 파일 서버의 역할을 합니다. 여기서는 Travis CI에서 생성된 Build 파일을 저장하도록 구성하였으며, 이는 앞으로 AWS CodeDeploy에서 배포할 파일입니다.
📢 S3 버킷 생성과정은 교재 334p ~ 337p에 있습니다.
.travis.yml 추가
Travis CI에서 빌드하여 만든 Jar 파일을 S3에 올릴 수 있도록 다음 코드를 추가합니다.
before_deploy:
- zip -r 프로젝트명 *
- mkdir -p deploy
- mv 프로젝트명.zip deploy/프로젝트명.zip
deploy:
- provider: s3
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: springboot-build-zip
region: ap-northeast-2
skip_cleanup: true
acl: private
local_dir: deploy
wait-until-deployed: true
- before_deploy: CodeDeploy는 Jar파일을 인식하지 못하므로 Jar파일 + 설정파일들을 압축합니다.
- deploy: S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언합니다.
여기까지 진행했다면 코드를 커밋/푸시하고 Travis CI의 모든 빌드가 성공했을 때, S3 버킷에 압축파일이 생성된 것을 확인할 수 있습니다.
Travis CI와 AWS S3, CodeDeploy 연동하기/CodeDeploy 권한 생성과 CodeDeploy생성
이번에는 EC2가 CodeDeploy를 연동받을 수 있게 IAM 역할을 생성합니다. EC2에서 사용하기 때문에 사용자가 아닌 역할로 생성하며, EC2 인스턴스의 [IAM 역할 수정]으로 들어가서 생성이 완료된 IAM 역할을 등록합니다.
마찬가지로 CodeDeploy에서 EC2에 접근하기 위한 IAM 역할을 생성합니다.
이후, CodeDeploy를 생성합니다. CodeDeploy는 AWS의 배포 삼형제 중 하나로 이를 간단하게 소개하자면 아래와 같습니다.
Code Commit
- Github와 같은 코드 저장소 역할.
- 프라이빗 기능을 지원.
Code Build
- Travis CI와 같은 빌드용 서비스.
- 멀티 모듈을 배포해야하는 경우 사용해 볼만하지만, 규모가 있는 서비스에서는 대부분 젠킨스/팀시티 등을 이용
CodeDeploy
- AWS의 배포 서비스.
- 앞에서 언급한 다른 서비스들은 대체재가 있지만, CodeDeploy는 대체재가 없습니다.
- 오토 스케일링 그룹 배포, 블루/그린 배포, 롤링 배포, EC2 단독 배포 등 많은 기능을 지원.
여기서는 Code Commit의 역할을 Github가, Code Build의 역할은 Travis CI가 하고 있습니다.
📢 IAM역할 생성과 CodeDeploy 생성과정은 교재 341p ~ 353p에 있습니다.
Travis CI, S3, CodeDeploy 연동
마지막으로 셋을 연동하며, CodeDeploy의 로그까지 확인해보겠습니다.
Travis CI의 Build가 끝나면 S3에 zip파일이 전송되고, 이 zip파일은 home/ec2-user/app/step2/zip로 복사되어 압축을 풀 예정입니다.
Travis CI의 설정은 .travis.yml로 진행하고,
AWS CodeDeploy의 설정은 appspec.yml로 진행합니다.
appspec.yml의 코드는 아래와 같습니다.
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/app/step3/zip/
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks:
ApplicationStart:
- location: start.sh
timeout: 60
runas: ec2-user
- file의 source: CodeDeploy에서 전달해 준 파일 중 destination으로 이동시킬 대상을 지정합니다. 루트 경로(/)를 지정하면 전체 파일을 지정합니다.
- destination: source에서 지정된 파일들을 받을 위치입니다. 이후, jar를 실행하는 등은 destination에서 옮긴 파일들로 진행됩니다.
- overwrite: 기존에 파일들이 있으면 덮어쓸지를 결정합니다.
- permissions: CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 합니다.
- hooks: CodeDeploy 배포 단계에서 실행할 명령어를 지정합니다. timeout을 통해 스크립트 실행 시간에 제한을 주며, 추가적으로 무중단 배포를 위한 명령어를 지정할 예정입니다.
이외에도 프로젝트에서 .travis.yml과 scripts/deploy.sh를 작성합니다. (해당 부분은 Github 코드로 대체합니다.)
마지막으로 코드를 커밋/푸시하여 Travis CI의 Build까지 성공하면 CodeDeploy 배포가 성공한 것을 확인할 수 있습니다.
실제 배포가 진행된 로그는 /opt/codedeploy-agent/deployment-logs/codedeploy-deployments.log에서 확인할 수 있습니다. 작성한 echo 내용도 포함되며, 배포 내용 중 입/출력 내용은 모두 여기에 담겨 있습니다.
🙋♂️느낀점
지금까지 프로젝트의 코드를 저장소에 커밋/푸시하면 자동으로 서버에 배포되는 과정을 진행하였습니다. 인프라를 다루는 부분이 많아서 사소한 이슈들이 많았지만, 기본적인 설정과 연동방법들을 알 수 있어서 서버에 관한 내용을 익힐 수 있었습니다.
아직까지 팀 프로젝트로 배포하며 서비스한 경험이 없어서인지, CI/CD의 효율성이 크게 와닿진 않습니다. 하지만, 팀원들과 Github에서 Master/Branch로 협업할 때, Master에 merge한 코드를 테스트하기가 번거로웠습니다. 이러한 과정들을 CI/CD를 통한 빌드 & 배포로 쉽게 확인할 수 있음을 알 수 있었습니다.
실제 서비스를 하는 어플리케이션은 분명 잦은 변동사항과 수정, 이슈 대응이 존재합니다. 이럴 때마다 매번 진행하는 빌드 & 배포 작업은 시간 소모가 엄청날 것입니다. 바로 CI/CD는 이런 상황들을 해결해주며, 개발자의 작업 시간을 단축시키는 데 큰 역할을 한다는 것!
결국, 지금까지 사용한 도구들은 어떻게하면 개발자의 작업을 단축시킬 수 있는가를 목적으로 만들어졌다고 느껴졌습니다. 수행 시간이나 유지보수 시간을 단축시키기 위해 코드를 개선하는 것처럼 개발 도구를 활용한 개발 시간 단축도 개발자에게 중요한 역량임을 알 수 있었습니다.
✅ Reference
'Developer's_til > 스프링 프레임워크' 카테고리의 다른 글
[Spring] 유연하고 확장하기 쉬운 코드 만들기! 코드의 분리와 확장 (0) | 2021.08.17 |
---|---|
[Spring boot] Nginx를 통한 무중단 배포 (0) | 2021.07.28 |
[Spring boot] 소셜 로그인 (Spring Security와 OAuth2.0) (0) | 2021.07.27 |
[Spring boot] API의 CRUD 구현과 JPA Auditing 활용하기 (0) | 2021.07.14 |
[Spring boot] IntelliJ와 gradle로 시작하는 Spring Boot (0) | 2021.07.07 |