Artikel ini membahas sandboxing di Bazel dan men-debug lingkungan sandboxing 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 di direktori kerja yang hanya berisi input yang diketahui, sehingga compiler dan alat lainnya tidak melihat file sumber yang seharusnya tidak mereka akses, kecuali jika mereka mengetahui jalur absolutnya.
Sandbox tidak menyembunyikan lingkungan host dengan cara apa pun. Proses dapat mengakses semua file di sistem file secara bebas. Namun, di 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.
Lebih khusus lagi, 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 container untuk semua
output yang dihasilkan. Kemudian, Bazel menggunakan teknik yang disediakan sistem operasi,
yaitu container di Linux dan sandbox-exec
di macOS, untuk membatasi tindakan dalam
execroot/
.
Alasan untuk melakukan sandbox
Tanpa sandbox tindakan, Bazel tidak tahu apakah alat menggunakan file input yang tidak dideklarasikan (file yang tidak tercantum secara eksplisit dalam dependensi tindakan). Saat salah satu file input yang tidak dideklarasikan berubah, Bazel tetap menganggap bahwa build sudah terbaru dan tidak akan membangun ulang tindakan. Hal ini dapat menghasilkan build inkremental yang salah.
Penggunaan kembali entri cache yang salah 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.
Sandboxing meniru perilaku eksekusi jarak jauh — jika build berfungsi dengan baik dengan sandboxing, kemungkinan build 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 cluster kompilasi secara signifikan dibandingkan dengan harus menginstal alat di setiap mesin 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
flag strategi. Menggunakan strategi sandboxed
membuat Bazel memilih salah satu implementasi sandbox yang tercantum di bawah, dengan lebih memilih sandbox khusus OS daripada sandbox generik yang kurang hermetik.
Pekerja persisten berjalan di sandbox generik jika Anda meneruskan
flag --worker_sandboxing
.
Strategi local
(alias standalone
) tidak melakukan sandboxing apa pun.
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. Tindakan 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. Tindakan ini mencegah
tindakan menggunakan file input yang tidak dideklarasikan secara tidak sengaja dan
mencegah execroot dipenuhi dengan file output yang tidak diketahui.
linux-sandbox
melangkah lebih jauh dan dibangun di atas
processwrapper-sandbox
. Mirip dengan yang dilakukan Docker di balik layar, alat ini menggunakan
Namespace Linux (namespace Pengguna, Pemasangan, PID, Jaringan, dan IPC) untuk mengisolasi
tindakan dari host. Artinya, seluruh sistem file menjadi hanya baca, kecuali direktori sandbox, sehingga tindakan ini tidak dapat memodifikasi apa pun secara tidak sengaja di sistem file host. Hal ini mencegah situasi seperti pengujian yang penuh bug secara tidak sengaja menjalankan 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 secara andal (bahkan daemon
yang dibuat oleh tindakan) di akhir.
darwin-sandbox
serupa, tetapi untuk macOS. Alat ini menggunakan alat sandbox-exec
Apple
untuk mencapai hasil yang hampir 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 keajaiban 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
akan otomatis melakukan fallback ke penggunaan processwrapper-sandbox
.
Jika Anda lebih memilih mendapatkan error build — misalnya, agar tidak secara tidak sengaja membangun dengan strategi eksekusi yang kurang ketat — ubah secara eksplisit daftar strategi eksekusi yang dicoba digunakan Bazel (misalnya, bazel build
--spawn_strategy=worker,linux-sandbox
).
Eksekusi dinamis biasanya memerlukan sandbox untuk eksekusi lokal. Untuk menonaktifkan,
teruskan tanda --experimental_local_lockfree_output
. Eksekusi dinamis secara diam-diam
mengisolasi pekerja persisten.
Kekurangan sandbox
Sandbox menimbulkan biaya penyiapan dan penonaktifan tambahan. Seberapa besar biaya ini bergantung pada banyak faktor, termasuk bentuk build dan performa OS host. Untuk Linux, build sandbox jarang lebih lambat lebih dari beberapa persen. Menetapkan
--reuse_sandbox_directories
dapat mengurangi biaya penyiapan dan penonaktifan.Sandbox secara efektif menonaktifkan cache apa pun yang mungkin dimiliki alat tersebut. Anda dapat mengurangi risiko ini dengan menggunakan pekerja persisten, dengan biaya jaminan sandbox yang lebih lemah.
Pekerja multiplex memerlukan dukungan pekerja eksplisit agar dapat di-sandbox. Pekerja yang tidak mendukung sandbox multiplex berjalan sebagai pekerja simpleks dalam eksekusi dinamis, yang dapat memerlukan memori tambahan.
Proses debug
Ikuti strategi di bawah untuk men-debug masalah terkait sandbox.
Namespace yang dinonaktifkan
Di 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
Sandbox mungkin gagal mengeksekusi aturan karena penyiapan 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 persis 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)
Sekarang Anda dapat memeriksa direktori sandbox yang dibuat 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 sedang men-debug secara aktif, Anda harus menonaktifkan
--sandbox_debug
karena akan mengisi disk Anda seiring waktu.