GitHub Actions는 GitHub Repository에서 발생하는 이벤트를 기준으로 빌드, 테스트, 배포 같은 작업을 자동으로 실행하는 CI/CD 플랫폼이다.
코드를 push하거나 Pull Request를 생성했을 때 자동으로 테스트를 실행하거나, main에 Merge되면 서버에 배포하는 식으로 사용할 수 있다.
Git 자체가 코드의 변경 이력을 관리한다면 GitHub Actions는 그 변경을 트리거로 실제 작업을 실행하는 자동화 시스템이라고 보면 된다.
Git -> 코드 변경 관리
GitHub -> Repository + 협업
GitHub Actions -> Repository 이벤트 기반 작업 자동 실행
실무에서는 다음과 같은 흐름으로 많이 사용한다.
개발 -> Commit -> Push -> GitHub -> GitHub Actions -> Build -> Test -> Deploy
GitHub Actions의 기본 구조
GitHub Actions는 .github/workflows 디렉터리에 Workflow 파일을 작성하는 방식으로 구성한다.
Project -> .github -> workflows -> ci.yml / deploy.yml
Workflow는 YAML 파일로 작성한다.
간단한 예시는 다음과 같다.
name: CI
on:
push:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: ./build.sh
- name: Test
run: ./test.sh
전체적인 구조는 다음과 같이 이해할 수 있다.
Workflow -> Event / Job / Runner / Steps -> Action / Command
이 구조를 이해하는 것이 GitHub Actions의 출발점이다.
Workflow
Workflow는 자동화 작업 하나의 전체 정의다.
예를 들어 CI Workflow는
CI Workflow -> 코드 검사 -> Build -> Test
처럼 구성할 수 있다.
Deploy Workflow는
Deploy Workflow -> Build -> Docker Image 생성 -> 서버 배포
처럼 구성할 수 있다.
하나의 Repository에 여러 Workflow를 둘 수 있다.
.github/workflows -> ci.yml / deploy.yml / release.yml / nightly.yml
각 Workflow는 서로 독립적으로 실행될 수 있다.
Event
Workflow를 언제 실행할지를 정의하는 것이 on이다.
Push가 발생했을 때 실행하려면
on:
push:
Pull Request가 생성되거나 업데이트될 때 실행하려면
on:
pull_request:
를 사용할 수 있다.
Branch도 제한할 수 있다.
on:
push:
branches:
- main
그러면 main Branch에 Push가 발생했을 때만 실행된다.
GitHub의 Event와 연결된다
GitHub Actions가 강력한 이유는 Repository에서 발생하는 다양한 이벤트를 자동화의 시작점으로 사용할 수 있기 때문이다.
대표적인 Event는 다음과 같다.
push / pull_request / issues / workflow_dispatch / schedule / release / workflow_call
예를 들어 PR이 올라오면 자동으로 테스트를 실행할 수 있다.
개발자 -> Pull Request -> GitHub Event -> GitHub Actions -> Build + Test
Job
Job은 Workflow 안에서 실행할 작업 단위다.
예를 들어 CI에서
Workflow -> Build / Test / Lint
각각을 Job으로 구성할 수 있다.
jobs:
build:
...
test:
...
lint:
...
Job 사이에 의존관계를 지정할 수도 있다.
jobs:
build:
...
test:
needs: build
...
그러면 다음과 같이 실행된다.
build -> test
Step
Job 안에서 실제로 실행할 작업을 정의하는 것이 Step이다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install
run: npm install
- name: Build
run: npm run build
- name: Test
run: npm test
Step은 크게 두 가지 방식으로 생각할 수 있다.
uses -> 다른 사람이 만들어 놓은 Action 사용
run -> 직접 명령어 실행
Action
Action은 특정 작업을 수행하도록 만들어진 재사용 가능한 자동화 구성요소다.
대표적으로 Repository의 코드를 Runner로 가져오는 데 사용하는
- uses: actions/checkout@v4
가 있다.
Node.js 환경을 구성할 때는
- uses: actions/setup-node@v4
with:
node-version: 22
같은 Action을 사용할 수 있다.
직접 모든 환경 설정을 작성할 필요 없이 이미 만들어진 Action을 가져와 사용할 수 있다는 것이 장점이다.
Runner
Workflow가 실제로 실행되는 컴퓨터가 Runner다.
GitHub -> Runner -> Checkout / Build / Test / Deploy
GitHub에서 제공하는 Hosted Runner를 사용할 수도 있고, 직접 관리하는 Self-hosted Runner를 사용할 수도 있다.
대표적인 환경은 다음과 같다.
Runner OS -> Ubuntu / Windows / macOS
예를 들어
runs-on: ubuntu-latest
라고 하면 GitHub가 제공하는 Ubuntu 환경에서 Job을 실행한다.
GitHub-hosted Runner
가장 간단한 방식이다.
runs-on: ubuntu-latest
처럼 지정하면 GitHub가 실행 환경을 준비한다.
개발자가 별도의 서버를 관리할 필요가 없다.
전체적인 흐름은 다음과 같다.
Workflow -> GitHub -> Runner 생성 -> Job 실행 -> Runner 종료
CI 용도로는 이런 방식이 상당히 편하다.
Self-hosted Runner
직접 관리하는 서버나 PC를 Runner로 등록할 수도 있다.
GitHub -> Self-hosted Runner -> 내 서버 / 사내 서버
특정 하드웨어나 사내 네트워크에 접근해야 하는 경우 사용할 수 있다.
게임 개발에서도 상황에 따라 활용할 수 있다.
예를 들어 특정 Windows 환경에서만 가능한 빌드 작업이나 사내 네트워크에 접근해야 하는 빌드 시스템 등을 Self-hosted Runner에서 처리할 수 있다.
다만 Runner 자체를 직접 관리해야 하기 때문에 보안과 유지보수 부담이 증가한다.
CI
GitHub Actions를 가장 먼저 사용하는 목적 중 하나가 CI다.
CI는 Continuous Integration의 약자로, 개발자가 코드를 Repository에 통합할 때마다 자동으로 빌드와 테스트 등을 수행하는 방식이다.
예를 들어
Feature Branch -> Pull Request -> GitHub Actions -> Build / Unit Test / Integration Test / Lint -> 결과
PR을 Merge하기 전에 자동으로 코드를 검증할 수 있다.
PR 검증
실무에서 특히 유용한 형태다.
name: CI
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
개발자가 PR을 만들면 다음 과정이 자동으로 실행된다.
PR 생성 -> Actions 실행 -> Checkout -> 의존성 설치 -> Test -> 성공 / 실패
결과가 PR에 표시된다.
Branch Protection과 함께 사용하면 CI가 통과해야 Merge할 수 있도록 강제할 수도 있다.
CD
GitHub Actions는 배포 자동화에도 사용할 수 있다.
CD는 Continuous Delivery 또는 Continuous Deployment를 의미한다.
예를 들어
main Merge -> GitHub Actions -> Build -> Docker Image -> Registry Push -> Server Deploy
같은 Pipeline을 구성할 수 있다.
게임 서버라면
main Merge -> 서버 빌드 -> Docker Image 생성 -> Registry Push -> 서버 업데이트 -> 서비스 재시작
같은 Workflow를 만들 수 있다.
Secrets
CI/CD에서는 서버 비밀번호나 API Key 같은 민감한 정보가 필요할 수 있다.
하지만 이런 값을 YAML에 직접 작성하면 안 된다.
run: deploy --token=MY_SECRET_TOKEN
GitHub Actions에서는 Secrets를 사용할 수 있다.
Repository -> Secrets -> AWS_ACCESS_KEY / DATABASE_PASSWORD / DEPLOY_TOKEN
Workflow에서는 다음과 같이 사용할 수 있다.
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
이렇게 하면 민감한 값을 Repository 코드에 직접 저장하지 않아도 된다.
Variables와 Secrets
둘은 비슷해 보이지만 목적이 다르다.
Variables -> 일반적인 설정값
Secrets -> 공개되면 안 되는 민감한 값
예를 들어
Variables -> ENVIRONMENT=production / REGION=ap-northeast-2
Secrets -> API_KEY=... / DATABASE_PASSWORD=...
같은 식이다.
Environment
Production과 Development 같은 배포 환경을 분리할 수도 있다.
Environment -> Development / Staging / Production
각 Environment에 별도의 Secret이나 승인 정책을 설정할 수 있다.
예를 들어 Production 배포에는 관리자 승인을 요구하도록 만들 수 있다.
main Merge -> Build -> Production Deploy 요청 -> 승인 -> Deploy
운영 서버에 바로 배포되는 것을 막을 수 있다.
Matrix
같은 테스트를 여러 환경에서 실행해야 하는 경우 Matrix를 사용할 수 있다.
예를 들어 여러 Node.js 버전을 테스트하려면
strategy:
matrix:
node-version: [20, 22, 24]
처럼 설정할 수 있다.
그러면
Node 20 -> Test
Node 22 -> Test
Node 24 -> Test
를 병렬로 실행할 수 있다.
운영체제도 Matrix로 구성할 수 있다.
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
그러면
Ubuntu -> Test
Windows -> Test
macOS -> Test
처럼 여러 환경에서 동일한 테스트를 수행할 수 있다.
Job 의존성
Job은 서로 독립적으로 실행할 수 있지만 특정 Job이 끝난 뒤 다음 Job을 실행하도록 만들 수도 있다.
jobs:
build:
...
test:
needs: build
...
deploy:
needs: test
구조는 다음과 같다.
build -> test -> deploy
따라서 Build가 실패하면 Test와 Deploy도 실행되지 않는다.
CI/CD Pipeline을 구성할 때 자주 사용하는 방식이다.
병렬 실행
서로 관계가 없는 작업은 병렬로 실행할 수 있다.
Build -> Unit Test / Lint -> Deploy
여기서 Unit Test와 Lint가 서로 의존하지 않는다면 둘을 병렬로 실행할 수 있다.
Build -> Unit Test
Build -> Lint
Unit Test / Lint -> Deploy
불필요하게 모든 작업을 순차적으로 실행하면 Pipeline이 느려진다.
GitHub Actions에서는 Job 의존성을 적절히 설계해서 독립적인 작업을 병렬화할 수 있다.
Artifact
Workflow에서 생성된 파일을 다음 Job이나 이후 실행에서 사용해야 하는 경우 Artifact를 사용할 수 있다.
예를 들어
Build Job -> game-server.zip -> Artifact -> Deploy Job
빌드 결과물을 저장하고 다음 단계에서 사용할 수 있다.
게임 개발이라면
Build -> Windows Build / Linux Server Build / Asset Bundle -> Artifact
같은 결과물을 관리하는 방식도 가능하다.
Cache
빌드나 의존성 설치에는 반복적으로 같은 파일을 다운로드하는 작업이 발생한다.
예를 들어 Node.js 프로젝트라면 패키지 Cache를 사용할 수 있다.
첫 실행 -> Dependency 다운로드 -> Cache 저장
다음 실행 -> Cache 사용 -> Build
CI 실행 시간을 줄이는 데 도움이 된다.
다만 Cache는 결과물을 영구적으로 보관하는 저장소가 아니다.
재사용 가능한 중간 데이터를 빠르게 가져오기 위한 용도로 보는 편이 맞다.
Workflow Dispatch
Push나 PR 같은 이벤트가 없어도 사람이 직접 Workflow를 실행할 수 있다.
on:
workflow_dispatch:
그러면 GitHub Actions 화면에서 직접 실행할 수 있다.
배포 Workflow를 예로 들면
GitHub Actions -> Deploy Workflow -> Staging / Production
처럼 사람이 원하는 시점에 실행할 수 있다.
수동 배포나 운영 작업에서 유용하다.
Schedule
정해진 시간에 Workflow를 실행할 수도 있다.
Cron 형식을 사용한다.
on:
schedule:
- cron: "0 0 * * *"
예를 들어
매일 -> 데이터 검사 -> 테스트 -> Report 생성
같은 자동화에 사용할 수 있다.
Nightly Build 같은 작업도 이런 방식으로 구성할 수 있다.
조건문
특정 조건에서만 Step이나 Job을 실행할 수도 있다.
if: github.ref == 'refs/heads/main'
예를 들어
Pull Request -> Test
main Merge -> Test -> Deploy
처럼 조건을 나눌 수 있다.
CI와 CD를 하나의 Workflow에 구성할 때 특히 유용하다.
GitHub Actions와 Docker
GitHub Actions는 Docker와 같이 사용하는 경우가 많다.
예를 들어 서버 애플리케이션을 Docker Image로 빌드한다고 하면
Push -> GitHub Actions -> Docker Build -> Docker Image -> Container Registry -> Server
Workflow가 Docker Image를 만들고 Registry에 Push한 뒤 서버가 새로운 Image를 가져오도록 구성할 수 있다.
이 구조를 사용하면 개발자의 로컬 환경과 서버 환경을 일정하게 유지하기 쉽다.
GitHub Actions와 Cloud
AWS, Azure, Google Cloud 같은 Cloud 환경과도 연결할 수 있다.
예를 들어
GitHub -> GitHub Actions -> AWS -> EC2 / ECS / ECR / Lambda
처럼 구성할 수 있다.
다만 GitHub Actions가 Cloud 자체를 대체하는 것은 아니다.
역할이 다르다.
GitHub Actions -> 자동화 / CI/CD 실행
AWS -> 실제 서버 / 인프라 제공
실제 CI Workflow
일반적인 Backend 프로젝트라면 다음 정도의 Workflow를 생각할 수 있다.
Pull Request -> Checkout -> Dependency Install -> Build -> Unit Test -> Integration Test -> Lint / Static Analysis -> Success
모든 검증이 통과하면 PR을 Merge할 수 있게 구성한다.
실제 CD Workflow
main에 Merge되면 자동으로 배포하는 구조라면
main Merge -> Checkout -> Build -> Test -> Docker Build -> Registry Push -> Production Deploy
같은 구조가 된다.
조직에 따라 Production 배포 전에 승인 단계를 넣을 수도 있다.
Build -> Test -> Staging Deploy -> 검증 -> Production 승인 -> Production Deploy
GitHub Actions를 Git과 연결해서 보면
Git만 사용할 때는 개발자가 직접 많은 작업을 수행해야 한다.
코드 작성 -> Build -> Test -> Push -> 배포
GitHub Actions를 연결하면
코드 작성 -> Push -> GitHub Actions -> Build -> Test -> Deploy
처럼 사람이 수행하던 반복 작업을 자동화할 수 있다.
PR 기반 개발에서는 더 명확하다.
Feature Branch -> Pull Request -> GitHub Actions -> Build / Test / Lint -> Code Review -> Merge
그래서 GitHub Actions는 Git Workflow와 분리해서 생각하기보다 Git 기반 개발 Workflow에 자동화 계층을 추가하는 기술로 이해하는 편이 좋다.
GitHub Actions를 사용할 때 주의할 점
자동화한다고 모든 작업을 Workflow에 넣는 것이 좋은 것은 아니다.
예를 들어 모든 테스트와 빌드, 배포를 하나의 거대한 Workflow에 넣으면 문제가 생겼을 때 원인을 찾기 어렵다.
build.yml -> Build
test.yml -> Test
deploy.yml -> Deploy
release.yml -> Release
처럼 역할에 따라 분리하는 것도 방법이다.
또한 CI가 너무 오래 걸리면 개발자가 결과를 기다리는 시간이 길어진다.
그래서
병렬화 / Cache / 불필요한 작업 제거 / 변경된 영역만 검사
등을 고려해야 한다.
Secrets 관리도 중요하다. API Key나 Cloud Credential을 Workflow 파일에 직접 작성하면 안 된다.
GitHub Actions의 핵심 구조
전체를 하나로 묶으면 다음과 같다.
GitHub Repository -> Event -> Workflow -> Job -> Runner -> Steps -> Action / run -> Build / Test / Deploy
여기에 CI/CD를 연결하면
Pull Request -> CI -> Build / Test / Lint -> Review -> Merge -> CD -> Build / Package / Deploy
가 된다.
정리
GitHub Actions는 단순히 “GitHub에서 코드를 실행하는 기능”으로 볼 필요는 없다.
GitHub에서 발생하는 이벤트를 트리거로 개발 Workflow를 자동화하는 CI/CD 시스템이다.
핵심 개념은 다음과 같이 정리할 수 있다.
Workflow -> 자동화 작업의 전체 정의
Event -> Workflow를 실행시키는 조건
Job -> 독립적인 작업 단위
Step -> Job 내부의 실행 단계
Action -> 재사용 가능한 자동화 구성요소
Runner -> 실제 작업이 실행되는 환경
Artifact -> Workflow에서 생성된 결과물
Cache -> 반복 작업을 빠르게 하기 위한 임시 데이터
Secrets -> API Key, Password 같은 민감한 설정
Environment -> Development / Staging / Production 같은 실행 환경
실무에서는 보통 다음 구조로 연결된다.
개발자 -> Feature Branch -> Commit -> Push -> Pull Request -> GitHub Actions -> Build / Test -> Code Review -> Merge -> GitHub Actions -> Build / Deploy
Git이 코드 변경을 관리하는 시스템이라면 GitHub Actions는 그 변경을 기준으로 검증하고 빌드하고 배포하는 자동화 시스템이다.
둘을 같이 구성하면 개발자가 매번 직접 수행해야 했던 반복적인 검증과 배포 작업을 Repository Workflow에 편입시킬 수 있다.