CI/CD 툴은 대표적으로 젠킨스가 있지만 젠킨스는 별도의 서버가 필요하는 등 설정이 어렵다. 그래서 규모가 작은 프로젝트에 적합하고 빠르게 구축이 가능한 Github Actions를 선택하였다.
Github Actions 플로우
Github Actions 빌드 배포 플로우는 Github Actions를 작동시켜서 빌드 결과물 jar 파일을 S3에 전송한다. 그리고 S3에 있는 jar파일을 CodeDeploy가 EC2에 배포 해서 실행 시킨다.
위에서 Github Actions가 CI(지속적인 통합) 역할을 하고 CodeDeploy가 CD(지속적인 배포) 역할을 한다.
Github Actions는 프로젝트 소스를 빌드및 테스트코드도 실행시켜 배포하기에 적합한 소스인지 확인 한다. 만약 테스트 코드중 하나라도 실패하면 배포는 실패한다.
Github Actions 빌드 세팅
Github Actions로 프로젝트를 테스트코드가 정상적동한지 확인하고 빌드한다음 zip파일로 압축까지 하는 과정이다.
먼저 프로젝트 루트에서 .github > wrokflows 폴더를 만들고 그 안에 deploy.yml 파일을 만들고 그 안에 아래 코드를 넣는다.
env:
S3_BUCKET_NAME: clothstar-bucket
CODE_DEPLOY_APP_NAME: clothstar-deploy-v2
DEPLOYMENT_GROUP_NAME: clothstar_deploy
ZIP_FILE_NAME: clothstar-deploy.zip
name: aws-deploy
on:
push:
branches: develop
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
- name: Build with Gradle
run: ./gradlew build
- name: Make zip file
run: zip -r ./$ZIP_FILE_NAME .
shell: bash
"on.push.branches: develop" 은 develop으로 merge가 될때마다 develop 브랜치 기준으로 빌드및 테스트를 하겠다는 뜻이다.
그리고 Springboot Gradle 빌드 및 테스트는 공식문서를 참고해서 인입하였다.
※ 참고 공식문서 : https://docs.github.com/ko/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
빌드 및 테스트를 완료하고 빌드된 파일을 zip 파일로 압축(Make zip file)한다.
그리고 위까지 세팅이 완료후 develop브랜치로 merge된후 빌드가 되는지 확인한다. 또 테스트 코드가 깨졌을때 빌드가 되는지도 확인한다
AWS 세팅
AWS 세팅으로 Github Actions로 만들어진 zip파일을 S3 전송 후 CodeDeploy가 S3에 있는 zip파일을 EC2로 옮겨서 zip 파일을 풀고 jar를 실행 시켜야 한다. 그러므로 기본적으로 AWS 세팅은 아래와 같다. 참고영상을 보고 세팅을 하였다.
1. S3 생성
2. S3 권한(AmazonS3FullAccess), CodeDeploy(AWSCodeDeployFullAccess) 권한 가진 IAM 사용자 생성,
3. EC2 생성
4. S3 권한(AmazonS3FullAccess), CodeDeploy(AWSCodeDeployFullAccess) 권한 가진 EC2에 매핑할 IAM 생성후 매핑
5. EC2에 Code Deploy Agent 설치
6. CodeDeploy 생성
7. CodeDeploy(AWSCodeDeployFullAccess) 권한 가진 CodeDeoploy에 매핑할 IAM 생성후 매핑
※ 참고영상 : https://www.youtube.com/watch?v=UF2Giz9PE-E&t=1s
CodeDeploy는 S3의 파일을 appspec.yml 의 내용 스펙에 따라 EC2에 배포 툴이다. 그래서 S3가 필요하다. 그리고 EC2 에는 CodeDeploy의 기능을 실행할 수 있도록 CodeDeploy Agent를 설치해야 한다.
참고 : CodeDeploy Agent란 배포를 진행할 EC2 인스턴스에 설치되어 CodeDeploy의 명령을 기다리는 프로그램이다. appspec.yml 파일의 절차에 따라 배포를 진행한다.
1, 2번 세팅을 하고 나서는 deploy.yml 에 아래 내용을 추가한다.
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # 등록한 Github Secret이 자동으로 불려온다.
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # 등록한 Github Secret이 자동으로 불려온다.
aws-region: ap-northeast-2
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./$ZIP_FILE_NAME s3://$S3_BUCKET_NAME/$ZIP_FILE_NAME
"Configure AWS credntials"는 AWS 자격증명을 설정을 한다. id, key는 2번 세팅에서 만든 S3 IAM 사용자의 정보인데 이 사용자의 권한으로 CodeDeploy를 실행시키는 것이다. 위까지 세팅하고 나서 빌드하면 S3에 zip파일이 올라갔을것이다.
※ [참고] AWS_ACCESS_KEY_ID와 AWS_SECRET_ACCESS_KEY를 GitHub Secrets에 저장하는 방법.
${{ secrets.AWS_ACCESS_KEY_ID }} 와 ${{ secrets.AWS_SECRET_ACCESS_KEY }} 는 secrests의 AWS_ACESS_KEY_ID와 AWS_SECRET_ACCESS_KEY의 변수 값을 사용한다는 뜻이다. 깃허브의 settings에 들어가서 Secrets and variables > Actions 탭에서 New repository scret 버튼을 눌러서 값을 추가할 수 있다.
그리고 3~7번까지 세팅을 모두 해야 하는데 쫌 까다로운게 EC2에 ssh 접속을하여 java와 CodeDeploy Agent 설치를 해야 한다.
아래 링크를 보고 참조하였다.
자바 설치 참조 링크 : https://languagestory.tistory.com/154
CodeDeploy Agent 설치 참조 링크 : https://jinmay.github.io/2020/05/13/aws/how-to-install-code-deploy-agent-ubuntu/
※ [참고] EC2 SSH 접속해서 CodeDeploy Agent 설치 방법과 상태 확인
sudo apt-get update
# ubuntu 16.04
# CodeDeploy agent는 ruby로 실행되므로 ruby 다운로드
sudo apt-get install ruby
sudo apt-get install wget
# CodeDeploy agent install 파일 다운로드할 경로로 이동
cd /home/ubuntu
# bucket-name과 region-identifier를 각자의 상황에 맞게 변경
# wget https://<bucket-name>.s3.<region-identifier>.amazonaws.com/latest/install
# Seoul region 만약에 Seoul Region이 아니라면 <bucket-name>과 <region-identifier>를 수정
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
# agent 자동실행
chmod +x ./install
sudo ./install auto
# codedeploy-agent 상태 확인
sudo service codedeploy-agent status
# codedeploy-agent 서비스 시작
sudo service codedeploy-agent start
지역별 bucket-name과 region-identifier 는 아래 링크를 참조
https://docs.aws.amazon.com/codedeploy/latest/userguide/resource-kit.html#resource-kit-bucket-names
CodeDeploy 세팅
7번까지 모두 세팅하고 나서 CodeDeploy가 실행할 appspec.yml 파일을 만들고 배포때 실행될 bash shell 파일을 만들어야 한다.
CodeDeploy 참고 링크 : https://velog.io/@bagt/Github-Actions%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B0%B0%ED%8F%AC
appspec.yml 은 위 참조링크와 동일하지만 deploy.sh 파일은 쫌 수정하였다. JAR_DEV_ENV를 넣어서 nohub java -jar 뒤에 둬서 dev profiles로 실행 시키도록 하였다 왜냐하면 인텔리제이에서는 test 하위에 application.yml을 만들어두면 자동으로 main 하위의 application.yml보다 우선적으로 적용된다.
그리고 sudo nohub java -jar로 jar파일을 실행시키면 root 계정으로 실행되고 PID가 2개 생긴다. $CURRENT_PID가 2개가 생기고 한개 kill을 하더라도 하나가 남아있기 때문에 이미 사용중인 포트가 있다고 하면서 새로운 jar 파일을 실행시키지 못하게 된다. 그래서 앞에 sudo를 뺐다.
참고 : sudo nohub java -jar로 jar파일을 실행시키면 sudo 프로세스가 nohup java -jar 명령을 root 권한으로 실행한다. 그리고 nohup 프로세스가 JVM을 실행한다. 그래서 2개의 PID가 생성된다.
하지만 nohub java -jar로 jar파일을 실행시키면 nohup 프로세스가 JVM을 사용자 계정으로 실행만 하기 때문에 PID가 한개만 생성된다.
#!/bin/bash
BUILD_JAR=$(ls /home/ubuntu/action/build/libs/clothstar-0.0.1-SNAPSHOT.jar)
JAR_NAME=$(basename "$BUILD_JAR")
JAR_DEV_ENV=-Dspring.profiles.active=dev
echo "> 현재 시간: $(date)" >> /home/ubuntu/action/deploy.log
echo "> build 파일명: $JAR_NAME" >> /home/ubuntu/action/deploy.log
echo "> build 파일 복사" >> /home/ubuntu/action/deploy.log
DEPLOY_PATH=/home/ubuntu/action/
cp "$BUILD_JAR" $DEPLOY_PATH
echo "> 현재 실행중인 애플리케이션 pid 확인" >> /home/ubuntu/action/deploy.log
CURRENT_PID=$(pgrep -f "$JAR_NAME")
if [ -z "$CURRENT_PID" ]
then
echo "> 현재 구동중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ubuntu/action/deploy.log
else
echo "> kill -9 $CURRENT_PID" >> /home/ubuntu/action/deploy.log
sudo kill -9 "$CURRENT_PID"
sleep 5
fi
DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo "> DEPLOY_JAR 배포" >> /home/ubuntu/action/deploy.log
nohup java -jar ${JAR_DEV_ENV} "$DEPLOY_JAR" >> /home/ubuntu/deploy.log 2>/home/ubuntu/action/deploy_err.log &
Code Deploy 설정까지 완료 하면 deploy.yml에 아래 코드를 추가한다. CodeDeploy를 실행시키는 구문이다.
- name: Code Deploy
run: >
aws deploy create-deployment --application-name $CODE_DEPLOY_APP_NAME
--deployment-config-name CodeDeployDefault.AllAtOnce
--deployment-group-name $DEPLOYMENT_GROUP_NAME
--s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$ZIP_FILE_NAME
위까지 완료하고 나서 develop 브랜치에 merge를 해보면 ec2의 ~/actions 폴더에 jar 파일이 생기고 자동으로 실행이 된다.
그리고 자동배포시 springboot가 kill 되고 재시작이 됐는지 알려면 ~/deploy.log를 tail -f deploy.log 해서 확인하면 된다.
Github Actions 디스코드 알림 설정
보통 알림설정은 노션에 하지만 디스코드에 깃허브 알림을 설정해놔서 배포 알림도 디스코드에 같이 하는게 좋을거같아서 디스코드에 했다.
디스코드 알림 설정 참고 링크 : https://github.com/marketplace/actions/actions-status-discord
deploy.yml 파일에 아래 소스를 추가 한다. ${{ secrets.DISCORD_WEBHOOK_URL }}은 GitHub Secrets 에서 추가해주면되고.
${{ job.status }}는 추가 할 필요없이 쓰면된다. if: always()에서 말고 failure()로 설정하면 실패시에만 알림을 받을수 있다.
- name: Discord Notify
uses: sarisia/actions-status-discord@v1
if: always()
with:
webhook: ${{ secrets.DISCORD_WEBHOOK_URL }}
status: ${{ job.status }}
title: "deploy"
description: "Build and deploy to GitHub Pages"
url: "https://github.com/sarisia/actions-status-discord"
username: GitHub Actions
한가지 주의할점은 DISCORD_WEBHOOK_URL 에 값을 인입할때 WebHook URL주소에 뒤에 붙어있는 /github를 지워줘야 Error: Webhook response: 400: {"sender":["This field is required"]} 에러가 발생하지 않는다.
알림세팅이 성공적으로 세팅되면 아래처럼 discord로 알림이 온다.
AWS 프리티어 자동 배포 서버 다운 장애 해결
AWS 프리티어를 사용하는 중이였는데 처음에는 자동배포가 잘되고 2번째 배포를 하면은 서버가 다운이 됐다. 처음에는 무슨 문제인지 잘 몰랐으나 서치해보고 의심되는것은 메모리 부족이었다. 프리티어의 메모리는 1GB 밖에 안돼서 SpringBoot가 실행중에 CodeDeploy Agent가 실행되면 메모리 부족으로 다운되는것 같았다.
그래도 t2.small로 업그레이드 하기에는 비용때문에 참 애매했는데 서칭해서 swap 메모리로 해결했다는것을 보았다.
아래 링크를 참고하여 swap 메모리 2기가를 추가하여 자동배포시 서버 다운이 안되도록 하였다.
swap 메모리 설정 참고링크 : https://okky.kr/articles/884329
아래 링크대로 swap 메모리를 추가하면 아래와 같이 swap이 영역이 생긴다.
이로써 자동배포를 계속해도 서버다운이 되지 않았다.
자동배포를 완료하였고 추가적으로 탄력적 IP를 만들어 매핑하고, ngnix도 설치하고 도메인도 만들예정이다.
참고
- https://blog.naver.com/PostView.naver?blogId=meohin&logNo=222917599051
- https://okky.kr/articles/884329
- https://docs.aws.amazon.com/ko_kr/codedeploy/latest/userguide/reference-appspec-file.html
- https://jinmay.github.io/2020/05/13/aws/how-to-install-code-deploy-agent-ubuntu/
- https://www.youtube.com/watch?v=UF2Giz9PE-E
- https://velog.io/@bagt/Github-Actions%EB%A5%BC-%ED%86%B5%ED%95%9C-%EB%B0%B0%ED%8F%AC
- https://docs.github.com/ko/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
'Project > B2C-Side-Project(second)' 카테고리의 다른 글
[SpringBoot] Redis 활용한 회원가입 이메일 인증 방법(개선후) (0) | 2024.07.06 |
---|---|
[SpringBoot] 스프링 시큐리티 활용한 회원가입 이메일 인증 방법(개선전) (0) | 2024.06.29 |
[SpringBoot] GlobalException 활용한 파라미터 유효성 검증 리팩토링 (0) | 2024.06.10 |
[프로젝트] 스프링시큐리티 5->6, JWT 버전 업그레이드 하고 error와 warning 수정 (0) | 2024.06.10 |
[프로젝트] DIP 지켜가며 기존 MyBatis기능에서 JPA기능으로 변경하기 (0) | 2024.06.09 |