[vllm] [ROCm CI 최적화] Docker 3단계 빌드 전략으로 빌드 시간 26분 단축하기
PR 링크: vllm-project/vllm#36949 상태: Merged | 변경: +2745 / -157
들어가며: 26분의 기다림, 무엇이 문제인가?
대규모 오픈소스 프로젝트인 vLLM에서 CI(계속적 통합) 속도는 개발 생산성과 직결됩니다. 특히 AMD GPU를 위한 ROCm 환경은 빌드 과정에서 RIXL, DeepEP, rocshmem, torchcodec 등 무거운 라이브러리들을 매번 처음부터 컴파일해야 했습니다.
기존 방식에서는 모든 PR(Pull Request)마다 이러한 의존성들을 다시 빌드하느라 평균 26분이라는 막대한 시간이 소요되었습니다. 이는 개발자의 피드백 루프를 늦추고 컴퓨팅 자원을 낭비하는 병목 지점이었습니다. 이번 PR은 이를 해결하기 위해 3단계(Three-tier) Docker 빌드 전략과 Content-addressed 캐싱 시스템을 도입했습니다.
핵심 전략: 3단계 Docker 빌드 아키텍처
이번 개선의 핵심은 이미지의 변경 빈도에 따라 레이어를 세 가지 티어로 나누어 관리하는 것입니다.
- Tier-1 (
rocm/vllm-dev:base): OS 패키지 등 거의 변하지 않는 기초 환경 (월 단위 업데이트) - Tier-2 (
rocm/vllm-dev:ci_base):DeepEP,rocshmem등 무거운 의존성 라이브러리 (주 단위 또는 의존성 변경 시 업데이트) - Tier-3 (
rocm/vllm-ci:$COMMIT): 실제 vLLM 소스 코드와 휠(Wheel) 파일 (PR마다 빌드)
이 구조를 통해 대부분의 PR 빌드에서는 Tier-1과 Tier-2를 캐시에서 가져오고, 가벼운 Tier-3만 빌드하면 되므로 빌드 시간을 획기적으로 줄일 수 있습니다.
코드 분석: 무엇이 어떻게 바뀌었나?
1. 빌드 파이프라인의 지능화 (.buildkite/hardware_tests/amd.yaml)
기존에는 단순히 docker build 명령어를 무겁게 호출했지만, 이제는 ci_base 이미지가 최신인지 먼저 확인하는 단계가 추가되었습니다.
Before:
# 모든 것을 한 번에 빌드하는 무거운 방식
- label: "AMD: :docker: build image"
commands:
- >
docker build
--build-arg max_jobs=16
--tag "rocm/vllm-ci:${BUILDKITE_COMMIT}"
-f docker/Dockerfile.rocm
--target test
--no-cache
--progress plain .
After:
# 1단계: ci_base가 최신인지 확인 (Content Hash 비교)
- label: "AMD: :docker: ensure ci_base"
key: ensure-ci-base-amd
commands:
- bash .buildkite/scripts/ci-bake-rocm.sh ci-base-rocm-ci-with-deps
# 2단계: 이미 준비된 ci_base 위에서 테스트 이미지 빌드
- label: "AMD: :docker: build test image and artifacts"
depends_on:
- ensure-ci-base-amd
commands:
- |
if [[ "${ROCM_CI_ARTIFACT_ONLY:-0}" == "1" ]]; then
IMAGE_TAG="" bash .buildkite/scripts/ci-bake-rocm.sh test-rocm-ci-with-artifacts
else
bash .buildkite/scripts/ci-bake-rocm.sh test-rocm-ci-with-wheel
fi
ensure-ci-base-amd 단계는 약 30초 내외로 소요되며, 의존성 파일들의 해시값이 변경되지 않았다면 빌드를 건너뜁니다.
2. Content-addressed 캐싱의 핵심 (.buildkite/scripts/ci-bake-rocm.sh)
이 스크립트는 이번 최적화의 '두뇌' 역할을 합니다. 단순히 파일 이름이 아니라 파일의 내용(Content)을 해싱하여 캐시 키를 생성합니다.
# ci-bake-rocm.sh 내의 해시 계산 로직
compute_content_hash() {
local path
for path in "$@"; do
if [[ -d "${path}" ]]; then
# 디렉토리 내 모든 파일을 정렬하여 해싱
while IFS= read -r -d '' file; do
sha256sum "${file}"
done < <(find "${path}" -type f -print0 | sort -z)
elif [[ -f "${path}" ]]; then
sha256sum "${path}"
fi
done | sha256sum | cut -d' ' -f1
}
DEFAULT_CI_BASE_CONTENT_FILES="requirements/common.txt requirements/rocm.txt requirements/test/rocm.txt docker/Dockerfile.rocm_base ..."
DEFAULT_CI_BASE_CONTENT_FILES에 정의된 파일들(의존성 목록, 빌드 스크립트 등) 중 하나라도 내용이 바뀌면 해시값이 변하고, 그제서야 ci_base 이미지를 새로 빌드하여 푸시합니다. 내용이 같다면 이미 존재하는 이미지를 재사용합니다.
3. Dockerfile의 구조적 개선
리뷰어 gshtras의 피드백에 따라 REMOTE_VLLM 인자를 처리하는 방식과 아키텍처별 빌드 최적화가 반영되었습니다. 특히 PYTORCH_ROCM_ARCH를 명시적으로 관리하여 불필요한 아키텍처용 컴파일을 방지했습니다.
# ci-bake-rocm.sh에서 아키텍처별 캐시 스코프 분리
cache_scope_suffix() {
local arch_hash=""
arch_hash=$(printf '%s' "${PYTORCH_ROCM_ARCH:-default}" | sha256sum | cut -c1-12)
printf 'arch-%s\n' "${arch_hash}"
}
이는 gfx90a, gfx942 등 특정 AMD GPU 아키텍처에 최적화된 빌드 결과물을 캐싱할 때 충돌을 방지하고 정확한 캐시를 찾아가게 해줍니다.
왜 이게 좋은 개선인가?
1. 결정론적 빌드 환경 (Deterministic Build)
단순히 latest 태그를 사용하는 것이 아니라, 의존성 파일의 해시를 기반으로 이미지를 관리하므로 빌드 환경의 일관성이 보장됩니다. "어제는 됐는데 오늘은 왜 안 되지?" 같은 상황을 방지합니다.
2. 리소스 효율성
26분 걸리던 빌드가 캐시 히트 시 수 분 내외로 단축됩니다. 이는 CI 서버의 부하를 줄일 뿐만 아니라, 개발자가 PR을 올린 후 결과를 기다리는 시간을 90% 이상 절감합니다.
3. 유연한 아티팩트 관리
리뷰 과정에서 논의된 것처럼, 테스트용 이미지 빌드와 배포용 휠(Wheel) 아티팩트 생성을 분리하여 상황에 맞는 최적의 빌드 타겟을 선택할 수 있게 되었습니다.
마치며: 시니어의 관점에서 본 교훈
이번 PR은 단순한 스크립트 수정을 넘어 인프라를 코드로 관리(IaC)하고 빌드 파이프라인을 계층화하는 정석적인 접근을 보여줍니다.
특히 docker buildx bake를 활용하여 복잡한 빌드 설정을 HCL(HashiCorp Configuration Language)로 관리하고, 쉘 스크립트로 이를 정교하게 래핑한 점은 대규모 프로젝트에서 참고할 만한 훌륭한 패턴입니다. 빌드 시간이 길어 고통받고 있다면, 여러분의 프로젝트에도 이러한 Multi-tier 캐싱 전략을 도입해 보시기 바랍니다.
참고 자료
- https://docs.docker.com/build/bake/
- https://pytorch.org/docs/stable/notes/rocm.html
- https://github.com/vllm-project/vllm/blob/main/docker/Dockerfile.rocm
⚠️ 알림: 이 분석은 AI가 실제 코드 diff를 기반으로 작성했습니다.
관련 포스트
PR Analysis 의 다른글
- 이전글 [transformers] Hugging Face Transformers: Slow Tokenizer 성능 회귀 문제 해결하기
- 현재글 : [vllm] [ROCm CI 최적화] Docker 3단계 빌드 전략으로 빌드 시간 26분 단축하기
- 다음글 [feast] Feast 온라인 서빙 성능 튜닝: Sub-2ms 달성을 위한 여정
댓글