Rabu, 09 April 2025

Cara Membuat Server GPU Farm dengan Docker Rootless Mode dan Ubuntu

Docker telah menjadi alat yang sangat populer untuk mengelola container, memungkinkan pengembang dan administrator sistem untuk menjalankan aplikasi dalam lingkungan yang terisolasi dan portabel. Namun, keamanan tetap menjadi perhatian utama, terutama ketika daemon Docker berjalan dengan hak akses root. Untuk mengatasi masalah ini, Docker memperkenalkan rootless mode, sebuah fitur yang memungkinkan Docker daemon dan container berjalan tanpa hak akses root, sehingga mengurangi risiko kerentanan keamanan.

Dalam tutorial ini, kita akan membahas secara mendalam tentang rootless mode pada Docker, mulai dari pengertian, cara kerja, prasyarat, langkah-langkah instalasi, hingga praktik terbaik untuk menggunakannya. Artikel ini dirancang untuk membantu Anda memahami dan mengimplementasikan rootless mode dengan mudah, bahkan jika Anda baru mengenal Docker. Mari kita mulai!

Apa Itu Rootless Mode?

Rootless mode adalah fitur pada Docker yang memungkinkan daemon Docker dan container dijalankan sebagai pengguna non-root. Dalam mode ini, Anda tidak memerlukan hak akses root, baik saat menjalankan daemon maupun saat mengelola container. Dengan kata lain, rootless mode menawarkan lapisan keamanan tambahan dengan meminimalkan potensi kerentanan yang dapat dieksploitasi jika daemon Docker diretas.

Berbeda dengan mode tradisional (sering disebut "rootful"), di mana daemon Docker berjalan dengan hak akses root, rootless mode menjalankan seluruh proses dalam ruang pengguna (user namespace). Ini berarti bahkan jika terjadi pelanggaran keamanan, penyerang tidak akan mendapatkan akses root ke sistem host.

Mengapa Rootless Mode Penting?

Berikut adalah beberapa alasan mengapa rootless mode menjadi pilihan yang menarik:

  1. Keamanan yang Ditingkatkan: Dengan menghilangkan kebutuhan akan hak akses root, rootless mode mengurangi risiko eskalasi privilese jika terjadi kerentanan pada daemon atau container.
  2. Isolasi yang Lebih Baik: Rootless mode menggunakan user namespace untuk mengisolasi proses, memastikan bahwa container tidak memiliki akses langsung ke sumber daya sistem yang sensitif.
  3. Fleksibilitas untuk Pengguna Non-Root: Pengguna tanpa hak akses root, seperti pengembang di lingkungan bersama, dapat menjalankan Docker tanpa memerlukan izin khusus dari administrator sistem.
  4. Kesesuaian dengan Praktik Keamanan Modern: Banyak organisasi kini mengadopsi prinsip least privilege, dan rootless mode mendukung pendekatan ini dengan meminimalkan hak akses yang diperlukan.

Namun, rootless mode juga memiliki beberapa batasan, seperti dukungan terbatas untuk fitur tertentu (misalnya, AppArmor atau jaringan overlay). Kita akan membahas batasan ini secara lebih rinci di bagian selanjutnya.

Cara Kerja Rootless Mode

Untuk memahami cara kerja rootless mode, kita perlu menyelami konsep user namespace dan bagaimana Docker memanfaatkannya.

User Namespace

User namespace adalah fitur kernel Linux yang memungkinkan pemetaan ID pengguna (UID) dan ID grup (GID) di dalam namespace ke UID/GID yang berbeda di luar namespace. Dalam konteks rootless mode, Docker daemon dan container dijalankan di dalam user namespace, di mana UID 0 (biasanya root) di dalam namespace dipetakan ke UID non-root di sistem host.

Misalnya, jika pengguna bernama testuser memiliki UID 1001 di sistem host, maka proses di dalam user namespace akan melihat UID 0 sebagai "root" di dalam container, tetapi sebenarnya tetap berjalan sebagai UID 1001 di host. Ini memastikan bahwa proses tidak memiliki hak akses root yang sebenarnya di luar namespace.

