[이제와서 시작하는 GitHub 마스터하기 - 고급편 #1-3] GitHub Actions: 고급 기능과 최적화
[이제와서 시작하는 GitHub 마스터하기 - 고급편 #1-3] GitHub Actions: 고급 기능과 최적화
들어가며
이전 편에서 CI/CD 파이프라인을 구축하는 방법을 배웠습니다. 이번 편에서는 워크플로우를 더 효율적으로 만드는 고급 기능들을 알아보겠습니다.
💡 이 글은 누구를 위한 글인가요?
- 기본 CI/CD 파이프라인을 구축해본 분
- 워크플로우를 재사용하고 싶은 분
- 실행 시간과 비용을 최적화하고 싶은 분
1. 재사용 가능한 워크플로우 (⭐ 중급자 필수)
왜 재사용이 필요한가요?
문제: 여러 프로젝트에서 비슷한 워크플로우 반복
1
2
3
project-a/.github/workflows/test.yml (100줄)
project-b/.github/workflows/test.yml (100줄, 거의 같음)
project-c/.github/workflows/test.yml (100줄, 거의 같음)
해결: 하나의 템플릿을 만들어서 재사용!
1
2
3
4
5
.github/workflows/reusable-test.yml (템플릿)
↓ (사용)
project-a/.github/workflows/test.yml (10줄)
project-b/.github/workflows/test.yml (10줄)
project-c/.github/workflows/test.yml (10줄)
재사용 가능한 워크플로우 만들기
Step 1: 템플릿 파일 생성
.github/workflows/reusable-test.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
name: Reusable Test Workflow
on:
workflow_call: # 다른 워크플로우에서 호출 가능
inputs:
node-version:
required: true
type: string
description: 'Node.js version to use'
run-lint:
required: false
type: boolean
default: true
description: 'Run lint'
secrets:
npm-token:
required: false
description: 'NPM registry token'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- name: Install dependencies
run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.npm-token }}
- name: Lint
if: ${{ inputs.run-lint }}
run: npm run lint
- name: Test
run: npm test
Step 2: 다른 워크플로우에서 사용
.github/workflows/ci.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
name: CI
on: [push, pull_request]
jobs:
test-node-18:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '18.x'
run-lint: true
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}
test-node-20:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20.x'
run-lint: false
장점
| 이점 | 설명 | 예시 |
|---|---|---|
| 재사용성 | 한 번 작성, 여러 곳에서 사용 | 모든 프로젝트에 동일한 테스트 |
| 유지보수 | 한 곳만 수정하면 모든 곳에 적용 | 버그 수정 한 번에 배포 |
| 일관성 | 모든 프로젝트가 같은 방식 사용 | 표준화된 CI/CD |
2. 매트릭스 전략: 여러 환경에서 동시 테스트
기본 매트릭스
목표: Node.js 16, 18, 20 버전에서 모두 테스트하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16, 18, 20] # 3개 버전
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
이 워크플로우는 3개의 병렬 작업을 생성합니다!
graph LR
A[Git Push] --> B[Matrix Strategy]
B --> C[Node 16 Test]
B --> D[Node 18 Test]
B --> E[Node 20 Test]
C --> F[결과]
D --> F
E --> F
style B fill:#bbf,stroke:#333,stroke-width:2px
style F fill:#9f9,stroke:#333,stroke-width:2px
다차원 매트릭스
목표: 여러 OS + 여러 Node 버전 조합 테스트
1
2
3
4
5
6
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20]
runs-on: ${{ matrix.os }}
이것은 6개의 조합을 만듭니다!
| OS | Node 18 | Node 20 |
|---|---|---|
| Ubuntu | ✅ | ✅ |
| Windows | ✅ | ✅ |
| macOS | ✅ | ✅ |
특정 조합 제외하기
1
2
3
4
5
6
7
8
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [16, 18, 20]
exclude:
# Windows + Node 16은 불안정하여 제외
- os: windows-latest
node-version: 16
🚀 고급 옵션 (클릭하여 펼치기)
특정 조합 추가하기
1
2
3
4
5
6
7
8
9
strategy:
matrix:
os: [ubuntu-latest]
node-version: [18, 20]
include:
# macOS에서 최신 버전만 추가 테스트
- os: macos-latest
node-version: 20
experimental: true
하나 실패해도 나머지 계속 실행
1
2
3
4
strategy:
fail-fast: false # 기본값: true
matrix:
node-version: [16, 18, 20]
fail-fast: true- 하나 실패하면 나머지 중단fail-fast: false- 모두 실행
3. 조건부 실행
브랜치별 다른 동작
1
2
3
4
5
6
7
8
9
10
11
12
13
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to Production
if: github.ref == 'refs/heads/main'
run: echo "Deploying to production"
- name: Deploy to Staging
if: github.ref == 'refs/heads/develop'
run: echo "Deploying to staging"
PR에서만 실행
1
2
3
4
5
- name: Comment on PR
if: github.event_name == 'pull_request'
run: |
echo "This is a PR!"
echo "PR number: $"
이전 단계 결과에 따라 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Run tests
id: tests
run: npm test
continue-on-error: true # 실패해도 계속
- name: Notify on failure
if: failure()
run: echo "Tests failed!"
- name: Notify on success
if: success()
run: echo "All tests passed!"
- name: Always cleanup
if: always()
run: echo "Cleanup resources"
조건 함수
| 함수 | 언제 true? | 예시 |
|---|---|---|
success() | 이전 단계 모두 성공 | 배포 |
failure() | 이전 단계 실패 | 에러 알림 |
always() | 항상 실행 | 정리 작업 |
cancelled() | 워크플로우 취소됨 | 리소스 정리 |
4. 모니터링과 알림
Slack 알림
목표: 배포 성공/실패 시 Slack으로 알림
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy
id: deploy
run: |
# 배포 로직
echo "deploy-url=https://app.example.com" >> $GITHUB_OUTPUT
- name: Notify Slack (Success)
if: success()
uses: slackapi/slack-github-action@v1.24.0
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "✅ 배포 성공!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*배포 성공!* 🎉\n*URL:* ${{ steps.deploy.outputs.deploy-url }}"
}
}
]
}
- name: Notify Slack (Failure)
if: failure()
uses: slackapi/slack-github-action@v1.24.0
with:
webhook-url: ${{ secrets.SLACK_WEBHOOK }}
payload: |
{
"text": "❌ 배포 실패!",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*배포 실패* ❌\n*로그:* ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
}
}
]
}
Slack Webhook 설정 방법
- Slack 워크스페이스에서 Apps → Incoming Webhooks 추가
- Webhook URL 복사
- GitHub → Settings → Secrets →
SLACK_WEBHOOK추가
Discord 알림
1
2
3
4
5
6
- name: Discord notification
uses: Ilshidur/action-discord@master
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
with:
args: '배포 완료! https://app.example.com'
Email 알림
1
2
3
4
5
6
7
8
9
10
11
12
- name: Send email
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.EMAIL_USERNAME }}
password: ${{ secrets.EMAIL_PASSWORD }}
subject: GitHub Actions 실패 알림
to: team@example.com
from: GitHub Actions
body: 워크플로우가 실패했습니다!
상태 배지 추가
README.md에 추가:
1
2
3
4
# My Project


