728x90
반응형
24시간 무중단 배포
- CI & CD
- CI(Continuous Integration) : 코드 버전 관리하는 VCS 시스템(Git, SVN 등)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정
- CD(Continuous Deployment) : 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정
- CI 규칙
- 모든 소스 코드가 살아있고, 누구든 현재의 소스에 접근할 수 있는 단일 지점을 유지할 것
- 빌드 프로세스를 자동화해서 누구든 소스로부터 시스템을 빌드하는 단일 명령어를 사용할 수 있게 할 것
- 테스팅을 자동화해서 단일 명령어로 언제든지 시스템에 대한 건전한 테스트 수트를 실행할 수 있게 할 것
- 누구나 현재 실행 파일을 얻으면 지금까지 가장 완전한 실행 파일을 얻었다는 확신을 하게 할 것
- Travis CI 연동
- Travis CI : 깃허브에서 제공하는 무료 CI 서비스
- Travis CI 웹 서비스 설정
- https://travis-ci.org/에서 깃허브 계정으로 로그인한 뒤, 계정명 클릭 후에 Setting 클릭
- 설정 페이지에 깃허브 저장소 검색창에 이름을 입력해서 찾은 다음, 활성화 시킴
- 활성화한 저장소를 클릭 후, 저장소 빌드 히스토리 페이지로 이동
- 프로젝트 설정
- Travis CI의 상세한 설정은 프로젝트에 존재하는 .travis.yml 파일로 할 수 있으며, yml 파일 확장자를 YAML(야믈)이라 함
- YAML은 JSON에서 괄호를 제거한 것
- Travis CI 설정
- 프로젝트의 build.gradle과 같은 위치에서 .travis.yml 생성 후 코드 추가
- branches : Travis CI를 어느 브랜치가 푸시될 때, 수행할 지 지정함. 현재 옵션은 오직 master 브랜치에 push될 때만 수행함
- cache : 그레이들을 통해 의존성을 받게 되면, 이를 해당 디렉토리에 캐시하여, 같은 의존성은 다음 배포 때부터 다시 받지 않도록 설정함
- script : master 브랜치에 푸시되었을 때, 수행하는 명령어이며, 프로젝트 내부에 둔 gradlew을 통해 clean & build를 수행함
- notifications : Travis CI 실행 완료 시 자동으로 알람이 가도록 설정함
- 빌드가 성공한 것이 확인되면, .travis.yml에 등록한 이메일을 확인하면 됨
- 프로젝트의 build.gradle과 같은 위치에서 .travis.yml 생성 후 코드 추가
language: java
jdk :
- openjdk8
branches :
only :
- master
# Travis CI 서버의 Home
cache :
directories :
- '$HOME/.m2/repository'
- '$HOME/.gradle'
script : "./gradlew clean build"
# CI 실행 완료 시 메일로 알람
notifications :
email :
recipients :
- 본인 메일 주소
3. Travis CI와 AWS S3 연동
- S3 : AWS에서 제공하는 일종의 파일 서버
- 이미지 파일을 비롯한 정적 파일들을 관리하거나 지금 진행하는 것처럼 배포 파일들을 관리하는 등의 기능 지원
- S3를 비롯한 AWS 서비스와 Travis CI를 연동하게 되면 전체 구조
- 첫 번째 단계, Travis CI와 S3 연동
- 실제 배포는 AWS CodeDeploy라는 서비스 이용하지만, S3 연동이 먼저 필요한 이유는 Jar 파일을 전달하기 위해서임
- CodeDeloy는 저장 기능이 없고, Travis CI가 빌드한 결과물을 받아서 CodeDeploy가 가져갈 수 있도록 보관할 수 있는 공간이 필요하며, 보통 이럴 때는 AWS S3를 이용함
- Travis CI와 AWS S3 연동
- AWS key 발급
- 일반적으로 AWS 서비스에 외부 서비스가 접근할 수 없으므로, 접근 가능한 권한을 가진 Key를 생성해서 사용해야 함
- AWS에서는 이러한 인증과 관련된 기능을 제공하는 서비스로 IAM(Identity and Access Management) 있음
- IAM은 AWS에서 제공하는 서비스의 접근 방식과 권한을 관리함
- IAM을 통해 Travis CI가 AWS의 S3와 CodeDeploy에 접근
- AWS 웹 콘솔에서 IAM을 검색하여 이동함
- IAM 페이지 사이드 바에서 사용자 추가버튼을 클릭
- 생성할 사용자의 이름과 엑세스 유형 선택하고, 엑세스 유형은 프로그래밍 방식 엑세스임
- 권한 설정 방식은 3개 중 기존 정책 직접 연결 선택
- 화면 아래 정책 검색 화면에서 s3full로 검색하여 체크하고, 다음 권한으로 CodeDeployFull을 검색하여 체크함
- 실제 서비스 회사에서는 권한도 S3와 CodeDeploy를 분리해서 관리하기도 하며, 간단하게 둘을 합쳐서 관리함. 2개의 권한이 설정되었으면 다음으로 넘어감
- 태그 Name 값을 지정하는데, 본인이 인지 가능한 정도의 이름으로 만들고, 본인이 생성한 권한 설정 항목을 확인함
- 최종 생성 완료되면, 엑세스 키와 비밀 엑세스 키가 생성되고, 이 두 값이 Travis CI에서 사용될 키이고, 이 키를 Travis CI에 등록함
- Travis CI에 키 등록
- 먼저 TravisCI의 설정화면으로 이동함
- 설정화면 아래로 내려보면, Environment Variables 항목이 있음
- AWS_ACCESS_KEY, AWS_SECRET_KEY를 변수로 해서 IAM 사용자에서 발급받은 키 값들을 등록함
- AWS_ACCESS_KEY : 엑세스 키 ID
- AWS_SECRET_KEY : 비밀 엑세스 키
- 등록된 값들을 .travis.yml에서 $AWS_ACCESS_KEY, $AWS_SECRET_KEY란 이름으로 사용할 수 있고, 키를 사용해서 Jar를 관리할 S3버킷을 생성함
- S3 버킷 생성
- S3에 관해 설정하고, AWS의 S3 서비스는 일종의 파일 서버임(순수하게 파일들을 저장하고 접근 권한을 관리, 검색 등을 지원하는 파일 서버의 역할을 함)
- S3 : 보통 게시글을 쓸 때, 나오는 첨부파일 등록을 구현할 때 파일 서버의 역할 때문에 많이 이용하며, Travis CI에서 생성된 Build 파일을 저장
- S3에 저장된 Build 파일은 이후 AWS의 CodeDeploy에서 배ㅗ할 파일로 가져가도록 구성할 예정이고, AWS 서비스에서 S3를 검색하여 이동하고 버킷을 생성함
- 원하는 버킷명을 작성하고, 이 버킷에 배포할 Zip 파일이 모여있는 장소임을 의미하도록 짓는 것을 추천
- 다음으로, 버젼관리를 설정하고, 별다른 설정 없이 바로 넘어감
- 버킷의 보안과 권한 설정 부분이고, 퍼블릭 액세스를 열어두지 말고, 모든 차단을 해야 함(실제 서비스에서 할 때는 Jar 파일이 퍼블릭일 경우 누구나 내려받을 수 있어 코드나 설정값, 주요 키값들이 다 탈취될 위험이 있음)
- 버킷이 생성되면 다음과 같이 버킷 목록에서 확인할 수 있음
- S3가 생성되었으면, 이제 S3로 배포 파일을 전달
- .travis.yml 추가
- 이전에 만든 .travis.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 # Travis repo setting에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: freelec-springboot-build # S3 버킷
region: ap-northeast-2
skip_cleanup: true
acl: private # zip 파일 접근을 private으로
local dir: deploy # before_deploy에서 생성한 디렉토리
wait-until-deployed: true
- Travis CI Settings 항목에서 등록한 $AWS_ACCESS_KEY와 $AWS_SECRET_KEY가 변수로 사용됨
- before_deploy: deploy 명령어가 실행되기 전에 수행되며, CodeDeploy는 Jar 파일은 인식하지 못하므로 Jar+기타 설정 파일들을 모아 압축함
- zip -r freelec-springboot2-webservice : 현재 위치의 모든 파일을 freelec-springboot2-webservice 이름으로 압축하고, 명령어의 마지막 위치는 본인의 프로젝트 이름이어야 함
- mkdir -p deploy : deploy라는 디렉토리를 Travis CI가 실행 중인 위치에서 생성함
- mv freelec-springboot2-webservice.zip deploy/freelec-springboot2-webservice.zip : deploy로 이동시킴
- deploy : S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언함
- local_dir: deploy : 앞에서 생성한 deploy 디렉토리를 지정하고, 해당 위치의 파일들만 S3로 전송함
- 설정이 다 되면 깃허브로 푸시하고, Travis CI에서 자동으로 빌드가 진행되는 것을 확인하고, 모든 빌드가 성공하는 지 확인함
- 로그가 나오면 Travis CI의 빌드가 성공한 것이며, S3 버킷을 가보면 업로드가 성공한 것을 확인할 수 있음
4. Travis CI와 AWS S3, CodeDeploy 연동
- AWS 배포 시스템인 CodeDeploy를 이용하기 전에 배포 대상인 EC2가 CodeDeploy를 연동 받을 수 있게 IAM 역할 하나 생성
- EC2에 IAM 역할 추가
- S3와 마찬가지로 IAM을 검색하고, 이번에는 역할 탭을 클릭해서 이동하여 역할 만들기 버튼을 차례로 클릭함
- IAM 사용자와 역할 차이
- 역할 : AWS 서비스에만 할당할 수 있는 권한. EC2, CodeDeploy, SQS 등
- 사용자 : AWS 서비스 외에 사용할 수 있는 권한. 로컬 PC, IDC 서버 등
- 지금 만들 권한은 EC2에서 사용할 것이기 때문에 사용자가 아닌 역할로 처리하고, 서비스 선택에서는 AWS서비스 클릭 후 EC2 클릭
- 정책에선 EC2RoleForA를 검색하여 AmazonEC2RoleforAWSCodeDeploy 선택
- 태그는 본인이 원하는 이름으로 작명
- 마지막으로 역할의 이름을 등록하고, 나머지 등록 정보를 최종적으로 확인함
- 이렇게 만든 역할을 EC2 서비스에 등록하고, EC2 인스턴스 목록으로 이동한 뒤, 본인의 인스턴스를 마우스 오른쪽 버튼으로 눌러 인스턴스 설정 -> IAM 역할 연결/바꾸기 를 차례로 선택
- 방금 생성한 역할을 선택하고, 완료되면 해당 EC2 인스턴스를 재부팅함(재부팅해야만 역할이 정상적으로 적용됨)
- 재부팅이 완료되었으면 CodeDeploy의 요청을 받을 수 있게 에이전트를 하나 설치함
- CodeDeploy 에이전트 설치
- EC2에 접속해서 다음 명령어 입력
- aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install .--region ap-northeast-2
- 내려 받기가 성공했다면, 메세지 콘솔 출력됨
- downlaod: s3://aws-codedeploy-ap-northeast-2/latest/install to ./install
- intall 파일에 실행 권한이 없어서 실행 권한을 추가함
- chmod +x ./install
- install 파일로 설치를 진행함
- sudo ./install auto
- 설치가 끝났으면 Agent가 정상적으로 실행되고 있는지 상태 검사
- sudo service codedeploy-agent status
- runnig 메시지 출력 : The AWS CoedDeploy agent is running as PID xxx
- EC2에 접속해서 다음 명령어 입력
- CodeDeploy를 위한 권한 생성
- CodeDeploy에서 EC2에 접근하려면 마찬가지로 권한이 필요하며, AWS의 서비스이니 IAM 역할 생성하고, 서비스는 AWS 서비스 -> CodeDeploy를 차례로 선택함
- CodeDeploy는 권한이 하나뿐이라서 선택 없이 바로 다음으로 넘아가면 됨
- 태그 역시 본인이 원하는 이름으로 작명
- CodeDeploy를 위한 역할 이름과 선택 항목들을 확인한 뒤, 생성완료함
- CodeDeploy 생성
- CodeDeploy는 AWS의 배포
- Code Commit
- 깃허브와 같은 코드 저장소의 역할을 함
- 프라이빗 기능을 지원한다는 강점이 있지만, 현재 깃허브에서 무료로 프라이빗 지원을 하고 있어서 거의 사용되지 않음
- Code Build
- Travis CI와 마찬가지로 빌드용 서비스
- 멀티 모듈을 배포해야 하는 경우, 사용해볼만하지만 규모가 있는 서비스에서는 대부분 젠킨스/팀시티 등을 이용하니 이것 역시 사용할 일이 없음
- CodeDeploy
- AWS의 배포 서비스
- 다른 서비스들은 대체제가 있고, 딱히 대체제보다 나은 점이 없지만, CodeDeploy는 대체제가 없음
- 오토 스케일링 그룹 배포, 블루 그린 배포, 롤링 배포, EC2 단독 배포 등 많은 기능을 지원함
- 현재 프로젝트는 Code Commit의 역할을 깃허브가, Code Build의 역할을 Travis CI가 하고 있기 때문에 추가로 사용할 서비스는 CodeDeploy임
- Code Commit
- CodeDeploy 서비스로 이동해서 화면 중앙에 있는 애플리케이션 생성 버튼을 클릭함
- 생성할 CodeDeploy의 이름과 컴퓨팅 플랫폼을 선택하고, 컴퓨터 플랫폼에선 EC2/온프레미스를 선택
- 생성이 완료되면 배포 그룹을 생성하라는 메시지를 볼 수 있으며, 화면 중앙의 배포 그룹 생성 버튼을 클릭함
- 배포 그룹 이름과 서비스 역할을 등록하고, 서비스 역할은 좀 전에 생성한 CodeDeploy용 IAM 역할을 선택함
- 배포 유형에서는 현재 위치를 선택(만약 본인이 배포할 서비스가 2대 이상이라면 블루/그린을 선택하면 됨)
- 환경 구성에서는 Amazon EC2 인스턴스에 체크함
- 마지막으로 배포 구성을 선택하고 로드밸런싱은 체크 해제함
- 배포 구성이란 한번 배포할 때, 몇 대의 서버에 배포할지를 결정함
- CodeDeploy는 AWS의 배포
- Travis CI, S3, CodeDeploy 연동
- S3에서 넘겨줄 zip 파일을 저장할 디렉토리를 하나 생성하고, EC2 서버에 접속해서 다음과 같이 디렉토리 생성함
- mkdir ~/app/step2 && mkdir ~/app/step2/zip
- Travis CI의 Build가 끝나면 S3에 zip 파일이 전송되고, zip 파일은 /home/ec2-user/app/step2/zip로 복사되어 압축을 풀 예정이고, Travis CI의 설정은 .travis.yml로 진행하고, AWS CodeDeploy의 설정은 appspec.yml로 진행함
- version: 0.0
- CodeDeploy 버젼을 말하며, 프로젝트 버전이 아니므로 0.0 외에 다른 버전을 사용하면 오류가 발생함
- source
- CodeDeploy에서 전달해준 파일 중 destination으로 이동시킬 대상을 지정함
- 루트 경로(/)를 지정하면 전체 파일을 말함
- destination
- source에서 지정된 파일을 받을 위치이며, 이후 Jar를 실행하는 등은 destination에서 옮긴 파일들로 진행됨
- overwrite
- 기존에 파일들이 있으면 덮어쓸지를 결정하고, 현재 yes라고 했으니 파일들을 덮어쓰게 됨
version: 0.0 os: linux files: - source: / destination: /home/ec2-user/app/step2/zip/ overwrite: yes
- 기존에 파일들이 있으면 덮어쓸지를 결정하고, 현재 yes라고 했으니 파일들을 덮어쓰게 됨
- version: 0.0
- S3에서 넘겨줄 zip 파일을 저장할 디렉토리를 하나 생성하고, EC2 서버에 접속해서 다음과 같이 디렉토리 생성함
- .travis.yml에도 CodeDeploy 내용 추가하고, deploy 항목에 다음 코드 추가
deploy:
...
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY # Travis repo setting에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: freelec-springboot-build # S3 버킷
key: freelec-springboot2-webservice.zip # 빌드 파일을 압축해서 전달
bundle_type: zip # 압축 확장자
application: freelec-springboot2-webservice # 웹 콘솔에서 등록한 CodeDeploy 애플리케이션
deployment_group: freelec-springboot2-webservice-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
wait-until-deployed: true
- 모든 내용을 작성했다면, 프로젝트를 커밋하고 푸시하고, 깃허브로 푸시가 되면 Travis CI가 자동으로 시작됨
- Travis CI가 끝나면 CodeDeploy 화면 아래에서 배포가 수행되는 것을 확인할 수 있음
- 배포가 끝났다면, 다음 명령어로 파일들이 잘 도착했는지 확인할 수 있음
- cd /home/ec2-user/app/step2/zip
- ll
5. 배포 자동화 구성
- Travis CI, S3, CodeDeploy 연동까지 구현된 것을 기반으로 실제로 Jar를 배포하여 실행
- deploy.sh 파일 추가
- step2 환경에서 실행될 deploy.sh를 생성하고, scripts 디렉토리를 생성해서 여기에 스크립트를 생성함
- 우선 git pull을 통해 직접 빌드했던 부분을 제거하고 Jar를 실행하는 단계에서 몇가지 코드가 추가됨
#!/bin/bash
REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=freelec-springboot2-webservice
echo "> Build 파일복사"
cp $REPOSITORY/zip/*.jar $REPOSITORY/
echo">현재 구동 중인 애플리케이션 pid 확인"
CURRENT_PID=$(pgrep -fl freelec-springboot2-webservice | grep jar | 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 &
- 코드 설명
- CURRENT_PID : 현재 수행 중인 스프링부트 애플리케이션의 프로세스 ID를 찾고, 실행 중이면 종료하기 위해서임. 스프링부트 애플리케이션 이름으로 된 다른 프로그램이 있을 수 있어 freelec-springboot2-webservice로 된 jar 프로세스를 찾은 뒤 ID를 찾음
- chmod +x $JAR_NAME : Jar 파일은 실행 권한이 없는 상태이고, nohup으로 실행할 수 있게 실행 권한을 부여함
- $JAR_NAME > $REPOSITORY/nohup.out 2>&1 & : nohup 실행 시 CodeDeploy는 무한대기하며, 이 이슈를 해결하기 위해서는 nohup.out 파일을 표준 입출력용으로 별도 사용함. 이렇게 하지 않으면, nohup.out 파일이 생기지 않고, CodeDeploy 로그에 표준 입출력이 출력됨. nohup이 끝나기 전까지 CodeDeploy도 끝나지 않으니 꼭 이렇게 해야 함
- .travis.yml 파일 수정
before_deploy:
- mkdir -p before-deploy # zip에 포함시킬 파일들을 담을 디렉토리 생성
- cp out/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/freelec-springboot2-webservice.zip # deploy로 zip파일 이동
- appspec.yml 파일 수정
- permissions : CodeDeploy에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 함
- hooks : CodeDeploy 배포 단계에서 실행할 명령어를 지정하고, ApplicationStart라는 단계에서 deploy.sh를 ec2-user 권한으로 실행하게 하고, timeout:60으로 스크립트 실행 60초 이상 수행되면 실패가 됨
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
- 모든 설정이 완료되었으니 깃허브로 커밋과 푸시를 하고, Travis CI에서 성공 메시지 확인 및 CodeDeploy에서 배포 성공을 확인함
728x90
반응형
'Web > SpringBoot' 카테고리의 다른 글
10. 24시간 365일 중단없는 서비스 구축 (0) | 2022.03.15 |
---|---|
8. EC2 서버에 프로젝트 배포 (0) | 2022.03.07 |
7. AWS 데이터베이스 서버환경 - AWS RDS (0) | 2022.03.05 |
6. AWS 서버환경 - AWS EC2 (0) | 2022.03.04 |
5. Spring security와 OAuth2.0으로 로그인 기능 구현 (0) | 2022.03.03 |
댓글