Artikel ini membahas sandbox di Bazel dan proses debug lingkungan sandbox Anda.
Sandboxing adalah strategi pembatasan izin yang mengisolasi proses dari satu sama lain atau dari resource dalam suatu sistem. Untuk Bazel, ini berarti membatasi akses sistem file.
Sandbox sistem file Bazel menjalankan proses di direktori kerja yang hanya berisi input yang diketahui, sehingga compiler dan alat lain tidak melihat file sumber yang tidak boleh diakses, kecuali jika mengetahui jalur absolutnya.
Sandbox tidak menyembunyikan lingkungan host dengan cara apa pun. Proses dapat dengan bebas mengakses semua file di sistem file. Namun, pada platform yang mendukung namespace pengguna, proses tidak dapat mengubah file apa pun di luar direktori kerjanya. Hal ini memastikan bahwa grafik build tidak memiliki dependensi tersembunyi yang dapat memengaruhi reproduksi build.
Lebih spesifik lagi, Bazel membuat direktori execroot/
untuk setiap tindakan,
yang bertindak sebagai direktori kerja tindakan pada waktu eksekusi. execroot/
berisi semua file input untuk tindakan dan berfungsi sebagai penampung untuk
setiap output yang dihasilkan. Bazel kemudian menggunakan teknik yang disediakan sistem operasi,
container di Linux dan sandbox-exec
di macOS, untuk membatasi tindakan dalam
execroot/
.
Alasan sandboxing
Tanpa sandbox tindakan, Bazel tidak tahu apakah suatu alat menggunakan file input yang tidak dideklarasikan (file yang tidak tercantum secara eksplisit dalam dependensi suatu tindakan). Saat salah satu file input yang tidak dideklarasikan berubah, Bazel masih yakin bahwa build-nya sudah yang terbaru dan tidak akan mem-build ulang tindakannya. Hal ini dapat menghasilkan build inkremental yang salah.
Penggunaan ulang entri cache yang salah akan menimbulkan masalah selama penyimpanan cache jarak jauh. Entri cache yang buruk pada cache bersama akan memengaruhi setiap developer pada project, dan menghapus seluruh cache jarak jauh bukanlah solusi yang layak.
Sandbox meniru perilaku eksekusi jarak jauh — jika build berfungsi baik dengan sandbox, build tersebut kemungkinan juga akan berfungsi dengan eksekusi jarak jauh. Dengan membuat eksekusi jarak jauh mengupload semua file yang diperlukan (termasuk alat lokal), Anda dapat mengurangi biaya pemeliharaan untuk cluster kompilasi secara signifikan dibandingkan dengan menginstal alat di setiap mesin dalam cluster setiap kali Anda ingin mencoba compiler baru atau melakukan perubahan pada alat yang ada.
Strategi sandbox yang akan digunakan
Anda dapat memilih jenis sandbox yang akan digunakan, jika ada, dengan tanda strategi. Dengan menggunakan strategi sandboxed
, Bazel dapat memilih salah satu implementasi sandbox yang tercantum di bawah, dan lebih memprioritaskan sandbox khusus OS daripada sandbox yang generik.
Pekerja persisten berjalan di sandbox generik jika Anda meneruskan flag --worker_sandboxing
.
Strategi local
(alias standalone
) tidak melakukan jenis sandbox apa pun.
Dengan begitu, command line tindakan akan dijalankan dengan direktori kerja yang disetel ke execroot ruang kerja Anda.
processwrapper-sandbox
adalah strategi sandbox yang tidak memerlukan fitur "lanjutan" apa pun - strategi ini dapat langsung berfungsi pada sistem POSIX apa pun. Alat ini
mem-build direktori sandbox yang terdiri dari symlink yang mengarah ke file
sumber asli, mengeksekusi command line tindakan dengan direktori kerja yang disetel
ke direktori ini, bukan execroot, lalu memindahkan artefak output yang diketahui
dari sandbox ke execroot dan menghapus sandbox. Tindakan ini mencegah
tindakan tersebut secara tidak sengaja menggunakan file input yang tidak dideklarasikan dan
tidak memenuhi execroot dengan file output yang tidak dikenal.
linux-sandbox
melangkah lebih jauh dan dibuat berdasarkan
processwrapper-sandbox
. Seperti yang dilakukan Docker pada prinsipnya, Docker menggunakan Namespace Linux (namespace Pengguna, Mount, PID, Jaringan, dan IPC) untuk mengisolasi tindakan dari host. Artinya, tindakan ini membuat seluruh sistem file menjadi hanya-baca kecuali
untuk direktori sandbox, sehingga tindakan tersebut tidak dapat mengubah apa pun secara tidak sengaja pada
sistem file host. Hal ini mencegah situasi seperti pengujian yang berisi bug secara tidak sengaja melakukan
rm-rf' pada direktori $HOME Anda. Secara opsional, Anda juga dapat mencegah tindakan
mengakses jaringan. linux-sandbox
menggunakan namespace PID untuk mencegah tindakan
melihat proses lain dan untuk menghentikan semua proses dengan andal (bahkan daemon
yang diaktifkan oleh tindakan) di akhir.
darwin-sandbox
serupa, tetapi untuk macOS. Opsi ini menggunakan alat sandbox-exec
Apple untuk mencapai hasil yang kurang lebih sama dengan sandbox Linux.
Baik linux-sandbox
maupun darwin-sandbox
tidak berfungsi dalam skenario "tumpang-tindih" karena pembatasan dalam mekanisme yang disediakan oleh sistem
operasi. Karena Docker juga menggunakan namespace Linux untuk keajaiban container-nya, Anda tidak dapat menjalankan linux-sandbox
di dalam container Docker dengan mudah, kecuali jika Anda menggunakan docker run --privileged
. Di macOS, Anda tidak dapat menjalankan sandbox-exec
di dalam proses yang sudah di-sandbox. Dengan demikian, dalam kasus ini, Bazel
otomatis kembali menggunakan processwrapper-sandbox
.
Jika Anda lebih suka mendapatkan error build — misalnya tidak melakukan build secara tidak sengaja dengan
strategi eksekusi yang kurang ketat — ubah secara eksplisit daftar strategi
eksekusi yang akan digunakan Bazel (misalnya, bazel build
--spawn_strategy=worker,linux-sandbox
).
Eksekusi dinamis biasanya memerlukan sandbox untuk eksekusi lokal. Untuk memilih tidak menggunakan,
teruskan flag --experimental_local_lockfree_output
. Eksekusi dinamis membuat sandbox pekerja persisten tanpa pemberitahuan.
Kelemahan sandboxing
Sandbox menimbulkan biaya penyiapan dan pemutusan koneksi tambahan. Seberapa besar biaya ini bergantung pada banyak faktor, termasuk bentuk build dan performa OS host. Untuk Linux, build dengan sandbox jarang lebih lambat beberapa persen. Menyetel
--reuse_sandbox_directories
dapat mengurangi biaya penyiapan dan pemutusan.Penggunaan sandbox secara efektif menonaktifkan cache yang mungkin dimiliki alat ini. Anda dapat mengatasi hal ini dengan menggunakan pekerja persisten, tetapi jaminan sandbox yang lebih rendah akan ditanggulangi.
Pekerja multipleks memerlukan dukungan pekerja eksplisit untuk di-sandbox. Pekerja yang tidak mendukung sandbox multipleks berjalan sebagai pekerja singleplex dalam eksekusi dinamis, yang dapat menghabiskan memori tambahan.
Proses debug
Ikuti strategi di bawah untuk men-debug masalah pada sandbox.
Namespace yang dinonaktifkan
Pada beberapa platform, seperti node cluster Google Kubernetes Engine atau Debian, namespace pengguna dinonaktifkan secara default karena masalah keamanan. Jika file /proc/sys/kernel/unprivileged_userns_clone
ada dan berisi 0, Anda dapat mengaktifkan namespace pengguna dengan menjalankan:
sudo sysctl kernel.unprivileged_userns_clone=1
Kegagalan eksekusi aturan
{i>Sandbox<i} mungkin gagal menjalankan aturan karena konfigurasi sistem. Jika Anda melihat pesan seperti namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory
, coba nonaktifkan sandbox dengan --strategy=Genrule=local
untuk genrules, dan --spawn_strategy=local
untuk aturan lainnya.
Proses debug mendetail untuk kegagalan build
Jika build Anda gagal, gunakan --verbose_failures
dan --sandbox_debug
untuk membuat
Bazel menampilkan perintah yang sama persis saat build Anda gagal, termasuk bagian
yang menyiapkan sandbox.
Contoh pesan error:
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)
Sekarang Anda dapat memeriksa direktori sandbox yang dihasilkan dan melihat file mana yang dibuat Bazel, lalu menjalankan perintah itu lagi untuk melihat perilakunya.
Perlu diperhatikan bahwa Bazel tidak menghapus direktori sandbox saat Anda menggunakan
--sandbox_debug
. Kecuali jika Anda aktif melakukan proses debug, sebaiknya nonaktifkan
--sandbox_debug
karena akan mengisi disk Anda seiring waktu.