5. 비용 최적화 (⭐ 중급자 필수)
GitHub Actions 요금제
| 플랜 | Public 저장소 | Private 저장소 (월 무료 시간) | 추가 비용 |
|---|---|---|---|
| Free | 무제한 | 2,000분 | $0.008/분 |
| Pro | 무제한 | 3,000분 | $0.008/분 |
| Team | 무제한 | 10,000분 | $0.008/분 |
⚠️ 주의: 무료 시간을 초과하면 요금이 부과됩니다!
비용 절감 전략
1. 중복 실행 방지
1
2
3
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true # 이전 실행 취소
효과: 같은 브랜치에 연속으로 푸시 시 이전 워크플로우 자동 취소!
2. 변경된 파일만 검사
1
2
3
4
5
6
7
8
on:
push:
paths:
- 'src/**' # src 폴더만
- 'package.json'
pull_request:
paths:
- 'src/**'
효과: 문서 수정 시에는 워크플로우 실행 안 함!
3. 조건부 Job 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
jobs:
check-changes:
runs-on: ubuntu-latest
outputs:
backend-changed: ${{ steps.filter.outputs.backend }}
frontend-changed: ${{ steps.filter.outputs.frontend }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
backend:
- 'backend/**'
frontend:
- 'frontend/**'
test-backend:
needs: check-changes
if: needs.check-changes.outputs.backend-changed == 'true'
runs-on: ubuntu-latest
steps:
- run: echo "Testing backend"
test-frontend:
needs: check-changes
if: needs.check-changes.outputs.frontend-changed == 'true'
runs-on: ubuntu-latest
steps:
- run: echo "Testing frontend"
효과: 백엔드만 변경하면 프론트엔드 테스트 건너뜀!
4. 캐싱 활용
1
2
3
4
5
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
효과: 의존성 설치 시간 2분 → 10초!
비용 모니터링
Settings → Billing and plans → Actions 에서 사용량 확인:
- 이번 달 사용 시간
- 남은 무료 시간
- 예상 비용
6. 2025년 최신 기능
GPU Runners (ML/AI 작업)
1
2
3
4
5
6
jobs:
train-model:
runs-on: [gpu, nvidia-t4] # GPU 러너
steps:
- name: Train ML model
run: python train.py
언제 사용?:
- 머신러닝 모델 학습
- 이미지/비디오 처리
- 3D 렌더링
💡 참고: GPU 러너는 유료입니다!
Copilot 통합 (AI 기반 워크플로우 생성)
1
2
3
4
5
- name: AI-powered workflow optimization
uses: github/copilot-actions@v1
with:
task: optimize-workflow
context: ${{ toJson(github) }}
기능:
- 자연어로 워크플로우 생성
- 자동 최적화 제안
- 에러 자동 수정
Merge Queue (안전한 병합)
1
2
on:
merge_group: # Merge Queue 이벤트
기능:
- PR을 순차적으로 테스트 후 병합
- 동시 병합으로 인한 충돌 방지
7. 트러블슈팅 가이드
일반적인 문제와 해결법
| 문제 | 원인 | 해결 방법 |
|---|---|---|
| 워크플로우 실행 안 됨 | 파일 위치 오류 | .github/workflows/ 확인 |
| 권한 오류 | 토큰 권한 부족 | permissions 추가 |
| 캐시 미스 | 키 변경됨 | hashFiles() 확인 |
| 시크릿 안 보임 | 이름 오타 | 대소문자 구분 확인 |
| 느린 빌드 | 캐싱 없음 | cache 옵션 추가 |
디버깅 팁
1. Context 정보 출력
1
2
3
4
5
- name: Dump GitHub context
run: echo '${{ toJson(github) }}'
- name: Dump Job context
run: echo '${{ toJson(job) }}'
2. SSH로 러너 접속 (고급)
1
2
3
4
- name: Debug with tmate
if: failure()
uses: mxschmitt/action-tmate@v3
timeout-minutes: 15
실패 시 SSH로 접속하여 직접 디버깅 가능!
3. 로컬에서 테스트
1
2
3
4
5
# act 설치
brew install act
# 워크플로우 로컬 실행
act push
8. 베스트 프랙티스 체크리스트
보안
- 시크릿을 코드에 쓰지 않기
permissions최소 권한으로 설정- Dependabot으로 의존성 업데이트
- 써드파티 Action은 특정 버전(
@v4)사용
성능
- 캐싱 활용하기
- 병렬 Job 최대한 활용
- 변경된 파일만 검사하기
- 불필요한 Step 제거
유지보수
- 재사용 가능한 워크플로우 작성
- 명확한 이름 사용
- 주석으로 복잡한 로직 설명
- README에 워크플로우 문서화
9. 실습 과제
📝 초보자 과제 (필수)
- 재사용 가능한 워크플로우 만들어보기
- 매트릭스 전략으로 여러 버전 테스트하기
- Slack 알림 추가하기
- README에 상태 배지 추가하기
🚀 중급자 과제 (도전)
- 조건부 배포 (main → production, develop → staging)
- 비용 최적화 (concurrency, paths 필터)
- 커스텀 Action 만들기
- 멀티 스테이지 파이프라인 구축
10. 정리
GitHub Actions는 무궁무진합니다! 기본만 알아도 90%는 해결됩니다.
이 시리즈에서 배운 것:
- [#1] 입문편: Workflow, Job, Step 기본 개념
- [#1-2] CI/CD편: 언어별 CI, 자동 배포
- [#1-3] 고급편 (현재): 재사용, 매트릭스, 알림, 최적화
다음 단계:
- 본인 프로젝트에 전체 파이프라인 구축
- 비용 최적화로 무료 플랜 내에서 활용
- [고급편 #2]에서 더 복잡한 패턴 배우기
📚 GitHub 마스터하기 시리즈
🚀 고급편 (전문가)
- GitHub Actions 입문
- GitHub Actions: CI/CD 파이프라인 ⬅️ 이전 편
- [GitHub Actions: 고급 기능] (현재 글)
- Actions 고급 활용 ⬅️ 다음 편
- Webhooks와 API
- GitHub Apps 개발
- 보안 기능
- GitHub Packages
- Codespaces
- GitHub CLI
- 통계와 인사이트
“늦었다고 생각할 때가 가장 빠른 때입니다. 지금 시작하세요!” 🚀
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.