GitHub Actions 입문 – 코드 푸시만으로 자동 빌드·배포하는 법
개인 프로젝트를 하다 보면 코드를 수정할 때마다 빌드하고, 테스트 돌리고, 서버에 배포하는 과정을 반복하게 됩니다. 처음엔 괜찮지만, 프로젝트가 커질수록 이 반복 작업이 꽤 귀찮아지죠. “코드만 푸시하면 나머지는 알아서 됐으면 좋겠다”는 생각, 한 번쯤 해보셨을 겁니다.
바로 그 역할을 해주는 것이 CI/CD(지속적 통합/지속적 배포)이고, GitHub를 쓰고 있다면 별도의 서버나 서비스 없이도 GitHub Actions로 이 모든 걸 무료로 자동화할 수 있습니다. 이번 글에서는 GitHub Actions가 뭔지, 어떻게 설정하는지, 그리고 실제로 개인 프로젝트에 바로 적용할 수 있는 실전 워크플로우까지 처음부터 끝까지 안내해 드리겠습니다.
CI/CD가 뭐고, 왜 개인 프로젝트에도 필요한가
CI/CD라는 용어가 기업 개발 환경에서만 쓰이는 것처럼 느껴질 수 있지만, 사실 개인 프로젝트에서야말로 그 효과가 즉각적으로 체감됩니다. 혼자 개발하면 코드 리뷰어도 없고, 실수를 잡아줄 동료도 없기 때문입니다.
CI(Continuous Integration, 지속적 통합)란
코드를 변경할 때마다 자동으로 빌드하고 테스트를 실행하는 것을 말합니다. 예를 들어, 블로그 사이트의 코드를 수정하고 GitHub에 푸시하면, 자동으로 “이 코드가 정상적으로 빌드되는지”, “기존 기능이 깨지지 않았는지” 확인해 주는 겁니다. 혼자 작업할 때 흔히 발생하는 “내 PC에서는 되는데 서버에서는 안 되는” 문제를 사전에 방지할 수 있습니다.
CD(Continuous Deployment, 지속적 배포)란
CI를 통과한 코드를 자동으로 실제 서버에 배포하는 과정입니다. 빌드와 테스트가 성공하면 별도의 수동 작업 없이 운영 환경에 반영되는 것이죠. FTP로 파일을 올리거나, SSH로 서버에 접속해서 명령어를 입력하는 번거로운 과정이 완전히 사라집니다.
개인 프로젝트에서 CI/CD가 주는 실질적인 이점
- 시간 절약: 빌드-테스트-배포를 수동으로 하면 매번 10~30분씩 소요되지만, 자동화하면 푸시 한 번이면 끝납니다.
- 실수 방지: 배포 전에 자동으로 테스트가 돌아가므로, 버그가 있는 코드가 실서버에 올라가는 걸 막아줍니다.
- 일관성 보장: 매번 동일한 환경에서 동일한 절차로 빌드와 배포가 진행되므로, “어제는 됐는데 오늘은 안 되네”라는 상황이 줄어듭니다.
- 포트폴리오 가치 상승: CI/CD가 적용된 프로젝트는 개발 역량을 보여주는 좋은 포트폴리오가 됩니다.
정리하면, CI/CD는 “귀찮은 반복 작업을 기계에게 맡기는 것”입니다. 그리고 GitHub Actions는 이걸 GitHub 안에서 무료로 할 수 있게 해주는 도구입니다.