Perbandingan dengan Userns-Remap Mode

Rootless mode sering dibandingkan dengan userns-remap mode, yang juga menggunakan user namespace. Namun, ada perbedaan mendasar:

  • Userns-Remap Mode: Daemon Docker tetap berjalan dengan hak akses root, tetapi container dijalankan dengan UID/GID yang dipetakan ke pengguna non-root. Ini berarti daemon masih memiliki potensi risiko keamanan jika diretas.
  • Rootless Mode: Baik daemon Docker maupun container dijalankan sebagai pengguna non-root. Tidak ada proses yang berjalan dengan hak akses root, sehingga risiko keamanan jauh lebih rendah.

Komponen Utama Rootless Mode

Rootless mode mengandalkan beberapa komponen untuk berfungsi dengan baik:

  1. RootlessKit: Alat yang digunakan untuk mengatur user namespace dan mengelola jaringan serta mount untuk container.
  2. newuidmap dan newgidmap: Utilitas yang diperlukan untuk memetakan beberapa UID/GID di dalam user namespace. Ini adalah satu-satunya komponen yang membutuhkan bit SETUID.
  3. Storage Driver: Rootless mode mendukung beberapa driver penyimpanan seperti overlay2, fuse-overlayfs, btrfs, dan vfs, dengan batasan tertentu tergantung pada versi kernel.
  4. Systemd (opsional): Untuk pengelolaan daemon yang lebih baik, rootless mode dapat diintegrasikan dengan systemd untuk menjalankan Docker sebagai layanan pengguna.

Batasan Rootless Mode

Meskipun rootless mode menawarkan banyak keuntungan, ada beberapa batasan yang perlu diperhatikan:

  • Driver Penyimpanan Terbatas: Hanya overlay2 (kernel 5.11+ atau kernel Ubuntu), fuse-overlayfs, btrfs, dan vfs yang didukung.
  • Fitur yang Tidak Didukung:
    • AppArmor
    • Checkpoint/restore
    • Jaringan overlay
    • Mengekspos port SCTP
    • Port TCP/UDP privilese (< 1024) tanpa konfigurasi tambahan
  • Cgroup: Pengelolaan sumber daya dengan cgroup hanya didukung pada sistem dengan cgroup v2 dan systemd.
  • NFS: Mount NFS sebagai direktori data Docker tidak didukung.

Kita akan membahas cara mengatasi beberapa batasan ini di bagian praktik terbaik.

Prasyarat untuk Menggunakan Rootless Mode

Sebelum menginstal dan menjalankan Docker dalam rootless mode, pastikan sistem Anda memenuhi prasyarat berikut:

1. Instalasi newuidmap dan newgidmap

Utilitas newuidmap dan newgidmap diperlukan untuk mengelola pemetaan UID/GID di dalam user namespace. Biasanya, kedua utilitas ini disediakan oleh paket uidmap di sebagian besar distribusi Linux.

Untuk menginstalnya di sistem berbasis Debian/Ubuntu, jalankan perintah berikut:

sudo apt-get update sudo apt-get install -y uidmap

Untuk memverifikasi instalasi, jalankan:

newuidmap --version newgidmap --version

Pastikan kedua perintah tersebut menghasilkan output yang menunjukkan versi yang terinstal.

2. Konfigurasi /etc/subuid dan /etc/subgid

File /etc/subuid dan /etc/subgid digunakan untuk menentukan rentang UID/GID bawahan (subordinate) yang dapat digunakan oleh pengguna dalam user namespace. Setiap pengguna harus memiliki setidaknya 65.536 UID/GID bawahan untuk menjalankan rootless mode dengan baik.

Untuk memeriksa konfigurasi pengguna saat ini (misalnya, pengguna bernama testuser dengan UID 1001), jalankan:

id -u whoami grep ^$(whoami): /etc/subuid grep ^$(whoami): /etc/subgid

Output yang diharapkan adalah seperti berikut:

1001 testuser testuser:231072:65536 testuser:231072:65536

