[etc] GitHub Actions로 CI/CD 자동화 하기

김채운·2024년 5월 25일
1

etc.

목록 보기
9/9

AWS의 S3와 cloudfront, Route53을 통해서 프로젝트 배포를 완료 했는데, 문제는 정적 웹 사이트를 호스팅하고 배포하기 위한 플랫폼인 netflify나 vercel처럼 코드를 수정하면 자동으로 배포되지 않는다는 점이다. 그래서 따로 자동 배포화 작업을 해줘야 하는데 ci/cd 플랫폼으로는 다양한 종류가 있는데 그중에서 github actions를 통해서 자동 배포화 작업을 해줬다.

➡️ GitHub Actions를 선택한 이유

Jenkins:

  • 설정에 자신 있고 완전한 제어를 원하는 경우에 적합.
  • Jenkins는 오픈 소스 자동화 서버이며, 사용자가 직접 설치하고 호스팅해야 한다. (사용자가 Jenkins application을 실행할 서버를 직접 설치해야 한다.)
  • 다양한 IDE를 지원하고 커스터마이징이 가능하다.

    Jenkins는 다양한 플러그인을 통해 기능을 확장하고, 파이프라인을 통해 빌드 및 배포 프로세스를 자유롭게 구성할 수 있다. 또한 Jenkins는 다양한 설정 옵션을 제공하여 사용자가 원하는대로 빌드 및 배포 작업을 조정할 수 있다. 이러한 기능들을 통해 Jenkins는 다양한 개발 환경에서 사용되며, 프로젝트의 요구에 맞게 자유롭게 커스터마이징할 수 있다.

  • 전세계에서 많은 사용자가 사용하며 문서가 다양하게 제공된다.
  • 호스팅을 직접 하나부터 열까지 모두 해야하기에 관련된 모든 문서를 관리해야 해서 호스팅 및 관리에 비용과 리소스가 발생한다.
  • Jenkins는 다양한 플러그인을 통해 기능을 확장하고, 사용자가 직접 빌드 및 배포 프로세스를 구성할 수 있다. Jenkins에서 빌드 및 배포 작업은 Jenkins 대시보드에서 설정되고 관리된다.
  • Jenkins는 주로 계정 및 트리거를 기반으로하며 빌드를 중심으로한다. 이는 GitHub 이벤트를 준수하지 않는다. (Jenkins는 GitHub과의 연동을 위해 특별한 플러그인을 사용하며, 이 플러그인을 통해 GitHub의 이벤트를 감지하고 빌드를 트리거할 수 있다. )
  • 규모가 작은 프로젝트의 경우 설정에 많은 리소스가 필요하므로 비효율적일 수 있다.

GitHub Actions:

  • GitHub에서 제공하는 완전 관리 형 서비스이다.(GitHub에서 호스팅되고 관리된다.)
  • 설정이 쉽고 클라우드에서 작동하기 때문에 초기 설정이 간단하다.(GitHub 작업은 클라우드에서 작동한다. 러너라고하는 로컬에서 실행할 수도 있습니다.)

클라우드에서 작동한다는 것의 의미

"클라우드에서 작동한다"는 말은 GitHub Actions의 작업이 GitHub의 서버에서 실행된다는 것을 의미합니다.
1. GitHub 호스팅 러너 사용

  • GitHub는 자체 클라우드 인프라에서 실행되는 가상 머신(러너)을 제공한다.
  • 사용자가 GitHub Actions 워크플로우를 설정하면, 해당 워크플로우는 GitHub의 클라우드 서버에서 실행된다.
  • 이 클라우드 기반 러너는 다양한 운영 체제 환경(예: Ubuntu, Windows, macOS)을 지원한다.
  • 사용자는 별도의 서버를 설정하거나 유지보수할 필요 없이, GitHub가 제공하는 러너를 통해 작업을 쉽게 실행할 수 있다.
    2. 초기 설정이 간단하다
  • 클라우드 기반 러너를 사용하면, 별도의 하드웨어나 서버 설정 없이 GitHub 플랫폼에서 바로 CI/CD 파이프라인을 설정하고 실행할 수 있다.
    이- 는 사용자가 복잡한 인프라 구성 없이, GitHub Actions 워크플로우 파일만 작성하면 된다는 것을 의미한다.
  • 도커 실행을 통해 실행 및 디버깅이 용이하다.
  • 모든 GitHub 이벤트에 대해 지원하며 다양한 언어와 프레임워크를 지원한다.(GitHub Actions를 사용하면 GitHub 리포지토리와 직접 통합되어 코드 리포지토리와 연결된 이벤트에 대한 작업을 트리거할 수 있다.)
  • Github Actions는 YAML로 작성된다. 따라서 코드처럼 편집, 재사용, 공유 및 분기 할 수 있다.(.github/workflows 디렉토리에 YAML 파일로 정의된다.)
  • GitHub Marketplace를 통해 액션을 공유하고 재사용할 수 있어 효율적이다.(다른 개발자가 작성한 액션을 재사용 할 수 있으므로 충분한 시간을 절약하고 이미 사용 가능한 코드를 다시 작성하지 않아도된다.)
  • 저장소를 포크하면 작업이 자동으로 포크되어 사용하기 편리하다.(이를 통해 프로젝트를 매우 효율적으로 테스트하고 빌드 할 수 있으며 개발자와 더 가깝게 실행할 수도 있다. 또한 GitHub API에 쉽게 액세스 할 수 있다)

