ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [CI/CD] Vue.js GitHub Actions 적용기 #1 (prod)
    CICD 2022. 8. 6. 15:52

    회사에서 기존에 모든 프로젝트를 GitLab을 통해 관리하고 있었는데 여러 이유로 GitHub으로 이전하기로 결정했다. 그래서 GitLab에 구축 해놓은 CI/CD를 GitHub에 맞게 다시 구축해야 됐고 그 일을 나도 맡게 되었다.

     

    GitLab CI/CD 작업을 내가 직접 해보진 않아서 정확히는 모르지만 GitHub Actions를 사용하면서 내가 느낀 점은 GitLab은 상대적으로 내가 직접 스크립트로 로직을 만들어줘야 하는 것들이 많은 반면에 GitHub Actions는 대부분의 기능을 플러그인으로 제공하기 때문에 사용하는 개발자 입장에서는 그냥 갖다가 쓰면 되기 때문에 매우 편했다.

     

    워크플로우는 총 3개다.

     

    1. prod를 deploy하는 워크플로우
    2. sandbox, qa를 deploy하는 워크플로우
    3. test를 하는 워크플로우

     

    이 글에서는 먼저 prod의 워크플로우를 다룬다!

     

    prod의 워크플로우

    1. tag가 push되면 동작
    2. repository checkout
    3. node setup 및 cache
    4. tag명 strip_v
    5. package.json, .env의 version을 tag에 맞게 update
    6. ci
    7. lint
    8. build
    9. upload to s3
    10. cloudfront invalidate
    11. commit, push
    12. send slack message

    이렇게 나열하고 보니 내용이 많아 보이지만 코드로 보면 의외로 간단하다.

     

    1. tag가 push되면 동작

    name: deploy-prod
    on:
      push:
        tags:
          - v[0-9]+.[0-9]+.[0-9]+

    tag가 v[0-9]+.[0-9]+.[0-9]+ 형식에 맞게 (ex : v1.0.1) push 되면 deploy-prod 워크플로우가 동작하게 된다.

     

     

    2. repository checkout

    jobs:
      deploy-prod:
        runs-on: ubuntu-latest
        steps:
          - name: checkout
            uses: actions/checkout@main

    별 거 없다. GitHub Actions에서 제공하는 actions/checkout을 사용하면 해당 repository로 checkout한다. (GitHub 최고 👍🏻)

     

     

    3. node setup 및 cache

    - name: setup node
      uses: actions/setup-node@main
      with:
        node-version: 16
        cache: 'npm'

    node setup과 의존성 cache도 그냥 플러그인을 가져다가 쓰면 되고 환경에 맞게 버전과 같은 변수만 설정해주면 된다. 이렇게 하면 해당 워크플로우 환경에 명시된 버전으로 node가 설치되고 cache도 알아서 해준다.

     

     

    4. tag명 strip_v

    - name: get tag
      id: tag
      uses: dawidd6/action-get-tag@master
      with:
        strip_v: true

    push된 tag명에서 'v'를 제거해서 추출하는 과정이다. (ex : v1.0.1이 push되면 1.0.1로 추출) 이것도 어느 개발자가 만들어 놓은 플러그인이다. 좋은데?.. 이렇게 추출한 이유는 다음에 나올 작업들에서 v를 제외한 태그명이 필요하기 때문이다.

     

     

    5. package.json, .env의 version을 tag에 맞게 update

    - name: update version of package.json
      uses: jossef/action-set-json-field@master
      with:
        file: package.json
        field: version
        value: ${{ steps.tag.outputs.tag }}
    
    - name: update VUE_APP_PRODUCT_VERSION of .env version
      uses: jacobtomlinson/gha-find-replace@master
      with:
        find: VUE_APP_PRODUCT_VERSION=(\d+\.)(\d+\.)(\d+)
        replace: VUE_APP_PRODUCT_VERSION=${{ steps.tag.outputs.tag }}
        include: ".env"

    요구사항 중 하나가 prod가 deploy 될 때마다 push된 tag에 맞게 package.json의 version과 .env의 version을 tag명에 맞게 update하는 것이었다.

     

    package.json의 version

    // package.json
    {
      "name": "my-project",
      "version": "1.0.0", // << 여기 version
      "scripts": {
         ...
    },
    ...

     

    .env의 version

    // .env
    ...
    VUE_APP_PRODUCT_VERSION=1.0.0 // << 여기 version
    ...

    위 기능을 구현하기 위해서도 플러그인 2개를 가져다가 파라미터만 적절히 세팅해서 구현할 수 있었다. (${{ steps.tag.outputs.tag }}가 위에서 strip_v로 추출한 tag이다.)

     

     

    6, 7, 8 : ci, lint, build 

    - name: ci
      run: npm ci
    
    - name: lint
      run: npm run lint
    
    - name: build
      run: npm run build -- --mode prod

    이제 소스를 업로드 하고 배포하기 위해

    1. ci (의존성 설치)
    2. lint (소스 오류 체크)
    3. build

    를 진행해준다.

     

    9. upload to s3

    build한 소스를 AWS S3에 업로드하는 과정이다.

    - name: upload to s3
      run: aws s3 sync --region $AWS_REGION dist $AWS_S3_URL/prod/

    매우 간단하다. 이렇게 하면 S3에 build한 파일들이 업로드 된다.

     

    여기에서 사용한 $AWS_REGION과 $AWS_S3_URL는 GitHub Repository에서 Secret 변수로 설정해준 값들이고 이 워크플로우에서 사용하기 위해 이 워크플로우 yaml 파일 상단에 아래와 같이 선언해놨다.

    env:
      AWS_ACCESS_KEY_ID: ${{ secrets.BASE_AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.BASE_AWS_SECRET_ACCESS_KEY }}
      AWS_REGION: ${{ secrets.BASE_AWS_REGION }}
      AWS_S3_URL: ${{ secrets.AWS_S3_URL }}
      SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

     

     

    10. cloudfront invalidate

    - name: invalidate cloudfront
      run: aws cloudfront create-invalidation --distribution-id 블라블라 --paths "/index.html"

     

    cloudfront는 AWS에서 제공하는 CDN서비스이다. 

     

    위에서 S3에 빌드된 파일들을 업로드 했고, 새로 빌드된 파일들을 클라이언트들이 요청할 수 있게 cloudfront에서 invalidate를 해준다.

    invalidate는 CDN cache의 값들을 지워주는 과정이라고 생각하면 된다.

     

     

    11. commit, push

    - name: commit
      run: |
        git config --local user.email "cavok699@naver.com"
        git config --local user.name "cavok699"
        git add .
        git commit -m "⬆️ Update version (package.json, .env) to v${{ steps.tag.outputs.tag }}"
    
    - name: push
      uses: ad-m/github-push-action@master
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        branch: prod

    위 5번의 과정(package.json, .env의 version을 tag에 맞게 update)에서 진행한 과정들을 commit하고 push하는 과정이다.

     

    commit하는 과정은 워낙 익숙한 과정이기에 그냥 스크립트로 작성했지만 아마 이것도 찾아보면 플러그인이 있을 것 같다.

    이후 push는 플러그인을 사용해서 작성했다.

     

     

    12. send slack message

    - name: send slack message
      uses: 8398a7/action-slack@v3
      if: always()
      with:
        status: ${{ job.status }}
        fields: repo,message,author,ref,workflow,took
        author_name: ''
    
    - name: send slack message (URL)
      uses: 8398a7/action-slack@v3
      if: success()
      with:
        status: custom
        custom_payload: |
          {
            attachments: [{
              text: '<https://my-project.io/|:house:*my-project - prod*>',
            }]
          }

    배포 이후 결과를 슬랙 메시지로 전송받기 위해 8398a7/action-slack 플러그인을 사용했다.

     

    위 슬랙 메시지는 배포 성공, 실패 여부 상관없이 결과를 알려주기 위함이고,

    아래 슬랙 메시지는 배포가 성공했으면 배포가 된 URL을 알려주기 위해 작성했다.

     

    이렇게 작성해 놓으면 prod를 배포할 때마다 결과를 슬랙 메시지로 알려준다!

     

    -워크플로우 끝-


    결과만 보면 매우 간단한데, 중간중간 여러 삽질이 존재했다. 뭐 당연한 것이지만..

     

    사실 GitHub Actions를 통해 적용했기 때문에 금방 적용할 수 있었다고 생각한다. 워낙 GitHub이 갖고 있는 커뮤니티가 강력해서 매우 다양한 것들을 플러그인으로 제공하고 있었고, 개발하는 내 입장에서는 그냥 가져다가 쓰기만 하면 됐다.

     

    흠.. 사실 요즘 들어 자주 느끼는 생각인데 내가 개발을 하는 것인지? 그냥 라이브러리들을 조립하고 있는 것인지? 잘 모르겠다.. 🤔

     

    옛날에 개발을 안 해봐서 잘은 모르겠지만.. 요즘은 개발이 너무 쉽다는 말에 극 공감한다. 어려운 게 있다면 공식 문서를 읽는 게 제일 어렵다.. 

     

    결론 : 영어 공부하자.

    댓글