AWS

[AWS] AWS EC2 & CodeDeploy & S3 & Github Actions 배포 자동화

HEY__ 2024. 5. 31. 16:19
728x90

이 글은 공부를 하면서 알게 된 내용들을 기록하는 글 입니다. 오류나 고쳐야 할 사항들이 있다면 지적 부탁드립니다!

 

🎯 목표

Github Actions와 AWS CodeDeploy, AWS S3, AWS EC2를 이용해서 개발자가 특정 브랜치에 PR/Push를 했을 때,

AWS 운영 환경에 서비스가 자동으로 배포되게끔 CICD 자동화를 해보자.

 

🖥️ 개발 환경
스프링 버전: Spring boot 3.2.1
빌드툴: Gradle
JDK: openjdk 17
데이터베이스: mariadb, mongodb

 


✅ AWS EC2 생성 및 환경 설정

개발한 서비스를 AWS EC2 인스턴스에 배포해도록 하자.

AWS에 처음 가입하면 1년간 프리티어 수준으로 서비스를 이용할 수 있는데, EC2의 경우에는 `12개월 동안 매월 750시간`을 제공한다.

750을 24로 나눴을 때 31을 넘기 때문에, 프리티어를 사용하고 있을 때에는 인스턴스 하나 정도는 무료로 사용할 수 있다 :)

 

1. AWS EC2 인스턴스 생성

 

[AWS] AWS 프리티어 EC2 Inatance 생성 & EIP(탄력적 IP) & swap memory 설정

이 글은 공부를 하면서 알게 된 내용들을 기록하는 글 입니다. 오류나 고쳐야 할 사항들이 있다면 지적 부탁드립니다!✅ 서론AWS는 새로 가입을 하면 1년동안 프리티어로 사용할 수 있다.AWS에서

m42-orion.tistory.com

 

2. Docker 통해 mariaDB 설치 및 계정 설정

 

[AWS] EC2에 Docker 이용해서 mariadb 설치하기

이 글은 공부를 하면서 알게 된 내용들을 기록하는 글 입니다. 오류나 고쳐야 할 사항들이 있다면 지적 부탁드립니다! GitGet 서비스에서는 RDBMS인 `MariaDB`와 NoSQL인 `mongoDB` 총 두 개의 데이터베이

m42-orion.tistory.com

 

3. Docker 통해 mongoDB 설치 및 계정 설정

 

[AWS] EC2에 Docker 이용해서 mongoDB 설치하기

이 글은 공부를 하면서 알게 된 내용들을 기록하는 글 입니다. 오류나 고쳐야 할 사항들이 있다면 지적 부탁드립니다!  GitGet 서비스에서는 RDBMS인 `MariaDB`와 NoSQL인 `mongoDB` 총 두 개의 데이터베

m42-orion.tistory.com

 

4. EC2에 CodeDeploy agent 설치하기

밑의 명령어를 하나씩 작성하여 EC2에 CodeDeploy agent를 설치하자

sudo apt update
sudo apt install ruby-full
sudo apt install wget
cd /home/ubuntu
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto > /tmp/logfile

 

설치 이후에 밑의 명령어를 통해 codedeploy-agent가 제대로 설치되었는지 확인하자.

이후에 밑의 사진처럼 active로 뜬다면 설치가 제대로 된 것이다.

sudo service codedeploy-agent status

 

 

 

5. EC2에 Java 설치하기

sudo apt update
sudo apt install openjdk-17-jdk

 

 


✅ AWS IAM 사용자 생성 후, Github Actions 값 입력

우리는 개발자가 특정 브랜치(ex: production)에 `PR` 혹은 `Push`를 했을 때 `Github Actions`가 적절한 일을 하여 AWS 운영 환경에 서비스를 올리기를 바랬다.

그런데 우리도 AWS 서비스를 이용하려면 로그인을 통해 권한을 얻어야하는데, `Github Actions`에서도 이러한 과정이 있어야하지 않을까?

 

따라서 필요한 권한들을 가진 `AWS IAM 사용자`를 생성하고, 

