[Github Action + AWS CodeDeploy] Spring Boot 서버 자동 배포 및 실행하기

Dev_ch·2022년 11월 24일
3

이번 글은 공유하기도 위함이지만 내가 프로젝트를 진행할때마다 잊지않기 위함이 더 크긴하다. 글대로 따라온다면 큰 문제없이 자신의 프로젝트를 Github Action과 AWS CodeDeploy를 통해 자동으로 서버에 배포할 수 있다.

1. CI/CD가 뭐에요? 🤔

CI/CD(지속적 통합/지속적 제공): 개념, 방법, 장점, 구현 과정

CI/CD는 애플리케이션 개발 단계를 자동화하여 애플리케이션을 보다 짧은 주기로 고객에게 제공하는 방법입니다. CI/CD의 기본 개념은 지속적인 통합, 지속적인 서비스 제공, 지속적인 배포입니다.

CI/CD는 약어로, 몇 가지의 다른 의미를 가지고 있습니다. CI/CD의 "CI"는 개발자를 위한 자동화 프로세스인 지속적인 통합(Continuous Integration)을 의미합니다. CI를 성공적으로 구현할 경우 애플리케이션에 대한 새로운 코드 변경 사항이 정기적으로 빌드 및 테스트되어 공유 리포지토리에 통합되므로 여러 명의 개발자가 동시에 애플리케이션 개발과 관련된 코드 작업을 할 경우 서로 충돌할 수 있는 문제를 해결할 수 있습니다.

CI/CD의 "CD"는 지속적인 서비스 제공(Continuous Delivery) 및/또는 지속적인 배포(Continuous Deployment)를 의미하며 이 두 용어는 상호 교환적으로 사용됩니다. 두 가지 의미 모두 파이프라인의 추가 단계에 대한 자동화를 뜻하지만 때로는 얼마나 많은 자동화가 이루어지고 있는지를 설명하기 위해 별도로 사용되기도 합니다.

2. 그렇다면 프로젝트에 적용해보자 !

준비물

  1. 배포할려는 프로젝트
  2. 따라올 끈기

그리고 배포할려는 EC2에 접속하여

# 패키지 매니저 업데이트, ruby 설치
sudo yum update
sudo yum install ruby
sudo yum install wget

# 서울 리전에 있는 CodeDeploy 리소스 키트 파일 다운로드
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

# 설치 파일에 실행 권한 부여
chmod +x ./install

# 설치 진행 및 Agent 상태 확인
sudo ./install auto
sudo service codedeploy-agent status

해당 커맨드들을 터미널에 입력해주어 codedeploy를 설치해주자.


GitHub Setting

  1. 자신이 현재 진행하고 있는 프로젝트의 Github의 Repository에서 Actions를 들어가준다.

  1. 우리는 SpringBoot를 사용하였고 해당 프로젝트를 서버에 배포할 것 이기 때문에 Java with Gradle로 Actions를 설정해준다.

  2. gradle.yml 파일을 생성할 수 있는 창과 우측 상단에 Start commit이 있다. 우리는 추후에 적용시킬 것 들을 고려하여 gradle.yml 파일에 아래와 같이 작성할 것 이다.

name: Java CI with Gradle

