aws S3 ➡ 버킷 ➡ 버킷 만들기
나는 이미 버킷을 생성해둔 상태다.

버킷 생성 시 리전은 꼭 EC2 인스턴스와 같은 것으로 지정해야 한다.
만약 리전이 다르다면 S3 리전에서 EC2 리전으로 데이터를 옮기는 데에 💸비용이 청구된다.
(그게 나야,, 둠빠둠빠두비두밥,,)

나머지는 모두 디폴트 값으로 놔두고 버킷 생성!
1. 태그 추가
2. IAM 역할 추가
3. EC2 서버에 CodeDeploy 에이전트 설치
CodeDeploy를 생성할 때 수행할 인스턴스를 지정해줘야하기 때문에 인스턴스들을 구분할 태그를 추가해줘야 한다.
인스턴스 선택 ➡ 작업 ➡ 인스턴스 설정 ➡ 태그 관리


EC2 인스턴스에서 S3에 접근할 수 있도록 AmazonS3FullAccess 권한을 추가한 뒤, 인스턴스에 연결한다.

EC2 서버에 접속한 뒤, 똑같이 입력하여 설치해준다.
$ sudo apt update
$ sudo apt install ruby-full
$ sudo apt install wget
$ cd /home/ubuntu
$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto > /tmp/logfile
$ sudo service codedeploy-agent status
1. IAM 역할 추가
2. CodeDeploy 애플리케이션 생성
3. CodeDeploy 배포 그룹 생성
AWSCodeDeployRole 권한을 추가하여 역할을 생성한다.

컴퓨팅 플랫폼은 EC2/온프레미스를 선택하여 생성한다.

위에서 생성한 CodeDeploy 애플리케이션 이름을 눌러 들어가면 배포 그룹을 생성할 수 있다.

서비스 역할에서는 3.1에서 생성한 AWSCodeDeployRole 권한을 가진 IAM을 선택한다.

다음 환경 구성에서는 Amazon EC2 인스턴스를 선택하고 2.1에서 태그를 추가했다면 아래와 같이 해당 태그의 인스턴스를 선택할 수 있다.

나머지 설정은 아래와 같이 해주고 배포 그룹을 생성한다.

1. IAM 사용자 생성
2. Access Key, Secret Key 생성 및 확인
IAM ➡ 액세스 관리 ➡ 사용자 ➡ 사용자 생성

직접 정책 연결을 선택하고
AmazonS3FullAccess, AWSCodeDeployRole 권한을 추가하여 사용자를 생성한다.

생성한 사용자 이름을 클릭하여 들어가서 아래와 같이 액세스 키 만들기를 클릭한다.

그러면 아래와 같은 화면이 뜨는데,
이 화면에서는 아무거나 선택해도 무방하다.

액세스 키를 생성하게 되면
Access Key, Secret Key가 발급이 되는데
❗ 이때, Secret Key는 이 화면을 나가게 되면 더이상 알 수 있는 방법이 없기 때문에 꼭 csv파일로 가지고 있는 것을 추천한다.

Github Repository ➡ Settings ➡ Secrets and variables ➡ Actions ➡ New repository secret

Access Key, Secret Key를 등록해준다.

APPLICATION 키는 바로 Spring 프로젝트 내의 application.properties 파일의 내용을 가지고 있는 키다.
Spring 프로젝트 내에 있는 application.properties 파일은 각종 민감정보를 담고있는 파일이기 때문에 깃허브에 올릴 때는 .gitignore에 작성해서 깃허브에 올라가지 않도록 설정하는데, github action을 사용해서 깃허브에 푸쉬한 코드로 빌드를 해야하기 때문에 application.properties 파일이 필요하다!
그렇기 때문에 우리는 Screts에 application.properties 파일의 내용을 저장해두고 빌드할 때마다 파일을 생성하여 빌드해주려고 한다.
application.properties 파일의 내용을 모두 복붙하여 키를 생성해두면 된다.
Spring 프로젝트 루트 디렉토리에 appspec.yml 파일을 생성하고 아래와 같이 작성한다.
# appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/app
overwrite: yes
permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ubuntu
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ubuntu
1. start.sh 작성
2. stop.sh 작성
3. build.gradle 파일 수정
아래와 같이 프로젝트 루트 디렉토리 아래 scripts 디렉토리를 만들고 그 안에 start.sh와 stop.sh를 작성했다.

