Bài viết này đề cập đến tính năng hộp cát trong Bazel, cách cài đặt sandboxfs
và gỡ lỗi môi trường hộp cát của bạn.
Hộp cát là một chiến lược hạn chế quyền giúp tách biệt các quy trình với nhau hoặc với các tài nguyên trong hệ thống. Đối với Bazel, điều này có nghĩa là hạn chế quyền truy cập vào hệ thống tệp.
Hộp cát hệ thống tệp của Bazel chạy các quy trình trong một thư mục đang hoạt động chỉ chứa dữ liệu đầu vào đã biết, sao cho trình biên dịch và các công cụ khác không xem được tệp nguồn mà chúng không nên truy cập, trừ phi ứng dụng biết đường dẫn tuyệt đối đến các quy trình đó.
Hộp cát không ẩn môi trường máy chủ lưu trữ theo bất kỳ cách nào. Các quy trình có thể tự do truy cập vào tất cả tệp trên hệ thống tệp. Tuy nhiên, trên các nền tảng hỗ trợ không gian tên của người dùng, các quy trình không thể sửa đổi bất kỳ tệp nào bên ngoài thư mục đang làm việc của các tệp đó. Điều này đảm bảo rằng biểu đồ bản dựng không có phần phụ thuộc ẩn có thể ảnh hưởng đến khả năng tái tạo của bản dựng.
Cụ thể hơn, Bazel tạo một thư mục execroot/
cho mỗi hành động, đóng vai trò là thư mục công việc của hành động tại thời điểm thực thi. execroot/
chứa mọi tệp đầu vào cho thao tác và đóng vai trò là vùng chứa cho mọi dữ liệu đầu ra đã tạo. Sau đó, Bazel sử dụng một kỹ thuật do hệ điều hành cung cấp, các vùng chứa trên Linux và sandbox-exec
trên macOS, để ràng buộc hành động trong execroot/
.
Lý do sử dụng hộp cát
Nếu không có hộp cát hành động, Bazel sẽ không biết liệu một công cụ có sử dụng các tệp đầu vào chưa được khai báo hay không (các tệp không được liệt kê rõ ràng trong phần phụ thuộc của một hành động). Khi một trong các tệp đầu vào chưa được khai báo thay đổi, Bazel vẫn tin rằng bản dựng đã được cập nhật và sẽ không tạo lại hành động. Điều này có thể dẫn đến việc tạo bản dựng tăng dần không chính xác.
Việc sử dụng lại các mục trong bộ nhớ đệm không chính xác sẽ tạo ra sự cố trong quá trình lưu vào bộ nhớ đệm từ xa. Một mục bộ nhớ đệm không hợp lệ trong bộ nhớ đệm dùng chung sẽ ảnh hưởng đến mọi nhà phát triển trong dự án và việc xoá toàn bộ bộ nhớ đệm từ xa không phải là giải pháp khả thi.
Môi trường hộp cát mô phỏng hành vi của quá trình thực thi từ xa – nếu một bản dựng hoạt động tốt với môi trường hộp cát, thì bản dựng đó cũng có thể hoạt động với quá trình thực thi từ xa. Bằng cách thực thi từ xa để tải tất cả tệp cần thiết lên (bao gồm cả các công cụ cục bộ), bạn có thể giảm đáng kể chi phí bảo trì cho các cụm biên dịch so với việc phải cài đặt các công cụ trên mọi máy trong cụm mỗi khi bạn muốn dùng thử một trình biên dịch mới hoặc thay đổi một công cụ hiện có.
Nên sử dụng chiến lược hộp cát nào
Bạn có thể chọn loại hộp cát để sử dụng (nếu có) với cờ chiến lược. Việc sử dụng chiến lược sandboxed
sẽ giúp Bazel chọn một trong các cách triển khai hộp cát được liệt kê bên dưới, ưu tiên hộp cát dành riêng cho hệ điều hành hơn là hộp cát chung chung kém kín đáo.
Worker ổn định sẽ chạy trong một hộp cát chung nếu bạn truyền cờ --worker_sandboxing
.
Chiến lược local
(còn gọi là standalone
) không thực hiện bất kỳ loại hộp cát nào.
Tệp này chỉ thực thi dòng lệnh của thao tác với thư mục đang làm việc được đặt thành thư mục thực thi của không gian làm việc.
processwrapper-sandbox
là một chiến lược hộp cát không yêu cầu bất kỳ tính năng "nâng cao" nào – chiến lược này sẽ hoạt động ngay trên mọi hệ thống POSIX. Công cụ này tạo một thư mục hộp cát bao gồm các đường liên kết tượng trưng trỏ đến các tệp nguồn gốc, thực thi dòng lệnh của thao tác với thư mục đang hoạt động được đặt thành thư mục này thay vì thư mục execroot, sau đó di chuyển các cấu phần phần mềm đầu ra đã biết ra khỏi hộp cát vào thư mục execroot và xoá hộp cát. Điều này giúp ngăn chặn việc vô tình sử dụng bất kỳ tệp đầu vào nào chưa được khai báo và làm hỏng tệp thực thi bằng các tệp đầu ra không xác định.
linux-sandbox
tiến thêm một bước và được xây dựng dựa trên processwrapper-sandbox
. Tương tự như cách Docker nâng cao, công cụ này sử dụng Không gian tên Linux (không gian tên Người dùng, Núi, PID, Mạng và IPC) để tách biệt hành động khỏi máy chủ. Điều này nghĩa là toàn bộ hệ thống tệp sẽ chuyển sang chế độ chỉ có thể đọc, ngoại trừ thư mục hộp cát, nhờ đó, thao tác không thể vô tình sửa đổi bất cứ nội dung nào trên hệ thống tệp lưu trữ. Điều này giúp ngăn chặn các tình huống như kiểm thử lỗi vô tình rm -rf thư mục $HOME. Nếu muốn, bạn cũng có thể ngăn hành động truy cập vào mạng. linux-sandbox
sử dụng không gian tên PID để ngăn hành động này nhìn thấy bất kỳ quy trình nào khác và để tắt tất cả quy trình (thậm chí cả các trình nền do hành động tạo ra) một cách đáng tin cậy ở cuối.
darwin-sandbox
cũng tương tự nhưng dành cho macOS. Công cụ này sử dụng công cụ sandbox-exec
của Apple để đạt được hiệu quả tương tự như hộp cát Linux.
Cả linux-sandbox
và darwin-sandbox
đều không hoạt động trong trường hợp "lồng nhau" do các hạn chế trong cơ chế mà các hệ điều hành cung cấp. Vì Docker cũng sử dụng không gian tên Linux để tạo sự kỳ diệu cho vùng chứa, nên bạn không thể dễ dàng chạy linux-sandbox
bên trong vùng chứa Docker, trừ phi bạn sử dụng docker run --privileged
. Trên macOS, bạn không thể chạy sandbox-exec
bên trong một quy trình đã được đưa vào hộp cát. Do đó, trong những trường hợp này, Bazel sẽ tự động quay lại sử dụng processwrapper-sandbox
.
Nếu bạn muốn nhận lỗi bản dựng (chẳng hạn như để không vô tình tạo bản dựng bằng một chiến lược thực thi ít nghiêm ngặt hơn), hãy sửa đổi rõ ràng danh sách các chiến lược thực thi mà Bazel cố gắng sử dụng (ví dụ: bazel build
--spawn_strategy=worker,linux-sandbox
).
Quá trình thực thi động thường yêu cầu hộp cát để thực thi cục bộ. Để chọn không tham gia, hãy chuyển cờ --experimental_local_lockfree_output
. Quá trình thực thi động sẽ tự động tạo hộp cát cho trình thực thi liên tục.
Nhược điểm của việc chạy trong môi trường hộp cát
Quá trình hộp cát phát sinh thêm chi phí thiết lập và chia nhỏ. Mức chi phí này phụ thuộc vào nhiều yếu tố, bao gồm cả hình dạng của bản dựng và hiệu suất của hệ điều hành máy chủ. Đối với Linux, các bản dựng trong hộp cát hiếm khi chậm hơn một vài phần trăm. Việc đặt
--reuse_sandbox_directories
có thể giúp giảm thiểu chi phí thiết lập và chia nhỏ.Chế độ hộp cát sẽ vô hiệu hoá hiệu quả mọi bộ nhớ đệm mà công cụ có thể có. Bạn có thể giảm thiểu điều này bằng cách sử dụng trình thực thi liên tục, với chi phí là sự đảm bảo hộp cát yếu hơn.
Trình thực thi Multiplex yêu cầu sự hỗ trợ rõ ràng của worker vào hộp cát. Các worker không hỗ trợ hộp cát nhiều luồng chạy dưới dạng worker đơn luồng trong quá trình thực thi động, điều này có thể làm tiêu tốn thêm bộ nhớ.
hộp cát
sandboxfs
là một hệ thống tệp FUSE hiển thị một chế độ xem tuỳ ý của hệ thống tệp cơ bản mà không bị phạt thời gian. Bazel sử dụng sandboxfs
để tạo execroot/
ngay lập tức cho mỗi hành động, tránh chi phí phải thực hiện hàng nghìn lệnh gọi hệ thống. Xin lưu ý rằng các hoạt động I/O khác trong execroot/
có thể chậm hơn do hao tổn FUSE.
Cài đặt sandboxfs
Hãy làm theo các bước sau để cài đặt sandboxfs
và tạo bản dựng Bazel bằng công cụ này:
Tải xuống
Tải xuống và cài đặt
sandboxfs
để tệp nhị phân sandboxfs
kết thúc trong PATH
của bạn.
Chạy sandboxfs
- (chỉ dành cho macOS) Cài đặt OSXFUSE.
(Chỉ dành cho macOS) Chạy:
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
Bạn cần thực hiện việc này sau khi cài đặt và sau mỗi lần khởi động lại để đảm bảo các dịch vụ hệ thống chính của macOS hoạt động được thông qua hộp cát.
Chạy bản dựng Bazel bằng
--experimental_use_sandboxfs
.bazel build target --experimental_use_sandboxfs
Khắc phục sự cố
Nếu bạn thấy local
thay vì darwin-sandbox
hoặc linux-sandbox
dưới dạng chú thích cho các thao tác được thực thi, thì điều này có thể có nghĩa là tính năng hộp cát bị tắt. Truyền --genrule_strategy=sandboxed --spawn_strategy=sandboxed
để bật tính năng này.
Gỡ lỗi
Hãy làm theo các chiến lược dưới đây để khắc phục sự cố liên quan đến hộp cát.
Không gian tên đã huỷ kích hoạt
Trên một số nền tảng, chẳng hạn như các nút cụm Google Kubernetes Engine hoặc Debian, không gian tên người dùng sẽ bị vô hiệu hoá theo mặc định do các vấn đề về bảo mật. Nếu tệp /proc/sys/kernel/unprivileged_userns_clone
tồn tại và chứa giá trị 0, bạn có thể kích hoạt không gian tên người dùng bằng cách chạy:
sudo sysctl kernel.unprivileged_userns_clone=1
Không thực thi được quy tắc
Hộp cát có thể không thực thi được các quy tắc do cách thiết lập hệ thống. Nếu bạn thấy một thông báo như namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory
, hãy thử huỷ kích hoạt hộp cát bằng --strategy=Genrule=local
cho genrules và --spawn_strategy=local
cho các quy tắc khác.
Gỡ lỗi chi tiết cho các lỗi bản dựng
Nếu bản dựng của bạn không thành công, hãy sử dụng --verbose_failures
và --sandbox_debug
để khiến Bazel hiển thị chính xác lệnh đã chạy khi bản dựng của bạn không thành công, bao gồm cả phần thiết lập hộp cát.
Ví dụ về thông báo lỗi:
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)
Giờ đây, bạn có thể kiểm tra thư mục hộp cát đã tạo và xem những tệp nào mà Bazel đã tạo, sau đó chạy lại lệnh để xem cách hoạt động của lệnh đó.
Xin lưu ý rằng Bazel không xoá thư mục hộp cát khi bạn sử dụng --sandbox_debug
. Trừ phi đang gỡ lỗi, bạn nên tắt --sandbox_debug
vì tệp này sẽ làm đầy ổ đĩa theo thời gian.