결론적으로, 프로젝트의 규모와 요구 사항에 따라 Jenkins와 GitHub Actions 중에서 선택할 수 다. Jenkins는 유연성이 높고 다양한 플러그인을 제공하지만, GitHub Actions는 GitHub과 직접 통합되어 있고 GitHub의 네이티브 기능으로 제공되므로 GitHub 리포지토리와의 연동이 편리하며, 설정이 YAML 파일로 간단하게 정의될 수 있다. 그렇기 때문에 간단한 설정과 통합이 용이하며 GitHub의 다양한 기능과 연동되어 편리하다. 만약 규모가 크지않은 프로젝트거나 외부 클라우드 서비스를 이용하는 상황등이라면 Jenkins말고 github actions를 고려해볼 가치가 있다고 생각된다. 그래서 내 프로젝트 같은 경우에는 규모가 그렇게 크지 않기도 하고 따로 서버를 설치하고 직접적으로 설정을 하나하나 해줘야 하는 Jenkins같은 경우에 너무 불필요하게 시간과 비용이 많이 들 거라 생각이 돼서 github repository를 통해서 바로 자동화가 가능한 github actions를 선택했다.

➡️ GitHub Actions의 흐름

GitHub Actions는 이벤트 기반으로 작동하며, 저장소의 다양한 이벤트(예: 코드 푸시, 풀 리퀘스트, 이슈 생성 등)에 반응하여 지정된 작업을 수행한다. 그렇기 때문에 event가 일어나면, GitHub Actions은 Workflow -> Jobs -> Steps -> Action의 순서로 동작한다.

Event

  • GitHub Actions는 이벤트 기반으로 동작한다. 예를 들어, 코드 푸시, 풀 리퀘스트 생성, 이슈 생성 등이 이벤트가 된다.
  • 이벤트가 발생하면 해당 이벤트에 반응하도록 설정된 워크플로우가 트리거된다.

Workflow

  • 워크플로우는 하나 이상의 작업(Job)으로 구성된 자동화된 프로세스이다.

  • .github/workflows 디렉터리에 YAML 파일로 정의된다.

  • 예시

// yaml

name: CI

on:
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - name: Run a one-line script
      run: echo Hello, world!
    - name: Run a multi-line script
      run: |
        echo Add other actions to build,
        echo test, and deploy your project.
  • 해당 Workflows 는 build 작업을 수행하는 용도의 Job 으로 구성된 Workflows이다.
    Job 에서 runs-on 속성을 통해 가상 서버를 지정할 수 있다.

Jobs

  • 각 워크플로우는 하나 이상의 작업(Job)으로 구성된다.
  • 각 작업은 독립적으로 실행될 수 있으며, 기본적으로 병렬로 실행된다.
  • runs-on 속성을 사용하여 작업이 실행될 가상 서버(러너)를 지정할 수 있다.
  • 작업이 병렬이 아니라 순차적으로 실행되도록 하려면 needs 속성을 사용해 의존성을 지정할 수 있다.

Runner

  • 러너는 작업을 실행하는 가상 머신이다.
  • GitHub에서 호스팅하는 러너(예: ubuntu-latest, windows-latest, macos-latest)를 사용할 수 있고, 자체 호스팅 러너를 설정할 수도 있다.

runner?

GitHub Actions에서 사용자가 작성한 Jobs이 실행되는 가상 서버(runner)는 실제로 작업을 수행하는 환경이다. 이 가상 서버(runner)는 두 가지 주요 형태로 제공되는데, GitHub 호스팅 러너와 자체 호스팅 러너가 있다.

가상 서버(runner)란?

러너(Runner)는 워크플로우 내의 Jobs을 실행하는 머신이다. 러너는 특정 운영 체제(OS) 환경을 제공하며, 이 환경에서 스크립트, 명령어, 액션이 실행된다. 러너는 GitHub에서 제공하는 러너(GitHub 호스팅 러너)와 사용자가 직접 설정한 러너(자체 호스팅 러너)로 나뉜다.

