GitHub Actions로 CI/CD 구축 #3

artp·2024년 12월 16일

CI/CD

목록 보기
6/9
post-thumbnail

GitHub Actions로 CI/CD 구축 #2에서는 일반적인 프로젝트에서 주로 사용하는 CI/CD 구축 방법을 소개했습니다.

이번 글에서는 AWS의 CodeDeploy를 사용하여 확장성을 고려한 프로젝트에서 많이 사용하는 CI/CD 구축 방법을 알아보도록 하겠습니다.

CodeDeploy 세팅

CodeDeploy IAM 역할 생성

AWS의 배포 자동화 서비스인 CodeDeploy를 활용하므로, CodeDeploy를 먼저 세팅합니다.
CodeDeploy가 다른 리소스인 EC2에 접근 가능하도록 IAM 역할을 생성합니다.

  • IAM - 역할 생성을 선택합니다.
  • AWS 서비스 중 CodeDeploy를 선택합니다.
  • 권한을 확인합니다 (AWSCodeDeployRole).
  • 역할 이름을 작성한 후 역할 생성을 선택하여 생성을 완료합니다.

CodeDeploy 애플리케이션 생성

IAM 역할 생성을 완료했으면, CodeDeploy 애플리케이션을 생성합니다.

  • CodeDeploy - 애플리케이션 생성을 선택합니다.
    • CodeDeploy에서 애플리케이션은 배포 작업을 관리하기 위한 단위입니다.
      • CodeDeploy는 애플리케이션 단위로 배포를 수행합니다.
      • 애플리케이션에는 배포할 대상, 배포 방법, 배포 파일 등이 연관되어 있습니다.
      • 애플리케이션은 배포할 대상, 즉, 배포할 하나의 서비스라고 생각하면 편합니다.

CodeDeploy 애플리케이션 배포 그룹 생성

  • 배포 그룹 생성을 선택합니다.
    • CodeDeploy에서 배포 그룹은 애플리케이션을 어디에, 어떻게 배포할지를 정의합니다.
      • 배포 그룹에서는 배포 대상, 배포 방식, 배포 실패 처리 방식을 설정할 수 있습니다.



EC2 세팅

EC2 역할에 추가할 정책 생성

CodeDeploy 세팅을 완료한 후, EC2가 S3에 접근 가능하도록 IAM 역할을 생성합니다.

이 역할은 S3 권한을 포함하는 IAM 정책을 연결해 EC2가 S3에 접근할 수 있도록 설정합니다.
역할 생성에 앞서, 먼저 정책을 생성하여 필요한 권한을 정의해야 합니다.

// 이 정책은 EC2 인스턴스가 S3 버킷 및 객체에 대해 "읽기 권한"을 가지도록 정의합니다.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:Get*",
                "s3:List*"
            ],
            "Effect": "Allow",
            "Resource": "*"
        }
    ]
}



EC2 역할 생성

  • IAM - 역할 - 역할 생성을 선택합니다.
  • AWS 서비스, EC2를 선택합니다.
  • 권한 추가 부분에서는 앞에서 생성한 code-deploy-ec2-policy를 선택합니다.
  • 역할 이름을 작성하고, 역할 생성을 선택하여 완료합니다.

EC2 IAM 역할 수정

  • EC2 인스턴스 - 작업 - 보안 - IAM 역할 수정을 선택합니다.
  • 앞에서 생성한 역할을 선택합니다.

EC2 인스턴스에 CodeDeploy 에이전트 설치

// 아래 내용을 EC2 인스턴스 내부에 입력합니다.
$ sudo apt update && \
sudo apt install -y ruby-full 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
// CodeDeploy 에이전트 실행 확인
$ systemctl status codedeploy-agent



GitHub Actions 사용을 위한 세팅

GitHub Actions에서 CodeDeploy, S3에 접근할 수 있도록 IAM 발급

IAM 사용자 생성

  • IAM - 사용자 - 사용자 생성을 선택합니다.
  • 사용자 이름을 작성합니다.
  • 직접 정책 연결을 선택합니다.
  • AWSCodeDeployFullAccess, AmazonS3FullAccess 정책을 선택합니다.

액세스 키 발급

보안 자격 증명에서 액세스 키 발급

  • 앞에서 생성한 사용자를 선택합니다.
  • 보안 자격 증명 - 액세스 키 만들기를 선택합니다.
  • AWS 외부에서 실행되는 애플리케이션을 선택합니다.
  • 액세스 키 만들기를 선택합니다.
  • ❗️액세스 키와 비밀 액세스 키는 반드시 별도로 보관하도록 하고, 외부에 노출되지 않도록 주의합니다.

GitHub Actions의 Secret Key로 저장

