CodeDeploy를 통해 CICD/무중단배포를 해보자
CI/CD란 ?
- CI - 빌드/테스트 자동화 과정 과정
- CI는 개발자를 위한 자동화 프로세스인 지속적인 통합(Continuous Integration)을의미
- CI를 성공적으로 구현할 경우 애플리케이션에 대한 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트되어 공유 리포지토리에 통합되므로 여러 명의 개발자가 동시에 애플리케이션 개발과 관련된 코드 작업을 할 경우 서로 충돌할 수 있는 문제를 해결할 수 있음
- CD - 배포 자동화 과정
- CD는 지속적인 서비스 제공(Continuous Delivery) 또는 지속적인 배포(Continuous Deployment)를 의미하며 이 두 용어는 상호 교환적으로 사용됨
- 두 가지 의미 모두 파이프라인의 추가 단계에 대한 자동화를 뜻하지만 때로는 얼마나 많은 자동화가 이루어지고 있는지를 설명하기 위해 별도로 사용되기도 함
무중단 배포 과정

- 개발자가 Github에 변경 코드를 배포 브랜치에 푸시함
- Github Action 을 통해 개발자가 변경사항을 감지하여 설정된 Workflow를 실행
- AWS 인증, 및 IAM에 설정 된 정책에 따라 4,5번 과정이 수행됨
- Workflow가 수행되어 생긴 압축 파일을 AWS S3 버킷에 올림
- CodeDeploy 서비스를 실행
- 새로운 인스턴스 시작됨
- S3 버킷에 올라가있는 결과물들이 새 인스턴스에 배포되고, 애플리케이션이 실행됨
- 새 인스턴스를 기본 인스턴스로 리라우팅하고, 기존 인스턴스 종료
블루/그린 배포의 장점
- 블루/그린 배포는 하나의 버전만 프로덕션 되기 때문에 버전 관리 문제를 방지할 수 있음
- 운영 환경에 영향을 주지 않고 실제 서비스 환경으로 새 버전 테스트가 가능
- 새 버전으로 전환 후에 문제가 생겼을 시에 구 버전으로 되돌리기 위한 롤백이 용이함
- 기존에 쓰던 방식 (EC2 + Docker)에서 Docker가 중지 - 새로 받아옴 - 재시작하는 과정이 없어져서 무중단 배포 가능
EC2, CodeDeploy 등 초기세팅들은 아래의 레퍼런스 참고
GithubActions 워크플로우 작성
name: CICD Test
run-name: Running
on:
push:
branches:
- dev
env:
AWS_REGION: ap-northeast-2
AWS_S3_BUCKET: mytaek1-bucket
AWS_CODE_DEPLOY_APPLICATION: mytaek1-cicd
AWS_CODE_DEPLOY_GROUP: mytaek1-cicd-group
jobs:
build-with-gradle:
runs-on: ubuntu-22.04
steps:
- name: production 브랜치로 이동
uses: actions/checkout@v3
with:
ref: dev
- name: JDK 17 설치
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
- name: make application.properties
if: |
contains(github.ref, 'dev')
run: |
cd ./src/main/resources
touch ./application.properties
echo "${{ secrets.PROPERTIES }}" > ./application.properties
shell: bash
- name: Setup Gradle Wrapper
run: gradle wrapper --gradle-version 8.5
shell: bash
- name: gradlew에 실행 권한 부여
run: chmod +x ./gradlew
- name: 프로젝트 빌드
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.CICD_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.CICD_SECRET_KEY }}
- name: S3에 업로드
run: aws deploy push --application-name ${{ env.AWS_CODE_DEPLOY_APPLICATION }} --ignore-hidden-files --s3-location s3://$AWS_S3_BUCKET/mytaek1/$GITHUB_SHA.zip --source .
- name: EC2에 배포
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=mytaek1/$GITHUB_SHA.zip,bundleType=zip
- 중요 정보들은 Secret에 작성해서 가져와야함
appsepc.yml 작성
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/spring-github-action
overwrite: yes
permissions:
- object: /
pattern: "**"
mode: '755'
owner: ubuntu
group: ubuntu
hooks:
AfterInstall:
- location: scripts/stop.sh
timeout: 60
ApplicationStart:
- location: scripts/start.sh
timeout: 60
appspec.yml 은 aws의 공식 메뉴얼 사이트를 참고하면 좋다
AppSpec '후크' 섹션 - AWS CodeDeploy
배포의 시작 DownloadBundle, 설치 BlockTrafficAllowTraffic, 및 종료 이벤트는 스크립팅할 수 없으므로 이 다이어그램에서 회색으로 표시됩니다. 하지만 파일의 '파일' 섹션을 편집하여 설치 이벤트 중에
docs.aws.amazon.com
start.sh / stop.sh 작성
//start.sh
ROOT_PATH="/home/ubuntu/spring-github-action"
JAR="$ROOT_PATH/application.jar"
APP_LOG="/var/log/aws/codedeploy-agent/application.log"
ERROR_LOG="/var/log/aws/codedeploy-agent/error.log"
START_LOG="/var/log/aws/codedeploy-agent/start.log"
NOW=$(date +%c)
echo "[$NOW] $JAR 복사" >> $START_LOG
cp $ROOT_PATH/build/libs/mytaek1-0.0.1-SNAPSHOT.jar $JAR
echo "[$NOW] > $JAR 실행" >> $START_LOG
nohup java -jar $JAR > $APP_LOG 2> $ERROR_LOG &
SERVICE_PID=$(pgrep -f $JAR)
echo "[$NOW] > 서비스 PID: $SERVICE_PID" >> $START_LOG
//stop.sh
ROOT_PATH="/home/ubuntu/spring-github-action"
JAR="$ROOT_PATH/application.jar"
STOP_LOG="/var/log/aws/codedeploy-agent/stop.log"
SERVICE_PID=$(pgrep -f $JAR)
if [ -z "$SERVICE_PID" ]; then
echo "서비스 NotFound" >> $STOP_LOG
else
echo "서비스 종료 " >> $STOP_LOG
kill -9 "$SERVICE_PID"
fi
이후 여러가지 에러를 겪다보면..

