GitHub Actions란 무엇인가
workflow, job, step, runner를 실제 CI로 이해하기
GitHub Actions가 PR 같은 이벤트에서 무엇을 어떤 순서로 실행하는지, workflow·job·step·action·runner의 차이를 실제 CI 설정으로 읽고 첫 workflow를 만드는 법까지 설명합니다.

목차
weftware-web 저장소에서는 pull request를 열어도 사람이 터미널에서 검사 명령을 하나씩 실행하지 않습니다. GitHub Actions가 시작되어 GitHub가 제공하는 Ubuntu 머신에서 저장소 코드를 가져오고, lint, typecheck, test, build, check를 순서대로 돌립니다. PR 화면의 checks 목록에 check가 통과로 표시되면 이 작업이 끝까지 성공했다는 뜻입니다.
이 workflow는 배포를 하지 않습니다. 저장소 README는 GitHub Actions를 PR 검사에만 쓰고, 배포는 Cloudflare Workers Builds가 맡는다고 적고 있습니다. GitHub Actions를 쓴다고 해서 배포까지 맡겨야 하는 것은 아니라는 점이 이 구성에서 먼저 보입니다.
GitHub Actions를 한 문장으로 말하면, GitHub 저장소에서 어떤 일이 생겼을 때 미리 적어 둔 작업을 자동으로 실행하는 기능입니다. 공식 문서는 CI/CD 플랫폼이라고 소개하면서도, 거기에 그치지 않고 저장소의 다른 이벤트에도 반응할 수 있다고 설명합니다. 예를 들어 누가 새 issue를 만들면 알맞은 label을 자동으로 붙이는 workflow를 만들 수 있습니다.
PR 하나가 검사되는 과정
PR 하나가 열려서 검사 결과가 돌아오기까지는 다섯 단계를 거칩니다.
- PR을 엽니다. GitHub에 “pull request가 열렸다”는 이벤트(event, 저장소에서 일어난 일)가 생깁니다.
- GitHub가 저장소의
.github/workflows폴더에서 이 이벤트에 맞는 workflow 파일을 찾습니다. 파일의on에pull_request가 있으면 workflow 실행(run)이 만들어집니다. - workflow 안의 job이 runner(job을 실제로 실행하는 머신)에서 시작됩니다. weftware-web의 job은
check하나입니다. - job 안의 step 8개가 위에서 아래로 차례로 실행됩니다.
- 결과가 PR에 통과 또는 실패로 표시됩니다.
PR에 커밋을 더 올리면 같은 검사가 다시 돕니다. 공식 문서에 따르면 pull_request는 활동 유형을 따로 정하지 않았을 때 PR이 열릴 때(opened), 새 커밋이 올라올 때(synchronize), 다시 열릴 때(reopened) 실행됩니다. 반대로 이 workflow는 push에는 반응하지 않습니다. on에 pull_request만 적혀 있기 때문입니다.

PR에는 Cloudflare Workers Builds의 체크도 함께 나옵니다. 이 체크는 Actions가 아니라 Cloudflare가 만듭니다. PR의 checks 목록에 있다고 모두 GitHub Actions의 결과는 아닙니다.

