프로젝트를 진행하면서 개인서버에서 클라우드서버로 이전하게 된 사건이 있었습니다.
그 때 이전하면서 서버에 파일을 전송하는 프로그램 없이 그냥 깃허브에 푸시한 순간 배포가 되게 할 수는 없을까? 하는 생각이 들었고, 그렇게 자동배포의 여정이 시작 되었습니다.
👩🏻🏫 CI와 CD는 소프트웨어 개발과 배포에서 중요한 역할을 하는 모범 사례 및 원칙들입니다.
CI/CD 파이프라인을 사용하면 팀은 코드의 변경 사항을 자주, 빠르게, 안정적으로 프로덕션 환경에 배포할 수 있게 됩니다. 이로 인해 소프트웨어 제품의 품질이 향상되며, 버그 수정이나 새로운 기능의 배포가 더욱 빠르게 이루어질 수 있습니다. CI/CD 도구로는 Jenkins, Travis CI, GitLab CI/CD, CircleCI, GitHub Actions 등이 있습니다.
👩🏻🏫 가장 많이 들어보고, 그만큼 많이 쓰이는 두 개의 CI/CD 도구에 대해 알아봅시다.
저희 프로젝트의 경우 규모가 작고, 외부 클라우드(AWS) 에 서비스가 배포되기 때문에 깃허브 액션을 선택 하였습니다.
👩🏻🏫 세세하게 들어가기 전, 아키텍쳐로 큰 그림을 이해해 봅시다.
열심히 코드 작업을 한 뒤, 깃허브로 푸시를 합니다.
깃허브 액션은 깃허브에 코드가 올라오면 이를 알아채 배포과정을 밟게 됩니다.
깃허브 액션은 워크 플로우에 작성된 순서대로 작업을 수행합니다. 저의 경우,
이렇게 작성하였습니다.
EC2 에 배포한 후에 미리 작성한 appspec.yml 대로 작업이 수행됩니다. 저의 경우,
이렇게 작성하였습니다.
# 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 / dev
on:
push:
branches: [ 감지할 브랜치명을 넣어주세요. ]
pull_request:
branches: [ 감지할 브랜치명을 넣어주세요. ]
permissions:
contents: read
env:
S3_BUCKET_NAME: { s3 버킷 이름을 넣어주세요. }
CODE_DEPLOY_APP_NAME: { 코드디플로이 어플리케이션 이름을 넣어주세요. }
CODE_DEPLOY_GROUP_NAME: { 코드디플로이 그룹 이름을 넣어주세요.}
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
token: ${{ secrets.SUBMODULE_TOKEN }}
submodules: true
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
with:
arguments: build
gradle-version: 8.1.1
# 프로젝트 압축
- name: Make zip file
run: zip -r ./$GITHUB_SHA.zip ./
shell: bash
# AWS 권한 확인
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Upload to S3
run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/{ 디렉토리가 존재한다면 이곳에 작성해주세요. }/$GITHUB_SHA.zip
# Deploy
- name: Deploy
run: |
aws deploy create-deployment \
--application-name { 코드디플로이 어플리케이션 이름을 넣어주세요 } \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name { 코드디플로이 그룹 이름을 넣어주세요 } \
--file-exists-behavior OVERWRITE \
--s3-location bucket={ s3 버킷 이름을 넣어주세요 },bundleType=zip,key={ 디렉토리가 존재한다면 경로를 넣어주세요. }/$GITHUB_SHA.zip \
--region ap-northeast-2 \
⚠️ 이름 주의해서 작성해주세요!
version: 0.0
os: linux
files:
- source: /
destination: /home/ec2-user/{ 배포 경로를 입력해주세요. }
pattern: "*.jar"
permissions:
- object: /
pattern: "*.jar"
owner: ec2-user
group: ec2-user
mode: '755'
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
runas: ec2-user
ApplicationStart:
- location: scripts/start.sh
timeout: 60
runas: ec2-user
⚠️ 최상단 경로에 scripts 폴더를 만들고, 그 안에 스크립트 파일을 넣어 주세요.
#!/usr/bin/env bash
PROJECT_ROOT="/home/ec2-user/{ 배포 경로 }"
JAR_FILE="$PROJECT_ROOT/build/libs/{ 빌드 파일 이름 }"
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
#!/usr/bin/env bash
PROJECT_ROOT="/home/ec2-user/{ 배포 경로 }"
JAR_FILE="$PROJECT_ROOT/build/libs/{ 빌드 파일 이름 }"
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
저희 프로젝트처럼 ec2 가 두개인 경우를 생각해봅시다. 코드 디플로이는 S3 에서 압축된 파일을 가져와 적절한 서버에 압축을 풀어 배포합니다. 이때 서버를 어떻게 구분하는 걸까요?
이 배포그룹과 적절한 EC2 를 연결해줘야 합니다.
✅ 아래와 같이 배포그룹 생성시 EC2 에 설정한 태그를 제대로 작성해주세요.