두 가지 종류의 가상 서버(runner)

  1. GitHub 호스팅 러너 (GitHub-hosted Runner)

GitHub에서 제공하는 관리형 가상 머신이다. 이 러너는 GitHub가 관리하고 유지 보수하며, 사용자는 설정이나 유지 보수에 신경 쓰지 않고 사용할 수 있다.

  • 운영 체제: 다양한 운영 체제를 지원한다. 대표적으로 ubuntu-latest, windows-latest, macos-latest 등이 있다.
  • 장점: 설정이 간편하고, 유지 보수 부담이 없으며, 최신 버전의 운영 체제와 도구가 자동으로 업데이트된다.
  • 사용 방법
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    - name: Run a script
      run: echo "Running on a GitHub-hosted runner"
  1. 자체 호스팅 러너 (Self-hosted Runner)
    사용자가 직접 관리하는 물리적 머신이나 가상 머신에 GitHub Actions Runner 애플리케이션을 설치하여 사용하는 러너이다. 사용자는 이 러너를 설정하고 유지 보수해야 한다.
  • 운영 체제: 사용자가 원하는 운영 체제를 선택할 수 있다. 예를 들어, 특정 환경이나 사양이 필요한 경우 적합하다.
  • 장점: 커스터마이징이 가능하고, 특정 하드웨어나 네트워크 환경이 필요한 작업에 적합하다.
  • 사용 방법
  • 먼저 GitHub의 자체 호스팅 러너 설정 문서를 참고하여 러너를 설정한다.
  • 설정 후, 워크플로우 파일에서 runs-on 속성에 self-hosted를 지정한다.
jobs:
  build:
    runs-on: self-hosted
    steps:
    - name: Checkout code
      uses: actions/checkout@v3
    - name: Run a script
      run: echo "Running on a self-hosted runner"

가상 서버(runner)의 역할

  • 코드 체크아웃: 대부분의 Jobs는 먼저 actions/checkout@v3 액션을 사용하여 원격 레포지토리에서 코드를 클론한다.
  • 환경 설정: 러너는 설정된 운영 체제 환경에서 필요한 도구와 라이브러리를 설치하고 설정한다.
  • 스크립트 실행: 사용자가 정의한 스크립트와 명령어를 실행한다.
  • 액션 실행: GitHub Marketplace에서 제공하는 액션을 실행하여 빌드, 테스트, 배포 등의 작업을 수행한다.

Steps

  • 각 작업은 여러 단계로 구성된다. 단계는 순차적으로 실행된다.
  • 단계는 셸 명령어를 실행하거나, 사전 정의된 액션을 사용할 수 있다.

Actions

  • 액션은 특정 작업을 수행하는 재사용 가능한 구성 요소이다.
  • uses 속성을 사용하여 GitHub Marketplace에서 제공하는 액션을 사용할 수 있다.
- uses: actions/checkout@v3

프로세스 흐름 요약

1. Event 발생: 예를 들어, push 또는 pull_request 이벤트가 발생하면 워크플로우가 시작된다.
2. Workflow 트리거: 이벤트에 반응하여 설정된 워크플로우 파일이 실행된다.
3. Job 실행: 워크플로우 내의 각 작업(Job)이 정의된 가상 서버에서 실행된다.
runs-on 속성을 통해 사용할 가상 서버를 지정한다.
4. Steps 실행: 각 작업(Job)은 여러 단계(Step)로 구성되며, 순차적으로 실행된다.
대부분의 작업은 actions/checkout@v3를 사용하여 원격 레포지토리에서 코드를 클론한 후 작업을 시작한다.
5. 병렬 실행: 기본적으로 모든 작업(Job)은 병렬로 독립적으로 실행된다. 특정 작업이 다른 작업을 기다리도록 하려면 needs 속성을 사용해 의존성을 설정할 수 있다.

➡️ GitHub Actions 설정 과정

  • 프로젝트 repository에서 setting -> security탭의 Secrets and variables -> Actions에서 Repository secrets의 "New repository secret"을 클릭.

  • AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY에는 각각 AWS IAM 설정에서 만들었던 엑세스 키의 정보를 입력하면 되고, 나머지 환경 변수는 내 프로젝트의 .env파일에서 관리하는대로 설정해주면 된다.

  • 그럼 이렇게 Repository secrets 설정이 완료가 된다.

  • 내 프로젝트로 돌아가서 프로젝트의 루트에 .github이라는 폴더를 생성하고, 그 안에 workflows라는 폴더를 추가로 생성합니다. 그리고 그 안에 deploy.yml 파일을 생성한다.
name: Build
on:
  push:
    branches:
      - main #빌드하고싶은 브랜치
