샌드박스 기능

문제 신고 소스 보기 Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

이 도움말에서는 Bazel의 샌드박스, sandboxfs 설치, 샌드박스 환경 디버깅에 대해 설명합니다.

샌드박스는 프로세스를 서로 또는 시스템의 리소스로부터 격리하는 권한 제한 전략입니다. Bazel의 경우 이는 파일을 제한합니다. 액세스할 수 있습니다.

Bazel의 파일 시스템 샌드박스는 알려진 입력만 포함된 작업 디렉터리에서 프로세스를 실행하므로 컴파일러와 기타 도구는 소스 파일의 절대 경로를 알지 못하는 한 액세스해서는 안 되는 소스 파일을 보지 못합니다.

샌드박싱은 어떤 식으로든 호스트 환경을 숨기지 않습니다. 프로세스는 파일 시스템의 모든 파일에 자유롭게 액세스할 수 있습니다. 하지만 사용자 인터페이스 네임스페이스가 있는 경우 프로세스는 작업 디렉터리 외부의 파일을 수정할 수 없습니다. 이렇게 하면 빌드 그래프에 다른 빌드에 영향을 줄 수 있는 숨겨진 종속 항목이 빌드 재현성에 영향을 줄 수 있습니다.

더 구체적으로 Bazel은 실행 시 작업의 작업 디렉터리 역할을 하는 각 작업의 execroot/ 디렉터리를 생성합니다. execroot/ 작업에 대한 모든 입력 파일을 포함하며 모든 생성합니다. 그런 다음 Bazel은 운영체제 제공 기법을 사용하여 컨테이너(Linux의 경우) 및 sandbox-exec의 경우(macOS의 경우) execroot/입니다.

샌드박스를 사용하는 이유

  • 작업 샌드박스가 없으면 Bazel은 도구가 선언되지 않은 입력 파일(작업의 종속 항목에 명시적으로 나열되지 않은 파일)을 사용하는지 알 수 없습니다. 선언되지 않은 입력 파일 중 하나가 변경되더라도 Bazel은 여전히 빌드가 최신 상태라고 생각하고 작업을 다시 빌드하지 않습니다. 이렇게 하면 잘못된 증분 빌드가 생성됩니다.

  • 캐시 항목을 잘못 재사용하면 원격 캐싱 중에 문제가 발생합니다. 공유 캐시의 잘못된 캐시 항목은 프로젝트의 모든 개발자에게 영향을 미치며 전체 원격 캐시를 삭제하는 것은 실행 가능한 해결 방법이 아닙니다.

  • 샌드박싱은 원격 실행 동작을 모방(빌드가 잘 작동하는 경우) 샌드박싱을 사용하면 원격 실행에서도 작동할 가능성이 높습니다. 원격 실행에서 필요한 모든 파일(로컬 도구 포함)을 업로드하도록 하면 새 컴파일러를 사용해 보거나 기존 도구를 변경할 때마다 클러스터의 모든 머신에 도구를 설치해야 하는 것보다 컴파일 클러스터의 유지보수 비용을 크게 줄일 수 있습니다.

사용할 샌드박스 전략

전략 플래그를 사용하여 사용할 샌드박스 유형(있는 경우)을 선택할 수 있습니다. sandboxed 전략을 사용하면 Bazel이 아래에 나열된 샌드박스 구현 중 하나를 선택하여, 밀폐성이 떨어지는 일반 샌드박스보다 OS별 샌드박스를 선호합니다. --worker_sandboxing 플래그를 전달하면 영구 작업자가 일반 샌드박스에서 실행됩니다.

local (standalone) 전략은 어떤 종류의 샌드박스도 실행하지 않습니다. 작업 디렉터리를 워크스페이스의 execroot로 설정하여 작업의 명령줄을 실행하기만 합니다.

processwrapper-sandbox는 '고급' 기능이 필요하지 않은 샌드박스 전략입니다. 즉시 모든 POSIX 시스템에서 작동해야 합니다. 원본 소스 파일을 가리키는 심볼릭 링크로 구성된 샌드박스 디렉터리를 빌드하고, 작업 디렉터리를 execroot 대신 이 디렉터리로 설정하여 작업의 명령줄을 실행한 다음, 알려진 출력 아티팩트를 샌드박스에서 execroot로 이동하고 샌드박스를 삭제합니다. 이렇게 하면 선언되지 않은 입력 파일을 실수로 사용하지 못하도록 하고 execroot에 알 수 없는 출력 파일이 산재해 있습니다.

linux-sandbox는 한 걸음 더 나아가 processwrapper-sandbox입니다. Docker가 내부적으로 수행하는 작업과 마찬가지로 격리할 Linux 네임스페이스 (사용자, 마운트, PID, 네트워크, IPC 네임스페이스) 삭제할 수 있습니다 즉, 샌드박스 디렉터리를 제외한 전체 파일 시스템을 읽기 전용으로 설정하여 작업이 실수로 호스트 파일 시스템의 항목을 수정할 수 없습니다. 이렇게 하면 버그가 있는 테스트와 같은 상황이 실수로 발생하는 것을 방지할 수 있습니다. $HOME 디렉터리를 -rf'합니다. 원하는 경우 작업이 네트워크에 액세스하지 못하도록 할 수도 있습니다. linux-sandbox는 PID 네임스페이스를 사용하여 작업이 다른 프로세스를 보지 못하도록 하고 마지막에 모든 프로세스(작업에서 스폰된 데몬 포함)를 안정적으로 종료합니다.

darwin-sandbox는 macOS용으로 유사합니다. Apple의 sandbox-exec 도구를 사용합니다. Linux 샌드박스와 거의 동일한 목표를 달성할 수 있습니다.

