지난 3년간 GitHub Pages와 Jekyll로 운영해온 개인 블로그가 최근 몇 달 사이 빌드 프로세스에서 계속 정체되는 현상을 겪었습니다. 당시 저는 블로그 포스팅 수가 200개를 넘어가던 시점이었고, 각 포스팅마다 3~5장의 고해상도 이미지를 삽입하고 있었습니다. 이 글은 그 과정에서 발견한 근본 원인과 해결책을 공유하기 위해 작성되었습니다.

처음 발견한 증상: “Running Jobs”에서의 무한 대기

처음에는 GitHub Actions 워크플로우가 “Running Jobs” 상태에서 멈춘다고 생각했습니다. 대시보드에서는 여전히 진행 중이라고 표시되었지만, 실제로는 이미지 변환 작업(Image Transformation)에서 CPU와 메모리를 극도로 소비하고 있었던 것입니다.

초기에는 네트워크 연결이 끊겼거나 GitHub의 서버 문제라고 추측했습니다. 하지만 여러 번의 재시도 끝에 패턴을 발견할 수 있었습니다. 특히 새로운 이미지가 많이 포함된 포스팅을 올릴 때마다 빌드 시간이 30분을 초과했고, 결국 GitHub의 빌드 타임아웃인 6시간에 도달하게 되는 상황이 반복되었습니다. 이는 단순한 성능 저하가 아니라 시스템적인 병목 현상이었습니다.

근본 원인: 이미지 최적화 플러그인의 과도한 리소스 소비

문제의 핵심은 Jekyll의 이미지 최적화 플러그인들이 모든 이미지를 중복 처리하고 있었다는 점입니다. 특히 jekyll-image-optim, jekyll-picture-tag, jekyll-responsive-images 같은 플러그인들이 동시에 활성화되어 있으면서 발생했습니다.

각 플러그인이 같은 이미지를 다른 형식(WebP, AVIF 등)으로 변환하고, 다양한 해상도의 썸네일을 생성하면서 연산량이 기하급수적으로 증가했던 것입니다. 제 블로그의 경우 이미지 포스팅 하나당 원본 포함 최대 24개의 변환된 이미지 파일이 생성되고 있었습니다. 이것이 매 빌드마다 반복되니 당연히 시간이 오래 걸릴 수밖에 없었습니다.

더 심각한 문제는 GitHub Actions의 컨테이너 환경에서 사용할 수 있는 메모리가 제한되어 있다는 점입니다. 로컬 환경에서는 충분한 리소스가 있어서 문제가 없었지만, CI/CD 환경에서는 여러 작업이 동시에 실행되면서 메모리 부족 현상이 발생했습니다.

실제 적용한 해결책: 단계별 최적화 전략

첫 번째 조치로 Gemfile에서 불필요한 이미지 처리 플러그인을 제거했습니다. 저는 가장 핵심적인 기능만 유지하고 나머지는 삭제하는 방식을 선택했습니다. 특히 로컬 빌드에서만 이미지 최적화를 진행하고, CI/CD에서는 이미 최적화된 이미지만 배포하도록 전환했습니다.

두 번째는 이미지 크기 제한입니다. 포스팅에 사용하는 모든 이미지를 사전에 600x400 이상 2000x1500 이하로 정규화했습니다. 이렇게 하면 플러그인이 처리해야 할 작업량이 현저히 줄어듭니다. ImageMagick을 이용해 배치 처리하면 몇 분 안에 완료됩니다.

셋째, GitHub Actions 워크플로우에서 빌드 타임아웃을 60분으로 재설정하고, 캐싱 전략을 추가했습니다. 특히 actions/cache를 활용해 이전 빌드의 이미지 캐시를 재사용하도록 구성했습니다. 이렇게 하니 같은 이미지가 반복된 포스팅의 빌드 시간이 3분 이내로 단축되었습니다.

마지막으로 jekyll-build-stats 플러그인을 도입해 각 페이지별 빌드 시간을 모니터링하기 시작했습니다. 이를 통해 어느 포스팅이 시간을 가장 많이 소비하는지 파악할 수 있게 되었고, 문제가 재발할 징조를 조기에 감지할 수 있습니다.

이러한 최적화를 모두 적용한 결과, 전체 빌드 시간이 45분에서 3분으로 단축되었습니다. 무엇보다 더 이상 빌드가 중간에 멈추는 현상은 발생하지 않고 있습니다. 비슷한 문제로 고민하고 계신 분들이라면, 먼저 어느 플러그인이 가장 많은 시간을 소비하는지 파악하는 것부터 시작해보시기를 권장합니다.

혹시 현재 Jekyll 블로그의 빌드 시간이 점점 늘어나고 있다면, 댓글로 당신의 상황을 공유해주세요. 더 구체적인 해결책을 함께 찾아보겠습니다.