IAM 사용자를 사용할 수 있는 값을`Github Actions`에 `secret`으로 설정하여 `Github Actions`에서 필요한 일들을 할 수 있도록 하자.


1. AWS IAM 사용자 생성하기

1) AWS IAM 서비스 접속 후, `엑세스 관리` - `사용자` - `사용자 생성` 선택

2) `사용자 이름`에 원하는 이름 설정

 

3) `직접 정책 연결`을 누른 후, 밑에 해당하는 정책들을 추가

AmazonS3FullAccess
AWSCodeDeployFullAccess
AWSCodeDeployRole

 

 

 


2. IAM 사용자의 엑세스 키 만들기

`Github Actions`에게 IAM 사용자 정보를 전달하기 위한 엑세스 키를 만들어보자.

1) IAM 사용자 목록에서 방금 생성한 IAM 사용자를 클릭

2) 요약 란의 `엑세스 키 만들기` 선택

 

3) `기타` 선택 이후 생성을 누르면 엑세스 키 생성

 

 

엑세스 키 생성이 완료되면, `access key`와 `secret key`가 나오는데, 이 둘을 복사해서 안전한 곳에 저장하거나

.csv 파일을 안전한 곳에 다운받아놓자.

 


3. Github Actions에 IAM 정보 입력하기

우리가 배포하고 싶은 코드가 있는 Repository에 들어가자.

`Github Settings` - `Secrets and variables` - `Actions` - `New repository secret`를 누른 후, 

위에서 발급받은 값을 각각 입력해주자

 

 


EC2에서 S3에 접근하기 위한 IAM 역할 생성

위에서 EC2 인스턴스에 CodeDeploy agent를 설치했는데, 이 agent는 S3에 접근하여 빌드 파일을 가져오는 역할을 한다.

따라서 EC2 인스턴스에 S3에 접근할 수 있는 IAM 역할을 부여해주어야 한다.

 

1. AWS IAM 역할 생성하기

1) AWS IAM 서비스 접속

2) `엑세스 관리` - `역할` - `역할 생성` 선택

3) 신뢰할 수 있는 엔티티 선택에 `AWS 서비스` 선택

4) 사용 사례에 `EC2` 선택

 

5) 권한 추가에 `AmazonS3FullAccess` 선택

 

6) 역할 이름에 사용하고자하는 이름 입력

 

 

2. EC2에 역할 부여하기

이전에 생성한 EC2 인스턴스 선택 - `작업` - `보안` - `IAM 역할 수정` 선택

 

IAM 역할 목록에서 생성한 IAM 역할을 연결해주자

 

IAM 역할 연결 이후에, EC2 인스턴스의 세부 정보를 확인해보면 우리가 부여한 IAM 역할이 설정되어 있음을 확인할 수 있다.

 


S3 설정하기 - 버킷 생성

Github Actions의 워크플로우를 통해서 빌드 파일(.jar)을 생성하게 되는데, 이를 zip 형식으로 S3에 저장할 것이다.

빌드 파일을 저장할 `버킷`을 생성하자.

 

AWS S3 서비스 접속 - 버킷 - 버킷 만들기 선택

 

버킷 이름에는 원하는 이름을 작성하고 생성 버튼을 누르면 된다.


 AWS CodeDeploy 설정하기

AWS CodeDeploy는 배포 그룹에 해당되는 EC2 인스턴스에게 적절한 스크립트를 통해 서비스를 실행하도록 한다.

 

1. AWS CodeDeploy용 IAM 역할 생성하기

1) AWS IAM 서비스 접속 - 역할 생성

2) 신뢰할 수 있는 엔터티 유형에 `AWS 서비스` 선택

3) 사용 사례에 `CodeDeploy` 선택

    기본적으로는 AWSCodeDeployRole이 적용되어 있으므로 그대로 생성하면 된다 :)

 

 

 

 


2.  애플리케이션 생성

