Artikel ini membahas sandbox di Bazel dan proses debug lingkungan sandbox Anda.
Sandbox adalah strategi pembatasan izin yang mengisolasi proses dari satu sama lain atau dari resource dalam sistem. Untuk Bazel, hal ini berarti membatasi akses sistem file.
Sandbox sistem file Bazel menjalankan proses dalam direktori kerja yang hanya berisi input yang diketahui, sehingga compiler dan alat lainnya tidak melihat file sumber yang tidak boleh mereka akses, kecuali jika mereka mengetahui jalur absolut ke file tersebut.
Sandbox tidak menyembunyikan lingkungan host dengan cara apa pun. Proses dapat mengakses semua file di sistem file secara bebas. 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 kemampuan reproduksi build.
Secara khusus, Bazel membuat direktori execroot/ untuk setiap tindakan, yang berfungsi sebagai direktori kerja tindakan pada waktu eksekusi. execroot/
berisi semua file input ke tindakan dan berfungsi sebagai penampung untuk 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 menggunakan sandbox
Tanpa sandbox tindakan, Bazel tidak mengetahui apakah alat menggunakan file input yang tidak dideklarasikan (file yang tidak tercantum secara eksplisit dalam dependensi tindakan). Jika salah satu file input yang tidak dideklarasikan berubah, Bazel tetap yakin bahwa build sudah yang terbaru dan tidak akan membangun ulang tindakan tersebut. Hal ini dapat mengakibatkan build tambahan yang salah.
Penggunaan kembali entri cache yang salah akan menimbulkan masalah selama caching jarak jauh. Entri cache yang buruk dalam cache bersama memengaruhi setiap developer dalam project, dan menghapus seluruh cache jarak jauh bukanlah solusi yang layak.
Sandbox meniru perilaku eksekusi jarak jauh — jika build berfungsi dengan baik menggunakan sandbox, kemungkinan besar build tersebut 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 harus menginstal alat di setiap komputer dalam cluster setiap kali Anda ingin mencoba compiler baru atau membuat perubahan pada alat yang ada.
Strategi sandbox yang akan digunakan
Anda dapat memilih jenis sandbox yang akan digunakan, jika ada, dengan the
flag strategi. Menggunakan strategi sandboxed akan membuat Bazel memilih salah satu penerapan sandbox yang tercantum di bawah, dengan lebih memilih sandbox khusus OS daripada sandbox generik yang kurang hermetis.
Worker persisten berjalan di sandbox generik jika Anda meneruskan
flag --worker_sandboxing.
Strategi local (alias standalone) tidak melakukan jenis sandbox apa pun.
Strategi ini hanya menjalankan command line tindakan dengan direktori kerja yang ditetapkan ke execroot ruang kerja Anda.
processwrapper-sandbox adalah strategi sandbox yang tidak memerlukan fitur "lanjutan" apa pun - strategi ini akan berfungsi di sistem POSIX apa pun secara langsung. Strategi ini membuat direktori sandbox yang terdiri dari symlink yang mengarah ke file sumber asli, menjalankan command line tindakan dengan direktori kerja yang ditetapkan ke direktori ini, bukan execroot, lalu memindahkan artefak output yang diketahui dari sandbox ke execroot dan menghapus sandbox. Hal ini mencegah tindakan menggunakan file input yang tidak dideklarasikan secara tidak sengaja dan membuang file output yang tidak diketahui ke execroot.
linux-sandbox melangkah lebih jauh dan dibangun di atas processwrapper-sandbox. Mirip dengan yang dilakukan Docker di balik layar, strategi ini menggunakan Namespace Linux (namespace Pengguna, Pemasangan, PID, Jaringan, dan IPC) untuk mengisolasi tindakan dari host. Artinya, strategi ini membuat seluruh sistem file bersifat hanya baca, kecuali untuk direktori sandbox, sehingga tindakan tidak dapat mengubah apa pun di sistem file host secara tidak sengaja. Hal ini mencegah situasi seperti pengujian yang rusak secara tidak sengaja menghapus 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 (bahkan daemon yang dibuat oleh tindakan) secara andal pada akhirnya.
darwin-sandbox serupa, tetapi untuk macOS. Strategi ini menggunakan alat sandbox-exec Apple untuk mencapai hasil yang kurang lebih sama dengan sandbox Linux.
linux-sandbox dan darwin-sandbox tidak berfungsi dalam skenario "bertumpuk" karena batasan dalam mekanisme yang disediakan oleh sistem operasi. Karena Docker juga menggunakan namespace Linux untuk container-nya, Anda tidak dapat menjalankan linux-sandbox dengan mudah di dalam container Docker, kecuali jika Anda menggunakan docker run --privileged. Di macOS, Anda tidak dapat menjalankan sandbox-exec di dalam proses yang sudah di-sandbox. Oleh karena itu, dalam kasus ini, Bazel otomatis kembali menggunakan processwrapper-sandbox.
Jika Anda lebih memilih mendapatkan error build — misalnya, agar tidak secara tidak sengaja melakukan build dengan strategi eksekusi yang
kurang ketat — ubah secara eksplisit daftar strategi eksekusi yang
coba digunakan Bazel (misalnya, bazel build
--spawn_strategy=worker,linux-sandbox).
Eksekusi dinamis biasanya memerlukan sandbox untuk eksekusi lokal. Untuk memilih tidak ikut, teruskan flag --experimental_local_lockfree_output. Eksekusi dinamis secara diam-diam
melakukan sandbox pada worker persisten.
Kekurangan sandbox
Sandbox menimbulkan biaya penyiapan dan penghapusan tambahan. Besarnya biaya ini bergantung pada banyak faktor, termasuk bentuk build dan performa OS host. Untuk Linux, build yang di-sandbox jarang lebih lambat dari beberapa persen. Menetapkan
--reuse_sandbox_directoriesdapat mengurangi biaya penyiapan dan penghapusan.Sandbox secara efektif menonaktifkan cache apa pun yang mungkin dimiliki alat. Anda dapat mengurangi hal ini dengan menggunakan worker persisten, dengan mengorbankan jaminan sandbox yang lebih lemah.
Worker multipleks memerlukan dukungan worker eksplisit untuk di-sandbox. Worker yang tidak mendukung sandbox multipleks berjalan sebagai worker singlepleks dalam eksekusi dinamis, yang dapat menghabiskan memori tambahan.
Proses debug
Ikuti strategi di bawah untuk melakukan proses debug masalah sandbox.
Namespace yang dinonaktifkan
Di beberapa platform, seperti
Google Kubernetes Engine
node cluster 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=1Kegagalan eksekusi aturan
Sandbox mungkin gagal menjalankan aturan karena penyiapan sistem. Jika Anda melihat a
pesan seperti namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory, coba nonaktifkan sandbox dengan --strategy=Genrule=local untuk
genrule, 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 tepat yang dijalankannya 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)
Anda kini dapat memeriksa direktori sandbox yang dihasilkan dan melihat file mana yang dibuat Bazel, lalu menjalankan perintah lagi untuk melihat perilakunya.
Perhatikan bahwa Bazel tidak menghapus direktori sandbox saat Anda menggunakan --sandbox_debug. Kecuali jika Anda melakukan proses debug secara aktif, Anda harus menonaktifkan --sandbox_debug karena akan mengisi disk Anda dari waktu ke waktu.