GitHub Actions 강좌 #4 매트릭스·캐시·아티팩트: 조합 실행과 시간·비용 절약
테스트가 파이썬 3.12에서는 통과하는데 3.13에서 깨진다면, 두 버전 모두에서 돌려야 알 수 있습니다. 잡 정의를 복사해 버전만 바꿔 두 벌 만들면 되지만, OS까지 조합하면 여섯 벌, 아홉 벌로 불어나 유지보수가 무너집니다. 이번 편의 첫 주제인 매트릭스가 이 문제를 잡 정의 하나로 풉니다. 이어서 반대 방향, 즉 늘어난 실행의 시간과 비용을 줄이는 캐시, 그리고 #2에서 미뤄 둔 “잡 사이 파일 전달"의 답인 아티팩트까지 다룹니다.
매트릭스: 잡 하나를 조합으로 늘리기 #
strategy.matrix에 축을 선언하면, 잡이 조합 수만큼 병렬로 실행됩니다.
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
python: ["3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}
- run: pip install -r requirements.txt
- run: pytest2×2로 네 개의 잡이 만들어지고, 각 잡 안에서 matrix.os, matrix.python으로 자기 조합 값을 씁니다. 조합을 다듬는 옵션이 셋 있습니다.
- exclude: 특정 조합을 뺍니다. “macOS에서는 3.12를 건너뛴다” 같은 조정입니다.
- include: 조합을 추가하거나 특정 조합에만 변수를 얹습니다. “우분투 3.13 조합에만 커버리지 측정을 켠다” 같은 예외 처리입니다.
- fail-fast: 기본값 true는 한 조합이 실패하면 나머지를 즉시 취소합니다. 어떤 조합이 실패하는지 전부 보고 싶다면 false로 바꿉니다. 실패 원인을 조합별로 비교해야 하는 테스트라면 false가 유용하고, 비용이 우선이면 true를 유지합니다.
매트릭스는 러너 사용 분량을 조합 수만큼 곱한다는 것도 기억해 둡니다. #1에서 본 대로 macOS 러너는 과금 배수가 높아서, 프라이빗 저장소라면 macOS 축은 정말 필요한지 따져 보는 것이 비용 관리의 시작입니다.
캐시: 매번 새로 받지 않기 #
러너는 매번 깨끗한 머신이라 의존성 설치가 매번 처음부터 돕니다. actions/cache는 지정한 디렉터리를 실행 사이에 보존해 이 낭비를 줄입니다.
- uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}
restore-keys: |
pip-${{ runner.os }}-핵심은 key 설계입니다. hashFiles('requirements.txt')가 의존성 파일의 해시를 키에 넣으므로, 의존성이 바뀌면 키가 바뀌어 캐시가 자연스럽게 무효화됩니다. restore-keys는 정확히 일치하는 키가 없을 때 접두사로 찾는 예비 경로라, 의존성이 바뀐 직후에도 대부분의 패키지는 이전 캐시에서 복원되고 바뀐 부분만 새로 받습니다.
실무에서는 이보다 더 간단한 길이 먼저입니다. setup 계열 액션의 내장 캐시입니다.
- uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: "pip"cache: "pip" 한 줄이 위의 cache 액션 구성과 같은 일을 합니다. setup-node, setup-go 등도 같은 옵션을 제공하므로, 언어 의존성 캐시는 내장 옵션을 기본으로 쓰고, 내장이 커버하지 않는 경로(빌드 중간 산출물 등)에만 actions/cache를 직접 씁니다. 캐시는 저장소당 총량 제한이 있고 오래 안 쓰이면 자동 삭제되는 임시 저장소라는 점, 즉 없어도 돌아가야 하고 빨라지기만 하는 존재여야 한다는 원칙만 지키면 부작용이 없습니다.
아티팩트: 잡 사이의 파일 전달과 결과물 보관 #
#2에서 잡끼리 문자열은 outputs로 넘기지만 파일은 안 넘어간다고 했습니다. 파일의 통로가 아티팩트입니다.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./build.sh -o dist/
- uses: actions/upload-artifact@v4
with:
name: app-dist
path: dist/
deploy:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: app-dist
path: dist/
- run: ./deploy.sh dist/빌드 잡이 올린 결과물을 배포 잡이 내려받는, “한 번 빌드해서 그대로 배포"의 기본 골격입니다. 아티팩트는 실행 화면에서 사람이 내려받을 수도 있어 테스트 리포트나 로그 뭉치의 보관함으로도 쓰입니다. retention-days로 보존 기간을 지정할 수 있고, 기본 보존 기간은 길게 잡혀 있어 용량 과금의 원인이 되기도 하므로 빌드 산출물처럼 수명이 짧은 것은 짧게 명시하는 것이 비용 습관입니다. 캐시와의 구분은 명확합니다. 캐시는 “없어도 되는 가속 장치”, 아티팩트는 “실행이 만든 결과물"입니다.
정리 #
이번 글에서 다룬 내용입니다.
- 매트릭스는 잡 정의 하나를 조합 수만큼 병렬 실행으로 늘립니다. exclude·include로 조합을 다듬고, fail-fast는 비용과 정보량의 절충입니다
- 매트릭스는 러너 분량을 곱셈으로 늘립니다. macOS 축은 배수가 높아 비용 검토 대상 1순위입니다
- 캐시 키에 hashFiles를 넣어 의존성 변경 시 자연 무효화되게 하고, restore-keys로 부분 복원을 잡습니다
- 언어 의존성은 setup 액션의 내장 cache 옵션이 먼저이고, actions/cache는 내장이 없는 경로에 씁니다
- 파일 전달과 결과물 보관은 아티팩트입니다. 캐시는 가속 장치, 아티팩트는 결과물이며, retention-days 명시가 비용 습관입니다
다음 글(#5 재사용)에서는 여러 저장소와 워크플로에 반복되는 스텝 뭉치를 부품으로 만드는 방법, composite action과 reusable workflow를 다룹니다.