jobs:
  build:
    runs-on: ubuntu-latest

    steps:
         # 1 - 소스코드 복사.
      - name: Check out repository code
        uses: actions/checkout@main

        # 2 - node_modules 캐싱
      - name: Cache node modules
        uses: actions/cache@v4
        with:
          path: node_modules
          key: ${{ runner.os }}-build-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
              ${{ runner.os }}-build-
              ${{ runner.os }}-

         # 3 - 의존성 패키지 설치.
      - name: Install Dependencies 
        if: steps.cache.outputs.cache-hit != 'true'
        run: npm install

        # 4 - 빌드
      - name: Build
        run: CI='false' npm run build

        # 5 - aws에 접근하기 위한 권한을 받아옵니다.
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SCRET_ACCESS_KEY }}
          aws-region: ${{secrets.AWS_DEFAULT_REGION}}

        # 6 - S3에 build 파일 배포.
      - name: Deploy to S3
        run: aws s3 sync ./build s3://${{ secrets.AWS_BUCKET_NAME }}

        # 7 - CloudFront 캐시 무효화.
      - name: CloudFront Invalidation
        run: aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CLOUDFRONT_ID }} --paths "/*"

1 - 소스코드 복사.

GitHub의 체크아웃 액션

GitHub Actions의 Checkout 액션은 코드 저장소에서 코드를 가져와 CI 서버로 내려받고, 필요에 따라 특정 브랜치로 전환하는 작업을 간편하게 수행할 수 있도록 도와주는 기능이다. 이 액션을 사용하면 매번 쉘 스크립트로 작성해야 하는 체크아웃 과정을 자동화할 수 있다. 따라서 개발자는 이 액션을 워크플로우에 추가함으로써 코드를 손쉽게 내려받고 브랜치를 전환할 수 있다. 이렇게 함으로써 복잡한 설정이나 인증 과정을 신경 쓰지 않고도 워크플로우를 효율적으로 구성할 수 있다.

  • 워크플로우에서 코드를 체크아웃하고 레포지토리의 소스 코드를 가져오는 데 사용된다. 이 액션은 현재 레포지토리의 코드를 워크플로우가 실행 중인 가상 환경(런너)으로 가져온다.

  • 체크아웃된 코드에는 해당하는 브랜치의 최신 커밋 내역이 포함된다. 이를 통해 워크플로우에서 현재 브랜치의 상태를 파악하고 작업을 수행할 수 있다.

  • @main은 액션의 버전을 지정한다. 여기서 main은 액션의 메인 브랜치를 가리킨다. 이렇게 함으로써 항상 최신 버전의 액션을 사용할 수 있다. (다른 브랜치나 태그를 명시할 수도 있다.)

2 - node_modules 캐싱

이 코드는 GitHub Actions에서 제공하는 cache 액션을 사용하여 노드 모듈을 캐싱하는 부분이다.

actions/cache@v4: GitHub Marketplace에서 제공되는 cache 액션을 사용한다. 이 액션을 사용하여 종속성을 캐싱하여 빌드 시간을 최적화한다.

with: 액션의 옵션을 설정하는 부분.

path(node_modules): 캐시할 디렉토리 경로를 지정. 여기서는 주로 노드 프로젝트에서 사용되는 node_modules 디렉토리를 캐싱한다.

key: runner.osbuild{{ runner.os }}-build-{{ hashFiles('**/package-lock.json') }}: 캐시를 식별하기 위한 고유 키를 설정한다. 이는 캐시된 데이터를 식별하는 데 사용된다. 여기서는 실행 중인 운영 체제(os), 빌드 버전, 그리고 package-lock.json 파일의 해시 값을 조합하여 키를 생성한다.

restore-keys: 캐시된 데이터를 복원할 때 사용할 키를 설정한다. 여기서는 이전에 생성된 캐시를 복원하는 데 사용된다. 먼저 이전 빌드의 운영 체제 및 빌드 버전과 일치하는 캐시를 찾고, 그 다음에는 단순히 운영 체제에 해당하는 캐시를 찾는다. 이렇게 함으로써 이전 빌드에서 사용된 캐시를 재사용할 수 있다.

이렇게 설정된 cache 액션은 노드 프로젝트의 node_modules 디렉토리를 캐싱하여 빌드 시간을 최적화한. 캐시된 데이터는 액션에 지정된 키와 복원 키를 사용하여 식별되고 관리된다.

3 - 의존성 패키지 설치

이 작업은 종속성을 설치하는 명령어 npm install을 실행한다. 그러나 조건문 if: steps.cache.outputs.cache-hit != 'true'에 따라, 이 작업은 이전에 캐시된 종속성이 존재하지 않을 때만 실행된다.

if: steps.cache.outputs.cache-hit != 'true': 이 작업을 실행하기 전에 조건을 확인한다. 여기서는 이전 단계에서 생성된 캐시가 존재하지 않으면(즉, 캐시가 히트되지 않으면) 이 작업을 실행한다.