Jika file /etc/subuid atau /etc/subgid belum dikonfigurasi, Anda dapat menambahkannya secara manual. Misalnya, untuk menambahkan rentang UID/GID untuk testuser, jalankan:

sudo usermod --add-subuids 231072-296607 --add-subgids 231072-296607 testuser

Kemudian, verifikasi kembali dengan perintah grep di atas.

3. Instalasi Paket dbus-user-session

Paket dbus-user-session diperlukan untuk mendukung komunikasi antarproses dalam lingkungan pengguna. Untuk menginstalnya di sistem berbasis Debian/Ubuntu, jalankan:

sudo apt-get install -y dbus-user-session

Setelah instalasi, Anda mungkin perlu login ulang agar perubahan diterapkan. Jalankan:

exit

Lalu masuk kembali ke sesi pengguna Anda.

4. Instalasi Paket systemd-container (Opsional)

Jika Anda menjalankan Docker dari terminal di mana pengguna tidak login langsung (misalnya, melalui su atau sudo), Anda perlu menginstal paket systemd-container untuk mendukung manajemen sesi pengguna. Jalankan:

sudo apt-get install -y systemd-container

Kemudian, beralih ke pengguna target dengan perintah:

sudo machinectl shell testuser@

Ganti testuser dengan nama pengguna Anda.

5. Dukungan Storage Driver

Rootless mode mendukung beberapa driver penyimpanan, tetapi yang paling umum adalah overlay2. Pada sistem Ubuntu, overlay2 diaktifkan secara default berkat patch kernel khusus Ubuntu. Pastikan kernel Anda mendukung driver yang diperlukan:

  • overlay2: Memerlukan kernel 5.11 atau lebih baru, atau kernel Ubuntu.
  • fuse-overlayfs: Memerlukan kernel 4.18 atau lebih baru dan paket fuse-overlayfs terinstal.
  • btrfs: Memerlukan kernel 4.18 atau lebih baru, dan direktori data Docker harus memiliki opsi mount user_subvol_rm_allowed.
  • vfs: Selalu didukung, tetapi kinerjanya lebih lambat dibandingkan driver lain.

Untuk memeriksa versi kernel Anda, jalankan:

uname -r

Jika Anda menggunakan fuse-overlayfs, instal paketnya dengan:

sudo apt-get install -y fuse-overlayfs

6. Konfigurasi AppArmor (Jika Diperlukan)

Pada Ubuntu 24.04 dan versi yang lebih baru, user namespace tanpa privilese dibatasi secara default oleh AppArmor. Jika Anda menginstal docker-ce-rootless-extras melalui paket DEB (misalnya, dengan apt-get), profil AppArmor untuk rootlesskit sudah disertakan, sehingga tidak perlu konfigurasi tambahan.

Namun, jika Anda menginstal rootless mode menggunakan skrip instalasi manual, Anda perlu menambahkan profil AppArmor secara manual. Berikut langkah-langkahnya:

  1. Buat file profil AppArmor untuk rootlesskit:
filename=$(echo $HOME/bin/rootlesskit | sed -e s@^/@@ -e s@/@.@g) cat <<EOF > ~/${filename} abi <abi/4.0>, include <tunables/global> "$HOME/bin/rootlesskit" flags=(unconfined) { userns, include if exists <local/${filename}> } EOF
  1. Pindahkan file ke direktori AppArmor:
sudo mv ~/${filename} /etc/apparmor.d/${filename}
  1. Restart layanan AppArmor:
sudo systemctl restart apparmor.service

7. Nonaktifkan Daemon Docker Rootful (Opsional)

Jika sistem Anda sudah menjalankan daemon Docker dalam mode rootful (berjalan dengan hak akses root), sebaiknya nonaktifkan terlebih dahulu untuk menghindari konflik. Jalankan:

sudo systemctl disable --now docker.service docker.socket sudo rm /var/run/docker.sock

Jika Anda memilih untuk tidak menonaktifkan daemon rootful, Anda dapat menggunakan parameter --force saat menginstal rootless mode, tetapi ini tidak disarankan untuk produksi.

