🔀
Git·GitHub 심화
workflow yml · triggers · matrix · cache · secrets
8단원 — GitHub Actions
GitHub Actions는 코드 push, PR 생성, 일정 시간 등 이벤트에 반응해 자동으로 빌드·테스트·배포를 실행하는 CI/CD 플랫폼입니다. YAML 파일 하나로 복잡한 파이프라인을 정의할 수 있으며, 오픈 소스 액션을 재사용해 빠르게 구성할 수 있습니다.
actionsciworkflow
소요 시간
⏱ 1~2시간
난이도
📊 중급
선수 조건
🎯 7단원
결과물
GitHub Actions 로 CI 자동화
이 강의에서 배우는 것
- 1GitHub Actions 워크플로우 YAML의 기본 구조를 이해하고 작성할 수 있다.
- 2`push`·`pull_request` 트리거와 수동 트리거(`workflow_dispatch`)를 설정할 수 있다.
- 3매트릭스(matrix)로 여러 OS/버전 조합에서 병렬 테스트를 실행할 수 있다.
- 4의존성 캐시로 워크플로우 실행 시간을 단축할 수 있다.
- 5artifacts로 빌드 산출물을 저장하고, secrets로 민감 정보를 안전하게 사용할 수 있다.
핵심 개념
1) 워크플로우 구조
yaml
name: 워크플로우 이름
on: # 트리거
push:
branches: [main]
pull_request:
branches: [main]
jobs:
job-name:
runs-on: ubuntu-latest # 실행 환경
steps:
- uses: actions/checkout@v4 # 액션 사용
- name: 단계 이름
run: echo "Hello" # 셸 명령2) 트리거 종류
yaml
on:
push: # push 이벤트
branches: [main, develop]
paths: ['src/**'] # 특정 경로 변경 시만
pull_request:
types: [opened, synchronize, reopened]
schedule:
- cron: '0 9 * * 1' # 매주 월요일 09:00 UTC
workflow_dispatch: # 수동 실행 (UI 버튼)
inputs:
environment:
type: choice
options: [staging, production]3) 매트릭스 전략
yaml
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
fail-fast: false # 하나 실패해도 나머지 계속 실행
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}4) 캐시
yaml
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-5) Artifacts
yaml
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7
# 다운로드
- uses: actions/download-artifact@v4
with:
name: build-output6) Secrets
yaml
env:
API_KEY: ${{ secrets.API_KEY }}
DB_URL: ${{ secrets.DATABASE_URL }}
# GitHub → 저장소 Settings → Secrets and variables → Actions → New repository secret예제로 보기
예제 1 — `ex01_hello.yml` : push 시 "Hello" 출력
yaml
name: Hello World
on:
push:
branches: [main]
workflow_dispatch:
jobs:
greet:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Say Hello
run: |
echo "Hello, GitHub Actions!"
echo "Repo: ${{ github.repository }}"
echo "Branch: ${{ github.ref_name }}"
echo "Actor: ${{ github.actor }}"**실행 결과 (Actions 탭에서 확인)**
text
Hello, GitHub Actions!
Repo: username/my-repo
Branch: main
Actor: username핵심: `github` 컨텍스트로 저장소·브랜치·사용자 정보를 가져올 수 있다.
예제 2 — `ex02_test.yml` : Node.js 프로젝트 CI
yaml
name: Node.js CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test
- name: Build
run: npm run build핵심: `npm ci`는 `package-lock.json`을 기준으로 정확히 설치해 재현성을 보장한다.
예제 3 — `ex03_matrix.yml` : OS·Node 버전 매트릭스
yaml
name: Matrix Build
on:
push:
branches: [main]
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [18, 20, 22]
exclude:
- os: windows-latest
node-version: 18 # 특정 조합 제외
steps:
- uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install and test
run: |
npm ci
npm test핵심: 3 × 3 = 9개(제외 1개 포함 시 8개) 조합이 병렬로 실행된다.
예제 4 — `ex04_cache.yml` : 캐시로 설치 시간 단축 + artifacts 저장
yaml
name: Build with Cache
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # 내장 캐시 (actions/cache 자동 설정)
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/
retention-days: 7
deploy:
needs: build # build 완료 후 실행
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/
- name: Deploy
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
run: echo "Deploying with secret key (masked)"핵심: `needs`로 job 간 순서를 지정하고, secrets으로 민감 정보를 안전하게 전달한다.
다른 시각으로 보기
| Actions 개념 | 비유 |
|---|---|
| workflow | 공장 생산 라인 설계도 |
| job | 생산 라인의 각 작업장 |
| step | 작업장에서의 세부 작업 |
| action (`uses`) | 기성품 도구 |
| matrix | 여러 공장에서 동시 생산 |
| artifact | 완성품 포장 박스 |
| secrets | 금고에 잠긴 열쇠 |
자주 하는 실수
- **`actions/checkout` 없이 코드 접근** — 워크플로우는 코드를 자동으로 가져오지 않는다.
- **secrets를 `echo`로 출력** — GitHub가 마스킹하지만 로그에 남을 수 있다.
- **캐시 key를 고정** — 의존성이 바뀌어도 캐시가 갱신되지 않는다; `hashFiles`로 동적 키를 사용한다.
- **`fail-fast: true` 기본값 방치** — 하나 실패하면 모든 matrix job이 취소된다.
- **`on: push` 없이 `workflow_dispatch` 만 설정** — 자동 실행이 되지 않는다.
정리
- 워크플로우는 `.github/workflows/*.yml` 에 저장하며 이벤트 → job → step 구조다.
- 매트릭스로 여러 환경 조합을 병렬 실행해 테스트 커버리지를 높인다.
- `cache`로 의존성 설치 시간을 단축하고, `artifact`로 빌드 결과물을 저장한다.
- `secrets`는 GitHub UI에서 설정하고, 워크플로우에서 `${{ secrets.NAME }}`으로 참조한다.
- `needs`로 job 간 의존 관계를 설정해 순서를 제어한다.
직접 해 보기
bash
# Actions yml 파일은 GitHub 저장소에서 실행됩니다.
# 아래 명령으로 파일을 워크플로우 디렉토리에 복사하세요.
mkdir -p .github/workflows
cp 08_GitHub_Actions/src/ex01_hello.yml .github/workflows/
git add .github/workflows/ex01_hello.yml
git commit -m "ci: add hello workflow"
git push
# → GitHub 저장소 Actions 탭에서 결과를 확인하세요.응용:
- `workflow_dispatch` 에 `input` 파라미터를 추가해 수동 실행 시 환경을 선택하게 해 보세요.
- `schedule` 트리거로 매일 자정에 실행되는 워크플로우를 만들어 보세요.
💻 예제 (examples)
실제로 실행해 결과를 확인할 수 있는 예제입니다.
ex01_hello.yml— push 시 "Hello" 출력
CODE
name: Hello World
on:
push:
branches: [main]
workflow_dispatch:
jobs:
greet:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Print environment info
run: |
echo "=== Hello, GitHub Actions! ==="
echo "Repository : ${{ github.repository }}"
echo "Branch : ${{ github.ref_name }}"
echo "Actor : ${{ github.actor }}"
echo "Commit SHA : ${{ github.sha }}"
echo "Runner OS : ${{ runner.os }}"
- name: List files
run: ls -la
ex02_test.yml— Node.js 프로젝트 CI
CODE
name: Node.js CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint --if-present
- name: Run tests
run: npm test --if-present
- name: Build
run: npm run build --if-present
- name: Report status
if: always()
run: |
echo "Job status: ${{ job.status }}"
ex03_matrix.yml— OS·Node 버전 매트릭스
CODE
name: Matrix Build
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
name: Test on ${{ matrix.os }} / Node ${{ matrix.node-version }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node-version: [18, 20, 22]
exclude:
- os: windows-latest
node-version: 18
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Show environment
run: |
node --version
npm --version
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test --if-present
summary:
name: Matrix Summary
needs: test
runs-on: ubuntu-latest
if: always()
steps:
- name: Print result
run: echo "All matrix jobs completed with status ${{ needs.test.result }}"
ex04_cache.yml— 캐시로 설치 시간 단축 + artifacts 저장
CODE
name: Build with Cache and Artifacts
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js with npm cache
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests
run: npm test --if-present
- name: Build
run: npm run build --if-present
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: dist-${{ github.sha }}
path: |
dist/
!dist/**/*.map
retention-days: 7
if-no-files-found: warn
deploy:
name: Deploy to production
needs: build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: production
steps:
- name: Download artifacts
uses: actions/download-artifact@v4
with:
name: dist-${{ github.sha }}
path: dist/
- name: Deploy
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
TARGET_HOST: ${{ secrets.TARGET_HOST }}
run: |
echo "Deploying to $TARGET_HOST..."
echo "Token length: ${#DEPLOY_TOKEN} chars"
echo "Deploy complete!"
📝 과제 (exercises)
직접 풀어보고, 막힐 때 정답을 펼쳐 비교해보세요.
과제 1
문제 1 (hw01.yml)
목표: push 시 bash 스크립트를 실행하고 결과를 artifact로 저장하는 워크플로우를 작성하세요.
요구사항
- 파일명: hw01.yml
입출력 예시
# 예시 구조
name: CI Report
on:
push:
branches: [main]
workflow_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
...▶정답 코드 펼치기 / 접기
SOLUTION
name: CI Report
on:
push:
branches: [main]
workflow_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Generate report
run: |
{
echo "=== Build Report ==="
echo "Date: $(date)"
echo ""
echo "=== System Info ==="
uname -a
echo ""
echo "=== Recent Commits ==="
git log --oneline -5
} > report.txt
cat report.txt
- name: Upload report artifact
uses: actions/upload-artifact@v4
with:
name: ci-report
path: report.txt
retention-days: 3
▶ 실행 결과
# 예시 구조
name: CI Report
on:
push:
branches: [main]
workflow_dispatch:
jobs:
report:
runs-on: ubuntu-latest
steps:
...과제 2
문제 2 (hw02.yml)
목표: Python 프로젝트를 위한 매트릭스 CI 워크플로우를 작성하세요.
요구사항
- 파일명: hw02.yml
▶정답 코드 펼치기 / 접기
SOLUTION
name: Python Matrix CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
name: Python ${{ matrix.python-version }} on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
python-version: ['3.10', '3.11', '3.12']
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then
pip install -r requirements.txt
else
echo "requirements.txt 없음 — 건너뜀"
fi
- name: Run tests
run: |
if python -m pytest --version 2>/dev/null; then
python -m pytest
else
echo "pytest 없음 — 테스트 건너뜀"
fi
- name: Show Python version
run: python --version