Artikel ini membahas penggunaan sandbox di Bazel, penginstalan sandboxfs
, dan proses debug
lingkungan sandboxing Anda.
Sandboxing adalah strategi pembatasan izin yang mengisolasi proses dari satu sama lain atau dari sumber daya dalam suatu sistem. Untuk Bazel, ini berarti membatasi file akses sistem ke sistem.
{i>sandbox<i} sistem file Bazel menjalankan proses di direktori kerja yang hanya berisi input yang diketahui, sehingga compiler dan alat lain tidak dapat melihat file yang tidak boleh mereka akses, kecuali mereka mengetahui jalur absolut ke sana.
Sandbox tidak menyembunyikan lingkungan host dengan cara apa pun. Proses bisa dengan bebas mengakses semua file pada sistem file. Namun, pada platform yang mendukung ruangnama, proses tidak dapat memodifikasi 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
output yang dihasilkan. Bazel kemudian menggunakan teknik
yang disediakan sistem operasi,
container di Linux dan sandbox-exec
pada macOS, untuk membatasi tindakan dalam
execroot/
.
Alasan sandboxing
Tanpa {i>sandbox<i} tindakan, Bazel tidak tahu apakah suatu alat menggunakan {i>sandbox<i} file input (file yang tidak secara eksplisit tercantum dalam dependensi tertentu). Ketika salah satu file input yang tidak dideklarasikan berubah, Bazel tetap percaya bahwa build sudah diupdate dan tidak akan membangun ulang aksinya. Hal ini dapat menghasilkan build inkremental yang salah.
Penggunaan ulang entri cache yang salah menimbulkan masalah selama penyimpanan cache jarak jauh. J entri cache yang buruk dalam {i>cache<i} bersama mempengaruhi setiap pengembang pada proyek, dan menghapus seluruh cache jarak jauh bukanlah solusi yang tepat.
Sandboxing meniru perilaku eksekusi jarak jauh — jika build berfungsi dengan baik dengan {i>sandbox<i}, {i>sandbox<i} juga dapat dilakukan dengan eksekusi jarak jauh. Dengan membuat mengunggah semua file yang diperlukan (termasuk alat lokal) dengan eksekusi jarak jauh, Anda dapat mengurangi biaya pemeliharaan secara signifikan untuk cluster kompilasi dibandingkan dengan menginstal alat itu di setiap komputer di cluster setiap kali Anda ingin mencoba kompilator 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
flag strategi. Menggunakan sandboxed
membuat Bazel memilih salah satu
implementasi {i>sandbox <i}yang tercantum di bawah ini,
memilih {i>sandbox<i} khusus OS daripada {i>sandbox<i} yang umum.
Pekerja persisten akan berjalan di sandbox generik jika Anda meneruskan
flag --worker_sandboxing
.
Strategi local
(alias standalone
) tidak melakukan jenis sandbox apa pun.
Ini hanya mengeksekusi baris perintah tindakan dengan direktori kerja yang diatur ke
{i>execroot<i} dari ruang kerja Anda.
processwrapper-sandbox
adalah strategi sandbox yang tidak memerlukan
"lanjutan" - fitur ini harus berfungsi pada
sistem POSIX apa pun yang siap pakai. Ini
membangun direktori {i>sandbox<i} yang terdiri dari {i>symlink<i} yang mengarah ke tautan asli
file sumber, mengeksekusi command line tindakan dengan kumpulan direktori kerja
ke direktori ini, bukan ke {i>execroot<i}, lalu memindahkan artefak {i>output<i} yang diketahui
keluar dari {i>sandbox<i} ke dalam {i>
execroot<i} dan menghapus {i>sandbox<i} tersebut. Hal ini mencegah
tindakan dari penggunaan file input apa pun yang tidak dideklarasikan dan dari
mengotori execroot dengan
file {i>output<i} yang tidak dikenal.
linux-sandbox
selangkah lebih maju dan melakukan pengembangan berdasarkan
processwrapper-sandbox
. Mirip dengan apa yang dilakukan Docker
di balik layar, Docker menggunakan
Namespace Linux (User, Mount, PID, Network and IPC namespaces) untuk mengisolasi
tindakan dari {i>host<i}. Artinya, itu membuat seluruh
sistem file menjadi hanya-baca kecuali
untuk direktori {i>sandbox<i}, sehingga tindakan itu tidak bisa
secara tidak sengaja memodifikasi apa pun di
sistem file {i>host<i}. Ini mencegah situasi seperti uji
bug secara tidak sengaja
{i>-rf'ing <i}direktori $HOME Anda. Atau, Anda juga dapat mencegah tindakan
yang mengakses jaringan. linux-sandbox
menggunakan namespace PID untuk mencegah tindakan
agar tidak melihat proses lain dan membunuh semua proses (bahkan {i>daemon<i})
yang dihasilkan oleh aksi) di akhir.
darwin-sandbox
juga serupa, tetapi untuk macOS. Proses ini menggunakan alat sandbox-exec
Apple
untuk mencapai hampir sama
dengan Linux {i>sandbox<i}.
linux-sandbox
dan darwin-sandbox
tidak berfungsi di file "bertingkat"
skenario karena pembatasan dalam
mekanisme yang disediakan oleh sistem
yang berbeda. Karena Docker juga menggunakan namespace Linux
untuk keajaiban container-nya,
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
yang sudah di-sandbox. Jadi, dalam kasus ini, Bazel
secara otomatis kembali menggunakan processwrapper-sandbox
.
Jika Anda lebih memilih untuk mendapatkan error build, misalnya tidak membuat build secara tidak sengaja dengan
strategi eksekusi yang kurang ketat — secara eksplisit memodifikasi daftar eksekusi
strategi yang coba digunakan Bazel (misalnya, bazel build
--spawn_strategy=worker,linux-sandbox
).
Eksekusi dinamis biasanya memerlukan sandbox untuk eksekusi lokal. Untuk memilih tidak menggunakan fitur ini,
teruskan flag --experimental_local_lockfree_output
. Eksekusi dinamis tanpa suara
sandbox pekerja persisten.
Kelemahan sandboxing
Sandboxing menimbulkan biaya penyiapan dan penguraian tambahan. Seberapa besar biayanya bergantung pada banyak faktor, termasuk bentuk bangunan dan performa OS host. Untuk Linux, build dengan sandbox jarang lebih dari beberapa persen lebih lambat. Menyetel
--reuse_sandbox_directories
dapat memitigasi biaya penyiapan dan pemutusan.Sandboxing secara efektif menonaktifkan cache apa pun yang mungkin dimiliki alat tersebut. Anda dapat memitigasinya dengan menggunakan pekerja persisten, dengan biaya jaminan sandbox yang lebih lemah.
Pekerja multipleks memerlukan dukungan pekerja eksplisit untuk di-sandbox. Pekerja yang tidak mendukung sandbox multipleks berjalan sebagai pekerja singleplex di bawah 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
melakukan ribuan panggilan sistem. Perhatikan bahwa I/O selanjutnya dalam execroot/
mungkin
lebih lambat karena overhead FUSE.
Instal sandboxf
Gunakan langkah-langkah berikut untuk menginstal sandboxfs
dan menjalankan build Bazel dengan
hal tersebut:
Download
Mendownload dan menginstal
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 melakukan ini setelah instalasi dan setelah setiap {i>reboot<i} untuk memastikan layanan sistem macOS inti bekerja 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 elemen
untuk tindakan yang dijalankan, ini dapat berarti bahwa {i>sandbox<i}
dinonaktifkan. Teruskan --genrule_strategy=sandboxed --spawn_strategy=sandboxed
ke
mengaktifkannya.
Proses Debug
Ikuti strategi di bawah untuk men-debug masalah terkait 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=1
Kegagalan eksekusi aturan
Sandbox mungkin gagal menjalankan aturan karena penyiapan sistem. Jika Anda melihat
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 membuatnya
Bazel menampilkan perintah yang tepat yang dijalankan ketika 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 {i>sandbox<i} yang dihasilkan dan melihat file mana yang membuat dan menjalankan perintah lagi untuk melihat bagaimana perilakunya.
Perhatikan bahwa Bazel tidak menghapus direktori {i>sandbox<i} saat Anda menggunakan
--sandbox_debug
. Kecuali Anda aktif melakukan proses debug, Anda harus menonaktifkan
--sandbox_debug
karena kapasitas disk Anda akan terisi penuh dari waktu ke waktu.