yunicornlab

Github actions로 CI/CD 구현하기 - Vercel 배포와 함께 본문

Development/Git

Github actions로 CI/CD 구현하기 - Vercel 배포와 함께

yunicornlab 2024. 12. 13. 02:45
반응형

이번에 시작한 프로젝트를 Vercel로 배포하기로 했다.

그러던 중 빌드와 테스트, 배포의 과정을 자동화하는 CI/CD를 도입해보고 싶다는 생각이 들었다.

Jenkins와 같은 도구도 있지만 좀 더 쉽게 접근할 수 있는 Github Actions를 사용해보기로 했다.

CI/CD란?

  • CI : Continuous Integration (지속적 통합)
    • 코드 변경 사항을 자주 병합(Merge)하고, 자동으로 빌드(Build) 및 테스트(Test)하는 프로세스
  • CD : Continuous Delivery/Deployment (지속적 제공/배포)
    • (Delivery) CI의 확장으로, 자동화된 빌드와 테스트를 통과한 코드를 항상 프로덕션에 배포할 준비가 된 상태로 유지(수동 배포)
    • (Deployment) 모든 검증된 코드 변경 사항을 수동 승인 없이 자동으로 프로덕션에 배포(자동 배포)

소프트웨어 개발, 테스트, 배포 프로세스를 자동화하는 방법론(또는 도구)를 말한다.

처음에 설명만 봤을 때보다 직접 구현해보니 무엇을 하고자 하는 것인지가 이해됐다.

사실 이번 프로젝트에서 백엔드 부분까지 커버하기 위해 Supabase라는 서버리스 서비스를 사용하기 때문에 진정한 CI/CD 의미와는 조금 다르긴 하지만 그래도 의미있는 작업이었다.

 

기능 개발을 할 때마다 빌드, 테스트, 배포까지 진행하는 것은 상당히 많은 작업이 요구된다. 이것을 자동화하는 것이 바로 CI/CD다.

예를 들어 "내가 main branch에 push하면 Node.js 버전 20, 22에서 따로 빌드, 테스트를 진행해주고, 문제가 없으면 배포까지 진행해줘" 이런 식으로 명령을 작성해놓는 것이다.

개발은 결국 배포까지 문제없이 잘 되어야 사용자에게 서비스가 전달이 되기 때문에 실제 운영하는 서비스에서는 중요한 개념이라고 생각한다.

 

Github Actions CI/CD 구현 순서

1. Actions 탭 클릭

 

2. 원하는 패키지 검색 및 configure 선택

나는 Node.js를 선택했다.

 

3. 생성된 ./github/workflows/이름.yml 파일에 workflow 작성하기

 

기본 템플릿은 아래와 같다.

# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: Node.js CI

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18.x, 20.x, 22.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - uses: actions/checkout@v4
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    - run: npm ci
    - run: npm run build --if-present
    - run: npm test

 

4. Commit하면 끝!

 

커밋하면 가장 루트 경로에 .github/workflows가 자동으로 생성되고 그 안에 내가 작성한 yml 파일이 저장되어있다.

 

 

yml 파일 구성하기

https://docs.github.com/ko/actions

 

GitHub Actions 설명서 - GitHub Docs

GitHub Actions를 사용하여 리포지토리에서 바로 소프트웨어 개발 워크플로를 자동화, 사용자 지정 및 실행합니다. CI/CD를 포함하여 원하는 작업을 수행하기 위한 작업을 검색, 생성 및 공유하고 완

docs.github.com

아래 코드는 내가 작성한 yml 최종본이다.

# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs

name: CI/CD with GitHub Actions

env:
  VITE_SUPABASE_URL: ${{ secrets.VITE_SUPABASE_URL }}
  VITE_SUPABASE_ANON_KEY: ${{ secrets.VITE_SUPABASE_ANON_KEY }}
on:
  push:
    branches: [ "main", "develop", "release" ]
  pull_request:
    branches: [ "release", "hotfix" ]

jobs:
  build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20.x, 22.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - name: Checkout source code
      uses: actions/checkout@v4

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'yarn'

    - name: Install dependencies
      run: yarn

    - name: Build the project
      run: yarn build

        
  Deploy-Preview:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v3
      
      - name: Install Vercel CLI
        run: yarn global add vercel@latest
        
      - name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Build Project Artifacts
        run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Deploy Project Artifacts to Vercel
        run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}

 

