이 페이지에서는 원격 캐싱, 캐시를 호스팅할 서버 설정, 원격 캐시를 사용하여 빌드 실행을 설명합니다.
원격 캐시는 개발자팀 또는 지속적 통합(CI) 시스템에서 빌드 출력을 공유하는 데 사용됩니다. 빌드를 재현할 수 있는 경우 한 머신의 출력을 다른 머신에서 안전하게 재사용할 수 있으므로 빌드 속도가 훨씬 빨라질 수 있습니다.
개요
Bazel은 빌드를 작업이라고 하는 개별 단계로 나눕니다. 각 작업에는 입력, 출력 이름, 명령줄, 환경 변수가 있습니다. 필수 입력 및 예상 출력은 각 작업에 명시적으로 선언됩니다.
이러한 작업 출력인 빌드 출력의 원격 캐시가 되도록 서버를 설정할 수 있습니다. 이러한 출력은 출력 파일 이름 목록과 콘텐츠의 해시로 구성됩니다. 원격 캐시를 사용하면 새 출력을 매번 로컬에서 빌드하는 대신 다른 사용자 빌드의 빌드 출력을 재사용할 수 있습니다.
원격 캐싱을 사용하려면 다음 단계를 따르세요.
- 서버를 캐시의 백엔드로 설정
- 원격 캐시를 사용하도록 Bazel 빌드 구성
- Bazel 버전 0.10.0 이상 사용
원격 캐시는 두 가지 유형의 데이터를 저장합니다.
- 작업 캐시: 작업 해시와 작업 결과 메타데이터의 매핑입니다.
- 출력 파일의 콘텐츠 주소 지정 스토어(CAS)입니다.
원격 캐시는 모든 작업의 stdout 및 stderr을 추가로 저장합니다. 따라서 Bazel의 stdout/stderr을 검사하는 것은 캐시 적중을 추정하는 데 좋은 신호가 아닙니다.
빌드에서 원격 캐싱을 사용하는 방법
서버가 원격 캐시로 설정되면 다음과 같은 여러 가지 방법으로 캐시를 사용할 수 있습니다.
- 원격 캐시 읽기 및 쓰기
- 특정 타겟을 제외하고 원격 캐시 읽기 또는 쓰기
- 원격 캐시에서만 읽기
- 원격 캐시를 전혀 사용하지 않음
원격 캐시를 읽고 쓸 수 있는 Bazel 빌드를 실행하는 경우 빌드는 다음 단계를 따릅니다.
- Bazel은 빌드해야 하는 대상의 그래프를 만든 후 필요한 작업 목록을 만듭니다. 이러한 각 작업에는 입력 및 출력 파일 이름이 선언되어 있습니다.
- Bazel은 로컬 머신에서 기존 빌드 출력을 확인하고 찾은 출력을 재사용합니다.
- Bazel이 캐시에서 기존 빌드 출력을 확인합니다. 출력이 발견되면 Bazel이 출력을 검색합니다. 이는 캐시 적중입니다.
- 출력이 발견되지 않은 필수 작업의 경우 Bazel은 작업을 로컬에서 실행하고 필요한 빌드 출력을 만듭니다.
- 새 빌드 출력이 원격 캐시에 업로드됩니다.
서버를 캐시의 백엔드로 설정
캐시의 백엔드 역할을 할 서버를 설정해야 합니다. HTTP/1.1 서버는 Bazel의 데이터를 불투명한 바이트로 취급할 수 있으므로 많은 기존 서버를 원격 캐싱 백엔드로 사용할 수 있습니다. Bazel의 HTTP 캐싱 프로토콜은 원격 캐싱을 지원합니다.
캐시된 출력을 저장할 백엔드 서버를 선택, 설정, 유지관리할 책임은 개발자에게 있습니다. 서버를 선택할 때는 다음 사항을 고려하세요.
- 네트워크 속도 예를 들어 팀이 같은 사무실에 있는 경우 자체 로컬 서버를 실행하는 것이 좋습니다.
- 보안. 원격 캐시에는 바이너리가 있으므로 보안이 유지되어야 합니다.
- 관리 용이성. 예를 들어 Google Cloud Storage는 완전 관리형 서비스입니다.
원격 캐시에 사용할 수 있는 백엔드는 여러 가지가 있습니다. 다음은 몇 가지 옵션입니다.
nginx
nginx는 오픈소스 웹 서버입니다. [WebDAV 모듈]을 통해 Bazel의 원격 캐시로 사용할 수 있습니다. Debian 및 Ubuntu에서는 nginx-extras
패키지를 설치할 수 있습니다. macOS nginx는 Homebrew를 통해 사용할 수 있습니다.
brew tap denji/nginx
brew install nginx-full --with-webdav
다음은 nginx의 구성 예입니다. /path/to/cache/dir
을 nginx에 쓰기 및 읽기 권한이 있는 유효한 디렉터리로 변경해야 합니다. 출력 파일이 더 크면 client_max_body_size
옵션을 더 큰 값으로 변경해야 할 수도 있습니다. 서버는 인증과 같은 다른 구성이 필요합니다.
nginx.conf
의 server
섹션 구성 예시:
location /cache/ {
# The path to the directory where nginx should store the cache contents.
root /path/to/cache/dir;
# Allow PUT
dav_methods PUT;
# Allow nginx to create the /ac and /cas subdirectories.
create_full_put_path on;
# The maximum size of a single file.
client_max_body_size 1G;
allow all;
}
bazel-remote
bazel-remote는 인프라에서 사용할 수 있는 오픈소스 원격 빌드 캐시입니다. 2018년 초부터 여러 회사의 프로덕션에 성공적으로 사용되었습니다. Bazel 프로젝트는 bazel-remote에 대한 기술 지원을 제공하지 않습니다.
이 캐시는 디스크에 콘텐츠를 저장하고 가비지 컬렉션을 제공하여 스토리지 상한을 적용하고 사용하지 않는 아티팩트를 정리합니다. 캐시는 [Docker 이미지]로 사용할 수 있으며 코드는 GitHub에서 확인할 수 있습니다. REST 및 gRPC 원격 캐시 API가 모두 지원됩니다.
사용 방법에 관한 안내는 GitHub 페이지를 참고하세요.
Google Cloud Storage
[Google Cloud Storage]는 Bazel의 원격 캐싱 프로토콜과 호환되는 HTTP API를 제공하는 완전 관리형 객체 저장소입니다. 결제가 사용 설정된 Google Cloud 계정이 있어야 합니다.
Cloud Storage를 캐시로 사용하려면 다음 단계를 따르세요.
스토리지 버킷을 만듭니다. 네트워크 대역폭은 원격 캐시에서 중요하므로 가장 가까운 버킷 위치를 선택해야 합니다.
Bazel에서 Cloud Storage에 인증할 서비스 계정을 만듭니다. 서비스 계정 만들기를 참고하세요.
보안 비밀 JSON 키를 생성한 다음 인증을 위해 Bazel에 전달합니다. 키가 있으면 누구나 GCS 버킷에서 임의의 데이터를 읽고 쓸 수 있으므로 키를 안전하게 저장합니다.
Bazel 명령어에 다음 플래그를 추가하여 Cloud Storage에 연결합니다.
--remote_cache=https://storage.googleapis.com/bucket-name
플래그를 사용하여 다음 URL을 Bazel에 전달합니다. 여기서bucket-name
은 스토리지 버킷의 이름입니다.--google_credentials=/path/to/your/secret-key.json
플래그를 사용하여 인증 키를 전달하거나 애플리케이션 인증을 사용하려면--google_default_credentials
플래그를 사용합니다.
Cloud Storage가 오래된 파일을 자동으로 삭제하도록 구성할 수 있습니다. 이렇게 하려면 객체 수명 주기 관리를 참조하세요.
기타 서버
PUT 및 GET을 지원하는 모든 HTTP/1.1 서버를 캐시의 백엔드로 설정할 수 있습니다. 사용자들이 Hazelcast, Apache httpd, AWS S3와 같은 백엔드를 캐싱하는 데 성공했다고 보고했습니다.
인증
버전 0.11.0부터 HTTP 기본 인증 지원이 Bazel에 추가되었습니다.
원격 캐시 URL을 통해 사용자 이름과 비밀번호를 Bazel에 전달할 수 있습니다. 구문은 https://username:password@hostname.com:port/path
입니다. HTTP 기본 인증은 사용자 이름과 비밀번호를 네트워크를 통해 일반 텍스트로 전송하므로 항상 HTTPS와 함께 사용해야 합니다.
HTTP 캐싱 프로토콜
Bazel은 HTTP/1.1을 통한 원격 캐싱을 지원합니다. 프로토콜은 개념적으로 간단합니다. 바이너리 데이터(BLOB)는 PUT 요청을 통해 업로드되고 GET 요청을 통해 다운로드됩니다.
작업 결과 메타데이터는 /ac/
경로에 저장되고 출력 파일은 /cas/
경로에 저장됩니다.
예를 들어 http://localhost:8080/cache
에서 실행되는 원격 캐시를 생각해 보세요.
SHA256 해시 01ba4719...
가 있는 작업의 작업 결과 메타데이터를 다운로드하는 Bazel 요청은 다음과 같습니다.
GET /cache/ac/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b HTTP/1.1
Host: localhost:8080
Accept: */*
Connection: Keep-Alive
SHA256 해시 15e2b0d3...
가 있는 출력 파일을 CAS에 업로드하는 Bazel 요청은 다음과 같습니다.
PUT /cache/cas/15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225 HTTP/1.1
Host: localhost:8080
Accept: */*
Content-Length: 9
Connection: Keep-Alive
0x310x320x330x340x350x360x370x380x39
원격 캐시를 사용하여 Bazel 실행
서버를 원격 캐시로 설정한 후 원격 캐시를 사용하려면 Bazel 명령어에 플래그를 추가해야 합니다. 아래의 구성 및 플래그 목록을 참조하세요.
선택한 서버와 관련된 인증을 구성해야 할 수도 있습니다.
Bazel을 실행할 때마다 지정할 필요가 없도록 이러한 플래그를 .bazelrc
파일에 추가하는 것이 좋습니다. 프로젝트 및 팀 역학에 따라 다음과 같은 .bazelrc
파일에 플래그를 추가할 수 있습니다.
- 로컬 머신
- 팀과 공유된 프로젝트의 작업공간에서
- CI 시스템
원격 캐시 읽기 및 쓰기
원격 캐시에 쓸 수 있는 사용자를 주의 깊게 선택하세요. CI 시스템만 원격 캐시에 쓸 수 있도록 할 수 있습니다.
다음 플래그를 사용하여 원격 캐시에서 읽고 씁니다.
build --remote_cache=http://your.host:port
HTTP
외에도 HTTPS
, grpc
, grpcs
프로토콜도 지원됩니다.
위의 플래그 외에 다음 플래그를 사용하여 원격 캐시에서만 데이터를 읽습니다.
build --remote_upload_local_results=false
원격 캐시 사용에서 특정 타겟 제외
특정 타겟이 원격 캐시를 사용하지 못하도록 하려면 타겟에 no-remote-cache
태그를 지정하세요. 예를 들면 다음과 같습니다.
java_library(
name = "target",
tags = ["no-remote-cache"],
)
원격 캐시에서 콘텐츠 삭제
원격 캐시에서 콘텐츠를 삭제하는 것은 서버 관리의 일부입니다. 원격 캐시에서 콘텐츠를 삭제하는 방법은 캐시로 설정한 서버에 따라 다릅니다. 출력을 삭제할 때는 전체 캐시를 삭제하거나 이전 출력을 삭제합니다.
캐시된 출력은 이름 및 해시 집합으로 저장됩니다. 콘텐츠를 삭제하면 특정 빌드에 속하는 출력을 구별할 수 있는 방법이 없습니다.
다음과 같은 경우 캐시에서 콘텐츠를 삭제할 수 있습니다.
- 캐시가 감염된 후 클린 캐시 만들기
- 이전 출력을 삭제하여 사용되는 스토리지 양 줄이기
Unix 소켓
원격 HTTP 캐시는 Unix 도메인 소켓을 통한 연결을 지원합니다. 동작은 curl의 --unix-socket
플래그와 유사합니다. 다음을 사용하여 유닉스 도메인 소켓을 구성합니다.
build --remote_cache=http://your.host:port
build --remote_cache_proxy=unix:/path/to/socket
Windows에서는 이 기능이 지원되지 않습니다.
디스크 캐시
Bazel은 파일 시스템의 디렉터리를 원격 캐시로 사용할 수 있습니다. 이는 브랜치를 전환하거나 동일한 프로젝트의 여러 작업공간(예: 여러 체크아웃)에서 작업할 때 빌드 아티팩트를 공유하는 데 유용합니다. 다음과 같이 디스크 캐시를 사용 설정합니다.
build --disk_cache=path/to/build/cache
~
별칭을 사용하여 --disk_cache
플래그에 사용자별 경로를 전달할 수 있습니다(Bazel이 현재 사용자의 홈 디렉터리를 대체함). 이는 프로젝트의 체크인된 .bazelrc
파일을 통해 프로젝트의 모든 개발자를 위해 디스크 캐시를 사용 설정할 때 유용합니다.
가비지 컬렉션
Bazel 7.4부터는 --experimental_disk_cache_gc_max_size
및 --experimental_disk_cache_gc_max_age
를 사용하여 디스크 캐시의 최대 크기 또는 개별 캐시 항목의 수명을 설정할 수 있습니다. Bazel은 빌드 간에 유휴 상태인 동안 자동으로 디스크 캐시를 가비지 수집합니다. 유휴 타이머는 --experimental_disk_cache_gc_idle_delay
(기본값 5분)로 설정할 수 있습니다.
자동 가비지 컬렉션의 대안으로 가비지 컬렉션을 필요에 따라 실행하는 도구도 제공합니다.
알려진 문제
빌드 중 입력 파일 수정
빌드 중에 입력 파일이 수정되면 Bazel이 잘못된 결과를 원격 캐시에 업로드할 수 있습니다. --experimental_guard_against_concurrent_changes
플래그를 사용하여 변경 감지를 사용 설정할 수 있습니다. 알려진 문제는 없으며 향후 출시에서는 기본적으로 사용 설정될 예정입니다.
업데이트는 [문제 #3360]을 참고하세요. 일반적으로 빌드 중에 소스 파일을 수정하지 않는 것이 좋습니다.
환경 변수가 작업으로 유출됨
작업 정의에는 환경 변수가 포함됩니다. 이는 머신 간에 원격 캐시 적중을 공유하는 데 문제가 될 수 있습니다. 예를 들어 $PATH
변수가 다른 환경은 캐시 히트를 공유하지 않습니다. --action_env
를 통해 명시적으로 허용된 환경 변수만 작업 정의에 포함됩니다. $PATH
를 포함한 환경 변수의 허용 목록으로 /etc/bazel.bazelrc
를 설치하는 데 사용되는 Bazel의 Debian/Ubuntu 패키지입니다. 예상보다 캐시 히트 수가 적은 경우 환경에 이전 /etc/bazel.bazelrc
파일이 없는지 확인합니다.
Bazel은 작업공간 외부의 도구를 추적하지 않음
Bazel은 현재 작업공간 외부의 도구를 추적하지 않습니다. 예를 들어 작업이 /usr/bin/
의 컴파일러를 사용하는 경우 문제가 될 수 있습니다. 그러면 서로 다른 컴파일러가 설치된 두 사용자가 캐시 적중을 잘못 공유합니다. 출력은 다르지만 작업 해시는 동일하기 때문입니다. 업데이트는 문제 #4558을 참고하세요.
Docker 컨테이너 내에서 빌드를 실행할 때 증분 메모리 내 상태가 손실됨 Bazel은 단일 Docker 컨테이너에서 실행 중일 때도 서버/클라이언트 아키텍처를 사용합니다. 서버 측에서 Bazel은 빌드 속도를 높이는 인메모리 상태를 유지합니다. CI와 같이 Docker 컨테이너 내에서 빌드를 실행하면 메모리 내 상태가 손실되며 Bazel은 원격 캐시를 사용하기 전에 이를 다시 빌드해야 합니다.