액세스 키, 비밀 액세스 키를 GitHub Actions의 Secret Key로 저장

  • 발급받은 액세스 키와 비밀 액세스 키를 깃허브 액션의 시크릿 값으로 저장합니다.

S3 세팅

S3 버킷 생성

  • 버킷 이름을 작성합니다.
  • 나머지 설정은 기본값으로 유지하여 버킷 생성을 완료합니다.

appspec.yml, start-server.sh 작성

프로젝트의 최상단 경로(루트 경로)에 appspec.yml 파일을 생성합니다.

appspec.yml이란?

AWS CodeDeployappspec.yml 파일을 기반으로 동작합니다.
이 파일은 CodeDeploy가 애플리케이션을 배포할 때 수행해야 할 작업의 규칙을 정의하는 설정 파일입니다.

appspec.yml의 주요 역할

  1. 배포 파일의 위치 설정
    • 배포할 파일이 어디에 위치하며, 어떤 경로로 복사해야 하는지 명시합니다.
  2. 스크립트 실행
    • 배포 과정에서 실행할 스크립트(예: 서버 시작/중지, 권한 설정)를 지정합니다.
  3. 권한 설정
    • 배포된 파일에 대한 접근 권한을 설정할 수 있습니다.

appspec.yml 코드 설명

# CodeDeploy가 이 설정 파일(appspec.yml)을 기반으로 동작합니다.
# appspec.yml은 CodeDeploy가 애플리케이션을 배포할 때 따라야 할 작업의 규칙을 정의하는 파일입니다.
# 이 파일은 배포 파일의 위치, 파일 복사 경로, 권한 설정, 실행할 스크립트 등을 설정하여 CodeDeploy가 EC2에서 어떻게 작업해야 하는지 알려줍니다.
version: 0.0  # appspec.yml 파일의 버전 (기본값 0.0)
os: linux  # 배포 대상 운영 체제 (여기서는 Linux)

files:  # 배포 파일의 소스 경로와 대상 경로를 정의
  - source: /  # 소스 파일의 루트 경로 (S3에 업로드된 파일 전체)
    destination: /home/ubuntu/test-server  # EC2 인스턴스에서 파일이 복사될 경로

permission:  # 복사된 파일/폴더의 소유자와 그룹을 설정
  - object: /  # 권한을 설정할 대상 파일/폴더 (여기서는 모든 파일/폴더)
    owner: ubuntu  # 파일/폴더의 소유자를 'ubuntu' 사용자로 설정
    group: ubuntu  # 파일/폴더의 소유 그룹을 'ubuntu' 그룹으로 설정

hooks:  # 배포 과정 중 특정 단계에서 실행할 스크립트를 정의
  ApplicationStart:  # 애플리케이션 배포 후 실행되는 단계
    - location: scripts/start-server.sh  # 실행할 스크립트의 경로
      timeout: 60  # 스크립트 실행 시간 제한 (초 단위)
      runas: ubuntu  # 스크립트를 실행할 사용자 ('ubuntu' 사용자로 실행)

헤더 설정

version: 0.0  # appspec.yml 파일의 버전 (기본값 0.0)
os: linux  # 배포 대상 운영 체제 (여기서는 Linux)
  • version: 0.0: appspec.yml 파일의 버전입니다. 항상 0.0을 사용합니다.
  • os: linux: 배포할 대상 운영체제를 지정합니다. 여기서는 Linux 기반의 EC2 인스턴스입니다.

files 섹션: 배포할 파일의 복사 경로

files:  # 배포 파일의 소스 경로와 대상 경로를 정의
  - source: /  # 소스 파일의 루트 경로 (S3에 업로드된 파일 전체)
    destination: /home/ubuntu/test-server  # EC2 인스턴스에서 파일이 복사될 경로
  • source:

    • 애플리케이션 파일의 소스 경로입니다.
    • CodeDeploy는 S3 버킷이나 GitHub에서 배포 파일을 가져옵니다. 여기서는 루트 디렉토리(/)에서 가져온다고 명시했습니다.
  • destination:

    • 복사한 파일을 저장할 대상 경로입니다.
    • 여기서는 /home/ubuntu/test-server 디렉토리로 복사됩니다.

permissions 섹션: 권한 설정

permission:  # 복사된 파일/폴더의 소유자와 그룹을 설정
  - object: /  # 권한을 설정할 대상 파일/폴더 (여기서는 모든 파일/폴더)
    owner: ubuntu  # 파일/폴더의 소유자를 'ubuntu' 사용자로 설정
    group: ubuntu  # 파일/폴더의 소유 그룹을 'ubuntu' 그룹으로 설정
  • object:

    • 권한을 설정할 대상 파일/디렉토리입니다. /로 지정하면 모든 파일/폴더에 권한이 적용됩니다.
  • ownergroup:

    • 복사된 파일/폴더의 소유자와 그룹을 ubuntu 사용자로 설정합니다.

