Skip to content

GitHub Actions 기초 정리

GitHub Actions는 GitHub 저장소에서 자동으로 작업을 실행할 수 있는 CI/CD 도구다.

예를 들어 다음과 같은 자동화를 만들 수 있다.

  • 코드 push 시 테스트 자동 실행
  • Pull Request 생성 시 lint 검사
  • 배포 자동화
  • 빌드 결과 확인

GitHub Actions의 전체 구조

GitHub Actions는 다음과 같은 계층 구조로 이루어져 있다.

less
// Event > Workflow > Job > Step > Action

Event
 └ Workflow
     └ Jobs
         └ Steps
             └ Action / run
  • Event: 워크플로우를 실행시키는 트리거 (push, PR 등)
  • Workflow: 하나 이상의 Job을 실행하는 자동화된 전체 프로세스 (.yml 파일 하나가 하나의 워크플로우)
  • Job: 독립된 가상 머신(Runner)에서 실행되는 Step들의 집합. GitHub Actions는 여러 job을 기본적으로 병렬 실행한다.
  • Step: 명령어를 실행하거나 Action을 호출하는 개별 작업 단위
  • Action: 재사용 가능한 작업 단위

🚀 Job 병렬 실행

여러 개의 Job을 만들면 기본적으로 병렬로 실행된다.
예를 들어 테스트와 린트를 분리하면 CI 속도를 줄일 수 있다.

yml
jobs:
  test: ...

  lint: ...

단, 특정 작업이 성공해야만 다음 작업으로 넘어가게 하려면 needs 키워드를 사용해야 한다.

yml
jobs:
  build: ...

  test:
    needs: build

1. GitHub Actions 설정

1-1. .github/workflows 폴더 생성

GitHub Actions는 프로젝트 루트에 있는 .github/workflows 폴더에서 동작한다.

less
project-root
.github
 │  └ workflows
 │     └ example.yml
 ├ src
 └ package.json
  • 워크플로우 파일은 .yml 또는 .yaml 형식으로 작성한다.
  • 해당 파일이 있는 브랜치에 push되면 실행된다.

1-2. 기본 워크플로우 작성

yml
name: Github Actions 연습하기

on: push

jobs:
  push-job:
    runs-on: ubuntu-latest

    steps:
      - name: 첫 번째 작업
        run: echo "첫 번째 작업 실행 중"
  • name: 워크플로우의 이름으로 github repository에 표시된다.
  • on: 워크플로우 실행 조건
  • jobs: 워크플로우에서 실행할 작업 정의
    • push-job: 작업의 이름, 이름은 자유롭게 작성

    • runs-on: 작업이 실행될 환경 지정. 대부분의 경우 ubuntu-latest를 사용한다.

      🔍 ubuntu-latest를 쓰는 이유

      GitHub Actions runner에는 여러 OS가 있지만,
      ubuntu-latest가 가장 빠르고 범용적이라 CI에서 많이 사용된다고 한다.

    • steps: 워크플로우 내에서의 작업 단계를 정의

    • name: 각 단계의 이름. 워크플로우 실행 로그에서 어떤 작업이 실행됐는지 구분할 수 있게 해준다.

    • run: 작업을 실행하기 위한 shell 명령어를 정의


여러 명령어를 실행하려면 | 를 사용한다.

yml
steps:
  - name: 여러 명령어 실행
    run: |
      echo "첫 번째 명령어"
      echo "두 번째 명령어"

1-3. on 트리거 세부 설정

on: push처럼 단순하게 쓸 수도 있지만, 특정 브랜치나 이벤트에만 반응하도록 조건을 구체적으로 지정할 수 있다.

yml
on:
  push:
    branches: [main] # main 브랜치에 push될 때만 실행
  pull_request:
    branches: [main] # main 브랜치로 PR이 열릴 때 실행

이렇게 설정하면 feature 브랜치 작업 중에는 워크플로우가 불필요하게 실행되지 않아서 GitHub Actions 사용 시간을 절약할 수 있다.

Public repository에서는 GitHub Actions 사용이 사실상 무료이며,
Private repository에서는 무료 minutes가 제공되고 초과 시 요금이 발생할 수 있다고 한다.


2. 자주 쓰는 기능

2-1. GitHub Actions 기본 환경 변수

GitHub Actions에는 기본 제공되는 환경 변수가 있다.

yml
steps:
  - name: Github 환경 변수 확인
    run: |
      echo $GITHUB_SHA
      echo $GITHUB_REPOSITORY
대표적인 변수설명
GITHUB_SHA현재 커밋 SHA
GITHUB_REPOSITORY저장소 이름
GITHUB_REF브랜치 이름
GITHUB_ACTOR워크플로우를 트리거한 사용자 이름
GITHUB_WORKFLOW현재 실행 중인 워크플로우 이름

