GitHub Actions는 저장소 이벤트를 트리거로 빌드·테스트·배포 자동화를 실행하는 이벤트 기반 자동화 엔진이다. 자동화 로직 자체가 저장소 안에 코드로 들어가 있다.
Workflow / Job / Step
Actions의 모든 자동화는 세 단위로 정리된다.
flowchart TB
Event[("저장소 이벤트
(push / pull_request / schedule ...)")]
Event --> WF["workflow
(.github/workflows/*.yml)"]
WF --> J1["job A
(별개 runner)"]
WF --> J2["job B
(별개 runner)"]
J1 --> S1["step 1"]
J1 --> S2["step 2"]
J1 --> S3["step 3"]
J2 --> S4["step 1"]
J2 --> S5["step 2"]
workflow는 .github/workflows/ 안의 YAML 파일 하나다. 어떤 이벤트가 trigger인지, 그 이벤트가 발생하면 어떤 job들이 실행되는지를 선언한다.
job은 workflow 안에서 실행되는 단위다. job 단위로 별개 runner(가상 머신)에서 실행된다. 같은 workflow 안의 job들은 기본적으로 병렬 실행되고, needs 키워드로 순서 의존을 선언하면 순차로 실행된다.
step은 job 안의 한 줄이다. shell 명령(run)이거나, 재사용 가능한 action 호출(uses)이다. 같은 job의 step들은 같은 runner에서 순차로 실행되며 워크스페이스를 공유한다.
이 셋을 분명히 잡아 두면 복잡한 파이프라인도 안정적으로 구성된다. 자주 헷갈리는 지점은 “두 step이 다른 job에 있으면 워크스페이스가 공유되지 않는다"는 점이다. 같은 환경이 필요한 작업은 한 job에 묶거나, artifact upload/download로 데이터를 넘겨야 한다.
trigger 이벤트
Actions가 시작되는 trigger는 저장소에서 일어나는 거의 모든 이벤트다. 자주 쓰이는 것만 정리하면:
| 이벤트 | 발생 시점 | 주 사용처 |
|---|---|---|
push | 어떤 branch든 push | main 푸시 시 배포 |
pull_request | PR open / sync / close | PR CI (test / lint / build) |
schedule | cron 표현식 | 정기 작업 (의존성 체크, 정리) |
workflow_dispatch | 수동 실행 (UI/CLI) | 배포, 일회성 작업 |
release | GitHub Release 생성 | 패키지 publish, changelog |
repository_dispatch | 외부 시스템에서 webhook | 외부 트리거 통합 |
이 중 PR CI는 pull_request trigger에 lint/test/build job을 묶는 가장 흔한 패턴이다. 이 workflow의 status check이 branch protection의 머지 게이트로 묶인다.
runner
step이 실제로 도는 장소가 runner다. 두 종류로 나뉜다.
GitHub-hosted runner는 GitHub이 제공하는 가상 머신이다. ubuntu / windows / macos를 골라 쓰고, 매번 깨끗한 환경에서 시작한다. 셋업 비용이 거의 없고 보안 격리가 잘 되어 있어 대부분의 프로젝트가 여기서 시작한다.
self-hosted runner는 자체 인프라에 runner 데몬을 설치한 형태다. 큰 데이터셋, 특수 하드웨어(GPU), 사내 네트워크 접근이 필요한 경우에 쓰인다. 대신 보안 격리·유지보수·OS 패치까지 직접 책임져야 한다.
매트릭스 빌드는 같은 step을 여러 환경에서 동시 실행하는 도구다. 예를 들어 [ubuntu, macos] x [node-18, node-20, node-22] 조합이면 6개 job이 병렬로 실행된다. 라이브러리·CLI 도구가 다중 환경에서 동작하는지 검증하는 가장 흔한 패턴이다.
action 재사용
step에서 uses: actions/checkout@v4 같은 표현은 marketplace나 다른 저장소의 action을 끌어다 쓴다는 뜻이다. 자주 쓰는 action은 거의 정해져 있다.
actions/checkout— 저장소 코드 가져오기actions/setup-node,actions/setup-python,actions/setup-go— 런타임 설치actions/cache— 의존성 캐시actions/upload-artifact,actions/download-artifact— job 간 파일 전달
자체 step 묶음을 재사용하고 싶다면 두 가지 옵션이 있다. composite action은 action.yml로 step 묶음을 패키징한 형태이고, reusable workflow는 workflow 자체를 다른 workflow에서 호출 가능하게 만든 형태다. 단순 step 묶음은 composite, 큰 파이프라인 단위 재사용은 reusable workflow가 자연스럽다.
버전 핀은 보안과 안정성에 직결된다. @v4 같은 메이저 태그는 편하지만, 그 태그가 가리키는 SHA가 바뀔 수 있어 공급망 공격의 표적이 된다. 보안에 민감한 환경은 @<full-sha> 형태로 핀해 두는 게 안전하다.
secret과 권한
Actions에서 외부 서비스 인증이 필요한 경우 secret을 쓴다.
secrets.GITHUB_TOKEN은 workflow가 시작될 때 자동으로 발급되는 토큰이다. 그 저장소에 대한 기본 권한이 부여되며, push·PR comment·issue 코멘트 같은 동작에 쓰인다.
사용자 정의 secret은 저장소·환경·조직 단위로 등록할 수 있다. 환경 단위 secret은 deployment job에 환경 보호 규칙(승인 필요, 시간 제한)을 함께 걸 수 있어 production 배포에 자주 쓰인다.
permissions 블록은 토큰의 scope를 좁히는 도구다. 기본값은 저장소에 대해 폭넓은 권한이지만, workflow나 job 단위로 contents: read 같은 최소 권한만 명시하면 token이 탈취되더라도 영향이 제한된다. CI workflow는 read만 있으면 충분한 경우가 많아 명시해 두는 게 안전 마진이다.
자주 쓰는 패턴
운영 중 가장 흔한 흐름은 네 가지로 압축된다.
PR CI: pull_request trigger 에 lint / test / build job. branch protection 의 required check 으로 사용.
main push 배포: push to main trigger에 build → deploy job. staging 배포는 자동, production은 환경 보호 규칙 + 수동 승인을 거는 형태가 일반적이다.
tag push 시 release: push 중 tags: ['v*'] 필터로 태그 푸시만 잡아 release artifact 빌드 및 publish.
매트릭스 빌드: 라이브러리/CLI가 다중 환경에서 동작하는지 검증.
흔한 함정
secret 노출
echo $SECRET 같은 step이 들어가면 그 값이 로그에 그대로 찍힌다. Actions는 secret 패턴을 마스킹하려 시도하지만, base64 인코딩이나 부분 노출은 마스킹을 우회한다. secret은 절대 출력하지 않는 습관이 가장 단순한 안전판이다.
action 버전 무핀
uses: some-org/action@main 처럼 브랜치를 가리키면, 그 브랜치가 언제든 바뀔 수 있다. 공격자가 인기 action을 인수해 main 브랜치에 악성 코드를 주입한 사고 사례가 실제로 있었다. 메이저 태그 또는 SHA로 핀하는 게 표준이다.
cache 누락
매번 의존성을 새로 설치하면 PR CI 시간이 분 단위로 늘어난다. actions/cache로 npm/pip/go module 같은 의존성 디렉토리를 캐시하면 두 번째 실행부터는 거의 즉시 끝난다. cache key는 lock 파일의 hash를 포함해야 의존성 변경 시 자동으로 무효화된다.
무거운 workflow가 큐 대기
self-hosted runner를 한 대만 두면 동시 실행 요청이 쌓여 큐 대기가 길어진다. concurrency 그룹을 잡아 같은 PR/branch의 이전 실행을 자동 취소하거나, runner를 늘리는 게 일반적인 해결이다.
정리
GitHub Actions의 자동화는 3단 추상에 얹힌다.
- workflow / job / step: 한 workflow는 여러 job, 한 job은 여러 step
- trigger: 저장소 이벤트가 워크플로우 시작점
- runner: GitHub-hosted가 기본, self-hosted는 특수 환경
- secret + permissions: 최소 권한 + 핀된 action 버전이 보안 안전판
세 단 추상(workflow / job / step) + 이벤트 trigger + runner 조합이 GitHub Actions의 자동화 엔진을 만든다. secret과 permissions의 최소권한이 그 엔진을 안전하게 운용하는 테두리다.
다음 편은 코드 변경의 짝이 되는 작업 단위 — JIRA Sprint 워크플로우와 Git/GitHub 연동이다.