Bài viết này đề cập đến tính năng chạy trong môi trường hộp cát trong Bazel và cách gỡ lỗi môi trường chạy trong môi trường hộp cát.
Chạy trong 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 nhau hoặc tách biệt các quy trình với tài nguyên trong một 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 làm việc chỉ chứa các 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 nhìn thấy các tệp nguồn mà chúng không được truy cập, trừ phi chúng biết đường dẫn tuyệt đối đến các tệp đó.
Tính năng chạy trong môi trường hộp cát không ẩn môi trường máy chủ 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ả cá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 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 làm việc của chúng. Điều này đảm bảo rằng biểu đồ bản dựng không có cá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 làm việc của hành động tại thời điểm thực thi. execroot/
chứa tất cả các tệp đầu vào cho hành động và đóng vai trò là vùng chứa cho mọi đầu ra được tạo. Sau đó, Bazel sử dụng một 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, để giới hạn hành động trong execroot/.
Lý do chạy trong môi trường hộp cát
Nếu không có tính năng chạy trong môi trường hộp cát cho 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 khai báo (các tệp không được liệt kê rõ ràng trong các phần phụ thuộc của một hành động) hay không. Khi một trong các tệp đầu vào chưa khai báo thay đổi, Bazel vẫn tin rằng bản dựng đã được cập nhật và sẽ không xây dựng lại hành động. Điều này có thể dẫn đến một bản dựng gia tăng không chính xác.
Việc sử dụng lại không chính xác các mục trong bộ nhớ đệm sẽ tạo ra vấn đề trong quá trình lưu vào bộ nhớ đệm từ xa. Một mục trong bộ nhớ đệm không chính xác 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 xóa toàn bộ bộ nhớ đệm từ xa không phải là một giải pháp khả thi.
Tính năng chạy trong 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 tính năng chạy trong 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 yêu cầu quá trình thực thi từ xa tải lên tất cả các tệp cần thiết (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ó.
Chiến lược chạy trong môi trường hộp cát cần sử dụng
Bạn có thể chọn loại chạy trong môi trường hộp cát để sử dụng (nếu có) bằng các
cờ chiến lược. Việc sử dụng chiến lược sandboxed sẽ khiến 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 hộp cát chung ít kín hơn.
Các trình thực thi liên tục 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 chạy trong môi trường hộp cát nào.
Chiến lược này chỉ thực thi dòng lệnh của hành động với thư mục làm việc được đặt thành execroot của không gian làm việc.
processwrapper-sandbox là một chiến lược chạy trong môi trường 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 trên mọi hệ thống POSIX ngay khi bạn sử dụng. Chiến lược này 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 các tệp nguồn gốc, thực thi dòng lệnh của hành động với thư mục làm việc được đặt thành 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 giúp ngăn hành động vô tình sử dụng bất kỳ tệp đầu vào nào chưa được khai báo và ngăn việc làm lộn xộn 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à xây dựng dựa trên processwrapper-sandbox. Tương tự như những gì Docker thực hiện ở chế độ nền, chiến lược này sử dụng Không gian tên Linux (Không gian tên người dùng, Gắn kết, PID, Mạng và IPC) để tách biệt hành động khỏi máy chủ. Tức là chiến lược này khiến toàn bộ hệ thống tệp chỉ có thể đọc, ngoại trừ thư mục hộp cát, vì vậy, hành động không thể vô tình sửa đổi bất kỳ nội dung nào trên hệ thống tệp máy chủ. Điều này giúp ngăn chặn các tình huống như một bài kiểm tra có lỗi vô tình rm -rf'ing thư mục $HOME của bạn. Bạn cũng có thể ngăn hành động truy cập vào mạng (không bắt buộc). linux-sandbox sử dụng không gian tên PID để ngăn hành động nhìn thấy bất kỳ quy trình nào khác và để huỷ đáng tin cậy tất cả các quy trình (ngay cả các daemon do hành động tạo ra) ở cuối.
darwin-sandbox tương tự, nhưng dành cho macOS. Chiến lược này sử dụng công cụ sandbox-exec của Apple để đạt được kết quả tương tự như hộp cát Linux.
Cả linux-sandbox và darwin-sandbox đều không hoạt động trong tình huống "lồng nhau" do các hạn chế trong cơ chế do hệ điều hành cung cấp. Vì Docker cũng sử dụng không gian tên Linux 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 chạy trong môi trường 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 gặp lỗi bản dựng (chẳng hạn như để không vô tình xây dựng bằng 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 chạy trong môi trường hộp cát để thực thi cục bộ. Để chọn không sử dụng, hãy truyền cờ --experimental_local_lockfree_output. Quá trình thực thi động sẽ chạy trong môi trường hộp cát cho các trình thực thi liên tục một cách âm thầm.
sandboxes persistent workers.
Nhược điểm của việc chạy trong môi trường hộp cát
Việc chạy trong môi trường hộp cát sẽ phát sinh thêm chi phí thiết lập và huỷ thiết lập. Chi phí này lớn đến mức nào 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 chạy trong môi trường hộp cát hiếm khi chậm hơn vài phần trăm. Việc đặt
--reuse_sandbox_directoriescó thể giảm thiểu chi phí thiết lập và huỷ thiết lập.Việc chạy trong môi trường hộp cát sẽ vô hiệu hoá mọi bộ nhớ đệm mà công cụ có thể có. Bạn có thể giảm thiểu vấn đề này bằng cách sử dụng các trình thực thi liên tục, với chi phí là các đảm bảo về hộp cát yếu hơn.
Các trình thực thi đa hợp cần có sự hỗ trợ rõ ràng của trình thực thi để chạy trong môi trường hộp cát. Các trình thực thi không hỗ trợ tính năng chạy trong môi trường hộp cát đa hợp sẽ chạy dưới dạng trình thực thi đơn hợp trong quá trình thực thi động, có thể tốn thêm bộ nhớ.
Gỡ lỗi
Hãy làm theo các chiến lược bên dưới để gỡ lỗi các vấn đề khi chạy trong môi trường 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
các nút cụm hoặc Debian, không gian tên người dùng sẽ bị huỷ kích hoạt theo mặc định do
lo ngại về vấn đề 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=1Lỗi thực thi quy tắc
Hộp cát có thể không thực thi được các quy tắc do thiết lập hệ thống. Nếu bạn thấy a
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 không thành công, hãy sử dụng --verbose_failures và --sandbox_debug để Bazel hiển thị lệnh chính xác mà lệnh này đã chạy khi bản dựng không thành công, bao gồm cả phần thiết lập hộp cát.
Thông báo lỗi mẫu:
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 mà Bazel đã tạo, đồng thời chạy lại lệnh để xem hành vi 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 bạn đang tích cực gỡ lỗi, nếu không, bạn nên tắt --sandbox_debug vì tính năng này sẽ làm đầy ổ đĩa của bạn theo thời gian.