---
id: e62d78ef5850c982dbddc9d3ff9134ae
author: Lemon Mint
title: 'gvx: Uruchamianie kontenerów Linux, Docker i Kubernetes w jednym nieuprzywilejowanym procesie'
description: Przegląd techniczny gvx, zabezpieczonego pod kątem bezpieczeństwa, wieloplatformowego środowiska uruchomieniowego kontenerów oraz zestawu SDK dla języka Go, zbudowanego na jądrze gVisor działającym w przestrzeni użytkownika, które bezpiecznie uruchamia kontenery Linux, Docker-in-Docker oraz wielowęzłowe wysokodostępne klastry Kubernetes w jednym nieuprzywilejowanym procesie w systemach Windows, macOS i Linux.
language: pl
date: 2026-11-06T12:02:56.008516536Z
path: /blog/posts/gvx-cross-platform-linux-containers-z48916d01
go_package: z.gfire.dev/gvx
go_repourl: https://github.com/gfire-sigs/gvx.git
category: lowlevel
---

## Wprowadzenie: kontenery o wzmocnionym zabezpieczeniu bez roota i demonów hosta

Uruchamianie kontenerów Linux, `docker build` lub Kubernetes na maszynie deweloperskiej, runnerze CI lub węźle chmury wielodostępowej zazwyczaj wymusza niewygodny kompromis w zakresie bezpieczeństwa:

- W systemie **Linux** standardowe runtime'y OCI (`runc`, `crun`, `runsc`) wymagają albo uprawnień `root`, udostępnienia gniazda `/var/run/docker.sock` hosta, flagi `--privileged` (`CAP_SYS_ADMIN`), albo przestrzeni nazw użytkowników (`unshare(CLONE_NEWUSER)`), które poszerzają powierzchnię ataku jądra hosta.
- W systemach **Windows** i **macOS** silniki kontenerów (`Docker Desktop`, `Podman Machine`, `Lima`, `OrbStack`) uruchamiają pełne jądro maszyny wirtualnej Linux w ramach WSL2, Hyper-V lub `Virtualization.framework` i utrzymują trwały demon działający w tej maszynie wirtualnej.