ci.yml과 cd.yml 파일로 나눌까 하다가 작업이 복잡하지 않아서 cicd.yml 파일 하나로 작성했다.

나중에 백엔드 작업까지 포함해서 길어진다면 나누어볼 생각은 있지만 지금은 필요해보이진 않았다.

 

env: 부분은 사실 실제로 쓰이는 부분에만 적어놓아도 되는데 보기 편하도록 맨 위에 적어보았다.

그래서 on: 부분부터가 진짜 시작이라고 생각하면 된다.

on: 

on:
  push:
    branches: [ "main", "develop", "release" ]
  pull_request:
    branches: [ "release", "hotfix" ]

 

on: 에는 깃허브에서 인지할 이벤트를 적는 부분이다.

https://docs.github.com/ko/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows

 

워크플로를 트리거하는 이벤트 - GitHub Docs

GitHub에 대한 특정 작업이 예약된 시간에 발생하거나 GitHub 외부의 이벤트가 발생할 때 실행되도록 워크플로를 구성할 수 있습니다.

docs.github.com

적는 방식도 여러가지 있지만, 우리는 브랜치를 기준으로 생각했기 때문에 위 코드처럼 적었다. 

코드의 의미는 main, develop, release 브랜치에 push가 되었을 때와 release, hotfix 브랜치에 pull_request가 생성되었을 때(실제로는 공식문서에 나와있는대로 opened, synchronize, or reopened 되었을 때) 해당 워크플로우가 작동하도록 해달라는 것이다.

 

우리는 Git Flow 브랜치 전략을 채택했기 때문에 main, develop, feature, release, hotfix 이렇게 5 종류의 브랜치를 사용하기로 했고 그림으로 표현해서 pull request가 필요한 부분과 push 이벤트가 필요한 부분을 생각해보았다.

검은색 화살표는 파생 브랜치를 나타내고, 주황색 화살표는 실제 작업 후 pull_request 생성 또는 merge 작업을 나타낸다.

그래서 main, develop, release 브랜치에서는 merge로 통합하는 과정이 많을 것 같아서 push 이벤트로 설정했고,

release와 hotfix 브랜치에서는 pull_request 이벤트를 설정했다. 

feature도 pull_request로 고민하다가 develop으로 충분할 것 같아서 제외했다.

 

jobs:

이 부분에는 큰 단위의 job을 step별로 지정할 수 있다.

내가 작성한 코드에서는 build와 Deploy-Preview라는 두 개의 job을 설정했다.

각 job의 이름은 맨 위(jobs 아래)에 적어주면 된다.

그리고 어떤 환경에서 실행할 것인지를 runs-on에 적어주면 된다.

기본 템플릿에서 ubuntu-latest가 적혀있다.

strategy 부분에는 테스트해볼 node.js 버전을 적었다.

그 아래에 이제 어떤 흐름으로 동작시킬 것인지 step을 적으면 된다.

 

Build 작업

build:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [20.x, 22.x]
        # See supported Node.js release schedule at https://nodejs.org/en/about/releases/

    steps:
    - name: Checkout source code
      uses: actions/checkout@v4

    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'yarn'

    - name: Install dependencies
      run: yarn

    - name: Build the project
      run: yarn build

이 코드에서는 4개의 step이 있다.

주의할 점은 각 스텝별로 하이픈('-')은 하나 두면서 run이나 uses 둘 중에 하나는 꼭 있어야 한다. 

그렇지 않으면 "every step must define a uses or run key" 라는 에러가 발생한다.

각 스텝에서 사용하는 토큰을 evn: 부분에 적어도 된다. (나는 일단 맨 위에 적어놓았다.)

위 코드의 스텝은 다음과 같다.

checkout

-> Node.js를 strategy 부분에 지정해놓은 버전들로 각각 실행

-> yarn 명령어를 통해 dependencies를 설치

-> yarn build 명령어를 통해 프로젝트를 빌드

run은 명령어 자체를 적으면 되고, uses는 사용할(호출할) github actions를 적으면 된다. (with 키워드를 사용해 Action에 입력 값을 전달할 수 있다고 한다.)

 

Deploy 작업

Deploy-Preview 작업에서는 vercel에서 배포를 진행하도록 했다.

물론 vercel에서 원래 github와 연동해서 자동 배포가 된다.

