GitHub 활용하기
2024-04-20

모던 리액트 Deep Dive를 읽으며 정리한 내용입니다.

  • GitHub는 무료 Git 저장소 서비스를 시작으로
  • GitHub Packages: 패키지를 저장할 수 있는 이미지 레지스트리 서비스
  • Github Projects: 지라와 같이 프로젝트를 관리할 수 있게 도와주는 서비스
  • GitHub Pages: 간단한 웹사이트를 운영할 수 있게 해주는 서비스
  • GitHub Codespaces: 인공지능 코딩 어시스턴스 서비스

까지 다양한 서비스를 제공합니다.

코드 저장소의 역할을 기반으로 CI/CD 같은 자동화, 보안 이슈 점섬, 프로젝트 관리 등 일반적인 웹서비스 관리 및 운영에 필요한 많은 일을 할 수 있고, 이 다양한 기능을 무료로 사용할 수 있습니다.(개인 사용자)

자동화(CI/CD)

  • CI: Continuous Integration 여러 개발자들이 코드에 기여함으로써 코드가 계속해서 진화하고 발전하게 되는데, 이러한 코드의 변화를 모으고 관리하는 코드 중앙 저장소에서, 여러 기여자가 기여한 코드를 계속해서 빌드하고 테스트해 코드의 정합성을 확인하는 과정을 말합니다.

    CI의 핵심은 저장소에서 코드의 변화가 있을 때마다 코드의 정합성을 확인하는 작업이 자동으로 실행되어야 한다는 것 입니다. 여기서 자동으로 실행되어야 하는 작업이란 테스트, 빌드, 정적 분석, 보안 취약점 분석 등이 있습니다.

    이전에는 이러한 CI 환경을 구축하게 위해 젠킨스(Jenkins)를 자주 사용했습니다. 하지만 젠킨스가 CI 환경을 위한 여러가지 기능을 제공하는 무료 솔루션이라는 장점도 있지만 사용하는데 있어서 번거로운 측면도 많았습니다.(설치형 솔루션, 설치 및 유지보수 번거로움)

    그 대안으로 요즘에는 GitHub Actions를 많이 사용하고 있습니다.

GitHub Actions

  • GitHub에서 출시한 SaaS

  • 깃허브 저장소에서 발생하는 다양한 이벤트를 기반으로 깃허브에서 제공하는 가상 환경에서 사용자가 원하는 작업을 수행할 수 있도록 도와주는 서비스

  • ex. 어떤 브랜치에 푸시가 발생하면 빌드를 수행한다 / 특정 브랜치에 메인 브랜치를 대상으로한 PR이 열리면 빌드, 테스트, 정적 분석을 수행한다

  • 본래의 목적은 CI 솔루션을 대체하는 것이 아니었으나 이 서비스의 특징을 활용하여 CI/CD 솔루션을 대체할 수 있다는 것이 알려지면서 CI/CD 서비스로서 사용

  • 물론 젠킨스를 완벽하게 대체하는 수단이라고는 볼 수 없지만 아무튼 유용

  • 기본 개념

    • 러너: 파일로 작성된 깃허브 액션이 실행되는 서버로 따로 지정하지 않으면 공용 깃허브 액션 서버를 이용합니다. 별도의 러너를 구축하여 자체적으로 운영할 수도 있습니다.
    • 액션: 러너에서 실행되는 하나의 작업 단위, yaml 파일로 작성된 내용을 하나의 액션으로 볼 수 있음
    • 이벤트: 액션을 실행시키는 이벤트, 하나 이상의 이벤트를 지정할 수 있음, 특정 브랜치를 지정하는 것도 가능
      • pull_request: PR이 열리거나, 닫히거나, 수정되거나, 할당되거나, 리뷰 요청되는 등 PR 관련 이벤트
      • issues: 이슈가 열리거나, 닫히건, 삭제되거나, 할당 등 이슈 관련 이벤트
      • push: 커밋이나 태그가 푸시될 때 발생하는 이벤트
      • schedule: 저장소에서 발생하는 이벤트와는 별개로 특정 시간(cron)에 실행되는 이벤트
      • ...
    • 잡: 하나의 러너에서 실행되는 여러 스텝의 모음. 하나의 액션에 여러 잡을 생성 가능, 따로 선언하게 없다면 잡들은 병렬로 실행됨
    • 스탭: 잡 내부에서 일어나는 하나하나의 작업, 병렬X
name: Deploy to EB # 액션의 이름
run-name: ${{ github.actor }} # (선택)각 액션을 구별할 수 있는 타이틀 명, github.actor를 사용하면 누가 트리거했는지 확인 가능

on: # (필수)트리거 이벤트
  pull_request: # PR에 대한 이벤트
    branches: [main, staging] # 특정 브랜치 지정
    types: [closed] # PR이 닫혔을 때

