GitHub Actions 기초 정리
📚 Reference
GitHub Actions는 GitHub 저장소에서 자동으로 작업을 실행할 수 있는 CI/CD 도구다.
예를 들어 다음과 같은 자동화를 만들 수 있다.
- 코드 push 시 테스트 자동 실행
- Pull Request 생성 시 lint 검사
- 배포 자동화
- 빌드 결과 확인
GitHub Actions의 전체 구조
GitHub Actions는 다음과 같은 계층 구조로 이루어져 있다.
// 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 속도를 줄일 수 있다.
jobs:
test: ...
lint: ...단, 특정 작업이 성공해야만 다음 작업으로 넘어가게 하려면 needs 키워드를 사용해야 한다.
jobs:
build: ...
test:
needs: build1. GitHub Actions 설정
1-1. .github/workflows 폴더 생성
GitHub Actions는 프로젝트 루트에 있는 .github/workflows 폴더에서 동작한다.
project-root
├ .github
│ └ workflows
│ └ example.yml
├ src
└ package.json- 워크플로우 파일은
.yml또는.yaml형식으로 작성한다. - 해당 파일이 있는 브랜치에 push되면 실행된다.
1-2. 기본 워크플로우 작성
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 명령어를 정의
여러 명령어를 실행하려면 | 를 사용한다.
steps:
- name: 여러 명령어 실행
run: |
echo "첫 번째 명령어"
echo "두 번째 명령어"1-3. on 트리거 세부 설정
on: push처럼 단순하게 쓸 수도 있지만, 특정 브랜치나 이벤트에만 반응하도록 조건을 구체적으로 지정할 수 있다.
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에는 기본 제공되는 환경 변수가 있다.
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
steps:
- name: Github Actions Secret 변수 사용
run: |
echo ${{ secrets.MY_NAME }}
echo ${{ secrets.MY_HOBBY }}$문법은 GitHub Actions 표현식 문법으로, secrets 외에도 다양한 context 값에 접근할 때 사용한다.- secrets 값은 로그에
***로 마스킹되어 노출되지 않는다.
👀 더 권장되는 Secret 사용 방식
- 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
steps:
- name: 코드 가져오기
uses: actions/checkout@v4run이 직접 shell 명령어를 실행하는 방식이라면, uses는 이미 만들어진 액션을 가져다 쓰는 방식이다. GitHub Actions 마켓플레이스에는 다양한 액션이 공개되어 있고, 그 중 거의 모든 워크플로우에서 사용하는 것이 actions/checkout이다.
GitHub Actions runner는 워크플로우가 시작될 때마다 생성되는 깨끗한 가상 환경이다.
이 환경에는 기본적으로 repository 코드가 존재하지 않기 때문에, actions/checkout으로 현재 커밋의 코드를 가져와야 한다.
actions/checkout 없이 npm install을 실행하면 package.json을 찾을 수 없어서 실패한다.
3. 테스트 자동화 워크플로우
위의 개념을 바탕으로 Node.js 프로젝트의 테스트 자동화 워크플로우를 작성해보면 다음과 같다.
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의 역할은 다음과 같다.
actions/checkout@v4— runner 환경에 repository 코드를 가져온다.actions/setup-node@v4— Node.js 환경을 설치한다. cache: npm 옵션으로 node_modules 캐시를 활용해 CI 실행 속도를 줄일 수 있다.npm ci—package-lock.json기준으로 정확한 버전의 의존성을 설치한다. npm install과 달리 lock 파일을 수정하지 않아 CI 환경에서 일관된 빌드를 보장한다.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. 전체 흐름 요약
코드 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 브랜치에 들어오는 것을 방지할 수 있다.