Sandboxing

Laporkan masalah Lihat sumber Per Malam · 7,4 kami. 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Artikel ini membahas sandboxing di Bazel, menginstal sandboxfs, dan men-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.

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 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 di 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 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 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} kemungkinan juga dapat berfungsi dengan eksekusi jarak jauh. Dengan membuat eksekusi jarak jauh mengupload semua file yang diperlukan (termasuk alat lokal), Anda dapat secara signifikan mengurangi biaya pemeliharaan untuk cluster kompilasi 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 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 execroot, kemudian memindahkan artefak output 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 tersebut mengakses jaringan. linux-sandbox menggunakan namespace PID untuk mencegah tindakan melihat proses lain dan untuk menghentikan semua proses (bahkan daemon yang dihasilkan oleh tindakan) dengan andal di bagian akhir.

darwin-sandbox mirip, 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 penampungnya, Anda tidak dapat menjalankan linux-sandbox dengan mudah di dalam penampung 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 — seperti agar tidak sengaja mem-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 menggunakan fitur ini, teruskan flag --experimental_local_lockfree_output. Eksekusi dinamis secara diam-diam menyandingkan pekerja persisten.

Kekurangan sandbox

  • Sandboxing menimbulkan biaya penyiapan dan pembongkaran 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 memitigasi biaya penyiapan dan pembongkaran.

  • Sandboxing secara efektif menonaktifkan cache apa pun yang mungkin dimiliki alat. 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 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 membuat execroot/ secara instan untuk setiap tindakan, sehingga menghindari biaya yang dikeluarkan untuk mengeluarkan ribuan panggilan sistem. Perhatikan bahwa I/O lebih lanjut dalam execroot/ mungkin lebih lambat karena overhead FUSE.

Instal sandboxf

Gunakan langkah-langkah berikut untuk menginstal sandboxfs dan melakukan build Bazel dengan sandboxfs:

Download

Mendownload dan menginstal sandboxfs sehingga biner sandboxfs berakhir di PATH.

Jalankan sandboxfs

  1. (khusus macOS) Instal OSXFUSE.
  2. (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.

  3. 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 dijalankan, hal ini mungkin berarti sandboxing dinonaktifkan. Teruskan --genrule_strategy=sandboxed --spawn_strategy=sandboxed ke mengaktifkannya.

Proses Debug

Ikuti strategi di bawah untuk men-debug masalah terkait sandboxing.

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 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 persis yang dijalankan 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 {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 sandbox 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.