여섯 가지 말을 한 번에 구분하기
Actions 화면과 문서에는 비슷해 보이는 말이 여섯 개 나옵니다. 위 흐름에 나온 순서대로, 이 저장소의 값과 함께 구분합니다.
| 용어 | 뜻 | weftware-web에서는 |
|---|---|---|
| event(이벤트), trigger | 저장소에서 일어난 일. workflow를 시작시키는 조건 | pull_request |
| workflow | 하나 이상의 job을 실행하는 자동화 절차. .github/workflows의 YAML 파일 하나로 정의 | ci.yml(이름 CI) |
| job | 같은 runner에서 실행되는 step의 묶음 | check |
| step | job 안의 한 단계. 명령(run)을 실행하거나 action(uses)을 사용 | 8개 |
| action | workflow에서 가져다 쓰는, 미리 만들어진 재사용 단위 | actions/checkout, actions/setup-node |
| runner | job을 실제로 실행하는 서버 | GitHub가 제공하는 ubuntu-latest |
가장 많이 헷갈리는 것은 이름입니다. GitHub Actions는 이 기능 전체의 이름이고, action은 workflow 안에서 가져다 쓰는 부품 하나입니다. “GitHub Actions를 쓴다”와 “action을 쓴다”는 다른 말입니다. 이 저장소의 CI도 GitHub Actions를 쓰지만, 그 안에서 가져다 쓰는 action은 둘뿐이고 나머지 step은 npm 명령을 직접 실행합니다.
job과 step은 실행되는 방식이 다릅니다. 공식 문서에 따르면 job은 기본적으로 서로 의존하지 않고 병렬로 실행되며, 각 job은 자기 runner에서 돕니다. 반대로 한 job 안의 step은 같은 runner에서 순서대로 실행되므로, 앞 step이 만든 결과를 뒤 step이 쓸 수 있습니다. 이 저장소에서는 npm run build가 만든 결과물을 바로 뒤의 npm run check가 읽어서 링크와 SEO를 검사합니다. 둘이 같은 job의 step이라서 가능한 구조입니다.
runner는 job을 실제로 실행하는 서버입니다. 공식 문서는 GitHub가 Ubuntu Linux, Windows, macOS runner를 제공하고(GitHub-hosted runner), 직접 서버를 두는 self-hosted runner도 쓸 수 있다고 설명합니다. runner 하나는 한 번에 job 하나를 실행하고, GitHub-hosted runner를 쓰면 각 job은 runs-on으로 지정한 runner image의 새 인스턴스에서 실행됩니다. 이 저장소의 ubuntu-latest job도 실행할 때마다 새 가상 머신에서 시작합니다. 새 머신이라 저장소 코드가 처음에는 없으므로, 이 저장소의 첫 step이 actions/checkout입니다. 요금과 사용 시간 계산은 이 글에서 다루지 않습니다.
실제 ci.yml을 읽어 봅니다
아래는 weftware-web의 .github/workflows/ci.yml에서 핵심 구조만 발췌한 것입니다. 2026-10-09 main의 파일에서 몇 줄을 뺐을 뿐 나머지는 그대로입니다. 이 저장소의 workflow 파일은 이 하나뿐입니다.
name: CI
on:
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run build
- run: npm run check처음 보는 독자가 YAML 문법을 다 알 필요는 없습니다. 어디를 보면 무엇을 알 수 있는지만 짚습니다.
name: Actions 탭에 보이는 workflow 이름입니다. 생략하면 파일 경로가 대신 보입니다.on: 언제 실행할지입니다. 여기서는 PR이 열리거나 새 커밋이 올라올 때입니다.jobs: 실행할 job의 묶음입니다.check: job ID입니다. PR의 checks 목록에 이 이름으로 보입니다.runs-on: 어떤 runner에서 실행할지입니다.steps: job 안에서 순서대로 실행할 단계입니다.uses: 이미 만들어진 action을 사용합니다.actions/checkout은 저장소 코드를 runner로 가져오고,actions/setup-node는 Node.js 환경을 준비합니다. 바로 아래의with는 그 action에 넘기는 값으로, 여기서는 Node 버전을 적어 둔.nvmrc파일과 npm 의존성 캐시를 지정합니다.run: 셸 명령을 직접 실행합니다.npm ci로 의존성을 설치한 뒤 lint(코드 검사), typecheck(타입 검사), test(단위 테스트), build(사이트 빌드), check(빌드 결과의 링크·SEO 검사)를 차례로 돌립니다.

step 하나가 실패하면 job은 실패로 표시됩니다(step에 continue-on-error를 쓰지 않는 한). PR에서 빨간 표시가 나오면 Actions 탭에서 그 실행을 열고, 실패한 step을 펼쳐 로그를 읽는 것이 시작입니다.
첫 항목인 Set up job을 펼치면 이 job이 어떤 runner에서 어떤 설정으로 시작했는지 볼 수 있습니다.