hooks 섹션: 배포 단계별 스크립트 실행

hooks:  # 배포 과정 중 특정 단계에서 실행할 스크립트를 정의
  ApplicationStart:  # 애플리케이션 배포 후 실행되는 단계
    - location: scripts/start-server.sh  # 실행할 스크립트의 경로
      timeout: 60  # 스크립트 실행 시간 제한 (초 단위)
      runas: ubuntu  # 스크립트를 실행할 사용자 ('ubuntu' 사용자로 실행)
  • hooks:

    • 배포 과정에서 특정 단계에 실행될 스크립트를 지정합니다.
  • ApplicationStart:

    • 배포 후 애플리케이션을 시작하는 단계입니다.
    • 여기서 start-server.sh 스크립트를 실행해 애플리케이션 서버를 시작합니다.
  • location:

    • 스크립트 파일의 경로입니다. scripts/start-server.sh를 실행하도록 설정했습니다.
  • timeout:

    • 스크립트의 최대 실행 시간을 설정합니다. 여기서는 60초입니다.
  • runas:

    • 스크립트를 실행할 사용자 권한입니다. 여기서는 ubuntu 사용자로 실행합니다.

배포 흐름

  1. 배포 시작: CodeDeploy가 EC2 인스턴스에 접근합니다.
  2. 파일 복사: files 섹션에 따라 소스 파일이 EC2 인스턴스의 지정된 경로로 복사됩니다.
  3. 권한 설정: permissions 섹션에 따라 파일 소유권 및 권한이 설정됩니다.
  4. 스크립트 실행: hooks 섹션에 정의된 스크립트가 지정된 단계에서 실행됩니다.
    • ApplicationStart 단계에서 scripts/start-server.sh 스크립트가 실행되어 서버가 시작됩니다.

start-server.sh 작성

start-server.sh는 서버를 실행하는 스크립트입니다. 루트 경로 아래에 위치한 scripts 디렉토리에 저장하고, appspec.ymlApplicationStart 섹션에서 호출됩니다.

scripts/start-server.sh

#!/bin/bash
echo "--------------- 서버 배포 시작 -----------------"
cd /home/ubuntu/test-server
sudo fuser -k -n tcp 8080 || true
nohup java -jar project.jar > ./output.log 2>&1 &
echo "--------------- 서버 배포 끝 -----------------"

스크립트 작성 시 주의사항

  1. 실행 권한 부여

    • 스크립트를 실행하기 전에 권한을 부여해야 합니다.
      chmod +x scripts/start-server.sh
  2. 경로 확인

    • 애플리케이션이 배포될 경로와 스크립트 내에서 사용되는 경로가 일치해야 합니다.
  3. 로그 기록

    • 스크립트의 실행 결과를 로그 파일에 기록해 두면 디버깅이 용이합니다.

스크립트 설명

#!/bin/bash
  • #!/bin/bash:
    • 스크립트를 bash 쉘에서 실행하도록 명시하는 부분입니다. 모든 스크립트 파일의 첫 줄에 작성합니다.

echo "--------------- 서버 배포 시작 -----------------"
  • echo:
    • 터미널에 메시지를 출력합니다.
    • 배포 시작을 알리는 메시지를 출력하여 로그에 기록됩니다.

cd /home/ubuntu/test-server
  • cd:
    • 애플리케이션 파일이 있는 디렉토리로 이동합니다.
    • 이 경우 /home/ubuntu/test-serverappspec.yml 파일에서 설정한 배포 대상 경로와 일치합니다.

sudo fuser -k -n tcp 8080 || true
  • fuser -k -n tcp 8080:
    • 8080 포트를 사용 중인 프로세스를 강제로 종료합니다.
    • -k: 해당 포트를 사용하는 프로세스를 종료합니다.
    • -n tcp: TCP 프로토콜을 대상으로 합니다.
  • sudo:
    • 관리자 권한으로 명령을 실행합니다.
  • || true:
    • 만약 프로세스가 존재하지 않아도 스크립트가 실패하지 않도록 오류를 무시합니다.

nohup java -jar project.jar > ./output.log 2>&1 &
  • nohup:

    • 스크립트를 백그라운드에서 계속 실행하도록 합니다.
    • 터미널 세션이 종료되어도 프로세스가 중단되지 않습니다.
  • java -jar project.jar:

    • project.jar 파일을 실행합니다.
    • java -jar 명령어를 사용해 애플리케이션을 실행합니다.
  • > ./output.log 2>&1:

    • 출력 리다이렉션:
      • >: 표준 출력을 output.log 파일에 기록합니다.
      • 2>&1: 표준 에러(2)를 표준 출력(1)과 같은 곳에 기록합니다.
    • 이를 통해 표준 출력과 에러 로그output.log 파일에 기록됩니다.
  • &:

    • 명령을 백그라운드에서 실행하도록 설정합니다.

