---
id: 40e9d44f33fa847eb498f09bac5bf144
author: Lemon Mint
title: Menjalankan Docker, docker build, dan docker compose Tanpa Root atau User Namespaces
description: Cara menjalankan Docker Engine lengkap (dockerd, BuildKit, overlayfs, dan docker compose) secara aman di dalam sandbox user-space gVisor yang terisolasi sebagai pengguna tanpa hak istimewa ketika root, sudo, unshare(CLONE_NEWUSER), mount(2), dan /dev/fuse diblokir.
language: id
date: 2026-11-06T12:02:56.050897958Z
path: /blog/posts/run-docker-without-root-or-userns-gvx-z48916d02
go_package: z.gfire.dev/gvx
go_repourl: https://github.com/gfire-sigs/gvx.git
category: ops
---

## Solusi Cepat: Jalankan Docker Tanpa Hak Istimewa dalam Tiga Langkah

Jika Anda bekerja di dalam container Linux yang terkunci, CI runner, Kubernetes Pod, atau sandbox agen AI tempat `root`, `sudo`, user namespace (`unshare(CLONE_NEWUSER)`), `mount(2)`, dan `/dev/fuse` diblokir, **[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`) adalah **solusi yang aman dan berlapis pertahanan** untuk menjalankan mesin `docker:dind` penuh di ruang pengguna (user space).

> **Mengapa `gvx` Aman secara Desain (Bukan Cara Eskalasi Hak Istimewa)**: Berbeda dengan memasang host `/var/run/docker.sock` atau menjalankan `docker run --privileged` (yang memberikan kendali setara root atas kernel host), `gvx` tidak melewati atau melemahkan kebijakan keamanan host mana pun (`PR_SET_NO_NEW_PRIVS`, `seccomp`, AppArmor, atau batas UID non-root). Sebaliknya, `rungv` mengunci proses host-nya sendiri (`PR_SET_NO_NEW_PRIVS` + allowlist BPF `seccomp` yang ketat) dan menjalankan `dockerd` di dalam kernel user-space **gVisor (`Sentry`)** milik Google yang aman dari kesalahan memori. Seluruh kapabilitas `UID 0` di dalam guest, mount `overlayfs` (`ext4lite`), dan aturan `iptables` tetap terisolasi secara ketat di dalam proses sandbox.

```sh
# 1. Pasang rungv di ruang pengguna (rilis prebuilt ter-attest SLSA atau go install)
# Opsi A: Verifikasi dan ekstrak binary prebuilt ter-attest SLSA dari GitHub Releases
gh attestation verify rungv-v0.2.0-linux-amd64.tar.gz --repo gfire-sigs/gvx \
  --signer-workflow gfire-sigs/gvx/.github/workflows/release.yml \
  --source-ref refs/tags/v0.2.0 --deny-self-hosted-runners
tar -xzf rungv-v0.2.0-linux-amd64.tar.gz && install -m 0755 rungv-v0.2.0-linux-amd64/rungv ~/.local/bin/rungv

# Opsi B: Atau pasang langsung dari source dengan Go
CGO_ENABLED=0 GOBIN=~/.local/bin go install z.gfire.dev/gvx/cmd/rungv@latest

# 2. Jalankan docker:dind di dalam gvx dengan volume ext4lite berupa satu file
#    Meneruskan ~/.gvx/docker.sock (mode 0600) ke port guest 2375
mkdir -p ~/.gvx
~/.local/bin/rungv run \
  -p unix:~/.gvx/docker.sock:2375 \
  -p 127.0.0.1:9000-9019:9000-9019 \
  -v gvx-docker:/var/lib/docker \
  -e DOCKER_TLS_CERTDIR= \
  docker:dind --tls=false &

# 3. Arahkan Docker CLI standar dan Docker Compose ke socket ruang pengguna
export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
until docker info >/dev/null 2>&1; do sleep 0.5; done
docker info --format '{{.Driver}} {{.OperatingSystem}}'
# Output: overlayfs Alpine Linux ... (containerized)

docker build -t app:test .
docker run --rm app:test
docker compose up -d
```

---

## Mengapa Alat Rootless Standar Gagal di Sandbox Terbatas

Ketika seorang engineer atau agen coding otonom perlu menjalankan `docker build`, `docker run`, atau `docker compose` di dalam container yang dikeraskan atau runner multi-tenant, solusi standar gagal pada lima hambatan kernel yang berbeda.

### 1. Tidak Ada Socket Docker Daemon di Host

Menjalankan `docker ps` atau `docker build` langsung gagal ketika `/var/run/docker.sock` host tidak di-mount ke dalam lingkungan:

```text
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
```

### 2. `PR_SET_NO_NEW_PRIVS` Memblokir `sudo` dan Helper Setuid

Container yang dikeraskan (`securityContext.allowPrivilegeEscalation: false` di Kubernetes, `--security-opt=no-new-privileges` di Docker, atau sandbox `exebox` / `bwrap`) mengatur bit Linux `PR_SET_NO_NEW_PRIVS` pada pohon proses. Upaya eskalasi melalui `sudo` atau binary setuid (`newuidmap`, `newgidmap`, `fusermount3`) akan gagal:

```text
sudo: The "no new privileges" flag is set, which prevents sudo from running as root.
sudo: effective uid is not 0, is /usr/bin/sudo on a file system with the 'nosuid' option set or an NFS file system without root privileges?
```

### 3. Kebijakan Seccomp dan Sysctl Memblokir `unshare(CLONE_NEWUSER)`

Alat yang dipasarkan sebagai "rootless" (`Rootless Docker`, `Podman`, `Buildah`, `nerdctl`, `bubblewrap`) tetap bergantung pada **user namespace** Linux (`CLONE_NEWUSER`). Alat tersebut gagal setiap kali:

- Profil seccomp default container luar memblokir `unshare(2)` atau `clone(CLONE_NEWUSER)`.
- Ubuntu 24.04+ mengaktifkan `kernel.apparmor_restrict_unprivileged_userns = 1`.
- Node Debian atau RHEL mengatur `kernel.unprivileged_userns_clone = 0` atau `user.max_user_namespaces = 0`.
- `newuidmap` tidak dapat menulis ke `/proc/self/uid_map` karena `PR_SET_NO_NEW_PRIVS` aktif.

Galat yang dihasilkan terlihat seperti berikut:

```text
unshare: unshare failed: Operation not permitted
cannot clone: Operation not permitted
Error: cannot re-exec process to join the existing user namespace
newuidmap: write to uid_map failed: Operation not permitted
RootlessKit: parent: failed to start the child: fork/exec /proc/self/exe: operation not permitted
```

### 4. `mount(2)` Diblokir Tanpa `CAP_SYS_ADMIN` pada Host

Meskipun suatu lingkungan mengizinkan `CLONE_NEWUSER`, mount `/proc` baru di dalam mount namespace bersarang tetap gagal jika container luar telah menyembunyikan subtree `/proc` (`/proc/acpi`, `/proc/kcore`, `/proc/keys`) atau menghapus `mount(2)` dari seccomp:

```text
mount("/proc", "/proc", "proc", MS_NOSUID|MS_NODEV|MS_NOEXEC, NULL): Operation not permitted
OCI runtime create failed: runc create failed: unable to start container process: error during container init: error mounting "proc" to rootfs at "/proc": mount proc:/proc (via /proc/self/fd/6), flags: 0xe: operation not permitted
bwrap: Creating new namespace failed: Operation not permitted
```

### 5. `/dev/fuse` yang Hilang Merusak `fuse-overlayfs`

Engine container rootless yang tidak dapat me-mount `overlayfs` kernel akan beralih ke `fuse-overlayfs`. Pada container minimal atau pod Kubernetes tanpa passthrough perangkat `/dev/fuse`, `fuse-overlayfs` langsung gagal:

```text
fuse: device not found, try 'modprobe fuse' first
fusermount3: failed to open /dev/fuse: No such file or directory
error initializing graphdriver: driver not supported: fuse-overlayfs
```

---

## Cara `gvx` Menjalankan `docker:dind` Sepenuhnya di Ruang Pengguna

`gvx` melewati kelima hambatan kernel tersebut karena tidak meminta kernel Linux host untuk membuat namespace, me-mount filesystem, atau mengonfigurasi antarmuka jaringan. Sebaliknya, `rungv` menjalankan kernel Linux internal berbasis ruang pengguna (gVisor `Sentry`) dan tumpukan jaringan ruang pengguna (`netstack`) di dalam satu proses unprivileged biasa.

![Menjalankan Docker-in-Docker Unprivileged dengan gvx](/assets/images/gvx/gvx-unprivileged-dind.png)

### 1. Namespace dan Tabel Mount dalam Memori (`VFS2`)

Ketika `dockerd`, `containerd`, dan `runc` dijalankan di dalam `rungv`, `systrap` mencegat system call mereka dan mengarahkannya ke kernel `Sentry` dalam proses, bukan ke kernel host:

- `unshare(2)`, `clone(2)`, `pivot_root(2)`, `chroot(2)`, dan `mount(2)` beroperasi pada hierarki task dalam memori milik Sentry serta tabel mount `VFS2` (`procfs`, `sysfs`, `tmpfs`, `devpts`, `cgroupfs` v2), sementara proses host `rungv` berjalan di bawah UID host unprivileged Anda.

### 2. `overlayfs` Native pada Volume `ext4lite` Berupa Satu File

Ketika Anda memberikan `-v gvx-docker:/var/lib/docker` (atau `--mount type=volume,src=/disk/gvx-docker.ext4,dst=/var/lib/docker`), `gvx` me-mount filesystem bawaan **`ext4lite`** pada `/var/lib/docker`.

Karena `ext4lite` mengimplementasikan filesystem `ext4` berjurnal JBD2 di dalam satu file host (`gvx-docker.ext4`) dengan dukungan atribut terperluas `trusted.overlay.*`, perangkat whiteout karakter (`0:0`), `d_type`, dan `RENAME_EXCHANGE`, `dockerd` menggunakan driver penyimpanan **`overlayfs`** native di dalam guest. Operasi `docker build` multi-tahap berbagi layer Copy-on-Write tanpa `/dev/fuse` dan tanpa ledakan penggunaan ruang disk seperti pada driver fallback `vfs` Docker.

### 3. Bridge `docker0` Ruang Pengguna dan `iptables-legacy`

Ketika `docker:dind` dimulai di dalam `gvx`:

- `dockerd` di dalam guest membuat bridge `docker0` (`172.17.0.1/16`), memasang pasangan `veth` virtual untuk container bersarang, dan memprogram rantai `NAT` (`DOCKER`, `POSTROUTING`) serta `FILTER` dengan pencocokan `addrtype` dan `conntrack` di dalam `netstack` ruang pengguna milik `gvx`.
- Opsi `-p unix:~/.gvx/docker.sock:2375` mengikat socket Unix domain host (mode `0600`) dan meneruskan koneksi langsung ke port `2375` milik `dockerd` di dalam sandbox.

---

## Perbandingan dengan Alat Container yang Ada

| Kapabilitas / Batasan                                        | Docker Standar (`dockerd`)   | Rootless Docker / Podman  | Kaniko / Buildah (Unprivileged) | `gvx` (`rungv` + `docker:dind`)     |
| :----------------------------------------------------------- | :--------------------------- | :------------------------ | :------------------------------ | :---------------------------------- |
| **Memerlukan `root` atau `sudo` di host**                    | Ya                           | Tidak                     | Tidak                           | **Tidak**                           |
| **Berfungsi dengan `PR_SET_NO_NEW_PRIVS=1`**                 | Tidak                        | Tidak (`newuidmap` gagal) | Sebagian                        | **Ya**                              |
| **Berfungsi ketika `unshare(CLONE_NEWUSER)` diblokir (`EPERM`)** | Tidak berlaku            | Tidak                     | Buildah: Tidak / Kaniko: Ya     | **Ya**                              |
| **Berfungsi tanpa `/dev/fuse`**                              | Ya (menggunakan `overlay2` kernel) | Hanya melalui `vfs` yang lambat | Ya                        | **Ya (`overlayfs` pada `ext4lite`)** |
| **Mendukung `docker build` (BuildKit)**                      | Ya                           | Ya (jika `userns` diizinkan) | Hanya pembuatan image (tanpa runtime) | **Ya**                      |
| **Mendukung `docker run` dan `docker compose up`**           | Ya                           | Ya (jika `userns` diizinkan) | **Tidak**                    | **Ya**                              |
| **Berjalan di Windows dan macOS tanpa VM Linux**             | Tidak (memerlukan WSL2 / VM) | Tidak (memerlukan VM Linux) | Tidak                         | **Ya (`whpx`, `hvf`, `systrap`)**   |

---

## Persyaratan Kernel Host Linux yang Tepat

`gvx` tidak memerlukan kapabilitas istimewa apa pun (`CapEff: 0000000000000000`) dan tidak memerlukan user namespace. Pada host Linux, `rungv` hanya bergantung pada tiga primitif kernel unprivileged standar:

1. **`ptrace(PTRACE_ATTACH)` pada thread child-nya sendiri satu kali selama inisialisasi**: `systrap` menjalankan thread helper stub lokal saat startup, melakukan attach padanya untuk menginisialisasi konteks memori bersama, lalu melakukan detach. Jika host mengatur `kernel.yama.ptrace_scope = 3` (yang menonaktifkan seluruh `ptrace` pada sistem) atau memblokir `ptrace` dalam filter seccomp luar, inisialisasi `systrap` tidak dapat diselesaikan. (Dengan `yama.ptrace_scope = 1`, nilai default di Ubuntu dan Debian, `gvx` berhasil karena tracing dari parent ke child diizinkan.)
2. **`seccomp(SECCOMP_SET_MODE_FILTER)`**: Digunakan untuk menangkap system call guest dari thread stub container. Sebagaimana dibahas dalam [Bagian 3 seri ini](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03), `gvx` berfungsi baik ketika `SECCOMP_FILTER_FLAG_NEW_LISTENER` tersedia maupun ketika mengembalikan `EBUSY` di dalam sandbox bersarang.
3. **`mmap(..., PROT_EXEC, ...)`**: Digunakan untuk memetakan segmen ELF guest dan trampolin memori bersama `systrap`.

---

## Contoh Lengkap: Membangun dan Menguji Aplikasi Multi-Container Tanpa Root

Skrip berikut menjalankan `docker build` lengkap dan pengujian integrasi dua container (`redis` + container aplikasi) di dalam sesi pengguna unprivileged:

```sh
mkdir -p ~/.gvx
rungv run \
  -p unix:~/.gvx/docker.sock:2375 \
  -v gvx-docker:/var/lib/docker \
  -e DOCKER_TLS_CERTDIR= \
  docker:dind --tls=false &
DIND_PID=$!

export DOCKER_HOST="unix://$HOME/.gvx/docker.sock"
until docker info >/dev/null 2>&1; do sleep 0.5; done

mkdir -p /tmp/demo-app && cd /tmp/demo-app
cat <<'EOF' > Dockerfile
FROM alpine:3.20
RUN apk add --no-cache redis
CMD ["redis-cli", "-h", "cache", "ping"]
EOF

# Bangun image menggunakan overlayfs pada ext4lite
docker build -t demo-ping:latest .

# Buat jaringan bridge, jalankan Redis, dan verifikasi konektivitas antar container
docker network create demo-net
docker run -d --name cache --network demo-net redis:7-alpine
docker run --rm --network demo-net demo-ping:latest
# Output: PONG

# Bersihkan container beban kerja dan hentikan sandbox
docker rm -f cache
docker network rm demo-net
kill -INT $DIND_PID
```

---

## Bacaan Lanjutan dalam Seri Ini

1. **[gvx: Menjalankan Linux Container, Docker, dan Kubernetes dalam Satu Proses Unprivileged](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**: Ikhtisar arsitektur `gvx`, mesin eksekusi lintas platformnya (`whpx`, `hvf`, `systrap`), `VFS2` (`erofs`, `ext4lite`, `hostfs` v2), dan `netstack`.
2. **[Menjalankan Docker, docker build, dan docker compose Tanpa Root atau User Namespace](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)** (artikel ini)
3. **[Menjalankan Docker-in-Docker di dalam gVisor dan Sandbox Bersarang dengan gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Cara `gvx` menyelesaikan `modprobe`, `iptables-nft`, `overlay2` pada `gofer`, dan `SECCOMP_FILTER_FLAG_NEW_LISTENER` bersarang (`EBUSY`) di dalam `gVisor` (`runsc`).
4. **[Lingkungan Docker Terisolasi yang Cepat untuk Rollout RL Agen AI dengan gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: Penskalaan lingkungan rollout RL dan `SWE-bench` paralel dengan reset volume `.ext4` Copy-on-Write dalam 100 milidetik.
