GitHub Pages 정적 사이트 배포 정리: gh-pages 교체 방식, pip 캐시, requirements 통합
Python 정적 사이트 생성기를 GitHub Actions로 gh-pages에 배포할 때 매번 전체 교체가 정상인지, force_orphan과 pip 캐시, requirements.txt 통합은 언제 적용하면 좋은지 DevBJ 설정으로 정리했습니다.
DevBJ는 content/의 Markdown을 Python 빌더가 docs/로 만들고, 이 폴더를 GitHub Actions가 gh-pages 브랜치에 올리는 구조다. 배포 때마다 gh-pages의 내용이 통째로 교체되고, 이미지와 static 파일도 매번 다시 처리되는 것을 보고 "이래도 되나" 싶어 정리했다.
💡 바쁜 사람을 위한 요약
1. 매 배포마다 전체 교체는 이 방식의 기본 동작이며, 규모가 작으면 부담이 거의 없다.
2. 배포 브랜치 기록이 쌓이는 것은force_orphan: true로 막을 수 있다.
3. 설치 시간은 requirements.txt 하나로 모으고 pip 캐시를 켜서 줄인다.
4. 빌드 산출물은 캐시하지 않고 매번 깨끗하게 만드는 편이 안전하다.
1. 배포 구조 한눈에 보기
main에 push하면 워크플로가 실행된다.- 저장소를 체크아웃하고 Python을 설치한다.
python build.py로docs/를 만든다.peaceiris/actions-gh-pages가docs/내용을gh-pages브랜치에 올린다.- GitHub Pages가
gh-pages브랜치의 루트를 서비스한다.
docs/는 빌드 산출물이라 main에는 커밋하지 않고, 배포 전용 브랜치에만 올라간다.
2. 매번 전체 교체해도 괜찮을까
이 배포 액션의 기본 동작이 "브랜치 내용을 새 빌드로 교체하는 커밋 한 번"이다. 정적 사이트 배포에서 흔한 방식이다.
- git은 내용이 같은 파일을 같은 객체로 저장한다. 그래서 바뀌지 않은 HTML과 이미지는 저장소 용량을 거의 늘리지 않는다.
- 문제가 될 수 있는 것은 큰 바이너리를 자주 바꿔 올릴 때다. 이미지나 PDF가 많고 자주 바뀌면 기록이 눈에 띄게 불어날 수 있다.
- 사이트가 작을 때는 빌드와 배포가 짧게 끝나므로 증분 배포를 따로 만드는 복잡함이 이득보다 크다. 이번에 단계별 소요 시간을 직접 재 보지는 않았다.
3. 초기에 적용해 두면 좋은 설정 세 가지
force_orphan으로 배포 브랜치 기록 정리
force_orphan: true를 켜면 gh-pages가 매번 커밋 하나짜리로 새로 만들어진다. 배포 브랜치의 과거 기록은 필요하지 않고, 원본 기록은 main에 남기 때문에 문제가 없다. 용량이 커진 뒤에 켜도 되지만 처음부터 켜 두면 신경 쓸 일이 없다. 켜는 첫 배포 때 기존 gh-pages 기록은 한 번 사라진다.
requirements.txt로 의존성 한곳에 모으기
워크플로 안에서 패키지를 직접 나열하면 로컬 환경과 어긋나기 쉽다. requirements.txt에 Markdown, PyYAML, python-frontmatter, Pygments를 모으고 워크플로는 pip install -r requirements.txt만 실행하게 했다. 새 패키지를 쓰면 이 파일만 고치면 된다.
pip 캐시
actions/setup-python의 cache: pip를 켜면 다운로드한 패키지를 다음 실행에서 재사용한다. 캐시 키가 될 파일을 cache-dependency-path: requirements.txt로 지정했다. 패키지 수가 적어서 절약되는 시간은 크지 않을 수 있다.
- uses: actions/setup-python@v5
with:
python-version: "3.11"
cache: pip
cache-dependency-path: requirements.txt
- run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
python build.py
- uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs
force_orphan: true
cname: devbj.com
4. 이미지 생성과 static 복사는 캐시하지 않는다
빌더는 시작할 때 이전 HTML 산출물을 지우고 static/을 다시 복사한다. 캐시를 쓰면 빨라질 수 있지만 다음 문제가 생긴다.
- 삭제하거나 이름을 바꾼 글과 이미지가 이전 산출물로 남을 수 있다.
- 캐시가 낡았을 때 원인을 찾기 어렵다.
- 규모가 작아 얻는 시간이 적다.
빌드가 눈에 띄게 느려지면 그때 Actions 로그에서 어느 단계가 오래 걸리는지 먼저 확인하고 손대면 된다.
5. 배포할 때 자주 막히는 지점
- 빈 디렉토리는 git에 올라가지 않는다.
content/data처럼 비어 있는 폴더는 CI 체크아웃에 없다. 빌더가 폴더가 없어도 동작해야 하고, 필요하면.gitkeep을 둔다. 실제로 "content/data 디렉토리가 없습니다" 오류로 배포가 실패한 적이 있다. - Pages 설정을 확인한다. 저장소 Settings의 Pages에서 Source가
gh-pages브랜치(root)로 되어 있어야 한다. 이 설정이 없으면 배포가 성공해도 사이트에서 404가 나올 수 있다. - CNAME은 배포 때 같이 만든다. 액션의
cname옵션으로 도메인 파일을 유지한다. - 커밋되지 않은 로컬 파일에 의존하지 않는다. CI는 체크아웃한 상태만 빌드하므로, 새 이미지나 글을 같이 커밋해야 한다.
마무리: 이렇게 정리해 두면 된다
- 매번 전체 교체는 정상이고, 지금 규모에서는 부담이 거의 없다.
- 처음부터
force_orphan, requirements.txt, pip 캐시를 적용해 두면 나중에 손볼 일이 줄어든다. - 빌드 산출물은 캐시하지 않고 매번 새로 만든다.
위 설정을 적용한 뒤 첫 Actions 실행 결과는 아직 확인하지 못했다. 설치 단계 통과 여부와 소요 시간을 확인하면 이 글에 보강할 예정이다.