Bài viết này trình bày về tính năng hộp cát trong Bazel và cách gỡ lỗi về hộp cát môi trường.
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 với nhau hoặc từ 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ế tệp quyền truy cập hệ thống.
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 mà chỉ chứa dữ liệu đầu vào đã biết, chẳng hạn như trình biên dịch và các công cụ khác không xem được nguồn các tệp mà họ không nên truy cập, trừ khi họ biết đường dẫn tuyệt đối đến các tệp đó.
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ể tuỳ ý truy cập vào tất cả các tệp trên hệ thống tệp. Tuy nhiên, trên các nền tảng hỗ trợ 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 hoạt động của chúng. Đ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 lặp lại của bản dựng.
Cụ thể hơn, Bazel tạo một thư mục execroot/
cho mỗi thao tác,
đóng vai trò là thư mục công việc của tác vụ tại thời điểm thực thi. execroot/
chứa tất cả tệp đầu vào cho hành động và đóng vai trò là vùng chứa cho bất kỳ
dữ liệu đầu ra được tạo ra. Sau đó, Bazel sử dụng kỹ thuật do hệ điều hành cung cấp,
vùng chứa trên Linux và sandbox-exec
trên macOS để ràng buộc hành động trong
execroot/
.
Lý do tạo 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 hộp cát chưa được khai báo hay không các tệp đầu vào (các tệp không được liệt kê rõ ràng trong các phần phụ thuộc của 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 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. Đáp không hợp lệ trong bộ nhớ đệm dùng chung ảnh hưởng đến mọi nhà phát triển của dự án, và việc xoá toàn bộ bộ nhớ đệm từ xa không phải là một giải pháp khả thi.
Hộp cát bắt chước hành vi thực thi từ xa – nếu một bản dựng hoạt động tốt với hộp cát, nó cũng có thể hoạt động với chế độ thực thi từ xa. Bằng cách tạo thực thi từ xa và tải tất cả tệp cần thiết lên (bao gồm 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 phải cài đặt các công cụ này 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 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. Sử dụng sandboxed
giúp Bazel chọn một trong những cách triển khai hộp cát được liệt kê dưới đây,
thích hộp cát dành riêng cho hệ điều hành hơn hộp cát chung ít khép kín hơn.
Worker ổn định sẽ chạy trong một hộp cát chung nếu bạn vượt qua
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.
Hàm 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
phương thứ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
"nâng cao" tính năng – nó sẽ hoạt động trên mọi hệ thống POSIX ngay từ đầu. Nó
tạo một thư mục hộp cát bao gồm các liên kết tượng trưng trỏ đến thư mục gốc
tệp nguồn, thực thi dòng lệnh của thao tác bằng tập hợp thư mục đang hoạt động
vào thư mục này thay vì 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 execroot và xoá hộp cát. Điều này ngăn chặn
do vô tình sử dụng bất kỳ tệp đầu vào nào không được khai báo và
làm sạch execroot 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ư những tính năng nâng cao của Docker, công cụ này sử dụng
Không gian tên Linux (các không gian tên Người dùng, Gắn kết, PID, Mạng và IPC) để tách biệt vùng chứa
từ 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ừ
cho thư mục hộp cát, để thao tác không thể vô tình sửa đổi bất kỳ nội dung nào
hệ thống tệp lưu trữ. Việc này giúp ngăn chặn những tình huống như kiểm thử lỗi vô tình rm
đang ghi lại thư mục $HOME của bạn. Nếu muốn, bạn cũng có thể ngăn hành động này
truy cập mạng. linux-sandbox
sử dụng không gian tên PID để ngăn hành động này
không nhìn thấy bất kỳ quy trình nào khác và loại bỏ tất cả quy trình một cách đáng tin cậy (kể cả trình nền)
tạo ra bởi hành động) ở cuối.
darwin-sandbox
cũng tương tự, nhưng dành cho macOS. Thiết bị này sử dụng công cụ sandbox-exec
của Apple
gần giống với hộp cát của Linux.
Cả linux-sandbox
và darwin-sandbox
đều không hoạt động trong phần "lồng nhau"
tình huống do các hạn chế trong các cơ chế do cơ quan điều hành cung cấp
hệ thống. Vì Docker cũng sử dụng không gian tên của Linux để mang đến sự kỳ diệu của vùng chứa, nên bạn
không thể dễ dàng chạy linux-sandbox
bên trong một 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
đã được tạo hộp cát. Do đó, trong những trường hợp này, Bazel
tự động quay lại sử dụng processwrapper-sandbox
.
Nếu bạn không muốn nhận lỗi bản dựng — chẳng hạn như để không vô tình tạo bằng một
chiến lược thực thi ít nghiêm ngặt hơn — sửa đổi danh sách thực thi một cách rõ ràng
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ộ. Cách làm như sau:
truyền cờ --experimental_local_lockfree_output
. Thực thi động
hộp cát cho trình thực thi liên tục.
Nhược điểm của 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ỏ. Chi phí này là bao nhiêu phụ thuộc vào nhiều yếu tố, bao gồm cả hình dạng của công trình và hiệu suất của hệ điều hành máy chủ. Đối với Linux, bản dựng dạng 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ả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 nhân viên liên tục, ở chi phí của việc đảm bảo hộp cát yếu hơn.
Trình thực thi Multiplex yêu cầu hỗ trợ rõ ràng của worker được tạo hộp cát. Các trình thực thi không hỗ trợ hộp cát Multiplex sẽ chạy dưới dạng trình thực thi singleplex trong quá trình thực thi động. Tình trạng này có thể tốn thêm bộ nhớ.
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ư
Google Kubernetes Engine
nút cụm hoặc Debian, không gian tên của người dùng bị huỷ kích hoạt theo mặc định do
các mối lo ngại về bảo mật. Nếu tệp /proc/sys/kernel/unprivileged_userns_clone
tồn tại và chứa số 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
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 với --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 không tạo được, hãy sử dụng --verbose_failures
và --sandbox_debug
để tạo
Bazel cho thấy lệnh chính xác mà công cụ này đã 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 tệp Bazel nào đã tạo và chạy lại lệnh để xem lệnh đó hoạt động như thế nào.
Lưu ý rằng Bazel không xoá thư mục hộp cát khi bạn sử dụng
--sandbox_debug
. Nếu không chủ động gỡ lỗi, bạn nên tắt
--sandbox_debug
vì dịch vụ này sẽ làm đầy ổ đĩa của bạn theo thời gian.