2-2. Secrets 사용하기

민감한 값(API Key, Token 등)은 GitHub Secrets에 저장한다.

🔍 설정 방법

Repository → Settings → Secrets and variables → Actions → New repository secret

yml
steps:
  - name: Github Actions Secret 변수 사용
    run: |
      echo ${{ secrets.MY_NAME }}
      echo ${{ secrets.MY_HOBBY }}
  • $ 문법은 GitHub Actions 표현식 문법으로, secrets 외에도 다양한 context 값에 접근할 때 사용한다.
  • secrets 값은 로그에 ***로 마스킹되어 노출되지 않는다.

👀 더 권장되는 Secret 사용 방식

yml
- name: Use Secret
  env:
    MY_NAME: ${{ secrets.MY_NAME }}
  run: echo "Hello, $MY_NAME"

로그에서는 ***로 가려지지만, 코드 자체에 값을 직접 쓰는 것은 보안상 위험할 수 있다. (일부 상황에서 우회 노출될 가능성 때문) 보통은 env 섹션을 통해 환경 변수로 주입해서 사용하는 방식이 더 안전한 관습으로 통한다고 함!


2-3. github 마켓플레이스 액션 사용하기

GitHub Actions 마켓플레이스에는 미리 만들어진 액션들이 공개되어 있다.

npm으로 라이브러리를 설치하듯, 필요한 액션을 가져와 워크플로우에서 바로 쓸 수 있다. run이 직접 shell 명령어를 실행하는 방식이라면, uses는 이미 만들어진 액션을 가져다 쓰는 방식이다.

actions/checkout

yml
steps:
  - name: 코드 가져오기
    uses: actions/checkout@v4

run이 직접 shell 명령어를 실행하는 방식이라면, uses는 이미 만들어진 액션을 가져다 쓰는 방식이다. GitHub Actions 마켓플레이스에는 다양한 액션이 공개되어 있고, 그 중 거의 모든 워크플로우에서 사용하는 것이 actions/checkout이다.

GitHub Actions runner는 워크플로우가 시작될 때마다 생성되는 깨끗한 가상 환경이다.
이 환경에는 기본적으로 repository 코드가 존재하지 않기 때문에, actions/checkout으로 현재 커밋의 코드를 가져와야 한다.

actions/checkout 없이 npm install을 실행하면 package.json을 찾을 수 없어서 실패한다.


3. 테스트 자동화 워크플로우

위의 개념을 바탕으로 Node.js 프로젝트의 테스트 자동화 워크플로우를 작성해보면 다음과 같다.

yml
name: CI

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

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: 코드 가져오기
        uses: actions/checkout@v4

      - name: Node 설치
        uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm

      - name: 패키지 설치
        run: npm ci

      - name: 테스트 실행
        run: npm test

각 step의 역할은 다음과 같다.

  1. actions/checkout@v4 — runner 환경에 repository 코드를 가져온다.
  2. actions/setup-node@v4 — Node.js 환경을 설치한다. cache: npm 옵션으로 node_modules 캐시를 활용해 CI 실행 속도를 줄일 수 있다.
  3. npm cipackage-lock.json 기준으로 정확한 버전의 의존성을 설치한다. npm install과 달리 lock 파일을 수정하지 않아 CI 환경에서 일관된 빌드를 보장한다.
  4. npm test — 테스트를 실행한다.

보통은 push보다 pull_request 이벤트에서 CI를 많이 실행한다고 한다.
PR이 열렸을 때 테스트가 통과해야 merge가 가능하도록 설정하기 때문이다.


🧩 npm ci vs npm install

npm install

  • package.json 기준으로 의존성을 설치한다.
  • package-lock.json이 없으면 새로 생성한다.
  • 필요 시 package-lock.json을 업데이트할 수 있다.

npm ci

  • package-lock.json을 기준으로 정확한 버전의 의존성을 설치한다.
  • package-lock.json이 반드시 필요하다.
  • lock 파일과 package.json이 다르면 에러가 발생한다.
  • CI 환경에서 재현 가능한 빌드를 위해 권장된다.

4. 전체 흐름 요약

less
코드 push 또는 PR 생성

.github/workflows/*.yml 파일 감지

runner 환경(ubuntu-latest) 생성

jobs → steps 순서대로 실행

GitHub Actions 탭에서 결과 확인

실행 결과는 레포지토리의 Actions 탭에서 확인할 수 있고, 각 step별 로그도 볼 수 있다.

💡 Tip

PR에서 CI가 실패하면 GitHub에서 merge가 막히도록 설정할 수 있다.
Settings → Branch protection rule → Require status checks
이를 통해 테스트가 통과하지 않은 코드가 main 브랜치에 들어오는 것을 방지할 수 있다.