Instalasi Rootless Mode

Setelah memenuhi prasyarat, Anda siap untuk menginstal Docker dalam rootless mode. Ada dua metode utama: menggunakan paket RPM/DEB atau tanpa paket. Kami akan fokus pada metode dengan paket, karena ini adalah pendekatan yang paling umum dan didukung.

Langkah 1: Instal Paket docker-ce-rootless-extras

Jika Anda menggunakan Docker 20.10 atau versi lebih baru yang diinstal melalui paket RPM/DEB, Anda seharusnya sudah memiliki skrip dockerd-rootless-setuptool.sh di /usr/bin. Jika tidak, instal paket docker-ce-rootless-extras secara manual:

sudo apt-get install -y docker-ce-rootless-extras

Verifikasi keberadaan skrip:

which dockerd-rootless-setuptool.sh

Output yang diharapkan adalah:

/usr/bin/dockerd-rootless-setuptool.sh

Langkah 2: Jalankan Skrip Instalasi

Jalankan skrip dockerd-rootless-setuptool.sh sebagai pengguna non-root untuk mengatur daemon Docker:

dockerd-rootless-setuptool.sh install

Skrip ini akan melakukan beberapa tugas, termasuk:

  • Membuat file layanan systemd di ~/.config/systemd/user/docker.service.
  • Mengatur variabel lingkungan seperti PATH dan DOCKER_HOST.
  • Menampilkan instruksi untuk mengelola layanan Docker.

Output yang diharapkan akan terlihat seperti ini:

[INFO] Creating /home/testuser/.config/systemd/user/docker.service ... [INFO] Installed docker.service successfully. [INFO] To control docker.service, run: `systemctl --user (start|stop|restart) docker.service` [INFO] To run docker.service on system startup, run: `sudo loginctl enable-linger testuser` [INFO] Make sure the following environment variables are set (or add them to ~/.bashrc): export PATH=/usr/bin:$PATH export DOCKER_HOST=unix:///run/user/1000/docker.sock

Langkah 3: Atur Variabel Lingkungan

Tambahkan variabel lingkungan yang disarankan ke file ~/.bashrc agar tetap berlaku di setiap sesi:

echo 'export PATH=/usr/bin:$PATH' >> ~/.bashrc echo 'export DOCKER_HOST=unix:///run/user/1000/docker.sock' >> ~/.bashrc source ~/.bashrc

Ganti /run/user/1000 dengan direktori yang sesuai dengan UID Anda (misalnya, /run/user/1001 untuk UID 1001).

Langkah 4: Aktifkan Layanan Docker

Untuk memastikan daemon Docker berjalan otomatis saat login, aktifkan layanan systemd dan enable lingering untuk pengguna Anda:

systemctl --user enable docker sudo loginctl enable-linger $(whoami)

Langkah 5: Verifikasi Instalasi

Jalankan daemon Docker:

systemctl --user start docker

Periksa statusnya:

systemctl --user status docker

Jika semuanya berjalan dengan baik, Anda akan melihat output yang menunjukkan bahwa layanan sedang aktif (running).

Uji instalasi dengan menjalankan container sederhana:

docker run hello-world

Jika container berjalan dan menampilkan pesan "Hello from Docker!", maka rootless mode telah berhasil diinstal.

Mengelola Daemon Docker dalam Rootless Mode

Setelah instalasi selesai, Anda dapat mengelola daemon Docker menggunakan perintah systemctl --user. Berikut adalah beberapa perintah umum:

  • Memulai daemon:
systemctl --user start docker
  • Menghentikan daemon:
systemctl --user stop docker
  • Merestart daemon:
systemctl --user restart docker
  • Memeriksa status daemon:
systemctl --user status docker

Catatan tentang Direktori

Dalam rootless mode, beberapa direktori default berbeda dari mode rootful:

  • Socket: $XDG_RUNTIME_DIR/docker.sock (biasanya /run/user/$UID/docker.sock).
  • Direktori Data: ~/.local/share/docker.
  • Direktori Konfigurasi Daemon: ~/.config/docker (bukan ~/.docker seperti pada klien).