원본에는 발췌에서 뺀 설정이 세 가지 더 있습니다. 같은 PR의 이전 실행을 취소하는 concurrency, 토큰 권한을 읽기로 줄이는 permissions, 실행 시간 상한인 timeout-minutes입니다. 개념을 따라가는 데 필요하지 않아 뺐고, 이런 설정이 사용 시간과 어떻게 이어지는지는 GitHub Actions 비용 줄이는 방법에서 다룹니다.
CI와 CD는 따로 볼 수 있습니다
CI(continuous integration)는 코드를 합치기 전에 빌드, 테스트, 검사를 자동으로 반복해서 확인하는 과정입니다. CD(continuous delivery)는 검사를 통과한 변경을 배포 과정까지 자동으로 이어가는 방식입니다.
weftware-web에서는 CI를 GitHub Actions가, 배포를 Cloudflare Workers Builds가 맡습니다. 한 저장소 안에서도 두 일을 서로 다른 도구가 나눠 맡을 수 있다는 예입니다. 물론 GitHub Actions로 배포까지 이어갈 수도 있습니다. 공식 문서는 release가 만들어질 때마다 애플리케이션을 배포하는 workflow를 예로 듭니다. 어느 쪽이 낫다는 이야기가 아니라, GitHub Actions가 곧 배포 도구는 아니라는 점을 구분하자는 것입니다.
GitHub Actions로 할 수 있는 일
공식 문서가 드는 예를 이벤트별로 옮기면 이렇습니다.
- PR이 열릴 때: 빌드와 테스트를 돌립니다. 위에서 읽은 CI가 이 경우입니다.
- release가 만들어질 때: 애플리케이션을 배포합니다.
- issue가 열릴 때: 알맞은 label을 붙입니다.
- 정해진 시각마다:
schedule에 cron 형식으로 시각을 적으면 그 시각에 실행됩니다. 정기 실행은 기본 branch에서만 동작합니다. - 사람이 직접 누를 때:
workflow_dispatch로 수동 실행 버튼을 둘 수 있습니다.
공통점은 사람이 명령을 입력해서가 아니라 GitHub의 이벤트나 시각이 작업을 시작시킨다는 것입니다. 목록 전체는 공식 문서의 “Events that trigger workflows”에 있습니다.
쓸 만한 경우와 아직 필요 없는 경우
아래는 공식 문서의 설명을 바탕으로 한 판단 기준이고, 정답이 정해져 있는 것은 아닙니다.
쓸 만한 경우:
- PR마다 같은 검사를 반복하고, 사람이 하면 빠뜨릴 수 있습니다.
- 빌드와 테스트 결과가 코드 변경 옆에 기록으로 남아야 합니다.
- release나 배포처럼 반복되는 작업이 있습니다.
- GitHub의 특정 이벤트에 자동으로 반응해야 합니다.
아직 필요 없을 수 있는 경우:
- 혼자 하는 작은 실험이고 자동화할 반복 작업이 거의 없습니다.
- 한 번만 실행하면 되는 작업입니다.
- 저장소 이벤트와 상관없는 별도 시스템 작업입니다.
필요 없을 수 있다는 말이 쓰지 말라는 뜻은 아닙니다. 자동으로 돌려 두면 같은 검사를 매번 사람이 떠올리지 않아도 된다는 점은 규모와 상관없이 같습니다.
첫 workflow는 테스트 하나로 시작합니다
처음부터 배포까지 자동화하려고 하면 어디서 실패했는지 찾기 어렵습니다. PR에서 테스트 하나를 돌리는 정도로 시작하는 편이 낫습니다. 아래는 Node.js 프로젝트에 package-lock.json과 test 스크립트가 있다고 가정한 개념 예시이고, weftware-web의 파일이 아닙니다.
name: Test
on:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm ci
- run: npm test저장소에 만드는 순서입니다.
- GitHub의 저장소 첫 화면에서 Add file(파일 추가)을 눌러 Create new file을 고르고, 파일 이름을
.github/workflows/test.yml처럼 씁니다. 슬래시를 쓰면 폴더가 함께 만들어집니다. workflow 파일은 반드시.github/workflows폴더에 있어야 GitHub가 찾습니다. 확장자는.yml이나.yaml입니다. - 위 내용을 붙여 넣고 Commit changes(변경 사항 커밋)를 누릅니다. 새 branch를 만들어 PR을 시작하는 쪽을 고릅니다.
- 그 branch로 PR을 열면 workflow가 실행됩니다.
- 저장소 이름 아래의 Actions를 열고, 왼쪽에서 workflow를 고르고, 실행 목록에서 실행 한 건을 엽니다. 왼쪽 Jobs 아래의 job을 누르면 step별 로그가 나옵니다. 성공이면 PR의 checks에 통과로 표시됩니다.
저장소에 Actions 탭이 보이지 않으면 그 저장소에서 Actions가 꺼져 있을 수 있다고 공식 quickstart가 안내합니다. 이 경우 저장소 설정에서 Actions 사용 여부를 먼저 확인합니다.
action의 버전 표시(@v4)는 계속 바뀝니다. 이 저장소는 @v4를 쓰고, 공식 quickstart의 예시는 actions/checkout@v6을 씁니다. 복사해서 쓰기 전에 각 action 저장소의 안내에서 쓸 버전을 확인합니다.
테스트 하나가 PR마다 통과하는 것을 확인했다면, 그다음에 lint, typecheck, build를 step으로 하나씩 더합니다. 배포는 그 뒤에 필요할 때 따로 정합니다.
처음부터 지켜 둘 것
YAML을 그대로 복사해서 쓰는 일이 많으므로, 공식 보안 문서에서 초보자가 바로 적용할 수 있는 세 가지만 옮깁니다.
- 외부 action은 가려서 씁니다. 공식 문서는 workflow에서 쓰는 action 하나가 침해되면 저장소에 설정된 secret에 접근하고 토큰으로 저장소에 쓰기까지 할 수 있어서 위험이 크다고 설명합니다. 가장 안전한 방법은 action을 전체 길이 commit SHA로 고정하는 것이고, 태그로 쓸 때는 만든 사람을 신뢰할 수 있을 때만 쓰라고 합니다. Marketplace의 “Verified creator” 표시는 참고 신호입니다.
- 필요한 권한만 줍니다. workflow가 쓰는
GITHUB_TOKEN에는 필요한 최소 권한만 주는 것이 좋다고 공식 문서가 권합니다. 이 저장소의 CI도 원본에서permissions로 읽기 권한만 줍니다. - secret 값을 workflow 파일에 직접 쓰지 않습니다. 비밀 값은 저장소의 secret으로 저장하고, 파일에서는 이름으로만 참조합니다.
이 글은 보안 가이드가 아니므로 여기까지만 다룹니다. 자세한 내용은 공식 “Secure use reference”에 있습니다.
사용량과 비용이 궁금해지면
GitHub Actions의 사용 시간과 요금은 이 글의 범위 밖입니다. 숫자가 바뀔 수 있어서 이 글을 숫자에 묶어 두지 않았습니다. 사용 시간이 갑자기 늘어서 원인을 찾아야 한다면 GitHub Actions 사용량이 갑자기 늘어났을 때를, 내 플랜에서 Actions 사용량이 충분한지 보려면 GitHub Free vs Pro를 읽으면 됩니다.
출처 및 참고자료
마지막 확인
- GitHub Docs · Understanding GitHub Actions
- GitHub Docs · Workflows
- GitHub Docs · Quickstart for GitHub Actions
출처 8개 더 보기출처 접기
- GitHub Docs · Workflow syntax for GitHub Actions
- GitHub Docs · Events that trigger workflows
- GitHub Docs · GitHub Actions Runners
- GitHub Docs · GitHub-hosted runners
- GitHub Docs · About custom actions
- GitHub Docs · Secure use reference
- GitHub Docs · Use GITHUB_TOKEN for authentication in workflows
- GitHub · actions/setup-node


