Github가 공식적으로 제공하는 빌드, 테스트 및 배포 파이프라인을 자동화할 수 있는 CI/CD 플랫폼
repository에서 PR이나 push 같은 이벤트(event)를 트리거(trigger)로 github 작업 workflow를 구성할 수 있다. workflow는 하나 이상의 작업이 실행되는 자동화 프로세스로, 각 작업은 자체 가상 머신 또는 컨테이너 내부에서 실행된다.
workflow는 yml파일
에 의해 구성되며, 테스트, 배포 등 기능에 따라 여러 개의 workflow도 만들 수 있다. 생성된 workflow는 .github/workflows
디렉토리 이하에 위치한다.
- Pulbic Repository여야 무료로 사용할 수 있다.
- AWS CLI와 Code Deploy Agent가 EC2에 설치되어 있어야 한다.
- S3 버킷이 생성되어 있어야 한다.
- 프로젝트 repository -> Actions로 이동해 workflow를 설정한다.
set up a workflow yourself
를 클릭하여 빈 yml 설정파일로 workflow를 설정할 수 있고, 추천 workflow 구성(Java with Gradle 등)을 선택하여 진행할 수 있다.
set up a workflow yourself
로 workflow를 생성하면, main.yml 파일이 생성됨과 동시에 workflow에 작성되어있는 trigger(특정 branch로의 push)로 인해 Github Actions가 실행된다.
Actions 탭에서 생성된 workflow의 각 단계별 진행 상황을 확인할 수 있으며, 진행/성공/실패 여부는 repository에서 최근 commit 내역과 함께 표시된다.
이번엔 생성한 S3 버킷에 프로젝트 빌드 결과물을 전송해야 한다.
Github Actions에서 workflow를 실행하는 과정에서 access key가 필요하지만, 공개되면 보안 이슈가 발생할 수 있다. 따라서 Github Secret
을 이용해 access key 값을 저장한 후 사용한다.
1. Github Secret 등록하기
1-1. Repository -> Settings > Secrets > Actions 탭으로 이동한 후 New repository secret
를 클릭한다.
1-2. Name-Value에 IAM User 생성 시 볼 수 있는 Access Key ID 값과, 비밀 access key 값을 각각 저장합니다.
2. Github Action 설정 파일 수정하기
설정한 Secret을 반영하기 위해 기존의 gradle.yml 파일에 하단에 다음 코드를 추가한다.
main.yml
name: Backend CICD
run-name: Running
on:
push:
branches:
- sungmin
env: #env를 통해 자주 사용할 변수를 지정한다.
AWS_REGION: ap-northeast-2
AWS_S3_BUCKET: moim-image
AWS_CODE_DEPLOY_APPLICATION: mogether-cd
AWS_CODE_DEPLOY_GROUP: mogether-cd-group
jobs:
build-with-gradle:
runs-on: ubuntu-latest
steps:
- name: sungmin branch로 이동
uses: actions/checkout@v3
with:
ref: sungmin
- name: Install JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
# gradlew 파일이 있는 곳으로 이동 후 명령을 실행한다.
- name: gradlew에 실행 권한 부여
run: cd backend/mogether && chmod +x ./gradlew
- name: Build with Gradle
run: cd backend/mogether && ./gradlew clean build
# 디렉토리 생성
- name: Make Directory
run: mkdir -p deploy
# Jar 파일 복사
- name: Copy Jar
run: cp backend/mogether/build/libs/moim-0.0.1-SNAPSHOT.jar ./deploy
# appspec.yml 파일 복사
- name: Copy appspec.yml
run: cp backend/mogether/appspec.yml ./deploy
# script files 복사
- name: Copy script
run: cp backend/mogether/scripts/start.sh ./deploy
- name: Make zip file
run: zip -r ./mogether.zip ./deploy
shell: bash
# 등록한 ACCESS/SECRET KEY를 사용하기 위해 변수 등록
- name: Configure AWS credentials
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 S3
run: aws s3 cp --region ap-northeast-2 ./mogether.zip s3://$AWS_S3_BUCKET
프로젝트의 빌드 결과와 배포에 필요한 script를 S3 버킷에 업로드했고, 이제 CodeDeploy를 통해 S3의 파일을 EC2로 배포하는 과정을 진행한다.
CodeDeploy -> 배포 -> 애플리케이션 생성
을 클릭한다.
애플리케이션 이름을 작성하고, 컴퓨팅 플랫폼은 EC2/온프레미스를 선택한다.
애플리케이션 이름의 경우 Github Actions workflow에 작성할 것이기 때문에 규칙에 맞게 작성해야 한다.
생성 완료 후, 배포 그룹을 생성
한다.
배포 그룹은 방금 전 생성한 애플리케이션에 생성되어야 하며, 배포 그룹 이름 역시 Github Actions workflow에 작성이 필요하기 때문에, 애플리케이션과 구분할 수 있도록 규칙에 맞게 이름을 작성해야 한다.
CodeDeploy 의 권한 부여를 위한 IAM 역할을 생성되어있다면 선택하면 되고, 없다면 생성 후 선택한다.
환경 구성
파트에서는 EC2 인스턴스 태그를 이용해 배포 그룹 환경을 구성한다.
- 프로젝트 디렉토리 root 경로에
appspec.yml
파일을 생성한다. (Code Deploy의 작동과 연결)
하지만 프로젝트 구조에 따라 appspec.yml을 다른 곳에 위치시키고, main.yml에서 올바른 appspec.yml의 위치를 명시해주기만 해도 상관 없다.
나는 협업 프로젝트이기 때문에 /backend/mogether
하위에 위치시켰다. (build.gradle과 같은 위치)
(꼭 프로젝트의 root에 위치시켜야 한다는 글이 너무 많아서 많이 헤맸다😭)
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/app/ #이 위치에 복사한 파일들을 둘 예정이다.
overwrite: yes
permissions:
- object: /home/ubuntu/app/ #이 위치에 복사한 파일들을 둘 예정이다.
pattern: "**"
owner: ubuntu
group: ubuntu
hooks:
ApplicationStart:
- location: start.sh
timeout: 60
runas: ubuntu
- 마찬가지로
/backend/mogether
위치에 scripts 디렉토리를 생성한 후 scripts 아래에start.sh
파일을 생성한다. (EC2 배포 진행 상황 별 로그를 기록하고 새로 배포된 빌드 파일을 실행한다)
여기서도 삽질을 많이 했는데, main.yml에서 start.sh 파일만을 복사하도록 명시했기 때문에 결국 다른 복사한 파일들과 동일한 곳에 위치하게 된다. (/home/ubuntu/app)
따라서 location에는 그냥 start.sh
라고만 명시해주면 된다.
#!/usr/bin/env bash
REPOSITORY=/home/ubuntu/app
JAR_NAME=$(ls -tr $REPOSITORY/*SNAPSHOT.jar | tail -n 1)
echo "> 현재 구동 중인 애플리케이션 pid 확인"
# CURRENT_PID=$(pgrep -fla java | grep hayan | awk '{print $1}' | pgrep -f $JAR_NAME)
CURRENT_PID=$(pgrep -f $JAR_NAME)
echo "현재 구동 중인 애플리케이션 pid: $CURRENT_PID" >> /home/ubuntu/app/deploy.log
if [ -z "$CURRENT_PID" ]; then
echo "현재 구동 중인 애플리케이션이 없으므로 종료하지 않습니다." >> /home/ubuntu/app/deploy.log
else
echo "> kill -15 $CURRENT_PID"
kill -15 $CURRENT_PID
sleep 5
fi
echo "> 새 애플리케이션 배포" >> /home/ubuntu/app/deploy.log
JAR_NAME=$(ls -tr $REPOSITORY/*SNAPSHOT.jar | tail -n 1)
echo "> JAR NAME: $JAR_NAME"
echo "> $JAR_NAME 에 실행권한 추가" >> /home/ubuntu/app/deploy.log
chmod +x $JAR_NAME
echo "> $JAR_NAME 실행" >> /home/ubuntu/app/deploy.log
nohup java -jar -Duser.timezone=Asia/Seoul $JAR_NAME >> $REPOSITORY/nohup.out 2>&1 &
/home/ubuntu/app/deploy.log
파일에 저장된다.이제 모든 환경 세팅이 완료되었고, Github Actions workflow를 수정하여 배포 자동화를 구성한다.
main.yml
하단에 Code Deploy 배포 명령을 추가하면 된다.
# CodeDeploy에게 배로 명령을 내린다.
- name: Code Deploy
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=${{ env.AWS_S3_BUCKET }},bundleType=zip,key=mogether.zip
CodeDeploy 설정하며 작성한 CodeDeploy 애플리케이션의 이름, CodeDeploy 배포 그룹의 이름을 표시된 곳에 각각 작성한다.
EC2 터미널을 통해 main.yml에 작성한대로
/home/ubuntu/app
디렉토리 내에 빌드 파일이 이동했고,ps -ef | grep java
로 해당 빌드 파일이 실행 중인지 확인할 수 있다.
start.sh에는 배포가 진행될 때마다 상황을 기록하도록 작성 되어있다.
배포를 마치면 /home/ubuntu/app 디렉토리 내에 로그가 기록된 deploy.log 파일에 배포 상황이 기록된다.
cd /opt/codedeploy-agent/deployment-root/{deployment-group-id}/{deployment-id}/deployment-archive
/var/log/aws/codedeploy-agent
sudo service codedeploy-agent status
sudo service codedeploy-agent restart
❗️IAM User를 등록하지 않았다면, 등록 후 꼭 CodeDeploy-Agent를 restart 해줘야 한다.