**[gvx](https://github.com/gfire-sigs/gvx)** (CLI `rungv` oraz Go SDK `z.gfire.dev/gvx/pkg/gvx`) stanowi **bezpieczną alternatywę bez uprawnień**. Zbudowany jako śledzący upstream fork przestrzeni użytkownika jądra Linux `gVisor` firmy Google (`Sentry`) oraz stosu sieciowego w przestrzeni użytkownika (`netstack`), `gvx` uruchamia niezmodyfikowane pliki binarne `linux/amd64` i `linux/arm64` w formacie ELF64 oraz kontenery OCI bezpośrednio w **jednym, nieuprzywilejowanym, samozablokowanym procesie hosta** w systemach Windows, macOS i Linux.

> **Gwarancja bezpieczeństwa (trzypierścieniowa obrona w głąb)**: `gvx` nigdy nie osłabia granic bezpieczeństwa systemu operacyjnego hosta, nigdy nie instaluje sterowników jądra i nigdy nie wymaga `root`, `sudo`, `--privileged` na hoście ani `CLONE_NEWUSER`. Zanim wykona choćby jedną instrukcję gościa, `gvx` blokuje własny proces hosta przy użyciu Windows Restricted Tokens i Job Objects, macOS Seatbelt (`deny default`) lub Linux `PR_SET_NO_NEW_PRIVS` oraz BPF `seccomp`. Wszystkie wywołania systemowe gościa, wirtualne uprawnienia `UID 0`, montowania (`VFS2`) i tablice sieciowe (`netstack`) są ściśle ograniczone wewnątrz bezpiecznej pod względem pamięci jądra Go `Sentry`.

| Runtime                    | System operacyjny hosta                               |     Zimny start | Zużycie pamięci  | Wymagane uprawnienia administratora lub `sudo` | Demon maszyny wirtualnej w tle | Bezpośrednie uruchamianie obrazu OCI |
| :------------------------- | :---------------------------------------------------- | --------------: | ---------------: | :--------------------------------------------- | :----------------------------- | :----------------------------------- |
| **`gvx` (`whpx` / `hvf`)** | Windows (`amd64`, `arm64`) i macOS (`arm64`)          |        `~20 ms` |        `~30 MiB` | Nie                                            | Nie                            | Tak                                  |
| **`gvx` (`systrap`)**      | Windows (`amd64`, `arm64`) i Linux (`amd64`, `arm64`) |  `~25 do 65 ms` |        `~31 MiB` | Nie                                            | Nie                            | Tak                                  |
| **WSL2 / Docker Desktop**  | Windows i macOS                                       | `800 do 2500 ms` |      `> 512 MiB` | Tak (konfiguracja początkowa)                  | Tak                            | Wymaga demona                        |
| **QEMU (pełny system)**    | Windows i macOS                                       | `1500 do 4000 ms` |      `> 256 MiB` | Nie                                            | Nie                            | Wymaga obrazu dysku                  |

Na systemach Windows i macOS nie uruchamia się żadne jądro maszyny wirtualnej Linux. Na hoście nie działa żaden demon w tle. Na systemie operacyjnym hosta nie są wymagane uprawnienia `root`, `sudo`, przestrzenie nazw użytkowników (`CLONE_NEWUSER`), `mount(2)`, sterowniki `TUN`/`TAP` ani `CAP_NET_ADMIN`. Wewnątrz tego nieuprzywilejowanego procesu `gvx` uruchamia **Docker-in-Docker (`docker:dind`)**, `docker build`, `docker compose` oraz **wysoko dostępny, wieloWęzłowyKubernetes (`k3s` z osadzonym `etcd` i wtyczką CNI `Calico`)**.

---

## Cykl życia kontenera i trzypierścieniowa blokada hosta

Każda piaskownica `gvx` działa w jednym nieuprzywilejowanym procesie hosta i realizuje trzyfazowy cykl życia: wstępne otwarcie wszystkich wymaganych deskryptorów plików i gniazd hosta, zablokowanie procesu systemu operacyjnego hosta za pomocą `pkg/hostlockdown` oraz przejście do pętli wykonawczej `Sentry` działającej w procesie.

![Cykl życia kontenera gvx i samoblokada hosta](/assets/images/gvx/gvx-lifecycle-lockdown.png)

Przed przekazaniem sterowania do pierwszej instrukcji gościa `gvx` wstępnie otwiera buforowane deskryptory warstw obrazów `.erofs`, deskryptory plików woluminów `.ext4`, uchwyt `*os.Root` katalogu `/workspace` oraz gniazda sieciowe hosta, a następnie wywołuje `hostlockdown.Apply()`:

1. **Windows NT (`lockdown_windows.go`)**: wywołuje `AdjustTokenPrivileges` z `SE_PRIVILEGE_REMOVED`, aby usunąć uprawnienia w miejscu, wiąże token ograniczonego podszywania się `DISABLE_MAX_PRIVILEGE` na niskim poziomie integralności (`S-1-16-4096`), przypisuje proces do anonimowego Job Object z `JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1` (blokując tworzenie procesów potomnych) oraz włącza `DisallowWin32kSystemCalls = 1` przez `SetProcessMitigationPolicy`.
2. **macOS XNU (`lockdown_darwin.go`)**: ustawia `RLIMIT_NPROC = 0` i stosuje profil Seatbelt (`sandbox_init_with_parameters`) rozpoczynający się od `(version 1)(deny default)`, który blokuje `process-fork`, `process-exec*` oraz wszystkie nowe otwarcia plików hosta.
3. **Linux (`lockdown_linux.go` + `pkg/gvx/syscallfilter_linux.go`)**: ustawia `PR_SET_NO_NEW_PRIVS` i instaluje listę dozwolonych wywołań BPF `seccomp` Sentry dla wszystkich wątków (`SECCOMP_FILTER_FLAG_TSYNC`) wraz z jawnymi regułami `EPERM` dla `execve`, `execveat`, `clone`, `openat` i `socket`.

---

## Przechwytywanie wywołań systemowych między platformami i stronicowanie 4 KB (`pkg/sentry/platform`)

Pliki binarne Linux ELF64 zakładają ziarnistość stron pamięci 4 KB (`0x1000`) przy mapowaniu segmentów przez `mmap(MAP_FIXED)`. Tymczasem `VirtualAlloc` i `MapViewOfFile3` w systemie Windows wymuszają wyrównanie do 64 KB (`0x10000`), a macOS na Apple Silicon (`darwin/arm64`) używa stron hosta o rozmiarze 16 KB (`0x4000`). Ponadto każdy system operacyjny wymaga innego mechanizmu, aby przechwycić instrukcje Linux `SYSCALL` (`amd64`) i `SVC #0` (`arm64`) bez uruchamiania maszyny wirtualnej Linux.

`gvx` rozwiązuje oba problemy w czterech backendach wykonawczych, które implementują `pkg/sentry/platform.Context`:

![Mechanizmy przechwytywania wywołań systemowych i stronicowania 4KB w gvx](/assets/images/gvx/gvx-platform-syscalls.png)

### 1. Sprzętowy silnik Windows: `platform/whpx` (`WinHvPlatform.dll`)

W systemach `windows/amd64` i `windows/arm64` `platform/whpx` tworzy lekką partycję hipernadzorcy za pomocą `WHvCreatePartition`, bez uruchamiania jądra systemu gościa:

- **Dekoplер stronicowania 64 KB na 4 KB**: `whpx` rejestruje każdą 64-megabajtową arenę `pgalloc.MemoryFile` w partycji jednorazowo, za pomocą `WHvMapGpaRange`. Kolejne wywołania `MapFile` i `Unmap` modyfikują wyłącznie tablice stron gościa wewnątrz partycji, egzekwując dokładne uprawnienia `R/W/X` na poziomie 4 KB, mimo ziarnistości alokacji 64 KB w systemie Windows.
- **Wymiana rejestrów bez wywołań API przez `CommPage`**:
  - Na `amd64` instrukcja `SYSCALL` wykonana w Ring-3 gościa wchodzi do stubu `MSR_LSTAR` działającego w Ring-0 wewnątrz partycji (`stubgen_x86.go`), który zapisuje rejestry GPR ścieżki szybkiej (`RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP`) we wspólnej `CommPage` o rozmiarze 4 KB i wykonuje `HLT`, aby zakończyć działanie `WHvRunVirtualProcessor`.
  - Na `arm64` instrukcja `SVC #0` wykonana w EL0 gościa wchodzi do wektorów EL1 (`stubgen_a64.go`), zapisuje `X0..X8, SP_EL0, ELR_EL1, PSTATE` w `CommPage` i odczytuje z niezamapowanego adresu GPA zero, aby wywołać wyjście pamięciowe z powrotem do Sentry.

### 2. Sprzętowy silnik macOS: `platform/hvf` (`Hypervisor.framework`)

Na Apple Silicon (`darwin/arm64`) `platform/hvf` uruchamia wątki kontenerów wewnątrz vCPU `Hypervisor.framework` (`hv_vm_create`, `hv_vcpu_run`):

- **Dwuetapowa translacja MMU 4 KB nad 16 KB**: Stage-2 (`hv_vm_map`) mapuje fragmenty pliku pamięci o rozmiarze 1 GiB do przestrzeni Intermediate Physical Address (IPA) jednorazowo, z ziarnistością stron hosta 16 KB, z uprawnieniami `HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC`. Wewnątrz vCPU stub EL1 `bluepill` (`bluepill_arm64.go`) konfiguruje `TCR_EL1.TG0 = 0b00` (granula 4 KB) w `TTBR0_EL1` i wypełnia wpisy tablic stron Stage-1 o rozmiarze 4 KB z dokładnymi uprawnieniami `R-X` lub `RW-` (`UXN=1`). Ponieważ MMU ARM64 wymusza przecięcie uprawnień Stage-1 i Stage-2, sprzęt przechwytuje błędy uprawnień na dokładnych granicach 4 KB.
- **Pułapka wywołania systemowego**: instrukcja `SVC #0` wykonana w EL0 gościa trafia do `VBAR_EL1` w EL1, zapisuje rejestry we wspólnej `CommPage` o rozmiarze 4 KB i wykonuje `HVC #0`, aby powrócić z `hv_vcpu_run` do wątku Go Sentry.

### 3. Rezerwowy tryb użytkownika Windows: `platform/systrap` (`winsystrap`)

Gdy sprzętowa wirtualizacja jest niedostępna (na przykład wewnątrz zagnieżdżonych maszyn wirtualnych w chmurze), `winsystrap` uruchamia kod gościa w trybie użytkownika w systemach `windows/amd64` i `windows/arm64`:

- **Izolacja sprzętowa `CR3` / `TTBR0_EL1`**: wątki gościa działają wewnątrz izolowanych podprocesów stubowych uruchamianych z wygenerowanego pliku wykonywalnego o rozmiarze 1 KB (`stubimage_xplat.go`), ograniczonych tokenem o niskim poziomie integralności i Job Object.
- **Łatanie binarne w miejscu i IPC `winSysmsg`**: na `amd64` moduł łatający (`patcher_amd64_xplat.go`) zastępuje 2-bajtowe instrukcje `syscall` (`0f 05`) 5-bajtowymi skokami `jmp rel32` (lub pułapkami punktu przerwania `CC 90`, gdy 5-bajtowe okno jest niedostępne), kierującymi do wyspy ścieżki szybkiej. Na `arm64` instrukcja `svc #0` jest łatana gałęzią `B` do slotu wyspy. Wyspa zapisuje rejestry we wspólnej stronie `winSysmsg` i synchronizuje się z Sentry za pomocą `WaitOnAddress` oraz `WakeByAddressSingle`, podczas gdy niełatane pułapki i błędy stron zatrzymują działanie na obiekcie debugowania Windows (`WaitForDebugEventEx`).

### 4. Silnik trybu użytkownika Linux: `platform/systrap`

Na `linux/amd64` i `linux/arm64` `systrap` uruchamia wątki gościa (`sysmsg`), które przechwytują wywołania systemowe gościa za pomocą `SECCOMP_RET_TRAP` (`SIGSYS`) i łatają binarnie miejsca `syscall` w trampolinę we wspólnej pamięci (`sysmsg`), synchronizowaną przez `SYS_FUTEX`. Jednocześnie wątek stubowy `syscallThread` (`syscall_thread.go`) wykonuje operacje na przestrzeni adresowej (`mmap`, `munmap`, `clone`) za pośrednictwem `SECCOMP_RET_USER_NOTIF` (`_RUN_SECCOMP_LOOP`). Gdy `gvx` działa wewnątrz zewnętrznej piaskownicy `gVisor` (`runsc`), w której pojedynczy slot `SECCOMP_FILTER_FLAG_NEW_LISTENER` zwraca `EBUSY`, `gvx` automatycznie przełącza `syscallThread` na pętlę futex we współdzielonej pamięci (`_RUN_SYSCALL_LOOP`), co zostało szczegółowo opisane w [części 3 tej serii](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03).

---

## Jak `gvx` mapuje wywołania systemowe Linux gościa na wirtualne podsystemy i uchwyty hosta

Gdy silnik platformy przechwyci instrukcję `SYSCALL` (`amd64`) lub `SVC #0` (`arm64`) gościa i zapisze rejestry gościa we wspólnej stronie 4 KB (`CommPage`, `sysmsg` lub `winSysmsg`), sterowanie wraca do goroutine'a zadania Go `Sentry` (`pkg/sentry/kernel/task_syscall.go`). Zamiast przekazywać wywołania systemowe Linux do jądra systemu operacyjnego hosta, `Task.doSyscall()` zapisuje oryginalny stan rejestrów (`SyscallSaveOrig()`), ocenia wszelkie filtry BPF `seccomp` gościa oraz zatrzymania `ptrace`, po czym przekazuje numer wywołania systemowego przez `linux.AMD64` lub `linux.ARM64` (`pkg/sentry/syscalls/linux/linux64.go`, obejmujące około 370 wywołań systemowych Linux) do czterech wewnętrznych domen:

![Jak gvx mapuje wywołania systemowe Linux gościa na podsystemy i system operacyjny hosta](/assets/images/gvx/gvx-syscall-mapping.png)

| Domena wywołań systemowych | Reprezentatywne wywołania systemowe Linux gościa | Wewnętrzny podsystem `gvx` (`pkg/sentry`) | Interakcja z granicą systemu operacyjnego hosta (po `hostlockdown`) |
| :--- | :--- | :--- | :--- |
| **A. Procesy, przestrzenie nazw, montowania i synchronizacja** | `clone`, `execve`, `unshare`, `setns`, `mount`, `umount2`, `pivot_root`, `setuid`, `capset`, `futex`, `epoll_wait`, `pipe2` | `kernel.Task`, wirtualne poświadczenia, tablica futex oraz `VFS2` w pamięci (`procfs`, `sysfs`, `cgroupfs` v2, `tmpfs`, `overlayfs`) | **Zero wywołań systemowych hosta** (100% stanu Go w pamięci; całkowicie niewidoczne dla systemu operacyjnego hosta) |
| **B. Pamięć wirtualna (`MM`)** | `mmap`, `munmap`, `mremap`, `mprotect`, `brk`, `madvise`, `memfd_create` | `mm.MemoryManager` (drzewo VMA 4 KB) oraz `pgalloc.MemoryFile` | Dwukierunkowe aktualizacje tablic stron 4 KB przez `WHvMapGpaRange`, `hv_vm_map` + `TTBR0_EL1` lub stubowe `mmap`/`mprotect` |
| **C. Pliki i pamięć masowa (`VFS2`)** | `openat`, `pread64`, `pwrite64`, `getdents64`, `statx`, `renameat2`, `setxattr`, `mknod`, `inotify_add_watch` | Router tabeli montowań `vfs.VirtualFilesystem` (`fsimpl/erofs`, `fsimpl/ext4lite`, `fsimpl/hostfs` v2) | Dwukierunkowe `pread`/`pwrite` na 1 przypiętym deskryptorze `.erofs` lub 1 deskryptorze `.ext4`, albo ograniczone względne przejścia po `*os.Root` |
| **D. Sieć i Netfilter** | `socket`, `bind`, `listen`, `connect`, `sendmsg`, `recvmsg`, `netlink`, `setsockopt(IPT_SO_SET_REPLACE)` | `pkg/tcpip` w przestrzeni użytkownika (`lo`, `eth0`, `docker0`, `veth`, `vxlan`, `wireguard`, `ipset`, `iptables-legacy`) | Ruch wewnątrz piaskownicy nie wykonuje **żadnych wywołań systemowych hosta**; ruch zewnętrzny mapuje się na `net.Dial`/`net.Listen` (`-net=nat`) lub 1 gniazdo UDP (`-net=wg`) |

Gdy handler zwraca `(rval, ctrl, err)`, `Task.doSyscallInvoke()` przekształca każdy błąd w ujemny `errno` Linux (`-ExtractErrno(err, sysno)`), zapisuje wartość zwrotną z powrotem do współdzielonej strony rejestrów (`RAX` na `amd64`, `X0` na `arm64`) i wznawia wykonywanie kodu gościa.

---

## Pamięć masowa (`VFS2`) i dwutorowy stos sieciowy w przestrzeni użytkownika (`netstack`)

Wszystkie operacje plikowe i sieciowe gościa są obsługiwane wewnątrz Go `Sentry` przez trzy systemy plików `VFS2` oraz dwa tory `pkg/netbackend`:

![Silniki pamięci masowej VFS2 i dwutorowy netstack w gvx](/assets/images/gvx/gvx-storage-netstack.png)

| Silnik pamięci masowej | Rola montowania w `gvx`                          | Zasób bazowy hosta                     | Wywołania hosta `openat` / `NtCreateFile` podczas działania | Skanowania `WdFilter.sys` (Windows Defender) dla pojedynczych plików |
| :--------------------- | :----------------------------------------------- | :------------------------------------- | ----------------------------------------------------------: | -------------------------------------------------------------------: |
| **`fsimpl/erofs`**     | Dolne warstwy obrazów OCI tylko do odczytu       | Pojedynczy plik `<sha256>.erofs` na warstwę |                                                       `0` |                                                                `0` |
| **`fsimpl/ext4lite`**  | Nazwane woluminy (`-v name:/path`)               | Pojedynczy plik `<name>.ext4` na wolumin    |                                                       `0` |                                                                `0` |
| **`fsimpl/hostfs` v2** | Obszar roboczy hosta (`-workspace`, `-v /host:/guest`) | Przypięty katalog hosta `*os.Root`    |                                     `O(depth)` na każde nieobsłużone z pamięci podręcznej otwarcie |                                                 `1` na zamknięcie pliku hosta |

### Dlaczego `ext4lite` ma znaczenie dla Dockera, baz danych i menedżerów pakietów

Rozpakowywanie lub zapisywanie dziesiątek tysięcy plików kontenerów bezpośrednio na systemie plików NTFS w Windows lub APFS w macOS uruchamia skanowanie przez minifiltry antywirusowe (`WdFilter.sys`), kolizje wynikające z rozróżniania wielkości liter oraz brak rozszerzonych atrybutów POSIX.

`pkg/sentry/fsimpl/ext4lite` implementuje czysto w Go system plików `ext4` wewnątrz jednego wstępnie otwartego pliku hosta (`%LOCALAPPDATA%\gvx\cache\volumes\<name>.ext4` w systemie Windows, `~/Library/Caches/gvx/volumes/<name>.ext4` w macOS lub `~/.cache/gvx/volumes/<name>.ext4` w Linux), z następującymi cechami:

- **Bloki 4 KiB i dynamiczne grupy bloków po 16 MiB (`meta_bg`)**: rosną dynamicznie bez zacięć wynikających z alokacji plików rzadkich (`fallocate` w Linux, `fcntl(F_PREALLOCATE)` w macOS, `FileAllocationInfo` w Windows) i kompaktują nieużywane końcowe grupy przy czystym odmontowaniu.
- **Dziennik JBD2 w trybie uporządkowanym (inode 8)**: atomowe zatwierdzanie transakcji z sumami kontrolnymi CRC-32 i blokami revoke, a także odzyskiwanie za pomocą `fsckLite`.
- **Obsługa warstwy górnej `overlayfs`**: implementuje rozszerzone atrybuty `trusted.overlay.*` i `security.capability`, wymazania za pomocą urządzeń znakowych (`0:0`), raportowanie `d_type` wpisów katalogów oraz `RENAME_EXCHANGE`.

---

## Praktyczne obciążenia: Docker Engine, Kubernetes (`k3s` + `Calico`) i Go SDK

### Instalacja `rungv`: gotowe wydania z atestacją SLSA lub `go install`

Gotowe archiwum `rungv` możesz pobrać dla `linux/amd64`, `linux/arm64`, `darwin/arm64`, `windows/amd64` lub `windows/arm64` z [GitHub Releases](https://github.com/gfire-sigs/gvx/releases) (każde zbudowane przez potok wydań SLSA z pakietem pochodzenia Sigstore i plikiem `SHA256SUMS`) albo zainstalować bezpośrednio ze źródeł za pomocą `go install`:

```sh
# Opcja A: Pobierz gotowe wydanie i zweryfikuj pochodzenie builda SLSA
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
shasum -a 256 -c SHA256SUMS --ignore-missing
tar -xzf rungv-v0.2.0-linux-amd64.tar.gz

# Opcja B: Zainstaluj bezpośrednio przez Go (Linux / Windows)
CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest
```

> W systemie macOS (`darwin/arm64`) gotowe archiwum wydania jest już podpisane uprawnieniem `com.apple.security.hypervisor` (`xattr -d com.apple.quarantine rungv` usuwa kwarantannę przeglądarki). Jeśli budujesz lokalnie za pomocą `go install` lub `go build` na macOS, podpisz plik binarny poleceniem `codesign --sign - --entitlements entitlements.plist --force $(which rungv)`.

### 1. Uruchamianie nieuprzywilejowanego Docker Engine (`docker:dind`)

Zgodnie z [`docs/docker-engine.md`](https://github.com/gfire-sigs/gvx/blob/main/docs/docker-engine.md) możesz uruchomić niezmodyfikowany kontener `docker:dind` wewnątrz `rungv` w systemie Windows, macOS lub Linux i sterować nim za pomocą lokalnego CLI `docker`:

```sh
# 1. Utwórz katalog hosta dla przekazywanego gniazda Unix
mkdir -p ~/.gvx

# 2. Uruchom docker:dind w piaskownicy gvx z woluminem ext4lite
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
```

W drugim terminalu skieruj lokalne CLI `docker` na gniazdo piaskownicy:

```sh
docker context create gvx --docker host=unix://$HOME/.gvx/docker.sock
docker context use gvx

docker info --format '{{.Driver}} {{.OperatingSystem}}'
# Wynik: overlayfs Alpine Linux ... (containerized)

docker build -t myapp ./app
docker compose up -d
```

### 2. Uruchamianie Kubernetes (`k3s` + `Calico`) w nieuprzywilejowanych piaskownicach

Ponieważ `gvx` implementuje `/dev/kmsg`, `cgroup` v2 (zabójca OOM oparty na `memory.max` oraz ograniczanie przepustowości `cpu.max`), `/proc/diskstats`, urządzenia netlink `wireguard` i `vxlan`, `ipset` oraz `iptables-legacy` (`addrtype`, `conntrack`, `statistic`, `recent`), niezmodyfikowany obraz `rancher/k3s` osiąga stan `Ready` w obrębie pojedynczego procesu `rungv`:

```sh
mkdir -p ~/.gvx/k3s

rungv run \
  -e IPTABLES_MODE=legacy \
  -p 127.0.0.1:6443:6443 \
  -p 127.0.0.1:30000-30019:30000-30019 \
  -v k3s:/var/lib/rancher \
  --mount type=bind,src=$HOME/.gvx/k3s,dst=/output \
  rancher/k3s:v1.31.4-k3s1 server \
  --disable=traefik,servicelb \
  --write-kubeconfig=/output/kubeconfig.yaml \
  --write-kubeconfig-mode=644
```

Możesz także połączyć wiele węzłów `gvx` przez WireGuard (`flannel-backend=wireguard-native` lub siatka `wg0`) z osadzonym `etcd` w wysokiej dostępności albo uruchomić **Calico** (`calico-vxlan.yaml` z `FELIX_IPTABLESBACKEND=Legacy`), aby w pełni w przestrzeni użytkownika egzekwować `NetworkPolicy` Kubernetes.

### 3. Osadzanie kontenerów Linux w Go za pomocą `z.gfire.dev/gvx/pkg/gvx`

Aplikacje Go mogą osadzać kontenery Linux bezpośrednio, bez zewnętrznego demona kontenerów:

```go
package main

import (
	"context"
	"fmt"
	"os"

	"z.gfire.dev/gvx/pkg/gvx"
)

func main() {
	ctx := context.Background()
	sb, err := gvx.New(ctx, gvx.Config{
		Platform:      gvx.PlatformAuto,
		NetworkMode:   gvx.NetModeNAT,
		OCIImage:      "alpine:3.20",
		WorkspacePath: "./repo",
		Argv:          []string{"/usr/bin/git", "status"},
		Stdout:        os.Stdout,
		Stderr:        os.Stderr,
	})
	if err != nil {
		fmt.Fprintf(os.Stderr, "init sandbox: %v\n", err)
		os.Exit(1)
	}
	defer sb.Close()

	exitCode, err := sb.Run(ctx)
	if err != nil {
		fmt.Fprintf(os.Stderr, "run sandbox: %v\n", err)
		os.Exit(1)
	}
	os.Exit(exitCode)
}
```

---

## Dalsza lektura w tej serii

1. **[gvx: Uruchamianie kontenerów Linux, Dockera i Kubernetes w jednym nieuprzywilejowanym procesie](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)** (ten wpis)
2. **[Uruchamianie Dockera, docker build i docker compose bez roota i przestrzeni nazw użytkowników](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)**: jak uruchomić `docker:dind` w zablokowanych piaskownicach, w których zablokowane są `sudo`, `unshare(CLONE_NEWUSER)`, `mount(2)` i `/dev/fuse`.
3. **[Uruchamianie Docker-in-Docker wewnątrz gVisor i zagnieżdżonych piaskownic z gvx](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: dlaczego `apt-get install docker.io` oraz zagnieżdżone `runsc` kończą się niepowodzeniem wewnątrz `gVisor` na pięciu barierach jądra oraz jak `gvx` uruchamia zagnieżdżony `docker:dind` przy użyciu pętli futex we współdzielonej pamięci.
4. **[Szybkie izolowane środowiska Docker dla rolloutów uczenia ze wzmocnieniem agentów AI z gvx](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: skalowanie `SWE-bench` i rolloutów uczenia ze wzmocnieniem agentów z setkami równoległych nieuprzywilejowanych instancji `docker:dind` oraz 100-milisekundowymi resetami woluminów `.ext4` z kopiowaniem przy zapisie.