# master 브랜치의 push와 pull로 CI가 작동
on:
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 17
      uses: actions/setup-java@v3
      with:
      # 자신이 사용하는 자바 버전에 맞춰주자
        java-version: '17'
        distribution: 'temurin'
        
    - uses : actions/checkout@v3
    #1
    # 해당 부분은 상당히 중요함 (글에서 부가설명)
    # application.properties는 외부에 노출되면 안되므로 Actions가 빌드될때마다 해당 Repository의 Secret 설정을
    # 이용하여서 설정 파일을 생성해줌 (github에 commit 되는게 아님!)
    - run : touch ./src/main/resources/application.properties
    - run : echo "${{ secrets.APPLICATION }}" > ./src/main/resources/application.properties
    - run : cat ./src/main/resources/application.properties
    
    # gradlew에 권한 부여
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
    
    # gradlew 빌드
    - name: Build with Gradle
      run: ./gradlew clean build

	# 빌드를 성공하면 해당 프로젝트를 zip로 만듬
    # 이름은 run 에서 설정 가능
    - name: Make zip file
      run: zip -r ./<자신이 만들 ZIP 파일 이름>.zip .
      shell: bash

	#2
	# AWS 계정 설정
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
      # 깃허브 Secret에 넣어둔 Access key
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
      # 깃허브 Secret에 넣어둔 Secret key
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      # 깃허브 Secret에 넣어둔 Region
        aws-region: ${{ secrets.AWS_REGION }}

	#3
	# 만들어 놓은 S3에 해당 zip 파일 저장
    - name: Upload to S3
      run: aws s3 cp --region ${{ secrets.AWS_REGION }} ./<자신이 만든 ZIP 파일 이름>.zip s3://<만들어 놓은 버킷 이름>/<자신이 만든 ZIP 파일 이름>.zip
    
    #4
    # AWS CodeDeploy에 배포
    - name: Deploy
      env:
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      run: |
        aws deploy create-deployment \
        --application-name <AWS codeDeploy 애플리케이션 이름> \
        --deployment-group-name <codeDeploy group 이름> \
        --file-exists-behavior OVERWRITE \
        --s3-location bucket=<만들어 놓은 버킷 이름>,bundleType=zip,key=<자신이 만든 ZIP 파일 이름>.zip \
        --region ${{ secrets.AWS_REGION }}

#1 application.properties 설정하기

보안의 이유로 properties 파일을 github에 업로드 하지 않는다. 그러면 어떻게 CI를 구축 할 수 있을까?

우리는 해당 프로젝트의 Repository에서 Setting에 들어가 Security 탭에 Secrets를 클릭 후 Actions에 들어가 새로운 Secret 코드를 만들어 줄 것 이다. #1 주석의 ${{ secrets.APPLICATION }} 은 secrets에 APPLICATION이라는 이름으로 Secret을 하나 작성해주었고 해당 내용은 application.properties 파일의 내용과 동일하다.

#1과 같이 등록해두면 CI가 작동될때마다 secret에서 코드를 가져와 application.properties를 자체적으로 생성 후 빌드한다, 이러면 properties 파일을 깃헙에 올리지 않더라도 CI를 구축할 수 있다.

#2 AWS 계정 설정하기

#2 주석에서 ${{ secrets.AWS_ACCESS_KEY_ID }} 과 ${{ secrets.AWS_SECRET_ACCESS_KEY }} 는 각각 IAM의 액세스 키와 시크릿 키이다. IAM에서 사용자 계정을 추가할때 csv 파일을 꼭 저장하여 키 값을 확인하고 이 또한 Secrets에 해당 값들을 저장하여 불러와주자. ${{ secrets.AWS_REGION }} 의 경우 사용하고 있는 리전 주소를 Secret에 넣어주면 된다. ex) us-east-1 과 같은 명칭들

#3 CI를 통해 만든 zip 파일을 S3에 저장하기

#3 주석에서는 크게 어려울 것 없이 gradle.yml에 파일에서 자신이 만들 ZIP 파일 이름을 그대로 넣어주고 자신이 AWS에 만들어 놓은 버킷 이름을 그대로 넣어주면 된다.

#4 AWS CodeDeploy에 배포하기

#4 주석을 살펴보면 ${{ secrets.AWS_ACCESS_KEY_ID }}, ${{ secrets.AWS_SECRET_ACCESS_KEY }} 의 경우 #2 주석과 마찬가지로 등록해놓은 secrets를 그대로 사용하면 되고 run 부분에서 주석에 맞게끝 해당 값들을 작성해주자.

물론 위와같이 작성했다해도 빌드하면 오류날 것 이다. 왜냐면 아직 세팅이 안됐기 때문,, 아래는 AWS 관련 설정들을 만드는 법이다.


AWS S3와 CodeDeploy 설정하는법

1. IAM 역할 생성

IAM에서 역할을 생성해줄 것 이다. 하나는 AWS 서비스 -> 사용사례 EC2로 아래 권한 들을 추가해줄 것 이다.