Pastikan direktori data tidak berada di mount NFS, karena ini tidak didukung.

Praktik Terbaik untuk Rootless Mode

Untuk memaksimalkan manfaat rootless mode, ikuti praktik terbaik berikut:

1. Gunakan Systemd untuk Mengelola Daemon

Menggunakan systemd untuk mengelola daemon Docker adalah pendekatan yang sangat direkomendasikan, karena memudahkan manajemen siklus hidup daemon. Pastikan Anda telah mengaktifkan layanan dan lingering seperti dijelaskan di atas.

2. Hindari Menjalankan Rootless Docker sebagai Layanan Sistem

Menjalankan daemon Docker dalam rootless mode sebagai layanan sistem (/etc/systemd/system/docker.service) tidak didukung, bahkan dengan direktif User=. Selalu gunakan layanan pengguna (~/.config/systemd/user/docker.service).

3. Gunakan Image Khusus untuk Docker-in-Docker

Jika Anda perlu menjalankan Docker di dalam container (Docker-in-Docker) dalam rootless mode, gunakan image docker:<version>-dind-rootless alih-alih docker:<version>-dind. Contoh:

docker run -d --name dind-rootless --privileged docker:25.0-dind-rootless

Catatan: Opsi --privileged diperlukan untuk menonaktifkan seccomp, AppArmor, dan masker mount, tetapi container tetap berjalan sebagai pengguna non-root (UID 1000).

4. Batasi Sumber Daya tanpa Cgroup

Jika cgroup v2 tidak tersedia, Anda dapat menggunakan alat tradisional seperti ulimit dan cpulimit untuk membatasi sumber daya. Contoh:

  • Batasi penggunaan CPU (setara dengan docker run --cpus 0.5):
docker run <IMAGE> cpulimit --limit=50 --include-children <COMMAND>
  • Batasi memori (setara dengan docker run --memory 64m):
docker run <IMAGE> sh -c "ulimit -v 65536; <COMMAND>"
  • Batasi jumlah proses (setara dengan docker run --pids-limit=100):
docker run --user 2000 --ulimit nproc=100 <IMAGE> <COMMAND>

5. Aktifkan Cgroup v2 untuk Pengelolaan Sumber Daya

Untuk mendukung fitur seperti --cpus, --memory, dan --pids-limit, pastikan sistem Anda menggunakan cgroup v2 dan driver cgroup diatur ke systemd. Periksa driver cgroup dengan:

docker info --format '{{.CgroupDriver}}'

Jika outputnya adalah none, Anda perlu mengaktifkan cgroup v2. Tambahkan parameter kernel systemd.unified_cgroup_hierarchy=1 ke konfigurasi bootloader Anda (misalnya, GRUB), lalu reboot sistem.

Untuk memungkinkan delegasi semua pengontrol cgroup (cpu, cpuset, io, memory, pids), buat file konfigurasi systemd:

sudo mkdir -p /etc/systemd/system/user@.service.d cat > /etc/systemd/system/user@.service.d/delegate.conf << EOF [Service] Delegate=cpu cpuset io memory pids EOF sudo systemctl daemon-reload

6. Integrasi dengan GPU (NVIDIA)

Jika Anda menggunakan GPU NVIDIA, Anda dapat mengaktifkan dukungan GPU dalam rootless mode dengan konfigurasi tambahan.

Langkah 1: Edit Konfigurasi NVIDIA Container Runtime

Edit file /etc/nvidia-container-runtime/config.toml dan tambahkan baris berikut di bawah bagian [nvidia-container-cli]:

no-cgroups = true

Ini memungkinkan runtime NVIDIA berjalan tanpa cgroup, yang diperlukan untuk rootless mode.

Langkah 2: Konfigurasi Daemon Docker

Edit file /etc/docker/daemon.json untuk menambahkan runtime NVIDIA sebagai default:

{ "runtimes": { "nvidia": { "path": "nvidia-container-runtime", "runtimeArgs": [] } }, "default-runtime": "nvidia", "node-generic-resources": [ "NVIDIA-GPU=GPU-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "NVIDIA-GPU=GPU-yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy" ] }

Ganti ID GPU xxxxx dan yyyyy dengan ID yang sesuai untuk sistem Anda. Anda dapat menemukan ID GPU dengan menjalankan:

nvidia-smi -L

Langkah 3: Restart Daemon Docker

Restart daemon Docker untuk menerapkan perubahan:

systemctl --user restart docker

Langkah 4: Uji Dukungan GPU

Jalankan container dengan akses GPU untuk menguji konfigurasi:

docker run --gpus all nvidia/cuda:12.6.3-cudnn-devel-ubuntu22.04 nvidia-smi

Jika konfigurasi berhasil, Anda akan melihat output dari nvidia-smi yang menunjukkan informasi GPU.

Mengatasi Masalah Umum

Berikut adalah beberapa masalah umum yang mungkin Anda temui saat menggunakan rootless mode dan cara mengatasinya:

1. Error: "cannot setup user namespace"

Ini biasanya disebabkan oleh konfigurasi /etc/subuid atau /etc/subgid yang salah. Pastikan pengguna Anda memiliki rentang UID/GID bawahan yang cukup (minimal 65.536). Periksa dengan:

grep ^$(whoami): /etc/subuid grep ^$(whoami): /etc/subgid

Jika tidak ada entri, tambahkan rentang UID/GID seperti dijelaskan di bagian prasyarat.

2. Error: "AppArmor denies user namespace creation"

Jika Anda menggunakan Ubuntu 24.04 atau lebih baru, pastikan profil AppArmor untuk rootlesskit telah dikonfigurasi. Ikuti langkah-langkah di bagian prasyarat untuk membuat dan menginstal profil AppArmor.

3. Container Tidak Dapat Mengakses Port Privileged (< 1024)

Rootless mode tidak mendukung pengikatan port di bawah 1024 secara langsung. Untuk mengatasi ini, gunakan alat seperti slirp4netns untuk mengelola jaringan atau ubah port aplikasi ke port non-privilese (misalnya, 8080).

4. Performa Lambat dengan Storage Driver vfs

Driver vfs memiliki performa yang lebih lambat dibandingkan overlay2 atau fuse-overlayfs. Jika memungkinkan, gunakan overlay2 (memerlukan kernel yang mendukung) atau instal fuse-overlayfs untuk performa yang lebih baik.

Kesimpulan

Rootless mode pada Docker adalah langkah besar menuju keamanan yang lebih baik dalam pengelolaan container. Dengan menjalankan daemon dan container sebagai pengguna non-root, Anda dapat mengurangi risiko kerentanan keamanan tanpa mengorbankan fungsionalitas inti Docker. Meskipun ada beberapa batasan, seperti dukungan terbatas untuk fitur tertentu, rootless mode tetap menjadi pilihan yang sangat baik untuk lingkungan yang mengutamakan keamanan.

Dalam tutorial ini, kita telah membahas:

  • Apa itu rootless mode dan mengapa penting.
  • Cara kerja rootless mode menggunakan user namespace.
  • Prasyarat dan langkah-langkah instalasi.
  • Cara mengelola daemon Docker dalam rootless mode.
  • Praktik terbaik untuk penggunaan yang optimal.
  • Konfigurasi tambahan untuk mendukung GPU.
  • Cara mengatasi masalah umum.

Dengan mengikuti panduan ini, Anda seharusnya dapat menginstal dan menjalankan Docker dalam rootless mode dengan percaya diri. Jika Anda memiliki pertanyaan atau menemui masalah, jangan ragu untuk bergabung dengan komunitas Docker atau mencari bantuan di forum seperti Stack Overflow.

Sekarang, saatnya untuk mencoba rootless mode di sistem Anda sendiri! Bagikan pengalaman Anda atau ajukan pertanyaan di kolom komentar di bawah. Selamat mengontainerisasi dengan aman!

0 komentar:

Posting Komentar