steps.cache.outputs.cache-hit은 이전 단계에서 생성된 캐시 액션의 출력 중 하나인 cache-hit을 참조한다. 이 값은 캐시가 히트되었는지(true) 여부를 나타낸다. 만약 캐시가 히트되지 않았다면, 이 작업을 실행한다.

run(npm install): 조건이 충족되면, 즉 캐시가 히트되지 않았을 때, 이 명령어를 실행하여 종속성을 설치한다. npm install은 Node.js 프로젝트의 종속성을 설치하는 명령어이다.

이렇게 설정된 작업은 이전에 캐시된 종속성이 존재하지 않을 때만 종속성을 설치한다. 이를 통해 불필요한 종속성 설치 과정을 피하고 빌드 시간을 최적화할 수 있다.

4 - 빌드

run(CI='false' npm run build): npm run build 명령어를 실행하여 프로젝트를 빌드한다.

CI='false': 이 명령어는 CI(Continuous Integration) 모드를 비활성화한다. 보통 CI 환경에서 빌드할 때, 특정 환경 변수들이 자동으로 설정되는데, 경고를 오류로 처리한다. 이는 일반적으로 코드의 품질을 유지하기 위한 방법 중 하나로, CI 환경에서 자주 사용된다. 경고를 무시하지 않고, 반드시 해결하도록 하기 위해 경고를 오류로 취급하는데 여기서는 이를 비활성화 한다. 이렇게 함으로써, 빌드 과정에서 CI에 특화된 동작을 방지할 수 있습니다.

이렇게 설정된 작업은 프로젝트를 빌드하고, CI 모드를 비활성화하여 특정 환경에서 발생할 수 있는 문제를 방지한다.

5 - aws에 접근하기 위한 권한을 받아온다

uses(aws-actions/configure-aws-credentials@v4): AWS Actions에서 제공하는 configure-aws-credentials 액션을 사용. 이 액션은 AWS credentials를 구성하는 데 사용된다.

aws-access-key-id: AWS 계정의 액세스 키 ID를 설정. ${{ secrets.AWS_ACCESS_KEY_ID }}는 GitHub 저장소의 Secrets에 저장된 값으로 대체됨.

aws-secret-access-key: AWS 계정의 비밀 액세스 키를 설정. ${{ secrets.AWS_SECRET_ACCESS_KEY }}는 GitHub 저장소의 Secrets에 저장된 값으로 대체됨.

aws-region: AWS 리전을 설정합니다. ${{ secrets.AWS_DEFAULT_REGION }}는 GitHub 저장소의 Secrets에 저장된 값으로 대체됨.

이렇게 설정된 작업은 AWS credentials를 구성하여 AWS 리소스에 접근할 수 있도록 한다. GitHub의 Secrets를 통해 안전하게 액세스 키와 비밀 액세스 키를 관리하고, 해당 액션을 사용하여 이를 AWS credentials로 설정한다. 이를 통해 워크플로우에서 AWS 리소스를 사용할 수 있게 된다.

AWS credentials(인증 정보)?

AWS credentials(인증 정보)는 Amazon Web Services(AWS) 리소스에 액세스하기 위해 필요한 정보. 이것은 주로 다음과 같은 두 가지 요소로 구성된다.

액세스 키 ID: AWS 계정에 연결된 고유한 액세스 키 ID. 이 키는 AWS API를 호출할 때 클라이언트를 식별하는 데 사용된다. 이 키는 일종의 사용자 이름과 같은 역할을 한다.

비밀 액세스 키: 액세스 키 ID와 관련된 보안 비밀번호. 액세스 키 ID와 함께 사용되어 AWS 리소스에 대한 액세스를 인증하는 비밀번호 역할을 한다. 이 비밀 액세스 키는 AWS API를 호출할 때 사용자가 실제로 인증되는 데 사용된다. 액세스 키 ID와 함께 사용되므로, 액세스 키 ID만 있으면 AWS 리소스에 액세스할 수 없다. 항상 액세스 키 ID와 비밀 액세스 키가 함께 사용되어야 한다.

6 - S3에 build 파일 배포

AWS S3에 정적 파일을 배포하는 작업을 정의하고 있다.

S3에 파일 동기화