echo "--------------- 서버 배포 끝 -----------------"
  • echo:
    • 배포가 완료되었음을 알리는 메시지를 출력합니다.
    • 이 메시지도 로그에 기록됩니다.

스크립트 실행 흐름

  1. 배포 시작 메시지 출력:

    • --------------- 서버 배포 시작 -----------------
  2. 작업 디렉토리 이동:

    • /home/ubuntu/test-server 디렉토리로 이동합니다.
  3. 8080 포트 종료:

    • 이미 실행 중인 서버가 있다면 8080 포트를 종료합니다.
    • 새로운 서버 실행에 방해가 되지 않도록 프로세스를 정리합니다.
  4. 애플리케이션 실행:

    • project.jar 파일을 백그라운드에서 실행하고, 출력을 output.log에 저장합니다.
  5. 배포 완료 메시지 출력:

    • --------------- 서버 배포 끝 -----------------

스크립트 주요 포인트

  • 포트 정리: fuser 명령어를 통해 기존 프로세스를 종료합니다.
  • 백그라운드 실행: nohup&를 사용해 애플리케이션을 백그라운드에서 실행합니다.
  • 로그 관리: output.log에 표준 출력과 에러 로그를 저장해 디버깅 및 모니터링이 가능합니다.
  • 안정성 확보: 오류가 나더라도 스크립트가 중단되지 않도록 || true를 사용합니다.

GitHub Actions 코드 작성

루트 경로 아래에 .github/workflows 디렉터리를 생성한 후 그 아래에 deploy.yml 워크플로 파일을 생성합니다.

.github/workflows/deploy.yml

name: Deploy To EC2  # 워크플로 이름 정의, Actions 탭에서 이 이름으로 표시됨

on:
  push:
    branches:
      - main  # main 브랜치에 푸시될 때 워크플로 실행

jobs:
  deploy:
    runs-on: ubuntu-latest  # 최신 Ubuntu 환경에서 실행

    steps:
      # 리포지토리의 코드를 작업 환경에 가져오기
      - name: Github Repository 파일 불러오기
        uses: actions/checkout@v4

      # JDK(Java Development Kit) 설치
      - name: JDK 17버전 설치
        uses: actions/setup-java@v4
        with:
          distribution: temurin  # OpenJDK의 temurin 배포판 사용
          java-version: 17  # JDK 17 설치

      # application.yml 파일 생성 (환경 변수 적용)
      - name: application.yml 파일 만들기
        run: echo "${{ secrets.APPLICATION_PROPERTIES }}" > ./src/main/resources/application.yml

      # Gradle 빌드 도구를 사용해 프로젝트 테스트 및 빌드
      - name: 테스트 및 빌드하기
        run: ./gradlew clean build

      # 빌드된 결과물의 이름을 변경 (사용하기 쉽게 관리)
      - name: 빌드된 파일 이름 변경하기
        run: mv ./build/libs/*SNAPSHOT.jar ./project.jar

      # 배포 파일 및 설정을 하나의 tar.gz 파일로 압축
      - name: 압축하기
        run: tar -czvf $GITHUB_SHA.tar.gz project.jar appspec.yml scripts

      # AWS에 접근하기 위한 자격 증명 설정
      - name: AWS credentials 설정
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-region: ap-northeast-2  # AWS 리소스가 위치한 리전 (서울 리전)
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}  # AWS 액세스 키 ID
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}  # AWS 시크릿 액세스 키

      # 압축된 파일을 AWS S3 버킷에 업로드
      - name: S3에 프로젝트 폴더 업로드
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.tar.gz s3://mytestserverbucket/$GITHUB_SHA.tar.gz

      # AWS CodeDeploy를 사용해 EC2에 배포 명령 실행
      - name: CodeDeploy를 활용해 EC2에 프로젝트 배포
        run: |
          aws deploy create-deployment \
            --application-name test-server \  # CodeDeploy 애플리케이션 이름
            --deployment-config-name CodeDeployDefault.AllAtOnce \  # 배포 설정 (한 번에 배포)
            --deployment-group-name Production \  # CodeDeploy 배포 그룹 이름
            --s3-location bucket=mytestserverbucket,bundleType=tgz,key=$GITHUB_SHA.tar.gz  # S3에서 파일 로드
profile
donggyun_ee

0개의 댓글