이제 CodeDeploy에게 `애플리케이션`을 생성하고 `EC2` 인스턴스를 설정해주어 어떤 EC2 인스턴스에서 작업을 하게 할지 알려주자.

 

1) AWS CodeDeploy 접속 - 애플리케이션 생성 선택

 

2) 애플리케이션 이름에는 사용하고 싶은 이름 선택

3) 컴퓨팅 플랫폼에 `EC2/온프레미스` 선택

 


3. 배포 그룹 생성

생성한 AWS CodeDeploy 어플리케이션에 배포 그룹을 만들어 EC2 인스턴스를 설정해주자

 

1) 생성한 애플리케이션 - `배포 그룹 생성` 

 

2) 배포 그룹 이름에는 사용하고 싶은 이름 입력

3) 서비스 역할에 위에서 생성한 CodeDeploy용으로 생성한 IAM 역할 선택

 

4) 배포 유형: 현재 위치 선택

5) 환경 구성: `Amazon EC2 인스턴스` 선택 - 값에 배포에 사용하고자하는 EC2 인스턴스 이름 선택

 

6)AWS CodeDeploy 에이전트 설치에 `한 번만` 선택

7) 배포 구성에 `CodeDeployDefault.AllAtOnce` 선택

8) 로드밸런서는 비활성화


Github Actions workflow 파일 작성 - main.yml

이제 Github Actions의 workflow 파일을 작성하자.

`.github` - `workflow` 폴더에 `.yml` 파일이 있으면, Github Actions가 해당 파일들을 확인하고 조건에 맞는 워크플로우를 실행한다.

 

 

name: Build and Deploy to EC2

# 워크플로우가 언제 실행될 것인지 조건 명시
on:
  push:
    branches: [ "production"]
  pull_request:
    branches: [ "production" ]

# AWS 관련 값 변수로 설정
env:
  AWS_REGION: ap-northeast-2
  AWS_S3_BUCKET: gitget-deploy-bucket
  AWS_CODE_DEPLOY_APPLICATION: GitGet-Application-CD
  AWS_CODE_DEPLOY_GROUP: GitGet-Deployment-Group

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

	# JDK 17 설치
      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          java-version: '17'
          distribution: 'temurin'

	# 공개되면 안되는 정보를 담은 .yml 파일을 생성
      - name: make application.yml
        run: |
          mkdir -p ./src/main/resources
          cd ./src/main/resources
          touch ./application.yml
          touch ./application-common.yml
          touch ./application-prod.yml
          echo "${{ secrets.APPLICATION }}" > ./application.yml
          echo "${{ secrets.COMMON }}" > ./application-common.yml
          echo "${{ secrets.PROD }}" > ./application-prod.yml

	# 권한 부여
      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        shell: bash

      - name: Build and Test
        run: ./gradlew build test

	# 빌드 파일을 zip 형식으로 압축 - S3에서는 jar 저장이 안되기 때문에 zip으로 생성
      - name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash

	# AWS 권한
      - 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 }}

	# S3 버킷에 빌드파일(zip 파일)을 업로드
      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$AWS_S3_BUCKET/$GITHUB_SHA.zip

	# EC2 인스턴스에 S3에 저장되어 있던 zip 파일을 받아와 배포 시작
      - 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=$GITHUB_SHA.zip,bundleType=zip

 

 

여기에서 눈에 여겨볼 step은 `make application.yml` 이다.

서비스 개발을 하면서 민감한 정보(DB 비밀번호, JWT 시크릿 티 등)을 .yml 파일로 등록하고 이를 `.gitignore`에 저장하고 사용한다.

 

배포할 때 이러한 yml 파일이 필요한데 이를 Github Actions secrets로 저장해놓고, Github action이 실행될 때 yml 파일을 생성하도록 하자.

이 링크에서 더 자세한 내용을 확인할 수 있다.


appspec.yml 작성

AWS CodeDeploy가 `appspec.yml`의 내용을 읽고 이 흐름대로 작동한다.

`appspec.yml` 파일은 프로젝트의 제일 루트 경로에 존재해야 제대로 작동한다. 