run(aws s3 sync ./build s3://${{ secrets.AWS_BUCKET_NAME }} --delete): aws s3 sync 명령어를 사용하여 로컬 빌드 디렉토리(./build)의 파일을 AWS S3 버킷으로 동기화한다.

./build: 로컬에서 빌드된 정적 파일이 저장된 디렉토리를 나타낸다.

s3://${{ secrets.AWS_BUCKET_NAME }}: 배포할 S3 버킷의 경로를 지정. ${{ secrets.AWS_BUCKET_NAME }}는 GitHub 저장소의 Secrets에 저장된 S3 버킷 이름을 참조한다.

이렇게 설정된 작업은 로컬에서 빌드된 정적 파일을 AWS S3로 배포한다. 이를 통해 웹 애플리케이션의 정적 데이터를 호스팅하고 전 세계적으로 액세스할 수 있게 된다.

7 - CloudFront 캐시 무효화

AWS CloudFront에 대한 캐시 무효화를 수행하는 작업을 정의하고 있다. cloudfront로 배포되는 파일은 기본설정 상 24시간동안 캐시가 유지된다. 이 말은, 배포 후 S3에는 최신 정적리소스가 올라가있지만 엣지로케이션엔 이전 파일이 올라가있는 상태라는 의미이다. 그래서 바로 변화가 반영되길 바란다면 invalidation을 해주면 된다.

CloudFront 캐시 무효화 명령 실행

run(aws cloudfront create-invalidation --distribution-id ${{ secrets.AWS_CLOUDFRONT_ID }} --paths "/*"): AWS CLI를 사용하여 CloudFront 캐시를 무효화하는 명령을 실행.

aws cloudfront create-invalidation: AWS CLI를 사용하여 CloudFront 캐시 무효화를 수행하는 명령.

--distribution-id ${{ secrets.AWS_CLOUDFRONT_ID }}: 캐시 무효화를 적용할 CloudFront 배포(디스트리뷰션)의 ID를 지정. ${{ secrets.AWS_CLOUDFRONT_ID }}는 GitHub 저장소의 Secrets에 저장된 CloudFront 배포 ID를 참조.

--paths "/": 캐시 무효화를 적용할 경로를 지정합니다. "/"는 모든 파일 및 폴더를 의미하며, 모든 캐시를 무효화한다.

이렇게 설정된 작업은 CloudFront 캐시 무효화를 수행하여 변경된 정적 데이터가 사용자에게 신속하게 전달되도록 한다. 새로운 파일이나 변경된 파일이 업로드되었을 때 CloudFront 캐시를 즉시 무효화함으로써 최신 버전의 데이터를 제공할 수 있다.

주요 키워드 설명

  • name: 워크플로우의 이름.
  • on: 워크플로우를 트리거하는 이벤트를 지정한다. 이 예제에서는 push 이벤트로, main 브랜치에 푸시될 때마다 트리거된다.
  • jobs: 워크플로우에서 실행될 작업들을 정의한다.
  • runs-on: 작업이 실행될 러너 환경을 지정한다. 여기서는 최신 Ubuntu 버전을 사용한다.
  • steps: 작업 내에서 실행될 단계를 정의한다.
    • uses: GitHub Marketplace에서 제공되는 사전 정의된 액션을 사용하는 경우 사용합니다. 액션을 사용할 때 해당 액션의 위치를 나타낸다. 예를 들어, actions/checkout 액션은 코드를 체크아웃 한다.
    • run: 셸 명령어를 실행한다. ex) npm install,npm test...

➡️ Build Error 수정 과정

YAML파일 코드를 push 했더니 이미지에 처럼 많은 에러가 발생 했는데 Error 처리 과정에 대해서 어떻게 해결했는지 작성하고자 한다.

1. 첫 번째 Error

Treating warnings as errors because process.env.CI = true:

  • 이 부분은 현재 환경 변수가 process.env.CI = true로 설정되어 있기 때문에 경고를 오류로 처리하고 있다는 것을 의미한다.
  • process.env.CI는 환경 변수를 나타내며, CI 서버에서 자동으로 설정되는 경우가 많다.
  • 경고를 오류로 처리하는 것은 일반적으로 코드의 품질을 유지하기 위한 방법 중 하나로, CI 환경에서 자주 사용된다. 경고를 무시하지 않고, 반드시 해결하도록 하기 위해 경고를 오류로 취급한다.

Most CI servers set it automatically:

  • 대부분의 CI 서버(Jenkins, GitHub Actions, GitLab CI 등)는 CI 환경 변수를 자동으로 설정한다.
  • 이 환경 변수는 CI 환경에서 실행되고 있음을 나타내며, 이를 통해 빌드 스크립트나 테스트 도구가 CI 모드에서 동작하도록 할 수 있다.

원인

  • CI 환경: CI 서버에서 빌드를 실행할 때 CI 환경 변수가 true로 설정된다.

  • 경고 처리: 빌드 도구(예: TypeScript, ESLint 등)가 경고를 오류로 처리하도록 설정되어 있다. 이는 코드 품질을 높이기 위한 일반적인 방법이다.

  • 개발과 CI 환경의 차이: 로컬 개발 환경에서는 경고를 단순히 경고로 처리하지만, CI 환경에서는 경고를 오류로 처리하여 모든 경고를 해결하지 않으면 빌드가 실패하게 된다.

