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 해줘야 한다.