GitHub Actions 핵심 개념 5분 정리
GitHub Actions를 처음 접하면 워크플로우니 잡이니 스텝이니 용어가 좀 낯설 수 있는데, 구조 자체는 아주 단순합니다. 핵심 개념 다섯 가지만 알면 바로 시작할 수 있습니다.
워크플로우(Workflow)
자동화의 전체 흐름을 정의한 파일입니다. YAML 형식으로 작성하며, 프로젝트의 .github/workflows/ 폴더 안에 저장합니다. 하나의 프로젝트에 여러 개의 워크플로우를 만들 수 있어서, 예를 들어 “빌드 및 테스트용 워크플로우”와 “배포용 워크플로우”를 각각 분리해서 관리할 수 있습니다.
이벤트(Event)
워크플로우가 실행되는 조건, 즉 트리거입니다. 가장 흔한 이벤트는 push(코드 푸시)와 pull_request(PR 생성)인데, 이 외에도 스케줄(정해진 시간에 실행), 수동 트리거, 이슈 생성 등 다양한 이벤트를 활용할 수 있습니다. 예를 들어 매일 새벽 3시에 의존성 업데이트를 확인하도록 설정할 수도 있습니다.
잡(Job)
워크플로우 안에서 실행되는 작업 단위입니다. 각 잡은 독립된 가상 머신(러너)에서 실행되며, 여러 잡을 병렬로 실행하거나 순서를 지정할 수 있습니다. 예를 들어 “테스트 잡”이 성공한 후에만 “배포 잡”이 실행되도록 순서를 정할 수 있습니다.
스텝(Step)
잡 안에서 순서대로 실행되는 개별 명령어 또는 액션입니다. 셸 명령어를 직접 실행할 수도 있고, 다른 사람이 만들어 놓은 액션을 가져다 쓸 수도 있습니다. 예를 들어 “Node.js 설치 → 패키지 설치 → 테스트 실행”처럼 순서대로 나열합니다.
액션(Action)
재사용 가능한 자동화 블록입니다. GitHub Marketplace에 수천 개의 커뮤니티 액션이 공개되어 있어서, 대부분의 작업은 이미 누군가가 만들어 놓은 액션을 가져다 쓰면 됩니다. 코드 체크아웃, Node.js 설치, Docker 이미지 빌드, SSH 배포 등 거의 모든 작업에 대한 액션이 존재합니다.
이 다섯 가지를 요리에 비유하면 이렇습니다. 워크플로우는 레시피 전체, 이벤트는 “손님이 주문하면”이라는 시작 조건, 잡은 “전채 준비”와 “메인 요리”처럼 큰 작업 구분, 스텝은 “양파 썰기 → 볶기 → 소스 넣기” 같은 세부 단계, 액션은 미리 만들어진 소스나 반조리 식품 같은 겁니다.
첫 번째 워크플로우 만들기: 실전 따라하기
이론은 여기까지, 이제 직접 만들어 봅시다. GitHub 저장소에 코드를 푸시할 때마다 자동으로 빌드하고 테스트하는 워크플로우를 단계별로 작성해 보겠습니다.
Step 1: 워크플로우 파일 생성
프로젝트 루트에 .github/workflows/ 디렉토리를 만들고, 그 안에 YAML 파일을 생성합니다. 파일 이름은 자유지만, 역할을 알 수 있도록 짓는 게 좋습니다.
Node.js 프로젝트 기준 기본 예시 (ci.yml):
name: CI 빌드 및 테스트
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: 코드 체크아웃
uses: actions/checkout@v4
- name: Node.js 설치
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 의존성 설치
run: npm ci
- name: 린트 검사
run: npm run lint
- name: 테스트 실행
run: npm test
- name: 빌드
run: npm run build
이 워크플로우는 main 브랜치에 푸시하거나 PR을 올릴 때 자동으로 실행됩니다. Ubuntu 환경에서 코드를 가져와 Node.js 20 버전을 설치하고, 의존성을 설치한 뒤 린트 검사, 테스트, 빌드를 순서대로 진행합니다.
Step 2: YAML 문법 핵심 포인트
GitHub Actions의 YAML 파일을 작성할 때 자주 실수하는 부분들이 있습니다.
- 들여쓰기는 반드시 스페이스: 탭(Tab)을 쓰면 에러가 납니다. 스페이스 2칸을 기본으로 사용하세요.
- on 키워드: YAML에서 on은 true로 해석될 수 있어서, 일부 에디터에서 경고가 뜰 수 있습니다. 따옴표로 감싸서 ‘on’으로 쓰거나 그냥 무시해도 GitHub에서는 정상 동작합니다.
- uses vs run: uses는 미리 만들어진 액션을 사용할 때, run은 셸 명령어를 직접 실행할 때 씁니다.
- 환경 변수와 시크릿: API 키나 비밀번호는 절대 YAML 파일에 직접 쓰지 마세요. GitHub 저장소의 Settings → Secrets and variables → Actions에서 등록하고, ${{ secrets.MY_SECRET }} 형태로 참조합니다.
Step 3: 워크플로우 실행 확인
파일을 커밋하고 푸시하면, GitHub 저장소의 Actions 탭에서 워크플로우 실행 상태를 실시간으로 확인할 수 있습니다. 각 스텝별로 로그가 남으므로, 어디서 에러가 났는지 정확하게 파악할 수 있습니다. 초록색 체크 표시가 뜨면 성공, 빨간 X 표시가 뜨면 실패입니다.

