Artikel ini membahas penggunaan sandbox di Bazel, penginstalan sandboxfs
, dan proses debug lingkungan sandbox Anda.
Sandboxing 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 lain tidak melihat file sumber yang tidak boleh diakses, kecuali jika mereka mengetahui jalur absolut ke file tersebut.
Sandbox tidak menyembunyikan lingkungan host dengan cara apa pun. Proses dapat dengan bebas mengakses semua file pada 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 kemampuan reproduksi build.
Lebih spesifiknya, 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 dapat mengetahui 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 masih yakin bahwa build sudah yang terbaru dan tidak akan membangun ulang tindakan. Hal ini dapat menghasilkan build inkremental yang salah.
Penggunaan ulang entri cache yang salah menimbulkan masalah selama penyimpanan cache jarak jauh. Entri cache yang buruk dalam cache bersama memengaruhi setiap developer di project, dan menghapus seluruh cache jarak jauh bukanlah solusi yang memungkinkan.
Sandboxing meniru perilaku eksekusi jarak jauh; jika build berfungsi dengan baik dengan sandbox, build tersebut mungkin juga dapat 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 harus menginstal alat di setiap mesin dalam cluster setiap kali Anda ingin mencoba compiler baru atau membuat perubahan pada alat yang ada.
Strategi {i>sandbox<i} apa yang dapat digunakan
Anda dapat memilih jenis sandbox yang akan digunakan, jika ada, dengan tanda strategi. Menggunakan strategi sandboxed
membuat Bazel memilih salah satu implementasi sandbox yang tercantum di bawah, lebih memilih sandbox khusus OS daripada sandbox yang bersifat umum.
Pekerja persisten akan berjalan di sandbox generik jika Anda meneruskan flag --worker_sandboxing
.
Strategi local
(alias standalone
) tidak melakukan jenis sandbox apa pun.
Alat ini hanya mengeksekusi command line tindakan dengan direktori kerja yang ditetapkan ke execroot ruang kerja Anda.
processwrapper-sandbox
adalah strategi sandbox yang tidak memerlukan fitur "lanjutan" - strategi ini harus berfungsi di semua sistem POSIX yang siap pakai. Fungsi ini
mem-build direktori sandbox yang terdiri dari symlink yang mengarah ke file sumber
asli, mengeksekusi 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 agar tidak menggunakan file input apa pun yang tidak dideklarasikan secara tidak sengaja, dan agar
tidak memenuhi execroot dengan file output yang tidak dikenal.
linux-sandbox
selangkah lebih maju dan melakukan build berdasarkan
processwrapper-sandbox
. Mirip dengan fungsi Docker, Docker menggunakan
Namespace Linux (User, Mount, PID, Network, dan IPC namespaces) untuk mengisolasi
tindakan dari host. Artinya, tindakan tersebut membuat seluruh sistem file menjadi hanya-baca, kecuali
untuk direktori sandbox sehingga tindakan tersebut tidak dapat mengubah apa pun pada
sistem file host secara tidak sengaja. Hal ini mencegah situasi seperti pengujian yang berisi bug secara tidak sengaja melakukan rm
-rf'ing direktori $HOME Anda. Secara opsional, Anda juga dapat mencegah tindakan
mengakses jaringan. linux-sandbox
menggunakan namespace PID untuk mencegah tindakan
melihat proses lain apa pun dan untuk secara andal menghentikan semua proses (bahkan daemon
yang dihasilkan oleh tindakan tersebut) di akhir.
darwin-sandbox
juga serupa, tetapi untuk macOS. Game ini menggunakan alat sandbox-exec
Apple untuk memberikan hasil yang hampir sama dengan sandbox Linux.
linux-sandbox
dan darwin-sandbox
tidak berfungsi dalam skenario "bertingkat"
karena adanya pembatasan dalam mekanisme yang disediakan oleh
sistem operasi. Karena Docker juga menggunakan namespace Linux untuk keajaiban container-nya, Anda
tidak dapat dengan mudah menjalankan linux-sandbox
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 penggantian untuk menggunakan processwrapper-sandbox
.
Jika Anda lebih memilih mengalami error build, misalnya tidak mem-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 akan secara otomatis
sandbox untuk pekerja persisten.
Kelemahan sandboxing
Sandboxing menimbulkan biaya penyiapan dan penguraian tambahan. Besarnya biaya ini bergantung pada banyak faktor, termasuk bentuk build dan performa OS host. Untuk Linux, build dengan sandbox jarang lebih dari beberapa persen lebih lambat. Menetapkan
--reuse_sandbox_directories
dapat mengurangi biaya penyiapan dan penguraian.Sandboxing secara efektif menonaktifkan cache apa pun yang mungkin dimiliki alat tersebut. Anda dapat menguranginya dengan menggunakan pekerja persisten, dengan mengorbankan jaminan sandbox yang lebih lemah.
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.
sandboxf
sandboxfs
adalah sistem file FUSE yang mengekspos tampilan arbitrer dari
sistem file yang mendasarinya tanpa penalti waktu. Bazel menggunakan sandboxfs
untuk
menghasilkan execroot/
secara instan untuk setiap tindakan, sehingga menghindari biaya
untuk mengeluarkan ribuan panggilan sistem. Perhatikan bahwa I/O selanjutnya dalam execroot/
mungkin
menjadi lebih lambat karena overhead FUSE.
Instal sandboxf
Gunakan langkah-langkah berikut untuk menginstal sandboxfs
dan menjalankan build Bazel
dengannya:
Download
Download dan instal
sandboxfs
sehingga biner sandboxfs
berakhir di PATH
.
Jalankan sandboxfs
- (khusus macOS) Instal OSXFUSE.
(khusus macOS) Jalankan:
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
Anda harus melakukannya setelah penginstalan dan setelah setiap mulai ulang untuk memastikan layanan sistem macOS inti berfungsi melalui sandboxf.
Jalankan build Bazel dengan
--experimental_use_sandboxfs
.bazel build target --experimental_use_sandboxfs
Pemecahan masalah
Jika Anda melihat local
, bukan darwin-sandbox
atau linux-sandbox
sebagai
anotasi untuk tindakan yang dieksekusi, ini dapat berarti bahwa sandbox
dinonaktifkan. Teruskan --genrule_strategy=sandboxed --spawn_strategy=sandboxed
untuk
mengaktifkannya.
Proses Debug
Ikuti strategi di bawah untuk men-debug masalah terkait 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 angka 0, Anda dapat mengaktifkan namespace pengguna dengan menjalankan:
sudo sysctl kernel.unprivileged_userns_clone=1
Kegagalan eksekusi aturan
Sandbox mungkin gagal menjalankan 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 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)
Sekarang Anda dapat memeriksa direktori sandbox yang dihasilkan dan melihat file mana yang dibuat oleh Bazel dan menjalankan perintah tersebut lagi untuk melihat perilakunya.
Perlu diketahui bahwa Bazel tidak menghapus direktori sandbox saat Anda menggunakan
--sandbox_debug
. Kecuali jika Anda aktif melakukan proses debug, sebaiknya nonaktifkan
--sandbox_debug
karena ini akan memenuhi disk Anda seiring waktu.