사용자의 권한은 AmazonS3FullAccess, AWSCodeDeployFullAccess, AWSCodeDeployRole 이렇게 3가지 설정해주었다.
IAM 계정 생성 완료 후, 액세스 키와 비밀 액세스 키가 나오는데 github secrets에 등록해야하므로, 꼭 기억하고 있어야한다.
actions
1. Actions Wrokflow 작성하기
클라우드 설정이 끝났다면,
./github/workflows 폴더 아래에 yml 파일을 작성해주자.
해당 경로는 약속된 경로이기에 지켜주어야한다.
프로세스를 설명
1. 코드 변경사항이 main 브랜치에 push 될 때
2.Java 애플리케이션 빌드 및 배포 파일 생성
3. 배포 파일을 S3에 업로드
4. AWS CodeDeploy를 통해 EC2에 애플리케이션 배포
name: Build and Deploy to EC2
on:
push:
branches: [ "main" ]
permissions:
contents: read
env:
AWS_REGION: ap-northeast-2
AWS_S3_BUCKET: ***
AWS_CODE_DEPLOY_APPLICATION: ***
AWS_CODE_DEPLOY_GROUP: ***
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Grant execute permission for gradlew
run: chmod +x ./gradlew
shell: bash
- name: Build with Gradle
run: ./gradlew clean build
- name: Make Directory
run: mkdir -p deploy
- name: Copy Jar
run: cp ./build/libs/*.jar ./deploy
- name: Copy appspec.yml
run: cp appspec.yml ./deploy
- name: Copy script
run: cp ./*.sh ./deploy
- name: Make zip file
run: zip -r ./githubActionDeploy.zip ./deploy
shell: bash
- name: AWS credential 설정
uses: aws-actions/configure-aws-credentials@v2
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.CICD_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.CICD_SECRET_KEY }}
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./githubActionDeploy.zip s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip
- name: Deploy to EC2 using AWS CodeDeploy
run: |
aws deploy create-deployment \
--application-name $AWS_CODE_DEPLOY_APPLICATION \
--deployment-group-name $AWS_CODE_DEPLOY_GROUP \
--s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip \
--region $AWS_REGION
2. deploy.sh, appspec.yml작성하기
위 actions가 실행되면 빌드된 jar, deploy.sh, appspec.yml 파일이 zip 파일에 들어있다.
deploy.sh
현재 구동중인 프로세스를 중지시키고 새로 빌드된 jar 파일을 빌드시키는 shell script
#!/usr/bin/env bash
REPOSITORY=/home/ubuntu/app
echo "> 현재 구동 중인 애플리케이션 pid 확인"
# 기존 애플리케이션 PID 찾기
CURRENT_PID=$(pgrep -fla java | grep -e "SNAPSHOT" | 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
# 프로세스가 여전히 실행 중인지 확인
if ps -p $CURRENT_PID > /dev/null; then
echo "프로세스가 종료되지 않아 강제 종료합니다."
echo "> kill -9 $CURRENT_PID"
kill -9 $CURRENT_PID
else
echo "프로세스가 정상적으로 종료되었습니다."
fi
fi
echo "> 새 애플리케이션 배포"
# S3에서 ZIP 파일 다운로드
echo "> S3에서 ZIP 파일 다운로드"
aws s3 cp s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip $REPOSITORY/$GITHUB_SHA.zip
# ZIP 파일 압축 해제
echo "> ZIP 파일 압축 해제"
unzip -o $REPOSITORY/$GITHUB_SHA.zip -d $REPOSITORY
# JAR 파일 찾기
JAR_NAME="$REPOSITORY/******************.jar"
echo "> JAR NAME: $JAR_NAME"
# JAR 파일에 실행 권한 추가 (sudo 사용)
echo "> $JAR_NAME 에 실행권한 추가"
sudo chmod +x $JAR_NAME
# JAR 파일 실행 (sudo 사용)
echo "> $JAR_NAME 실행"
nohup sudo java -jar -Duser.timezone=Asia/Seoul $JAR_NAME > /dev/null 2>&1 &
jar 파일에 실행권한만 필요하고, 읽기, 쓰기 권한은 변경할 이유가 없기 때문에
sudo +x 명령어를 사용해 jar 파일 실행 권한만 추가했다.
(주의) chmod 777는 보안에 매우 취약한 설정이다.
chmod 777를 남발하지말고 상황에 따른 권한 부여를 생각하는 것이 중요하다.
처음에는 kill -9 명령어를 사용해 프로세스를 강제종료했다.
그러나 프로세스를 안전하게 종료하기 위해
파일 닫기, 메모리 해제, 데이터 저장 등을 수행한 후 종료하는 kill -15 명령어를 사용했다.
kill -15명령어로 프로세스가 종료되지 않을 경우를 대비해 기존 kill -9 명령어도 "프로세스가 종료되지않았을 때"라는조건을 추가해 유지했다.