jobs: # (필수) 액션에서 수행할 잡
  buildAndTest: # 잡의 이름(임의로 지정)
    name: CI Pipeline
    runs-on: ubuntu-latest # 어느 환경에서 작업이 실행될 지 / 기본을 사용하려면 ubuntu-latest, 설정에서 커스텀 러너 추가 가능
    strategy:
      matrix:
        node-version: ['18.x']

    steps: # 잡에서 수행할 작업
      # uses - 깃허브에서 제공하는 액션을 사용
      - uses: actions/checkout@v3 # 마지막 커밋을 기준으로 체크아웃

      # Initialize Node.js
      - name: Install Node.js ${{ matrix.node-version }} # 스템의 이름을 지정
        uses: actions/setup-node@v3 # 러너에 with에 지정한 버전의 Node를 설치
        with:
          node-version: ${{ matrix.node-version }}

      # Install project dependencies, test and build
      - name: Install dependencies
        run: npm ci
      - name: Run build
        run: npm run build --production

  deploy:
    name: CD Pipeline
    runs-on: ubuntu-latest

    needs: buildAndTest # 위의 buildAndTest가 실행되고 진행된다.
    steps:
      - uses: actions/checkout@v2

      - name: Get branch names
        id: branch-name
        uses: tj-actions/branch-names@v4.9
      - name: 버전 정보 추출(from Branch Name)
        run: echo "BRANCH=$(echo '${{ github.ref }}')"

      ....
  • 이 외에도 깃허브 API를 직접 호출하여 PR에 댓글을 달거나(actions/github-script), 일정 시간마다 특정한 작업을 수행하거나, 배포 서비스와 연동해 자동으로 배포를 실행하거나, 저장소 내부에 이미지가 추가될 때마다 이미지를 최적화(calibreapp/image-actions) 할 수 있음
  • 머지하기 전에 꼭 성공해야하는 액션을 저장소에 브랜치 보호 규직에 추가하여 기본 브랜치에서의 코드 정합성을 확보할 수 있다.
  • 모든 작업을 직접 작성하지 않아도 Marketplaces에서 여러 사람들이 작성해놓은 액션을 가져다가 사용할 수 있음
    • actions/checkout: 저장소를 체크아웃
    • sctions/setup-Node: Node 설치
    • actions/github-script: GitHub API
    • actions/stale: 오래된 이슈, PR 자동으로 닫기
    • actions/dependency-review-action: 의존성 분석 -> 보안, 라이선스 문제 확인
    • github/codeql-action: 저장소 내 코드 취약점 분석
    • calibreapp/image-actons: 저장소에 포함된 이미지를 최적화
    • lirantal/is-website-vulnerable: 특정 웹사이트에 라이브러리 취약점이 있는지 확인
    • Lighthous CI: 로컬에서 서버를 실행하여 분석하도록 할 수 있음

보안 이슈 점검

  • Dependabot
  • 의존성에 문제가 있다면 이에 대한 문제를 알려주고 가능하다면 해결할 수 있는 PR을 열어줌
  • 유의할 점은 dependabot이 알려주는 모든 취약점이 지금 당장 고쳐야하는 취약점이 아닐 수 있다는 것, 시나리오 상 문제가 발생할 수 없는데도 불구하고 취약점 관련 경고가 뜨는 경우가 꽤 많음
  • 예를 들어 예전에 browserslist의 인수로 잘못된 정규식을 넣으면 애플리케이션이 기하급수적으로 느려지는 취약점이 있었는데, 리액트에서 browserslist를 작성할 수 있는건 개발자뿐이므로 본인이 악의적인 목적으로 정규식을 넣어서 본인의 서비스를 느려지게 하지 않는 이상 실제 위협이 될수는 없다.
  • 그럼에도 취약점을 해결해야한다면 가장 간단한 방법은 dependabot이 PR을 열어준 경우이다. 이미 취약점을 해결한 패치가 존재한다는 것이기 때문에 PR을 검토하면 된다. 패키지를 올릴 때는 패치노트를 통해 변경된 API가 없는지, 혹시나 패치노트에 누락된 부분이 있을 수 있기에 직접 설치 후 정상 동작하는지 확인이 꼭 필요하다.
  • 그렇다고 너무 맹신해서는 안됨 -> 굳이 해결하지 않아도 되는 경우일 수 있기 때문
  • dependabot으로 수정하기 어려운 이슈라면 npm의 overrides를 적극 활용
  • overrieds: 사용하고 있는 라이브러리가 의존하고 있는 패키지의 버전을 강제로 덮어쓸 수 있음
    {
      "overrieds": {
        "minimatch": "^3.0.5"
      }
    }