지난번에 Docker를 사용해서 배포를 하였지만 도커 이미지를 만들고 허브에 업로드하는 작업이
속도가 꽤 걸리는 것 같았고, AWS EC2 서버에 API 서버를 올리기 때문에
AWS를 사용해서 배포하는 것으로 변경하기로 하였다.
배포 과정
1. Github Action에서 코드 빌드 후 압축해서 S3에 Push
2. CodeDeploy 실행
3. AppSpec로 EC2에 배포 명령
4. EC2에서 S3에 있는 파일 가져온 후 EC2에 배포
EC2 서버 생성 과정은 생략
EC2 설정
EC2 선택 -> 작업 -> 인스턴스 설정 -> 태그 관리
태그 관리에서 키로 태그를 추가합니다
EC2 -> 태그에서 해당 인스턴스에 대한 태그를 확인할 수 있습니다.
IAM 역할 추가
IAM -> 역할 -> 역할 만들기
AWS 서비스 -> EC2로 만든다
AmazonS3FullAccess 권한을 추가한다.
원하는 역할 이름을 입력한 뒤 생성
EC2 인스턴스 페이지 -> 작업 -> 보안 -> IAM 역할 수정
위에서 만들었던 IAM 역할을 추가한다.
CodeDeploy Agent 설치
$ 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
명령어 입력
AWS S3 생성
S3 -> 버킷 만들기
원하는 버킷이름을 설정합니다.
추가적인 변경없이 기본값으로 버킷을 만들어줍니다.
CodeDeploy 생성
IAM -> 역할 만들기
CodeDeploy를 선택합니다.
역할 이름만 설정하고 IAM을 만들어줍니다.
CodeDeploy -> 배포 -> 애플리케이션 -> 애플리케이션 생성
이름을 설정하고 컴퓨팅 플랫폼을 EC2/온프레미스로 선택합니다.
만들어진 애플리케이션을 선택 후 배포그룹을 생성해줍니다.
배포 그룹 이름을 입력하고 위에서 만들었떤 CodeDeploy를 선택합니다.
환경 구성에서 태그로 설정해두었던 인스턴스를 선택하고
배포 설정을 CodeDeployDefault.AllAtOnce를 선택합니다.
Github Action에서 사용할 사용자 추가
IAM -> 액세스 관리 -> 사용자 -> 사용자 추가
이름을 설정하고 직접 정책 연결을 합니다.
AWSCodeDeployFullAccess, AmazonS3FullAccess 2 가지 권한을 추가합니다.
사용자를 만들고 나면 Access Key와 Secret Key를 받을 수 있습니다.
Git Repository -> Settings -> Secrets -> Actions 에서
Access Key와 Secret Key를 설정해줍니다.
AppSpec 파일 작성
AppSpec는 CodeDeploy에서 배포를 위해 참조하는 파일입니다.
프로젝트의 어떤 파일들을 EC2의 어떤 경로에 복사하고, 배포 프로세스 이후에 수행할 스크립트를 지정할 수 있습니다.
해당 파일은 Repository의 루트 디렉토리에 위치해야합니다.
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: stop.sh
timeout: 60
runas: ubuntu
ApplicationStart:
- location: start.sh
timeout: 60
runas: ubuntu
files:
- source: /
destination: /home/ubuntu/app
overwrite: yes
- source : 인스턴스에 복사할 디렉토리 경로
- destination : 인스턴스에서 파일이 복사되는 위치
- overwrite : 복사할 위치에 파일이 있는 경우 대체
permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu-
- object: 권한이 지정되는 파일 또는 디렉터리
- pattern (optional): 매칭되는 패턴에만 권한 부여
- owner (optional): object 의 소유자
- group (optional): object 의 그룹 이름
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ubuntu
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ubuntu
- location: hooks 에서 실행할 스크립트 위치
- timeout (optional): 스크립트 실행에 허용되는 최대 시간이며, 넘으면 배포 실패로 간주됨
- runas (optional): 스크립트를 실행하는 사용자
stop.sh
#!/usr/bin/env bash
PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/omo.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
start.sh
#!/usr/bin/env bash
PROJECT_ROOT="/home/ubuntu/app"
JAR_FILE="$PROJECT_ROOT/omo.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/omo.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
workflow
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: <https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle>
name: Java CI with Gradle
on:
push:
branches: [ "main" ]
permissions:
contents: read
env:
AWS_REGION: ap-northeast-2
AWS_S3_BUCKET: omo-develop
AWS_CODE_DEPLOY_APPLICATION: omo-deploy
AWS_CODE_DEPLOY_GROUP: omo-deploy-group
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
- name: Copy appliaction.yml
run: |
echo "${{ secrets.PROD_YML }}" | base64 --decode > src/main/resources/application.yml
- name: chomod gralew
run: |
chmod +x gradlew
- name: Build with Gradle
run: |
./gradlew clean build -x test
- name: AWS credential 설정
uses: aws-actions/configure-aws-credentials@v1
with:
aws-region: ${{ env.AWS_REGION }}
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
- name: Upload to AWS S3
run: |
aws deploy push \
--application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} \
--ignore-hidden-files \
--s3-location s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip \
--source .
- name: Deploy to AWS EC2 from S3
run: |
aws deploy create-deployment \
--application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name ${{ env.AWS_CODE_DEPLOY_GROUP }} \
--s3-location bucket=$AWS_S3_BUCKET,key=$GITHUB_SHA.zip,bundleType=zip
workflow는 지난 docker 이미지 배포편에서 설명한 것을 제외한 것을 설명만 추가했습니다.
- name: Upload to AWS S3
run: |
aws deploy push \
--application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
--s3-location s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip \
--ignore-hidden-files \
--source .
- --application-name: CodeDeploy 애플리케이션 이름
- --s3-location: 압축 파일을 업로드 할 S3 버킷 정보
- --ignore-hidden-files (optional): 숨겨진 파일까지 번들링할지 여부
$GITHUB_SHA 라는 변수가 보이는데 간단하게 생각해서 Github 자체에서 커밋마다 생성하는 랜덤한 변수값입니다.
랜덤한 값을 사용하여 파일 업로드 시 중복으로 충돌날 일이 없습니다.
- 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
- --application-name: CodeDeploy 애플리케이션 이름
- --deployment-config-name: 배포 방식인데 기본값을 사용
- --deployment-group-name: CodeDeploy 배포 그룹 이름
- --s3-location: 버킷 이름, 키 값, 번들타입
배포 확인
Github Action
CodeDeploy
만일 오류가 날 경우 해당 로그를 확인하여 수정해주면 됩니다.
- CodeDeploy 배포 로그 확인: /var/log/aws/codedeploy-agent/codedeploy-agent.log
- CodeDeploy Hooks 로그 확인: /opt/codedeploy-agent/deployment-root/deployment-logs/codedeploy-agent-deployments.log
Docker -> AWS
Docker를 사용해서 배포를 진행했을 때는 평균적으로 시간대가 3분 40~50초 정도 걸렸지만
AWS를 사용함으로써 평균적으로 1분 40~50초 정도 걸리게 되었다.
도커 이미지 빌드 속도와 크기를 줄여서 배포 속도를 올려볼 수 있지 않을까 생각했지만 AWS로 배포하는 것보다 느릴 것으로 판단해서 이렇게 진행하게 되었다.
'CICD' 카테고리의 다른 글
Jenkins PipeLine으로 Docker Image 만들고 배포하기 (0) | 2023.09.18 |
---|---|
Jenkins로 Spring Boot 배포하기 (0) | 2023.09.15 |
GitHub Action & Docker를 사용해서 배포 (0) | 2023.09.08 |