결론은, process.env.CI가 true로 설정되어 있어서 CI환경에서 process.env.CI변수가 true로 설정되어 있어서 경고도 오류로 처리하기 때문에 build에 실팼다. 그래서

해결 방법

이렇게 build 단계에서 원래는 'npm run build' 명령어만 작성을 해줬었는데, 그 앞에 CI='false'문구를 추가 해줬다.

2. 두 번째 Error

이 에러 메시지는 AWS S3(Simple Storage Service)에서 ListObjectsV2 작업을 호출할 때 AccessDenied 오류가 발생했음을 나타낸다. 이는 S3 버킷의 객체 목록을 가져오려고 시도할 때 권한이 부족해서 발생하는 오류이다.

원인

요청을 실행하는 IAM 사용자 또는 역할이 S3 버킷에서 s3:ListBucket 권한을 가지고 있지 않기 때문.

ListObjectV2?

ListObjectsV2는 Amazon S3의 API 중 하나로, S3 버킷 내의 객체 목록을 가져오는 데 사용된다. 이 API 호출을 통해 특정 버킷에 저장된 객체(파일)의 목록을 검색할 수 있는데ListObjectsV2는 ListObjects API의 개선된 버전이다.

해결 방법

버킷 정책의 정책생성기를 통해서 Action에 S3:ListBuket 권한을 추가해줌.

Action 필드의 역할

Amazon S3 버킷 정책에서 Action 필드는 정책이 허용하거나 거부하는 특정 작업(액션)을 정의한다. 이는 AWS Identity and Access Management (IAM) 정책의 중요한 구성 요소 중 하나로, 사용자가 S3 버킷 또는 객체에 대해 수행할 수 있는 작업을 명시한다.

역할 및 기능

1. 작업 지정

  • Action 필드는 사용자가 수행할 수 있는 S3 작업을 지정한다. 예를 들어, 객체를 업로드, 다운로드, 삭제 또는 목록화할 수 있는 권한을 설정한다.

2. 권한 부여 또는 거부

  • Effect 필드와 함께 사용하여 작업을 허용(Allow)하거나 거부(Deny)할 수 있다.

3. 작업의 범위 설정

Action 필드를 통해 특정 작업에 대한 세밀한 권한 제어가 가능하다. 예를 들어, 버킷 수준의 작업(s3:ListBucket)과 객체 수준의 작업(s3:GetObject)을 분리할 수 있다.

일반적인 S3 작업 예시

  • 버킷 수준 작업
    • s3:ListBucket: 버킷 내 객체 목록을 나열한다.
    • s3:CreateBucket: 새 버킷을 생성한다.
    • s3:DeleteBucket: 기존 버킷을 삭제한다.
  • 객체 수준 작업
    • s3:GetObject: 버킷 내 객체를 다운로드한다.
    • s3:PutObject: 버킷 내 객체를 업로드한다.
    • s3:DeleteObject: 버킷 내 객체를 삭제한다.
    • s3:ListObjectsV2: 버킷 내 객체 목록을 나열한다 (버킷 정책에서 사용).

3. 세 번째 Error

원인

이 에러 메시지는 Amazon S3 버킷에 파일을 업로드 또는 삭제하려고 할 때 발생한 접근 권한 문제를 나타낸다. 위에 이미지에서 보면 run의 명령어에 --delete가 있는데 DeleteObject에 대한 권한이 S3버킷에 없다. 그리고 PutObject권한 같은 경우에는, aws s3 sync 명령어가 로컬 디렉토리에 있는 파일을 S3 버킷으로 업로드하여 동기화할 때, S3에 파일을 업로드하기 위한 권한이 필요하다. 이럴 때 작업은 PutObject 권한을 필요로 한다.
그러니까 PutObject 및 DeleteObject 작업에 대한 권한이 없어서 발생하는 "Access Denied" 에러.

해결방법

위 두 번째 에러에서 처럼 S3버킷 정책의 Action필드에 PutObject와 Deleteobject권한을 추가해줬다.

4. 네 번째 Error

원인

이 에러 메시지는 aws cloudfront create-invalidation 명령어를 실행할 때 발생하는 접근 권한 문제를 나타낸다. 구체적으로는 cloudfront:CreateInvalidation 작업에 대한 권한이 없어 발생하는 "Access Denied" 에러. 에러의 원인은 IAM 사용자 woon에게 cloudfront:CreateInvalidation 작업을 수행할 권한이 없기 때문이다. CloudFront 배포에서 특정 경로의 캐시를 무효화하려면 CreateInvalidation 권한이 필요하다.

해결 방법

