git
CI를 위한 github action사용기

CI를 위한 github action사용기

42서울 클러스터 입장시 활용되는 체크인웹 서비스를 이어받게 되면서 평소에 해보고 싶었던 기술을 사용해보고 싶었다.

내가 원했던 기능

  • 기존에 ec2에 올라간 nodejs서버를 업데이트할 때, 방법은 다음과 같았다.
    1. 로컬에서 빌드
    2. 터미널을 켜서 scp명령어로 직접 올린다.
    3. pm2를 사용해 상태를 업데이트시킨다
  • 이 부분을 자동화 하고자 했다.

github action이란?

  • 리포지토리의 상태를 특정 조건으로 반응하는 컴퓨팅 도구 이다. 예를 들면, 깃허브 리포지토리로 파일을 푸쉬 시, 그 푸쉬 된 파일을 베이스로 가상 리눅스가 만들어지고 사용자가 설정해놓은 순서대로 작업이 시작된다.(출처 (opens in a new tab))
  • 공개 레포지토리인 경우 무료로 사용가능하다.

흐름

git push나 풀 리퀘스트로 인해 master 브랜치에 새로운 커밋이 올라왔을 경우 아래와 같은 작업을 하는 깃허브 액션을 실행시킨다.

  1. .env.production파일을 만든다.
  2. yarn build로 빌드한다.
  3. 빌드된 파일을 scp를 사용해 ec2에 업로드한다.
  4. ec2에 접근하여 pm2로 상태를 업데이트시킨다.
  • 위 내용을 기준으로 작성된 .yml파일은 다음과 같다.
# This is a basic workflow to help you get started with Actions
 
name: CI
 
# Controls when the action will run.
on:
  # Triggers the workflow on push or pull request events but only for the master branch
  push:
    branches: [ master ]
  pull_request:
    branches: [ master ]
  • master브랜치에 push나 pull request가 이루어지면 해당 워크플로우가 작동한다.
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:
 
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest
 
    strategy:
      matrix:
        node-version: [12.x]
  • 사용할 nodejs 버전을 지정한다.
 
    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      - uses: actions/checkout@v1
 
      - name: Create env file
        env:
          API_KEY: ${{ secrets.API_KEY }}
          PORT: ${{ secrets.PORT }}
          NODE_secrets: ${{ secrets.NODE_secrets }}
          DATABASE_HOST: ${{ secrets.DATABASE_HOST }}
          DATABASE_PORT: ${{ secrets.DATABASE_PORT }}
          DATABASE_USERNAME: ${{ secrets.DATABASE_USERNAME }}
          DATABASE_PASSWORD: ${{ secrets.DATABASE_PASSWORD }}
          DATABASE_NAME: ${{ secrets.DATABASE_NAME }}
          CLIENT_ID: ${{ secrets.CLIENT_ID }}
          CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }}
          CLIENT_CALLBACK: ${{ secrets.CLIENT_CALLBACK }}
          JWT_SECRET: ${{ secrets.JWT_SECRET }}
 
        run: |
          touch .env.production
          echo API_KEY="$API_KEY" >> .env.production
          echo PORT="$PORT" >> .env.production
          echo NODE_ENV="$NODE_ENV" >> .env.production
          echo DATABASE_HOST="$DATABASE_HOST" >> .env.production
          echo DATABASE_PORT="$DATABASE_PORT" >> .env.production
          echo DATABASE_USERNAME="$DATABASE_USERNAME" >> .env.production
          echo DATABASE_PASSWORD="$DATABASE_PASSWORD" >> .env.production
          echo DATABASE_NAME="$DATABASE_NAME" >> .env.production
          echo CLIENT_ID="$CLIENT_ID" >> .env.production
          echo CLIENT_SECRET="$CLIENT_SECRET" >> .env.production
          echo CLIENT_CALLBACK="$CLIENT_CALLBACK" >> .env.production
          echo JWT_SECRET="$JWT_SECRET" >> .env.production
          cat .env.production | head -n 1
  • 깃허브 레포지토리 secret키를 .env.production파일에 한줄씩 추가한다. (cat은 확인용)
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
          registry-url: "https://npm.pkg.github.com"
  • 지정했던 nodejs버전을 다운받는다.
      - name: Install dependencies
        run: yarn install
        env:
          CI: true
  • yarn install을 통해 의존모듈들을 다운받는다.
      - name: Run Build
        run: yarn build
  • package.json에 지정했던 빌드 스크립트를 실행한다.
      - name: build file upload to ec2
        uses: garygrossgarten/github-action-scp@release
        with:
            local: ./dist
            remote: /home/yurlee/code/42s_checkin_server/dist/
            host: ${{ secrets.HOST }}
            username: ${{ secrets.SSH_USER }}
            privateKey: ${{ secrets.SSH_KEY }}
            recursive: true
      - name: ec2 update
        uses: appleboy/ssh-action@master
        with:
           host: ${{ secrets.HOST }}
           username: ${{ secrets.SSH_USER }}
           key: ${{ secrets.SSH_KEY }}
           script: pm2 restart 0 --update-env
 

ETC

  • .env파일을 저장소에 업로드하면 안되기 때문에 secret키로 등록한 후 액션이 실행될때마다 생성되게해서 해결했다.

참고