일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 유니크제약조건
- shared lock
- 이진탐색
- execute
- PS
- 연결리스트
- 지연로딩
- 스프링 폼
- fetch
- SQL프로그래밍
- 연관관계
- 스토어드 프로시저
- 다대다
- 동적sql
- exclusive lock
- 일대다
- JPQL
- 낙관적락
- 백트래킹
- eager
- BOJ
- querydsl
- CHECK OPTION
- dfs
- 즉시로딩
- 비관적락
- 데코레이터
- 힙
- FetchType
- 다대일
- Today
- Total
흰 스타렉스에서 내가 내리지
IAM ROLE, CI/CD, Travis CI, S3, CodeDeploy, IAM ROLE 본문
CI (Continuous Integration - 지속적 통합)
코드 버전 관리를 하는 VCS 시스템 (Git, SVN 등)에 PUSH가 되면 자동으로 테스트와 빌드가 수행되어 안정적인 배포 파일을 만드는 과정
CD (Continuous Deployment - 지속적인 배포)
이 빌드 결과를 자동으로 운영 서버에 무중단 배포까지 진행되는 과정
지속적으로 통합하기 위해서는 무엇보다 이 프로젝트가 완전한 상태임을 보장하기 위해 테스트 코드가 구현되어 있어야만 한다.
Travis CI 연동하기
Travis CI는 깃허브에서 제공하는 무료 CI 서비스이다.
젠킨스와 같은 CI 도구도 있지만, 젠킨스는 설치형이기 때문에 이를 위한 EC2 인스턴스가 하나 더 필요하다.
배포를 위한 EC2 인스턴스는 부담스럽기 때문에 오픈소스 웹 서비스인 Travis CI를 사용하자.
(AWS에서 Travis CI와 같은 CI 도구로 CodeBuild를 제공한다. 하지만 빌드 시간만큼 요금이 부과되는 구조라 초기에 사용하기는 부담스럽다.)
Travis CI 웹 서비스 설정
https://traivs-ci.org/ 에서 깃허브 계정으로 로그인 →
내 repository 연결, 활성화시키기
Travic CI 웹사이트에서 설정은 이게 끝이다. 상세한 설정은 프로젝트의 yml 파일로 진행한다.
프로젝트 설정
Travis CI의 설정은 프로젝트에 존재하는 .travis.yml 파일로 할 수 있다.
language: java
jdk:
- openjdk17
# Travis CI를 어느 브랜치가 push 될 때 수행할 지 지정한다.
branches:
only:
- master
# Travis CI 서버의 Home
# gradle을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여, 다음 배포 때부터 다시 받지 않도록 설정한다.
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
# master branch에 push 되었을 대 수행하는 명령어
script: "./gradlew clean build"
# CI 실행 완료 시 메일로 알림
notifications:
email:
recipients:
- 내 이메일
깃허브에 커밋 후 푸시하면 Travis CI에서 자동으로 빌드가 시작된다.
Travis CI와 AWS S3 연동하기
일단 Travis CI와 S3를 연동한다.
실제 배포는 AWS CodeDeploy 라는 서비스를 이용한다.
S3 연동이 먼저 필요한 이유는 jar 파일을 전달하기 위해서이다.
AWS CodeDeploy는 저장 기능이 없다.
그래서 Travis CI가 빌드한 결과물을 받아서 CodeDeploy가 가져갈 수 있도록 보관할 수 있는 공간이 필요하다.
이 때 AWS S3를 이용한다.
CodeDeploy가 빌드도 하고 배포도 할 수 있다. CodeDeploy에서는 깃허브 코드를 가져오는 기능을 지원하기 때문이다. 하지만 이렇게 할 때 빌드 없이 배포만 필요할 때 대응하기 어렵다.
빌드와 배포가 분리되어 있으면 예전에 빌드되어 만들어진 jar를 재사용하면 되지만, CodeDeploy가 모든 것을 하게 될 땐 항상 빌드를 하게 되니 확장성이 많이 떨어진다. 그래서 웬만하면 빌드와 배포는 분리하는 것을 추천한다.
Travis CI와 AWS S3 연동
원래 AWS 서비스에 외부 서비스가 접근할 수 없다.
그러므로 접근 가능한 권한을 가진 Key를 생성해서 사용해야 한다.
AWS에서는 이러한 인증과 관련된 기능을 제공하는 서비스로 IAM(Identity and Access Management)이 있다.
IAM은 AWS에서 제공하는 서비스의 접근 방식과 권한을 관리한다.
이 IAM을 통해 Travis CI 가 AWS의 S3와 CodeDeploy에 접근할 수 있도록 해보자.
IAM → Users → Add users
이름 설정
For programmatic access, you can generate access keys after you create the user
programmatic access 설정을 해야 하는데, 나중에 해보자.
권한 설정은 [Attach policies directly] 를 누르고,
[AmazonS3FullAccess] 와 [AWSCodeDeployFullAccess]를 체크해준다..
실제 서비스 회사에서는 권한도 S3와 CodeDeploy를 분리해서 관리하기도 한다.
태그는 맘대로 넣고싶으면 넣고.
최종 검토. 이렇게 되야함.
Access key 발급받기
이제 이키를 Travis CI에 등록해야 한다.
Travis CI 에 키 등록
Settings 들어가서, 아래로 내려보면 Environment Variables 항목이 있다.
아까 발급받은 IAM의 access key와 secret key를 넣어준다.
여기에 등록된 값들은 이제 .travis.yml 에서
$AWS_ACCESS_KEY, $AWS_SECRET_KEY 란 이름으로 사용할 수 있다.
이제 이 키를 사용해서 jar를 관리할 s3 버킷을 생성한다.
S3 버킷 생성
AWS의 S3 서비스는 일종의 파일 서버이다.
순수하게 파일들을 저장하고 접근 권한을 관리, 검색 등을 지원하는 파일 서버의 역할을 한다.
S3는 보통 게시글을 쓸 때 나오는 첨부파일 등록을 구현할 때 많이 이용한다.
파일 서버의 역할을 하기 때문인데, Travis CI 에서 생성된 Buid 파일을 저장하도록 구성하자.
S3에 저장된 Build 파일은 이후 AWS의 CodeDeploy에서 배포할 파일로 가져가도록 구성할 예정이다.
.travis.yml 추가
language: java
jdk:
- openjdk17
# Travis CI를 어느 브랜치가 push 될 때 수행할 지 지정한다.
branches:
only:
- master
# Travis CI 서버의 Home
# gradle을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여, 다음 배포 때부터 다시 받지 않도록 설정한다.
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
# master branch에 push 되었을 대 수행하는 명령어
script: "./gradlew clean build"
before_deploy: # CodeDeploysms jar 파일은 인식하지 못하므로 jar + 기타 설정 파일들을 모아 압축해야 한다.
- zip -r spring-general * # zip -r <압축파일명>.zip <압축하려는 폴더>
- mkdir -p deploy # mkdir -p 옵션은 안전하게 파일 경로를 생성해 준다
- mv spring-general.zip deploy/spring-general.zip
deploy: # S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언한다.
- provider: s3
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: spring-general-build-bucket
region: ap-northeast-2
skip_cleanup: true
acl: private # zip 파일 접근을 private 으로
local_dir: deploy # before_deploy 에서 생성한 디렉토리. 해당 위치의 파일들만 S3로 전송한다.
wait-until-deployed: true
# CI 실행 완료 시 메일로 알림
notifications:
email:
recipients:
- 내 이메일
Travis CI와 S3 연동이 완료되었다.
이제 AWS CodeDeploy로 배포까지 완료해보자.
Travis CI와 AWS S3, CodeDeploy 연동하기
EC2에 IAM roles 추가하기
IAM → Roles → Create role
IAM의 Users와 Roles의 차이는?
Role :
- AWS 서비스에만 할당할 수 있는 권한
- EC2, CodeDeploy, SQS 등
Users :
- AWS 서비스 외에 사용할 수 있는 권한
- 로컬 PC, IDC 서버 등
이렇게 만든 role 을 ec2 서비스에 등록한다.
ec2 인스턴스로 들어가서 Actions -> Security -> Modify IAM role
역할 선택이 완료되면 해당 ec2 인스턴스를 재부팅한다. 재부팅을 해야만 역할이 정상적으로 적용된다.
재부팅이 완료되었으면 CodeDeploy의 요청을 받을 수 있게 에이전트를 하나 설치한다.
CodeDeploy 에이전트 설치
ec2에 접속해서 다음 명령어를 입력
aws s3 cp s3://aws-codedeploy-ap-northeast-2/latest/install . --region ap-northeast-2
다운로드 성공했다면 다음과 같이 ㄱㄱ
chmod +x ./install
sudo ./install auto
엥 오류발생 ruby: No such file or directory
구글링 고고
해당 에러는 rvm 혹은 ruby 의 미설치로 발생하는 에러로, ruby 를 인스턴스에 설치하여 해결할 수 있습니다.
sudo yum install -y ruby
이거 실행후 다시 sudo ./install auto 하면 잘됨
설치가 끝났으면 Agent가 정상적으로 실행되고 있는지 상태검사를 한다.
sudo service codedeploy-agent status
다음과 같이 running 메시지가 출력되면 정상이다.
CodeDeploy 를 위한 권한 생성
CodeDeploy에서 EC2에 접근하려면 마찬가지로 권한이 필요하다.
AWS의 서비스이니 IAM 역할을 생성한다.
서비스는 CodeDeploy 선택
Create role
이제 CodeDeploy를 생성해보자
CodeDeploy 생성
CodeDeploy 서비스로 이동해서 Create application
Create deployment group 클릭
Deployment type에서는 In-place 를 선택한다.
만약 배포할 서비스가 2대 이상이라면 Blue/green을 선택하면 된다.
여기서는 1대의 EC2에만 배포하므로 선택하지 않는다.
Deployment settings 는 저렇게 하고, Load balencer는 체크해제 한다.
배포 구성이란 한번 배포할 때 몇대의 서버에 배포할 지를 결정한다.
2대 이상이라면 1대씩 배포할지, 30% 혹은 50%로 나눠서 배포할지 등등 여러 옵션을 선택하겠지만, 1대 서버다 보니 전체 배포하는 옵션으로 선택하면 된다.
배포 그룹까지 생성되었다면 CodeDeploy 설정은 끝이다.
이제 Travis CIdhk CodeDeploy를 연동해보자.
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의 설정은 .tracis.yml로 진행했다.
AWS CodeDeploy의 설정은 appspec.yml 로 진행한다.
version: 0.0 # CodeDeploy 버전이다. 프로젝트 버전이 아니므로 0.0 외에 다른 버전을 사용하면 오류가 발생한다.
os: linux
files:
- source: / # CodeDeploy에서 전달해 준 파일 중 destination으로 이동시킬 대상을 지정한다. 루트경로(/)로 지정하면 전체 파일을 이야기한다.
destination: /home/ec2-user/app/step2/zip/ # source에서 지정된 파일을 받을 위치다. 이후 jar을 실행하는 등은 destination에서 올긴 파일들로 진행된다.
overwrite: yes # 기존에 파일들이 있으면 덮어쓸지를 결정한다.
.travis.yml에도 추가한다.
deploy: # S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언한다.
- provider: s3
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: spring-general-build-bucket
region: ap-northeast-2
skip_cleanup: true
acl: private # zip 파일 접근을 private 으로
local_dir: deploy # before_deploy 에서 생성한 디렉토리. 해당 위치의 파일들만 S3로 전송한다.
wait-until-deployed: true
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: spring-general-build-bucket
key: spring-general.zip # 빌드 파일을 압축해서 전달
bundle_type: zip # 압축 확장자
application: spring-general # 웹 콘솔에서 등록한 CodeDeploy 애플리케이션
deployment_group: spring-general-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
wait-until-deployed: true
이제 프로젝트를 커밋하고 푸시한다.
Travis CI가 자동으로 시작되고, CI가 끝나면 CodeDeploy 화면 아래에서 배포가 수행되는 것을 확인할 수 있다.
배포가 끝났다면 다음 명령어로 파일들이 잘 도착했는지 확인해보자.
cd /home/ec2-user/app/step2/zip
Travis CI와 S3, CodeDeploy가 잘 연동이 됐네요
배포 자동화 구성
실제로 jar 를 배포하여 실행까지 해보자.
/scripts/deploy.sh 파일 추가
#!/bin/bash
REPOSITORY=/home/ec2-user/app/step2
PROJECT_NAME=spring-general
echo "> Build 파일 복사"
cp $REPOSITORY/zip/*.jar $REPOSITORY/
echo "> 현재 구동중인 애플리케이션 pid 확인"
CURRENT_PID=$(lsof -ti:8080) #6
echo "현재 구동중인 애플리케이션 pid: $CURRENT_PID"
if [ -z "$CURRENT_PID" ]; then #7
echo "> 현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다."
else
echo "> kill -9 $CURRENT_PID"
kill -9 $CURRENT_PID
sleep 5
fi
echo "> 새 애플리케이션 배포"
JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) #8
echo "> JAR Name : $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가"
chmod +x $JAR_NAME
echo "> $JAR_NAME 실행"
nohup java -jar -Dspring.config.location=classpath:/application.yml,classpath:/application-real.yml,/home/ec2-user/app/application-oauth.yml,/home/ec2-user/app/application-real-db.yml -Dspring.profiles.active=real $JAR_NAME > $REPOSITORY/nohup.out 2>&1 & #9
$JAR_NAME > $REPOSITORY/nohup.out 2>&1 &
- nohup 실행 시 CodeDeploy는 무한 대기 합니다.
- 이 이슈를 해결하기 위해 nohup.out 파일을 표준 입출력용으로 별도로 사용한다.
- 이렇게 하지 않으면 nohup.out 파일이 생기지 않고, CodeDeploy 로그에 표준 입출력이 출력된다.
- nohup이 끝나기 전까지 CodeDeploy도 끝나지 않으니 꼭 이렇게 해야한다.
이제 .travis.yml을 수정하자
.travis.yml 파일 수정
지금까지는 프로젝트의 모든 파일을 zip 파일로 만드는데, 실제로 필요한 파일들은 jar, appspec.yml, 배포를 위한 스크립트 들이다.
이 외 나머지는 배포에 필요하지 않으니 포함하지 않아야 한다.
그래서 .travis.yml의 before_deploy를 수정한다.
최종 .travis.yml
language: java
jdk:
- openjdk17
# Travis CI를 어느 브랜치가 push 될 때 수행할 지 지정한다.
branches:
only:
- master
# Travis CI 서버의 Home
# gradle을 통해 의존성을 받게 되면 이를 해당 디렉토리에 캐시하여, 다음 배포 때부터 다시 받지 않도록 설정한다.
cache:
directories:
- '$HOME/.m2/repository'
- '$HOME/.gradle'
# master branch에 push 되었을 대 수행하는 명령어
script: "./gradlew clean build"
before_deploy: # CodeDeploysms jar 파일은 인식하지 못하므로 jar + 기타 설정 파일들을 모아 압축해야 한다.
- mkdir -p before-deploy # zip에 포함시킬 파일들을 담을 디렉토리 생성. Travis CI는 S3로 디렉토리 단위로만 업로드 할 수 있기 때문에 항상 디렉토리를 생성해야 한다.
- 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/spring-general.zip # deploy로 zip 파일 이동
#
# - zip -r spring-general * # zip -r <압축파일명>.zip <압축하려는 폴더>
# - mkdir -p deploy # mkdir -p 옵션은 안전하게 파일 경로를 생성해 준다
# - mv spring-general.zip deploy/spring-general.zip
deploy: # S3로 파일 업로드 혹은 CodeDeploy로 배포 등 외부 서비스와 연동될 행위들을 선언한다.
- provider: s3
access_key_id: $AWS_ACCESS_KEY # Travis repo settings에 설정된 값
secret_access_key: $AWS_SECRET_KEY # Travis repo settings에 설정된 값
bucket: spring-general-build-bucket
region: ap-northeast-2
skip_cleanup: true
acl: private # zip 파일 접근을 private 으로
local_dir: deploy # before_deploy 에서 생성한 디렉토리. 해당 위치의 파일들만 S3로 전송한다.
wait-until-deployed: true
- provider: codedeploy
access_key_id: $AWS_ACCESS_KEY
secret_access_key: $AWS_SECRET_KEY
bucket: spring-general-build-bucket
key: spring-general.zip # 빌드 파일을 압축해서 전달
bundle_type: zip # 압축 확장자
application: spring-general # 웹 콘솔에서 등록한 CodeDeploy 애플리케이션
deployment_group: spring-general-group # 웹 콘솔에서 등록한 CodeDeploy 배포 그룹
region: ap-northeast-2
wait-until-deployed: true
# CI 실행 완료 시 메일로 알림
notifications:
email:
recipients:
- thisis.joos@gmail.com
마지막으로 CodeDeploy의 명령을 담당할 appspec.yml 파일 수정
최종 appspec.yml
version: 0.0 # CodeDeploy 버전이다. 프로젝트 버전이 아니므로 0.0 외에 다른 버전을 사용하면 오류가 발생한다.
os: linux
files:
- source: / # CodeDeploy에서 전달해 준 파일 중 destination으로 이동시킬 대상을 지정한다. 루트경로(/)로 지정하면 전체 파일을 이야기한다.
destination: /home/ec2-user/app/step2/zip/ # source에서 지정된 파일을 받을 위치다. 이후 jar을 실행하는 등은 destination에서 올긴 파일들로 진행된다.
overwrite: yes # 기존에 파일들이 있으면 덮어쓸지를 결정한다.
permissions: # CodeDeploy 에서 EC2 서버로 넘겨준 파일들을 모두 ec2-user 권한을 갖도록 한다.
- object: /
pattern: "**"
owner: ec2-user
group: ec2-user
hooks: # CodeDeploy 배포단계에서 실행할 명령어를 지정한다.
ApplicationStart: # ApplicationStart 라는 단계에서 deploy.sh 를 ec2-user 권한으로 실행하게 한다.
- location: deploy.sh
timeout: 60 # 스크립트가 60초 이상 수행되면 실패가 된다. (무한정 기다릴 순 없으니)
runas: ec2-user
모든 설정이 완료되었으므로 깃허브로 커밋과 푸시.
실제로 뭔가를 수정해서 배포해보자.
index.html 수정하고,
build.gradle에서 프로젝트 버전을 변경한다.
version '1.0.1-SNAPSHOT'
그리고 커밋 푸시.
아니 이게 뭔에러냐
no main manifest attribute
스냅샷 이름 겹쳐서 그런듯.
매번 build.gradle 에서 버전명을 다르게 해줘야 한다.
버전마다 jar이 생성되고 있다.
4시간의 대장정 끝 ㅠ
CodeDeploy 로그 확인
CodeDeploy와 같이 AWS가 지원하는 서비스에서는 오류가 발생했을 때 로그 찾는 방법을 모르면 오류를 해결하기가 어렵다.
배포가 실패하면 어느 로그를 보면 되는가?
ec2 서버에 접속 후, 다음 명령어 입력
cd /opt/codedeploy-agent/deployment-root
1. 최상단의 영문과 대시(-) 가 있는 디렉토리명은 CodeDeploy ID이다.
- 해당 디렉토리로 들어가 보면 배포한 단위별로 배포 파일들이 있다.
- 본인의 배포 파일이 정상적으로 왔는지 확인해 볼 수 있다.
2. ./deployment-logs/codedeploy-agent-deployments.loh
- CodeDeploy 로그 파일이다.
- CodeDeploy로 이루어지는 배포 내용 중 표준 입/출력 내용은 모두 여기에 담겨 있다.
- 작성한 echo 내용도 모두 표기된다.
남은 문제
배포하는 동안 스프링 부트 프로젝트는 종료 상태가 되어 서비스를 이용할 수 없다.
무중단 배포를 해야한다.
'AWS' 카테고리의 다른 글
Amazon Linux에 git을 설치하는 방법 (0) | 2023.05.15 |
---|---|
VPC 생성하기, 퍼블릭 서브넷, 프라이빗 서브넷 (0) | 2023.05.15 |
스프링 부트 프로젝트로 RDS 접근하기, RDS 설정 (0) | 2023.01.20 |
[신]배포 스크립트 만들기 - EC2, Amazon Linux (0) | 2023.01.20 |
EC2 서버에 프로젝트 배포하기 - git clone, test (0) | 2023.01.20 |