이 문제를 해결하려면 IAM 사용자 또는 역할에 cloudfront:CreateInvalidation 권한을 부여해야 한다.

IAM의 woon사용자에서 권한 정책 부분에서 "권한 추가"의 "인라인 정책 생성"클릭.

권한 지정에서 나는 JSON형식으로 확인하고 싶어서 JSON을 설정하고 "자겁 추가" 부분에서 CloudFront의 CreateInvalidation을 추가해줬다. 그리고 리소스 추가를 선택하는데 우선,

배포한 cloudfront의 아이디를 선택해서 이 아이디의 ARN을 복사한다.

그리소 리소스 추가 부분으로 돌아와서 리소스 유형을 distribution을 선택하고 리소스 ARN에는 cloudfront에서 복사한 ARN을 붙여넣기 한다. 그리고 "리소스 추가" 클릭.

리소스 ARN을 추가하는 이유?

IAM 정책에서 Resource 필드는 정책이 적용되는 AWS 리소스를 지정한다. 이는 정책의 범위를 정의하는 중요한 부분으로, 특정 리소스에 대한 작업을 허용하거나 거부할 수 있게 한다.

CloudFront에서 CreateInvalidation 작업을 수행하려면 해당 작업이 어떤 배포(Distribution)에서 수행될지 명확히 지정해야 한다. 따라서 Resource 필드에 배포의 Amazon Resource Name (ARN)을 지정한다.

예시

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "cloudfront:CreateInvalidation",
      "Resource": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
    }
  ]
}
  • 위 정책은 계정 123456789012의 EDFDVBD6EXAMPLE이라는 CloudFront 배포에 대해 CreateInvalidation 작업을 허용한다.

그러니까 결론적으로 필요한 리소스에만 정확한 권한을 부여할 수 있게하기 위함이다. 이를 통해 권한 남용을 방지하고, 보안 사고를 줄일 수 있다. 그래서 위에서는 CloudFront 배포에서 CreateInvalidation 작업을 수행할 때, 특정 배포의 ARN을 Resource 필드에 지정하여 권한을 제한하고 보안을 강화하고자 하는 것이다.

그럼 "다음"을 클릭하고 정책 편집이 완료된다.

관리형 정책? 인라인 정책?

관리형 정책 (Managed Policy)

정의 및 관리

  • 관리형 정책은 IAM 정책 라이브러리에서 별도로 정의하고 저장된다.
    하나의 정책을 여러 사용자, 그룹 또는 역할에 적용할 수 있다.
    정책을 수정하면 그 정책이 적용된 모든 사용자, 그룹, 역할에 즉시 반영된다.

재사용성

  • 관리형 정책은 여러 사용자나 그룹에 재사용될 수 있다.
    예를 들어, AmazonS3FullAccess 관리형 정책을 사용자 woon에게도, 사용자 woon2에게도 적용할 수 있다.

적용 예시

  • AmazonS3FullAccess라는 관리형 정책을 사용자 woon과 woon2에게 적용할 수 있다. 이 경우, 동일한 정책이 두 사용자에게 적용된다.

인라인 정책 (Inline Policy)

정의 및 관리

  • 인라인 정책은 특정 사용자, 그룹 또는 역할에 직접 정의된다.
    인라인 정책은 해당 사용자, 그룹 또는 역할과 강하게 결합되어 있으며, 다른 사용자나 그룹에 재사용할 수 없다.
    특정 사용자, 그룹 또는 역할에 특화된 권한을 정의할 때 사용된다.

재사용성

  • 인라인 정책은 다른 사용자나 그룹에 재사용될 수 없다.
    예를 들어, 사용자 woon에게만 특정 권한이 필요한 경우, 이 사용자에 대한 인라인 정책을 정의할 수 있다. 이 정책은 woon2에게 적용될 수 없다.

적용 예시

  • 사용자 woon에게 인라인 정책으로 cloudfront:CreateInvalidation 권한을 부여할 수 있다. 이 정책은 사용자 woon2에게는 직접 적용되지 않는다.

이렇게 오류까지 모두 해결해서

성공적으로 배포를 완료할 수 있었다!! 과정은 간단한데 AWS와 마찬가지로 Github Actions의 흐름과 역할을 이해하는데 시간이 정말 오래 걸렸다. 그때그때 이해한다고 여러 자료를 찾아봤지만 완성하고 나니 모든 게 뒤죽박죽 돼서 머리에서 정리가 되질 않는다.. 그래도 한 번의 과정을 겪고 나니 AWS의 복습도 되고 배포의 전반적인 프로세스를 익힐 수 있게 돼서 좋았다. 하지만 역시 한 번의 과정은 온전한 내 것이 아니기 때문에 반복적인 익힘이 필요하다 생각된다.

출처

0개의 댓글