#!/usr/bin/env bash
PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/spring-webapp.jar"
APP_LOG="$PROJECT_ROOT/application.log"
ERROR_LOG="$PROJECT_ROOT/error.log"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# build 파일 복사
echo "$TIME_NOW > $JAR_FILE 파일 복사" >> $DEPLOY_LOG
cp $PROJECT_ROOT/build/libs/*.jar $JAR_FILE
# jar 파일 실행
echo "$TIME_NOW > $JAR_FILE 파일 실행" >> $DEPLOY_LOG
nohup java -jar $JAR_FILE > $APP_LOG 2> $ERROR_LOG &
CURRENT_PID=$(pgrep -f $JAR_FILE)
echo "$TIME_NOW > 실행된 프로세스 아이디 $CURRENT_PID 입니다." >> $DEPLOY_LOG
#!/usr/bin/env bash
PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/spring-webapp.jar"
DEPLOY_LOG="$PROJECT_ROOT/deploy.log"
TIME_NOW=$(date +%c)
# 현재 구동 중인 애플리케이션 pid 확인
CURRENT_PID=$(pgrep -f $JAR_FILE)
# 프로세스가 켜져 있으면 종료
if [ -z $CURRENT_PID ]; then
echo "$TIME_NOW > 현재 실행중인 애플리케이션이 없습니다" >> $DEPLOY_LOG
else
echo "$TIME_NOW > 실행중인 $CURRENT_PID 애플리케이션 종료 " >> $DEPLOY_LOG
kill -15 $CURRENT_PID
fi
build.gradle에 아래 코드를 추가해준다.
jar {
enabled = false
}
1. Github Actions Workflow 생성
2. deploy.yml 파일 작성
Github Repository ➡ Actions ➡ Simple workflow 선택

name: Deploy to Amazon EC2
on:
push:
branches:
- main #브랜치명
# 본인이 설정한 값을 여기서 채워넣는다.
env:
AWS_REGION: us-east-1 #리전
S3_BUCKET_NAME: test-bucket #버킷 이름
CODE_DEPLOY_APPLICATION_NAME: test-app #CodeDeploy 애플리케이션 이름
CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: test-deployment-group #CodeDeploy 배포 그룹 이름
permissions:
contents: read
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
# (1) 기본 체크아웃
- name: Checkout
uses: actions/checkout@v3
# (2) application.properties 설정
- uses : actions/checkout@v3
- run: touch ./src/main/resources/application.properties
- run: echo "${{ secrets.APPLICATION }}" > ./src/main/resources/application.properties
- run: cat ./src/main/resources/application.properties
# (3) gradlew 권한 추가
- name: Run chmod to make gradlew executable
run: chmod +x ./gradlew
# (4) JDK 11 세팅
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
# (5) Gradle build (Test 제외)
- name: Build with Gradle
uses: gradle/gradle-build-action@0d13054264b0bb894ded474f08ebb30921341cee
with:
arguments: clean build -x test
# (6) AWS 인증 (IAM 사용자 Access Key, Secret Key 활용)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ${{ env.AWS_REGION }}
# (7) 빌드 결과물을 S3 버킷에 업로드
- name: Upload to AWS S3
run: |
aws deploy push \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--ignore-hidden-files \
--s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
--source .
# (8) S3 버킷에 있는 파일을 대상으로 CodeDeploy 실행
- name: Deploy to AWS EC2 from S3
run: |
aws deploy create-deployment \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
--s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip
action이 일어나면 워크 플로우가 동작하도록 설정한 브랜치에 push를 한 뒤,
워크 플로우가 정상적으로 수행이 끝나면 아래와 같이 ✔표시가 뜬다.

Actions 탭에서 보고 싶은 워크 플로우를 클릭하면 아래와 같이 수행 과정을 볼 수 있다.
만약 에러가 난다면 어떤 부분에서 에러가 났는지도 확인이 가능하다.

배포가 완료된 후 AWS S3에는 zip형식의 빌드파일이 저장되어 있고

AWS CodeDeploy에서 배포 내역을 확인할 수 있다.

배포 자동화는 참 힘든거구나 싶었다..
다음엔 도커를 사용해보고 싶다! 😊
참고한 블로그
https://bcp0109.tistory.com/363
https://velog.io/@sun1203/Github-Action-Spring-Application.properties
이 글을 읽는 모두, 좋은 하루 되세요. 🤗
설명 최고이십니다! 사진 자료까지 첨부해주셔서 덕분에 CICD 쉽게 구축했습니다 감사합니다 :)