Spring Boot(Java/Kotlin) 프로젝트 예시
Node.js가 아닌 Spring Boot 프로젝트를 운영하고 있다면, 다음과 같이 작성합니다.
name: Spring Boot CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: 코드 체크아웃
uses: actions/checkout@v4
- name: JDK 21 설치
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '21'
cache: 'gradle'
- name: Gradle 빌드 및 테스트
run: ./gradlew build
- name: 테스트 리포트 업로드
if: always()
uses: actions/upload-artifact@v4
with:
name: test-report
path: build/reports/tests/
Gradle 캐시를 활용하면 두 번째 실행부터 의존성 다운로드 시간이 대폭 줄어들고, 테스트 리포트를 아티팩트로 업로드하면 실패 원인을 나중에도 확인할 수 있습니다.
Python 프로젝트 예시
Python 프로젝트도 동일한 구조로 적용할 수 있습니다.
name: Python CI
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Python 3.12 설치
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: 의존성 설치
run: pip install -r requirements.txt
- name: 테스트 실행
run: pytest --tb=short
어떤 언어나 프레임워크를 쓰든 기본 구조는 동일합니다. 코드 체크아웃 → 런타임 설치 → 의존성 설치 → 테스트 → 빌드, 이 흐름만 기억하면 됩니다.
실전 활용: 개인 프로젝트에 바로 적용하는 워크플로우 레시피
기본 CI 워크플로우를 넘어서, 개인 프로젝트에서 실제로 유용하게 쓸 수 있는 워크플로우 패턴들을 소개합니다.
레시피 1: 정적 사이트를 GitHub Pages에 자동 배포
Next.js, Gatsby, Hugo 같은 정적 사이트 생성기로 만든 블로그나 포트폴리오를 GitHub Pages에 자동 배포하는 워크플로우입니다.
name: GitHub Pages 배포
on:
push:
branches: [main]
permissions:
contents: read
pages: write
id-token: write
jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- name: Pages 설정
uses: actions/configure-pages@v4
- name: 빌드 결과물 업로드
uses: actions/upload-pages-artifact@v3
with:
path: './dist'
- name: 배포
id: deployment
uses: actions/deploy-pages@v4
이 워크플로우를 설정해 두면, main 브랜치에 코드를 푸시하는 것만으로 사이트가 자동으로 빌드되고 GitHub Pages에 배포됩니다. 별도의 호스팅 비용도 들지 않습니다.
레시피 2: Docker 이미지 빌드 후 Docker Hub에 자동 푸시
컨테이너 기반으로 프로젝트를 운영한다면, 코드 변경 시 자동으로 Docker 이미지를 빌드하고 레지스트리에 올리는 워크플로우가 유용합니다.
name: Docker 빌드 및 푸시
on:
push:
tags: ['v*']
jobs:
docker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Docker Hub 로그인
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: 메타데이터 추출
id: meta
uses: docker/metadata-action@v5
with:
images: myuser/my-app
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: 빌드 및 푸시
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
v1.0.0 같은 태그를 붙여서 푸시하면, 해당 버전의 Docker 이미지가 자동으로 빌드되어 Docker Hub에 올라갑니다. 개인 NAS에서 Docker 컨테이너를 운영하고 있다면 특히 유용한 패턴입니다.
레시피 3: 스케줄 기반 자동 실행 (의존성 업데이트 확인)
매주 월요일 아침마다 자동으로 의존성 보안 취약점을 검사하는 워크플로우입니다.
name: 주간 보안 점검
on:
schedule:
- cron: '0 0 * * 1' # 매주 월요일 UTC 00:00 (한국시간 09:00)
workflow_dispatch: # 수동 실행도 가능
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: 보안 취약점 검사
run: npm audit --audit-level=high
continue-on-error: true
- name: 결과 알림
if: failure()
run: |
curl -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_TOKEN }}/sendMessage" \
-d chat_id=${{ secrets.TELEGRAM_CHAT_ID }} \
-d text="⚠️ 보안 취약점이 발견되었습니다. GitHub Actions에서 확인해주세요."
schedule 이벤트와 cron 표현식을 사용하면 특정 시간에 자동으로 워크플로우를 실행할 수 있고, Telegram이나 Slack으로 결과를 알림 받을 수도 있습니다. workflow_dispatch를 함께 설정하면 필요할 때 수동으로도 실행할 수 있어 편리합니다.
레시피 4: PR에 자동 코드 리뷰 코멘트 추가
혼자 개발하더라도 PR 기반으로 작업하면 변경 이력 추적이 쉬워집니다. 여기에 자동 린트 결과를 코멘트로 달아주면 더욱 체계적으로 관리할 수 있습니다.
name: PR 린트 리뷰
on:
pull_request:
branches: [main]
jobs:
lint-review:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- name: ESLint 리뷰
uses: reviewdog/action-eslint@v1
with:
reporter: github-pr-review
eslint_flags: 'src/'
reviewdog 액션을 활용하면 린트 결과가 PR의 변경된 코드 라인에 직접 코멘트로 달리기 때문에, 어디를 수정해야 하는지 한눈에 파악할 수 있습니다.