linux-sandboxdarwin-sandbox는 모두 운영체제에서 제공하는 메커니즘의 제한으로 인해 '중첩된' 시나리오에서 작동하지 않습니다. Docker는 컨테이너 매직을 위해 Linux 네임스페이스도 사용하므로 linux-sandbox를 Docker 컨테이너 내에서 쉽게 실행할 수 없습니다. docker run --privileged입니다. macOS에서는 이미 샌드박스 처리된 프로세스 내에서 sandbox-exec를 실행할 수 없습니다. 따라서 이 경우 Bazel은 자동으로 processwrapper-sandbox 사용으로 대체됩니다.

실행 전략이 덜 엄격한 것으로 실수로 빌드되지 않도록 빌드 오류를 발생시키고 싶다면 Bazel에서 사용하려는 실행 전략 목록(예: bazel build --spawn_strategy=worker,linux-sandbox)을 명시적으로 수정하세요.

동적 실행에는 일반적으로 로컬 실행을 위한 샌드박스가 필요합니다. 선택 해제하려면 --experimental_local_lockfree_output 플래그를 전달합니다. 동적 실행은 영구 작업자를 자동으로 샌드박스 처리합니다.

샌드박스의 단점

  • 샌드박스를 사용하면 추가 설정 및 해체 비용이 발생합니다. 이 비용의 크기는 빌드 형식, 호스트 OS의 성능 등 여러 요인에 따라 달라집니다. Linux의 경우 샌드박스 빌드가 몇 퍼센트 이상 느려지는 경우는 거의 없습니다. --reuse_sandbox_directories를 설정하면 설정 및 해체 비용을 줄일 수 있습니다.

  • 샌드박스는 도구에 있을 수 있는 모든 캐시를 효과적으로 비활성화합니다. 지속형 작업자를 사용하면 이를 완화할 수 있지만 샌드박스 보장이 약화됩니다.

  • 멀티플렉스 작업자는 샌드박스 처리되려면 명시적인 작업자 지원이 필요합니다. 멀티플렉스 샌드박스를 지원하지 않는 작업자는 다음과 같이 실행됩니다. 단일 플렉스 작업자가 동적으로 실행될 수 있기 때문에 추가 메모리가 낭비될 수 있습니다.

sandboxfs

sandboxfs는 시간 손실 없이 기본 파일 시스템의 임의 뷰를 노출하는 FUSE 파일 시스템입니다. Bazel은 sandboxfs를 사용하여 각 작업마다 즉시 execroot/를 생성하여 수천 건의 시스템 호출을 발행합니다. execroot/ 내의 추가 I/O가 FUSE 오버헤드로 인해 느려집니다

sandboxfs 설치

다음 단계에 따라 sandboxfs를 설치하고 다음을 사용하여 Bazel 빌드를 실행하세요. 다음과 같습니다.

다운로드

다운로드 및 설치 sandboxfs 바이너리가 PATH에 끝나도록 sandboxfs 합니다.

sandboxfs 실행

  1. (macOS만 해당) OSXFUSE를 설치합니다.
  2. (macOS만 해당) 실행:

    sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
    

    핵심 macOS 시스템 서비스가 sandboxfs를 통해 작동하도록 하려면 설치 후와 재부팅할 때마다 이 작업을 실행해야 합니다.

  3. --experimental_use_sandboxfs를 사용하여 Bazel 빌드를 실행합니다.

    bazel build target --experimental_use_sandboxfs
    

문제 해결

실행되는 작업의 주석으로 darwin-sandbox 또는 linux-sandbox 대신 local가 표시되면 샌드박스가 사용 중지되었을 수 있습니다. --genrule_strategy=sandboxed --spawn_strategy=sandboxed를 전달하여 사용 설정합니다.

디버깅

아래 전략에 따라 샌드박스 관련 문제를 디버그하세요.

비활성화된 네임스페이스

일부 플랫폼에서는 Google Kubernetes Engine 사용자 네임스페이스가 비활성화되어 있는 경우, 사용자 네임스페이스는 기본적으로 보안 문제를 일으킬 수 있습니다 /proc/sys/kernel/unprivileged_userns_clone 파일이 존재하고 0이 포함된 경우 다음을 실행하여 사용자 네임스페이스를 활성화할 수 있습니다.

   sudo sysctl kernel.unprivileged_userns_clone=1

규칙 실행 실패

시스템 설정으로 인해 샌드박스에서 규칙을 실행하지 못할 수 있습니다. namespace-sandbox.c:633: execvp(argv[0], argv): No such file or directory와 같은 메시지가 표시되면 genrules의 경우 --strategy=Genrule=local, 다른 규칙의 경우 --spawn_strategy=local를 사용하여 샌드박스를 비활성화해 보세요.

빌드 실패에 대한 상세 디버깅

빌드가 실패한 경우 --verbose_failures--sandbox_debug를 사용하여 빌드가 실패했을 때 실행된 정확한 명령어(샌드박스를 설정하는 부분 포함)를 Bazel에 표시합니다.

오류 메시지 예시:

ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:

Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned

namespace-sandbox failed: error executing command
  (cd /some/path && \
  exec env - \
    LANG=en_US \
    PATH=/some/path/bin:/bin:/usr/bin \
    PYTHONPATH=/usr/local/some/path \
  /some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
  /some/path/to/your/some-compiler --some-params some-target)

이제 생성된 샌드박스 디렉터리를 검사하여 Bazel이 어떤 파일을 만들고 명령어를 다시 실행하여 어떻게 작동하는지 확인합니다.

--sandbox_debug를 사용하면 Bazel에서 샌드박스 디렉터리를 삭제하지 않습니다. 디버깅 중인 경우가 아니라면 --sandbox_debug를 사용 중지해야 합니다. 시간이 지남에 따라 디스크가 가득 차기 때문입니다.