두번째는 AWS 서비스 -> 사용사례 CodeDeploy의 CodeDeploy 선택 후 아래 권한을 추가해준다.

그리고 CI/CD를 구축할려는 EC2 인스턴스의 IAM 역할 수정을 통해 만든 IAM 역할을 지정해준다. 이것은 두개의 권한을 추가해준 IAM 역할로 설정해주면 된다.

2. S3 생성

이 부분은 크게 어려울 것 없이 버킷 하나를 추가해주면 된다. 설정 건드릴거 없이 만들어주자. 참고로 만들때 IAM 사용자를 등록해놔야 하니 이것은 블로그 내 S3 이미지 업로드 포스팅을 참고해주자.

3. CodeDeploy 애플리케이션 생성

AWS의 CodeDeploy 애플리케이션을 하나 만들자. 설정할때 컴퓨팅 플랫폼은 EC2/온프레미스 로 설정해주자.
그리고 만든 애플리케이션으로 들어가 배포 그룹을 생성할건데 중요하게 볼 곳을 설명하면

  • 서비스 역할 : 만든 IAM 역할 중 AWSCodeDeployRole 권한을 추가한 IAM 역할을 설정해주자.
  • 환경 구성 : EC2 인스턴스 선택 후 키 (Name) : 값 (배포할려는 EC2)를 선택해준다.

에이전트 미설정하고 로드 밸런싱이 체크되어있다면 해제해서 해당 기능을 꺼주고 배포 그룹을 생성해주자.


이제 자신이 만들고 있는 프로젝트로 들어와 appspec.yml 파일을 프로젝트 내부 최상단에 만들어 줄 것 이다. 그리고 다음과 같이 적는다.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/app/deploy

hooks:
  AfterInstall:
    - location: scripts/stop.sh
      timeout: 60
      runas: ec2-user
  ApplicationStart:
    - location: scripts/start.sh
      timeout: 60
      runas: ec2-user

destination의 경우 EC2내부에 저장 될 경로이다. 그리고 hooks를 통해 쉘 스크립트를 실행해줄 것인데 location으로 해당 쉘의 위치를 잡아 주고 실행줄 것 이다. 위와같이 작성했다면 프로젝트 최상단에 scripts라는 패키지를 생성후 아래와 같이 파일들을 추가한다.

start.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ec2-user/app/deploy"
JAR_FILE="$PROJECT_ROOT/build/libs/어쩌구저쩌구.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/*.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

stop.sh

#!/usr/bin/env bash

PROJECT_ROOT="/home/ec2-user/app/deploy"
JAR_FILE="$PROJECT_ROOT/build/libs/어쩌구저쩌구.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

프로젝트 루트와 JAR 파일이 존재하는 경로를 꼭 정확히 입력해주자.


위의 과정들을 마쳤다면 깃헙 액션에 CI를 돌려보고 성공했다면 CodeDeploy로 들어가 해당 배포가 성공되었는지 확인하고 성공됐다면 서버가 배포 및 실행이 되어있을 것 이다.

CI/CD 구축을 위해 많은 삽질을 했다. 지금까지 했던 것 중에 가장 많은 블로그를 뒤져보았던것 같은데 다음에는 nginx를 통하여 무중단 배포도 해볼예정이다. 사실 도커로 배포해보고 싶은데 도커에 대한 이해도가 아직 높지 않아서 더 공부해보고 도커로 배포해보려 한다.

아무튼 오늘은 여기까지고 다음 포스팅에서 보도록 하자 👍

도움이 된 블로그

[Spring] Github Action + AWS CodeDeploy를 이용하여 프로젝트 자동 배포하기
Github Actions + CodeDeploy + Nginx 로 무중단 배포하기 (1)
Github Actions CD: AWS EC2 에 Spring Boot 배포하기
Github Action을 사용한 Spring boot & gradle CI/CD 구축
AWS S3, CodeDeploy 연동하기
AWS CodeDeploy Agent 설치 시 발생 오류
[Github Action] Spring Application.properties 민감정보 관리하기

profile
내가 몰입하는 과정을 담은 곳

0개의 댓글