하지만 위의 build job에서 빌드와 테스트 작업이 문제 없이 완료된다면 vercel에 배포가 되도록 하기 위해 아래 코드를 작성했다.

  Deploy-Preview:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v3
      
      - name: Install Vercel CLI
        run: yarn global add vercel@latest
        
      - name: Pull Vercel Environment Information
        run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Build Project Artifacts
        run: vercel build --token=${{ secrets.VERCEL_TOKEN }}
        
      - name: Deploy Project Artifacts to Vercel
        run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }}

 

그래서 이번엔 build 작업과 다르게 needs: build 가 추가되었다.

이 의미는 build 작업이 무사히 통과되었을 때에만 이 작업을 진행한다는 것이다.

needs를 추가하지 않으면 Actions 탭에서 확인했을 때 아래처럼 작업이 따로 놀지만

needs를 추가하면 아래처럼 연결이 된다.

이후는 동일하다. step만 나열해보면

checkout

-> yarn global add vercel@latest 명령어를 통해 vercel CLI 설치

-> vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} 명령어를 통해 Vercel 환경 정보 가져오기(vercel token을 통해 인식)

-> vercel build --token=${{ secrets.VERCEL_TOKEN }} 명령어를 통해 프로젝트 빌드

-> vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} 명령어를 통해 빌드된 프로젝트 파일을 vercel 서버로 업로드해서 배포 (다시 빌드하지 않고 이전에 빌드된 파일을 그대로 사용함)

< 주의할 점 >
로컬 터미널에서는 yarn add global ~~ 으로 작성해도 잘 실행됐는데,
yml 파일에 작성할 때는 yarn global add ~~ 로 작성해야 에러 발생하지 않고 잘 실행된다.

 

여기서 더 설명할 부분이 생겼다.

github secrets와 vercel token 부분이다.

 

GitHub Secrets

내가 작성한 yml 파일을 보면 ${{ secrets.VITE_SUPABASE_ANON_KEY }} 이런 부분이 있다.

여기서 secrets이 github secrets를 의미하는 것이다.

 

GitHub Secrets는 GitHub Actions에서 민감한 정보를 안전하게 저장하고 사용하는 기능으로, 주로 API 키, 액세스 토큰, 암호와 같은 비밀 정보를 저장하여 워크플로우에서 활용할 수 있다.
GitHub Secrets는 GitHub의 암호화된 스토리지에 안전하게 저장되고, 워크플로우 실행 시에만 액세스할 수 있다.

 

등록하는 위치는 레포지토리의

Settings > (Security 카테고리) Secrets and variables > Actions > Repository secrets 위치에 있다.

(Environment secrets이 아니라 아래 Repository secrets에 넣어야 한다.)

여기에서 New repository secret 버튼을 클릭해서 등록해주면 된다.

 

Vercel에서 필요한 키

vercel에서는 공식문서에 가보면 VERCEL_ORG_ID, VERCEL_PROJECT_ID, VERCEL_TOKEN 이 세 개의 토큰을 모두 사용한다.

https://vercel.com/guides/how-can-i-use-github-actions-with-vercel

 

How to Use GitHub Actions to Deploy to Vercel

Learn how to use GitHub Actions as your CI/CD provider to deploy to Vercel, including support for GitHub Enterprise Server.

vercel.com

그런데 사실 VERCEL_ORG_ID와 VERCEL_PROJECT_ID는 없어도 잘 동작한다....!🙃

VERCEL_TOKEN만 있어도 문제 없이 동작했다.

아마도 프로젝트나 organization이 많아질 경우에는 특정해서 인식하기 어려울 수 있기 때문에 명확하게 알려주는 것 같다.

하지만 일단 우리 프로젝트는 잘 인식하는 것 같아서 넣지는 않았다.

 

Vercel Token 발급하기

하지만, VERCEL_TOKEN은 꼭 필요하다!

https://vercel.com/account/settings/tokens

 

Dashboard

 

vercel.com

생성하는 위치는 vercel에서 프로필 사진을 클릭하면 Account Settings가 나온다.

 

여기서 Tokens로 들어가면 Create Token 하는 부분이 있다.

 

Name, Scope, Expiration을 설정해주고 Create를 클릭하면 Vercel_Token이 생성된다.

이걸 GitHub Secrets에 등록해서 사용해주면 된다.

반응형

'Frontend > Git' 카테고리의 다른 글

[GitHub] 깃허브 프로필 꾸미기 - Overview  (0) 2024.06.10