version: 0.0
os: linux

files:
  - source: /
    destination: /home/ubuntu/app
    overwrite: yes

permissions:
  - object: /
    owner: ubuntu
    group: ubuntu

hooks:
  ApplicationStart:
    - location: scripts/deploy.sh
      timeout: 60

 

 


 deploy.sh 작성

EC2 인스턴스에 설치한 CodeDeploy agent는 `appspec.yml`에서 설정해준 스크립트를 읽고 작업을 실행한다.

`appspec.yml`의 `location`에서 `scripts/deploy.sh`로 설정했으므로, 밑과 같은 위치에 스크립트가 있어야 한다.

 

밑의 스크립트가 하는 일은 다음과 같다.

1) build 파일이 있는 위치를 통해 build 파일을 특정 경로(DEPLOY_PATH)에 복사

2) 현재 EC2 인스턴스에서 java 어플리케이션이 돌아가고 있다면 모두 일괄 종료

3) build 파일을 백그라운드 옵션(`nohup java -jar`)으로 실행

##!/bin/bash

BUILD_JAR=$(ls /home/ubuntu/app/build/libs/*.jar)
JAR_NAME=$(basename $BUILD_JAR)
echo ">>> build 파일명: $JAR_NAME" >> /home/ubuntu/deploy.log

echo ">>> build 파일 복사" >> /home/ubuntu/deploy.log
DEPLOY_PATH=/home/ubuntu/app/
cp $BUILD_JAR $DEPLOY_PATH

echo ">>> 현재 실행중인 애플리케이션 pid 확인 후 일괄 종료" >> /home/ubuntu/deploy.log
sudo ps -ef | grep java | awk '{print $2}' | xargs kill -15

DEPLOY_JAR=$DEPLOY_PATH$JAR_NAME
echo ">>> DEPLOY_JAR 배포"    >> /home/ubuntu/deploy.log
echo ">>> $DEPLOY_JAR의 $JAR_NAME를 실행합니다" >> /home/ubunru/deploy.log
nohup java -jar $DEPLOY_JAR >> /home/ubuntu/deploy.log 2> /home/ubuntu/deploy_err.log &

 


 Github Actions 실행

Github Actions 워크플로우 파일인 main.yml에서 우리는 production 브랜치에 PR 혹은 Push를 했을 때 배포 프로세스가 실행되도록 했다.

production 브랜치에 PR을 날렸을 때, 밑과 같이 Github Actions에서 워크플로우가 실행이 되고, 그 결과 배포가 정상적으로 됨을 확인할 수 있다 :)

 

 


✅ 참고 링크

https://velog.io/@juhyeon1114/%EC%8B%A4%EC%A0%84-Github-actions-AWS-Code-deploy%EB%A1%9C-Spring-boot-%EB%B0%B0%ED%8F%AC-%EC%9E%90%EB%8F%99%ED%99%94%ED%95%98%EA%B8%B0

 

실전! Github actions, AWS Code deploy로 Spring boot 배포 자동화하기

아휴 힘드러 🤮

velog.io

 

https://diary-developer.tistory.com/32

 

[AWS] EC2 스왑 메모리 설정하기 (EC2 메모리 늘리기) - Swap Memory

AWS의 EC2를 사용하고 있는데 프리티어를 사용하다 보면 램 메모리가 1GB 밖에 되지 않기 때문에 메모리가 부족한 현상을 겪을 수 있다. 이를 해결하기 위해 램이 높은 인스턴스 유형을 선택하면

diary-developer.tistory.com

 

https://be-developer.tistory.com/56

 

[AWS CodeDeploy] AWS CodeDeploy 오류시 확인 후 해결하기

[AWS CodeDeploy] AWS CodeDeploy 오류시 확인 후 해결하기 Spring Boot 프로젝트를 깃허브 Actions과 AWS S3, EC2를 이용해 CI/CD를 구현했는데 Postman 테스트가 안되는거라~ 그래서 GitHub Actions부터 확인을 했는데

be-developer.tistory.com

 

728x90