비용 절약과 속도 최적화 팁
GitHub Actions는 퍼블릭 저장소에서는 완전히 무료이고, 프라이빗 저장소에서도 월 2,000분의 무료 실행 시간이 제공됩니다. 하지만 워크플로우를 비효율적으로 구성하면 실행 시간이 쓸데없이 길어지고, 무료 할당량을 빠르게 소진할 수 있습니다.
캐시를 적극 활용하세요
의존성 다운로드는 매 실행마다 반복되는 가장 큰 시간 낭비 요소입니다. setup-node, setup-java, setup-python 등의 공식 액션은 대부분 cache 옵션을 지원합니다.
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # 이 한 줄이 빌드 시간을 절반으로 줄입니다
npm ci 기준으로 캐시가 없으면 30초~1분 이상 걸리던 의존성 설치가, 캐시가 히트하면 5초 이내로 줄어듭니다. 반드시 설정하세요.
불필요한 트리거를 줄이세요
README만 수정했는데 전체 빌드가 돌아가는 건 낭비입니다. paths 필터를 사용하면 특정 파일이 변경되었을 때만 워크플로우가 실행되도록 할 수 있습니다.
on:
push:
branches: [main]
paths:
- 'src/**'
- 'package.json'
- 'package-lock.json'
paths-ignore:
- '**.md'
- 'docs/**'
이렇게 설정하면 소스 코드나 의존성 파일이 변경되었을 때만 워크플로우가 실행되고, 문서 파일만 수정했을 때는 건너뜁니다.
잡 병렬 실행과 매트릭스 전략
여러 환경에서 테스트해야 한다면, 매트릭스 전략을 사용하면 병렬로 실행됩니다.
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
Node.js 18, 20, 22 세 가지 버전에서 테스트가 동시에 실행되므로, 순차적으로 돌리는 것보다 전체 시간이 크게 줄어듭니다. 개인 프로젝트에서는 보통 한두 가지 버전이면 충분하지만, 오픈소스 라이브러리를 운영한다면 매트릭스 전략이 필수입니다.
concurrency 설정으로 중복 실행 방지
짧은 시간에 여러 번 푸시하면 이전 실행이 끝나기 전에 새 실행이 시작되어 리소스가 낭비됩니다. concurrency 설정으로 이전 실행을 자동 취소할 수 있습니다.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
이 두 줄을 워크플로우 최상단에 추가하면, 같은 브랜치에서 새로운 푸시가 발생했을 때 아직 진행 중인 이전 워크플로우를 자동으로 취소합니다. 무료 할당량을 아끼는 데 매우 효과적입니다.
보안 주의사항과 실수 방지 체크리스트
GitHub Actions는 강력한 만큼, 보안에 신경 쓰지 않으면 비밀 정보가 유출되거나 의도치 않은 동작이 발생할 수 있습니다. 개인 프로젝트라도 반드시 아래 사항을 체크하세요.
시크릿 관리 원칙
- 절대로 YAML 파일에 API 키, 비밀번호, 토큰을 직접 쓰지 마세요. 커밋 히스토리에 남아서 삭제해도 복구할 수 있습니다.
- GitHub의 Settings → Secrets and variables → Actions에서 시크릿을 등록하고, 워크플로우에서는 ${{ secrets.SECRET_NAME }}으로 참조합니다.
- 시크릿 값은 로그에 자동으로 마스킹되지만, base64 인코딩 같은 변환을 거치면 마스킹이 풀릴 수 있으므로 주의하세요.
서드파티 액션 사용 시 주의점
- 커뮤니티 액션을 사용할 때는 반드시 특정 버전(SHA 또는 태그)을 지정하세요. uses: some-action@main처럼 브랜치를 지정하면, 해당 액션이 업데이트될 때 예기치 않은 동작이 발생할 수 있습니다.
- uses: actions/checkout@v4처럼 메이저 버전 태그를 사용하는 것이 보안과 안정성 사이의 적절한 균형입니다.
- 중요한 프로젝트라면 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11처럼 커밋 SHA를 사용하는 것이 가장 안전합니다.
권한 최소화 원칙
워크플로우에 permissions를 명시적으로 설정하여 필요한 최소한의 권한만 부여하세요.
permissions:
contents: read # 코드 읽기만 필요
packages: write # 패키지 배포가 필요한 경우에만
permissions를 설정하지 않으면 기본적으로 넓은 권한이 부여되는데, 이는 보안 사고의 원인이 될 수 있습니다.
포크(Fork) 저장소에서의 실행
오픈소스 프로젝트를 운영한다면, 포크된 저장소에서 올라오는 PR에 대해 워크플로우가 실행될 때 시크릿에 접근할 수 없도록 GitHub가 기본적으로 보호하고 있습니다. 이 설정을 임의로 변경하지 마세요.
GitHub Actions 시작 전 체크리스트
마지막으로, GitHub Actions를 처음 도입할 때 확인해야 할 사항들을 정리합니다.
- 저장소 확인: GitHub에 저장소가 있어야 합니다. 퍼블릭 저장소는 무료 한도가 무제한이고, 프라이빗 저장소는 월 2,000분(무료 플랜 기준)입니다.
- 폴더 구조: .github/workflows/ 폴더를 만들고 그 안에 .yml 파일을 저장합니다.
- 시크릿 등록: 배포에 필요한 토큰, API 키 등을 미리 GitHub Secrets에 등록합니다.
- 워크플로우 파일 작성: 위에서 소개한 예시 중 프로젝트에 맞는 것을 복사해서 수정합니다.
- 푸시 후 확인: Actions 탭에서 실행 결과를 확인하고, 에러가 있으면 로그를 보면서 수정합니다.
처음에는 간단한 CI 워크플로우(빌드+테스트)부터 시작하고, 익숙해지면 배포 자동화, 스케줄 실행, 알림 연동 등을 하나씩 추가해 가는 것을 추천합니다. 한 번 세팅해 놓으면 그 다음부터는 코드에만 집중할 수 있어서, “왜 진작 안 했을까”라는 생각이 들 겁니다.
GitHub Actions는 개인 개발자에게 주어진 가장 실용적인 자동화 도구입니다. 복잡한 인프라 없이도 프로급 CI/CD 파이프라인을 구축할 수 있으니, 오늘 바로 첫 워크플로우를 만들어 보세요. 코드를 푸시하고 Actions 탭에서 초록색 체크 마크가 뜨는 그 순간의 만족감은 직접 경험해 봐야 알 수 있습니다.
이미지는 Leonardo AI 로 생성되었습니다.
이미지는 Claude AI 로 생성되었습니다.


