Mengatasi Container Enrichment Yang Tidak Bekerja Di Tracee
Container enrichment adalah fitur di Tracee yang menambahkan informasi container pada log deteksi yang dihasilkan. Tanpa container enrichment, nilai containerId
, container
dan kubernetes
di log JSON akan kosong. Ini akan mempersulit melakukan respon karena mesin yang sama bisa menjalankan banyak container sekaligus. Salah satu permasalahan yang sering saya hadapi adalah container enrichment kadang tidak bekerja sebagaimana seharusnya. Apa yang bisa saya lakukan untuk melakukan troubleshooting permasalahan seperti ini?
Untuk mendapatkan informasi untuk sebuah container, Tracee akan memanggil container runtime yang dipakai. Secara resmi, Tracee mendukung container runtime seperti Docker, Containerd, CRI-O dan Podman. Tracee akan berusaha mendeteksi apakah container runtime tersebut tersedia berdasarkan file socket yang di-bind ke /var/run
di container-nya Tracee. Berikut ini adalah daftar file socket yang dipakai untuk memanggil API container runtime:
/var/run/docker.sock
untuk Docker/var/run/containerd/containerd.sock
untuk containerd/var/run/crio/crio.sock
untuk CRI-O/var/run/podman/podman.sock
untuk Podman
Oleh sebab itu, langkah pertama yang perlu saya lakukan adalah memastikan bahwa baris seperti berikut ini ada di definisi Pod milik Tracee:
Agar lebih yakin, saya juga dapat masuk ke dalam Pod dan menggunakan perintah seperti berikut ini untuk melihat apakah file socket telah di-mount secara benar:
Berikutnya, aya akan mengaktifkan log level debug dengan menambahkan baris berikut ini pada file konfigurasi Tracee:
Setelah membuat ulang Pod Tracee, saya dapat memberikan perintah berikut ini untuk melihat apakah ada kesalahan dalam proses registrasi container enricher:
Tracee akan berusaha melakukan registrasi seluruh container runtime yang didukung olehnya. Namun, biasanya cluster Kubernetes hanya menggunakan satu container runtime saja. Dengan demikian, wajar bila saya menemukan pesan kesalahan seperti error registering enricher: unsupported runtime crio
selama itu bukan container runtime yang dipakai. Sebagai contoh, pada output di atas, karena saya menggunakan Docker, hasilnya adalah 3 pesan kesalahan untuk container runtime lain yang tidak saya pakai.
Bagaimana bila saya menemukan pesan kesalahan pada container runtime yang saya pakai? Ini berarti Tracee gagal menemukan file socket untuk berkomunikasi dengan container runtime tersebut. Saya perlu memastikan kembali bahwa file socket telah di-mount dengan benar. Selain itu, pada konfigurasi tertentu di Minikube, saya menemukan bahwa file socket berupa folder kosong (bukan file). Bila ini yang terjadi, saya dapat membuat ulang cluster dengan minikube delete dan minikube start.
Bila semuanya sudah benar sampai disini, apa kemungkinan lainnya yang menyebabkan container enrichment tidak bekerja? Sebagai contoh, saya menjalankan Tracee yang di-install lewat Helm di Minikube. Secara default, Minikube akan menggunakan Docker untuk mensimulasikan node Kubernetes. Ini juga mempermudah saya memindahkan image dari host ke dalam Minikube tanpa harus memakai registry tersendiri. Namun, saya menemukan bahwa container enrichment Tracee tidak bekerja pada instalasi default tersebut. Apa yang harus saya lakukan?
Tracee membaca daftar container yang sedang berjalan dengan menganalisa cgroup (v1 dan v2 didukung). cgroup adalah fitur kernel bawaan Linux untuk membatasi penggunaan resources (seperti CPU, memory, I/O, dan sebagainya) untuk satu atau lebih proses yang ditelah ditentukan. Bersamaan dengan fitur namespace isolation, cgroup merupakan fitur kernel Linux yang paling umum dipakai untuk mengimplementasikan container.
Aplikasi dapat berinteraksi dengan cgroup dengan membaca dan menulis ke file di cgroupfs. cgroupfs adalah virtual file system yang biasanya ada di lokasi /sys/fs/cgroup/
yang berisi file konfigurasi cgroup. Untuk memastikan cgroupfs tersedia, Tracee akan membaca file /proc/filesystems
dan memastikan bahwa terdapat baris seperti cgroup2
di file tersebut. Bila cgroupfs tersedia, Tracee akan mencari lokasi-nya dengan membaca file /proc/self/mountinfo
dan mencari file system cgroup2
. Bila cgroupfs tidak tersedia, Tracee akan men-mount cgroupfs di temporary folder.
Salah satu permasalahan yang saya jumpai disini adalah pada container Docker, cgroupfs-nya berbeda dari yang dimiliki oleh host. Sebagai contoh, pada perintah berikut ini, saya membandingkan jumlah files yang ada di /sys/fs/cgroup
dilihat dari mesin host dengan yang dilihat dari dalam container:
Terlihat bahwa folder /sys/fs/cgroup
di dalam container memiliki isi yang berbeda (lebih sedikit) dibandingkan dengan folder /sys/fs/cgroup
di mesin host. Bila ini adalah kasus yang terjadi, Tracee akan memberikan pesan warning seperti berikut ini:
Agar cgroupfs di dalam container sama dengan di host, saya dapat menambahkan argumen --cgroupns=host
saat menjalankan container Docker dengan perintah seperti berikut ini:
Namun, saya tidak menemukan cara untuk menerapkan --cgroupns=host
di Kubernetes sehingga sebagai alternatif, saya akan men-mount /sys/fs/cgroup
dari host ke dalam Pod-nya Tracee dengan menambahkan baris seperti berikut ini pada manifest Tracee:
Dengan konfigurasi di atas, Tracee dapat mengakses cgroupfs milik host di /host/sys/fs/cgroup
. Namun, kode program Tracee tetap akan berusaha men-mount cgroupfs sendiri bila folder tersebut tidak terdaftar sebagai cgroup2 mount di /proc/filesystems
. Saya tidak menemukan cara yang lebih mudah selain melakukan modifikasi kode program Tracee. Sebagai contoh, saya akan menambahkan sebuah function baru di pkg/mount/mount.go
dengan nama UseHostPath()
yang isinya seperti berikut ini:
Setelah itu, saya akan menggunakan function ini di pkg/cgroup/cgroup.go
di method CgroupV2.init()
yang saya modifikasi menjadi seperti berikut ini:
Setelah menggunakan kode program di atas, container enrichment akan bekerja dengan seharusnya karena ia akan membaca file /host/sys/fs/cgroup
dari host yang berisi informasi seluruh container yang berjalan di host tersebut.