성공하게된다.
트러블슈팅
1. 로드밸런서로 연결해줬는데, BlockTraffic에서 막혀서 로드밸런서를 거치지 않고 바로 코드디플로이로 가게 변경

-> 로드 밸런싱 활성화 체크를 해제해주었음
2. 루트에 액션 폴더가 생성이 안됨
-> appspecs.yml파일의 files 부분의 destination의 경로가 잘못 설정되어있었음
3. stop.sh에서 어플리케이션이 종료가 되지 않아 시작도 되지 않음
#!/bin/bash
ROOT_PATH="/home/ubuntu/spring-github-action"
JAR="$ROOT_PATH/application.jar"
STOP_LOG="/var/log/aws/codedeploy-agent/stop.log"
SERVICE_PID=$(pgrep -f $JAR)
if [ -z "$SERVICE_PID" ]; then
echo "서비스 NotFound" >> $STOP_LOG
else
echo "서비스 종료 " >> $STOP_LOG
kill -9 "$SERVICE_PID" # 강제 종료로 변경
fi
래퍼런스
실전! Github actions, AWS Code deploy로 Spring boot 배포 자동화하기
아휴 힘드러 🤮
velog.io
AppSpec '후크' 섹션 - AWS CodeDeploy
배포의 시작 DownloadBundle, 설치 BlockTrafficAllowTraffic, 및 종료 이벤트는 스크립팅할 수 없으므로 이 다이어그램에서 회색으로 표시됩니다. 하지만 파일의 '파일' 섹션을 편집하여 설치 이벤트 중에
docs.aws.amazon.com