---
id: e62d78ef5850c982dbddc9d3ff9134ae
author: Lemon Mint
title: 'gvx: Linux Containers, Docker ja Kubernetes suoritettuna yhdessä privilegioimattomassa prosessissa'
description: Tekninen yleiskatsaus gvx:ään, turvallisuutta lujittavaan, alustojen väliseen container runtime -ympäristöön ja Go SDK:hon, joka perustuu gVisor-käyttäjätilan ytimeen ja joka suorittaa turvallisesti Linux-kontteja, Docker-in-Docker-ympäristöjä sekä multi-node HA Kubernetes -klustereita yhdessä yksittäisessä, ilman erioikeuksia toimivassa prosessissa Windowsissa, macOS:ssä ja Linuxissa.
language: fi
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
---

## Johdanto: Tietoturvakovennetut kontit ilman juurioikeuksia tai isäntädaemoneita

Linux-konttien, `docker build`-komennon tai Kubernetesin ajaminen kehityskoneella, CI-ajurilla tai monivuokralaisella pilvisolmulla pakottaa yleensä epämiellyttävään tietoturvakompromissiin:

- **Linuxissa** tavalliset OCI-ajoympäristöt (`runc`, `crun`, `runsc`) vaativat joko `root`-oikeudet, isännän `/var/run/docker.sock`-socketin altistuksen, `--privileged`-tilan (`CAP_SYS_ADMIN`) tai käyttäjänimiavaruudet (`unshare(CLONE_NEWUSER)`), jotka laajentavat isäntäytimen hyökkäyspintaa.
- **Windowsissa** ja **macOS:ssä** konttimoottorit (`Docker Desktop`, `Podman Machine`, `Lima`, `OrbStack`) käynnistävät täyden Linux-virtuaalikoneen ytimen WSL2:n, Hyper-V:n tai `Virtualization.framework`-kehyksen sisällä ja ajavat pysyvää taustadaemonia kyseisessä virtuaalikoneessa.

**[gvx](https://github.com/gfire-sigs/gvx)** (`rungv`-komentorivityökalu ja `z.gfire.dev/gvx/pkg/gvx` Go-SDK) tarjoaa **turvallisen, nollaoikeuksisen vaihtoehdon**. Se on rakennettu ylävirran kanssa synkronoitavana haarukkana Googlen **gVisor**-käyttäjätilan Linux-ytimestä (`Sentry`) ja käyttäjätilan verkkopinosta (`netstack`). `gvx` suorittaa muuttamattomia `linux/amd64`- ja `linux/arm64`-ELF64-binäärejä sekä OCI-kontteja suoraan **yhdessä oikeuksettomassa, itse itseään lukitsevassa isäntäprosessissa** Windowsissa, macOS:ssä ja Linuxissa.

> **Tietoturvatakuu (Kolmirenkainen puolustus syvyyssuunnassa, Three-Ring Defense-in-Depth)**: `gvx` ei koskaan heikennä isäntäkäyttöjärjestelmän tietoturvarajoja, ei asenna ytimen ajureita eikä koskaan vaadi `root`-oikeuksia, `sudo`-komentoa, isännän `--privileged`-tilaa tai `CLONE_NEWUSER`-toimintoa. Ennen kuin se suorittaa yhdenkään vieraan käskyn, `gvx` lukitsee oman isäntäprosessinsa käyttämällä Windowsin rajoitettuja tunnuksia (Restricted Tokens) ja Job Objecteja, macOS:n Seatbelt-profiilia (`deny default`) tai Linuxin `PR_SET_NO_NEW_PRIVS`-asetusta sekä BPF-`seccomp`-suodatinta. Kaikki vieraan järjestelmän kutsut, virtuaaliset `UID 0` -oikeudet, liitokset (`VFS2`) ja verkkotaulukot (`netstack`) on tiukasti rajattu muistiturvalliseen Go-`Sentry`-ytimeen.

| Ajoympäristö              | Isäntäkäyttöjärjestelmä                               |  Kylmäkäynnistys | Muistijalanjälki | Vaaditaan ylläpitäjä tai `sudo` | Taustalla toimiva VM-daemon | Suora OCI-kuvan suoritus |
| :------------------------- | :---------------------------------------------------- | ----------------: | ---------------: | :------------------------------ | :--------------------------- | :----------------------- |
| **`gvx` (`whpx` / `hvf`)** | Windows (`amd64`, `arm64`) & macOS (`arm64`)          |          `~20 ms` |        `~30 MiB` | Ei                              | Ei                           | Kyllä                    |
| **`gvx` (`systrap`)**      | Windows (`amd64`, `arm64`) & Linux (`amd64`, `arm64`) |    `~25 - 65 ms` |        `~31 MiB` | Ei                              | Ei                           | Kyllä                    |
| **WSL2 / Docker Desktop**  | Windows & macOS                                       |  `800 - 2500 ms` |      `> 512 MiB` | Kyllä (alkuasennus)             | Kyllä                        | Vaatii daemonin          |
| **QEMU (Full System)**     | Windows & macOS                                       | `1500 - 4000 ms` |      `> 256 MiB` | Ei                              | Ei                           | Vaatii levykuvan         |

Windowsissa tai macOS:ssä ei käynnisty yhtään Linux-virtuaalikoneen ydintä. Isännällä ei ole taustadaemonia. Isäntäkäyttöjärjestelmä ei vaadi `root`-oikeuksia, `sudo`-komentoa, käyttäjänimiavaruuksia (`CLONE_NEWUSER`), `mount(2)`-kutsua, `TUN`/`TAP`-ajureita tai `CAP_NET_ADMIN`-oikeuksia. Tässä oikeuksettomassa prosessissa `gvx` ajaa **Docker-in-Docker (`docker:dind`)**-ympäristöä, `docker build`-komentoa, `docker compose`-komentoa ja **useita solmuja sisältävää korkean saatavuuden Kubernetesia (`k3s`, jossa on upotettu `etcd` ja `Calico` CNI)**.

---

## Kontin elinkaari ja kolmirenkainen isäntälukitus

Jokainen `gvx`-hiekkalaatikko ajetaan yhdessä oikeuksettomassa isäntäprosessissa, ja se noudattaa kolmivaiheista elinkaarta: kaikkien vaadittujen isäntätiedostokuvaajien ja -socketien esiavaus, isäntäkäyttöjärjestelmäprosessin lukitseminen `pkg/hostlockdown`-paketin kautta ja siirtyminen prosessinsisäiseen `Sentry`-suoritussilmukkaan.

![gvx-kontin elinkaari ja isäntäprosessin itselukitus](/assets/images/gvx/gvx-lifecycle-lockdown.png)

Ennen kuin ohjaus siirretään ensimmäiselle vieraalle käskylle, `gvx` avaa etukäteen välimuistissa olevien `.erofs`-kerrosten kuvaajat, `.ext4`-volyymitiedostojen kuvaajat, `/workspace`-kohteen `*os.Root`-kahvan ja isännän verkkosocketit. Tämän jälkeen se kutsuu `hostlockdown.Apply()`-funktiota:

1. **Windows NT (`lockdown_windows.go`)**: Kutsuu `AdjustTokenPrivileges`-funktiota arvolla `SE_PRIVILEGE_REMOVED` poistaakseen oikeudet paikallaan, sitoo `DISABLE_MAX_PRIVILEGE`-rajoitetun esiintymistunnuksen (restricted impersonation token) Low-eheystasolla (`S-1-16-4096`), liittää prosessin anonyymiin Job Objectiin asetuksella `JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1` (estää lapsiprosessien luonnin) ja ottaa käyttöön asetuksen `DisallowWin32kSystemCalls = 1` funktiolla `SetProcessMitigationPolicy`.
2. **macOS XNU (`lockdown_darwin.go`)**: Asettaa `RLIMIT_NPROC = 0` ja soveltaa Seatbelt-profiilia (`sandbox_init_with_parameters`), joka alkaa rivistä `(version 1)(deny default)` ja estää `process-fork`-, `process-exec*`- ja kaikki uudet isännän tiedostojen avaukset.
3. **Linux (`lockdown_linux.go` + `pkg/gvx/syscallfilter_linux.go`)**: Asettaa `PR_SET_NO_NEW_PRIVS`-asetuksen ja ottaa käyttöön Sentry-BPF-`seccomp`-sallintalistan kaikissa säikeissä (`SECCOMP_FILTER_FLAG_TSYNC`) eksplisiittisillä `EPERM`-säännöillä kutsuille `execve`, `execveat`, `clone`, `openat` ja `socket`.

---

## Alustojen välinen järjestelmäkutsujen sieppaus ja 4 KB:n sivutus (`pkg/sentry/platform`)

Linux-ELF64-binäärit olettavat 4 KB:n (`0x1000`) muistisivurakeisuuden `mmap(MAP_FIXED)`-segmenttikuvauksille. Windowsin `VirtualAlloc` ja `MapViewOfFile3` kuitenkin pakottavat 64 KB:n (`0x10000`) tasauksen, ja Apple Silicon -macOS (`darwin/arm64`) käyttää 16 KB:n (`0x4000`) isäntäsivuja. Lisäksi kukin käyttöjärjestelmä vaatii erilaisen mekanismin Linux-käskyjen `SYSCALL` (`amd64`) ja `SVC #0` (`arm64`) sieppaamiseen ilman Linux-virtuaalikoneen käynnistämistä.

`gvx` ratkaisee molemmat ongelmat neljällä suoritustaustaohjelmalla, jotka toteuttavat `pkg/sentry/platform.Context`-rajapinnan:

![gvx-alustan järjestelmäkutsujen sieppaus ja 4 KB:n sivutuksen mekaniikka](/assets/images/gvx/gvx-platform-syscalls.png)

### 1. Windowsin laitteistomoottori: `platform/whpx` (`WinHvPlatform.dll`)

Kohteissa `windows/amd64` ja `windows/arm64` `platform/whpx` luo kevyen hypervisor-osion `WHvCreatePartition`-funktiolla ilman vieraan käyttöjärjestelmän ydintä:

- **64 KB:stä 4 KB:hen sivutuksen erotin (Paging Decoupler)**: `whpx` rekisteröi kullekin 64 MiB:n `pgalloc.MemoryFile`-alueelle osion kanssa kerran `WHvMapGpaRange`-funktiolla. Myöhemmät `MapFile`- ja `Unmap`-kutsut muokkaavat vain osion sisäisiä vieraan sivutaulukoita ja toteuttavat tarkat 4 KB:n `R/W/X`-oikeudet huolimatta Windowsin 64 KB:n varauskoosta.
- **Nollasovellusliittymäinen rekisterivaihto `CommPage`-sivun kautta**:
  - Kohteessa `amd64` vieraan Ring-3 `SYSCALL` siirtyy osion sisäiseen Ring-0 `MSR_LSTAR`-tynkään (`stubgen_x86.go`), joka tallentaa nopean polun järjestelmäkutsurekisterit (`RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP`) jaettuun 4 KB:n `CommPage`-sivuun ja suorittaa `HLT`-käskyn poistuakseen `WHvRunVirtualProcessor`-funktiosta.
  - Kohteessa `arm64` vieraan EL0 `SVC #0` siirtyy EL1-vektoreihin (`stubgen_a64.go`), tallentaa rekisterit `X0..X8, SP_EL0, ELR_EL1, PSTATE` sivulle `CommPage` ja lataa arvon osoitteesta GPA nolla, jolloin muistipoikkeus palauttaa ohjauksen Sentryyn.

### 2. macOS:n laitteistomoottori: `platform/hvf` (`Hypervisor.framework`)

Apple Silicon -prosessorissa (`darwin/arm64`) `platform/hvf` ajaa konttisäikeitä `Hypervisor.framework`-kehyksen vCPU:illa (`hv_vm_create`, `hv_vcpu_run`):

- **Kaksivaiheinen 4 KB:n sivutus 16 KB:n MMU-käännöksen päällä**: Stage-2 (`hv_vm_map`) kuvaa 1 GiB:n muistitiedostopalat välimuistisoitteeseen (Intermediate Physical Address, IPA) kerran 16 KB:n isäntäsivurakeisuudella oikeuksilla `HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC`. vCPU:n sisällä EL1-`bluepill`-tynkä (`bluepill_arm64.go`) määrittää `TCR_EL1.TG0 = 0b00` (4 KB:n rakeisuus) kohteessa `TTBR0_EL1` ja täyttää 4 KB:n Stage-1-sivutaulukkomerkinnät tarkoin oikeuksin `R-X` tai `RW-` (`UXN=1`). Koska ARM64-MMU pakottaa Stage-1- ja Stage-2-oikeuksien leikkauksen, laitteisto pysäyttää oikeuspoikkeukset tarkasti 4 KB:n rajoilla.
- **Järjestelmäkutsun pysäytys (Syscall Trap)**: Vieraan EL0 `SVC #0` siirtyy EL1 `VBAR_EL1`-kohteeseen, tallentaa rekisterit jaettuun 4 KB:n `CommPage`-sivuun ja suorittaa `HVC #0`-käskyn palatakseen `hv_vcpu_run`-funktiosta Go-`Sentry`-säikeeseen.

### 3. Windowsin käyttäjätilan varamoottori: `platform/systrap` (`winsystrap`)

Kun laitteistovirtualisointi ei ole käytettävissä (esimerkiksi sisäkkäisissä pilvivirtuaalikoneissa), `winsystrap` ajaa vieraan koodin käyttäjätilassa kohteissa `windows/amd64` ja `windows/arm64`:

- **Laitteistotason `CR3`- / `TTBR0_EL1`-eristys**: Vieraat säikeet ajetaan eristetyissä tynkäalijärjestelmäprosesseissa, jotka käynnistetään generoidusta 1 KB:n suoritettavasta tiedostosta (`stubimage_xplat.go`), ja niitä rajoittaa Low-eheystason tunnus sekä Job Object.
- **Binäärin paikallinen muokkaus ja `winSysmsg`-prosessienvälinen viestintä (IPC)**: Kohteessa `amd64` muokkaaja (`patcher_amd64_xplat.go`) korvaa 2 tavun `syscall`- (`0f 05`) käskyt 5 tavun `jmp rel32`-hyppyillä (tai `CC 90` -keskeytyksillä, jos 5 tavun ikkuna ei ole käytettävissä) nopean polun saarekkeeseen. Kohteessa `arm64` `svc #0` korvataan `B`-haaralla saarekepaikkaan. Saareke tallentaa rekisterit jaettuun `winSysmsg`-sivuun ja synkronoituu Sentryn kanssa funktioilla `WaitOnAddress` ja `WakeByAddressSingle`. Muokkaamattomat pysäytykset ja sivuvirheet pysähtyvät Windowsin Debug Objectiin (`WaitForDebugEventEx`).

### 4. Linuxin käyttäjätilamoottori: `platform/systrap`

Kohteissa `linux/amd64` ja `linux/arm64` `systrap` ajaa vieraita säikeitä (`sysmsg`), jotka pysäyttävät vieraat järjestelmäkutsut `SECCOMP_RET_TRAP`-asetuksella (`SIGSYS`) ja muokkaavat binääristi `syscall`-kohdat jaettuun muistiin perustuvaan trampoliiniin (`sysmsg`), joka synkronoidaan `SYS_FUTEX`-kutsulla. Samalla tynkä `syscallThread` (`syscall_thread.go`) suorittaa osoiteavaruuden toimenpiteitä (`mmap`, `munmap`, `clone`) `SECCOMP_RET_USER_NOTIF`-asetuksella (`_RUN_SECCOMP_LOOP`). Kun `gvx` ajetaan ulomman `gVisor`- (`runsc`) hiekkalaatikon sisällä, jossa yksittäinen `SECCOMP_FILTER_FLAG_NEW_LISTENER`-paikka palauttaa `EBUSY`-virheen, `gvx` vaihtaa automaattisesti `syscallThread`-säikeen jaettuun muistiin perustuvaan futex-silmukkaan (`_RUN_SYSCALL_LOOP`), kuten on kuvattu [tämän sarjan osassa 3](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03).

---

## Miten `gvx` kuvaa vieraat Linux-järjestelmäkutsut virtuaalisiin alijärjestelmiin ja isäntäkahvoihin

Kun alustamoottori on pysäyttänyt vieraan `SYSCALL`- (`amd64`) tai `SVC #0`- (`arm64`) käskyn ja kirjoittanut vieraat rekisterit 4 KB:n jaettuun sivuun (`CommPage`, `sysmsg` tai `winSysmsg`), ohjaus palautuu Go-`Sentry`-tehtävän goroutinelle (`pkg/sentry/kernel/task_syscall.go`). Sen sijaan että Linux-järjestelmäkutsut välitettäisiin isäntäkäyttöjärjestelmän ytimelle, `Task.doSyscall()` tallentaa alkuperäisen rekisteritilan (`SyscallSaveOrig()`), arvioi vieraan BPF-`seccomp`-suodattimet ja `ptrace`-pysäytykset ja lähettää järjestelmäkutsunumeron `linux.AMD64`- tai `linux.ARM64`-rajapinnan kautta (`pkg/sentry/syscalls/linux/linux64.go`, joka kattaa noin 370 Linux-järjestelmäkutsua) neljään sisäiseen alueeseen:

![Miten gvx kuvaa vieraat Linux-järjestelmäkutsut alijärjestelmiin ja isännän käyttöjärjestelmään](/assets/images/gvx/gvx-syscall-mapping.png)

| Järjestelmäkutsualue | Edustavat vieraan Linuxin järjestelmäkutsut | Sisäinen `gvx`-alijärjestelmä (`pkg/sentry`) | Isäntäkäyttöjärjestelmän rajapintavuorovaikutus (`hostlockdown`-vaiheen jälkeen) |
| :--- | :--- | :--- | :--- |
| **A. Prosessi, nimiavaruus, liitokset ja synkronointi** | `clone`, `execve`, `unshare`, `setns`, `mount`, `umount2`, `pivot_root`, `setuid`, `capset`, `futex`, `epoll_wait`, `pipe2` | `kernel.Task`, virtuaaliset tunnistetiedot, futex-taulukko ja muistissa oleva `VFS2` (`procfs`, `sysfs`, `cgroupfs` v2, `tmpfs`, `overlayfs`) | **Nolla isäntäjärjestelmäkutsua** (100 % muistissa oleva Go-tila; täysin näkymätön isäntäkäyttöjärjestelmälle) |
| **B. Virtuaalimuisti (`MM`)** | `mmap`, `munmap`, `mremap`, `mprotect`, `brk`, `madvise`, `memfd_create` | `mm.MemoryManager` (4 KB:n VMA-puu) ja `pgalloc.MemoryFile` | Kaksisuuntaiset 4 KB:n sivutaulukkopäivitykset `WHvMapGpaRange`-, `hv_vm_map`- + `TTBR0_EL1`-funktioiden tai tynkän `mmap`/`mprotect`-kutsujen kautta |
| **C. Tiedostot ja tallennus (`VFS2`)** | `openat`, `pread64`, `pwrite64`, `getdents64`, `statx`, `renameat2`, `setxattr`, `mknod`, `inotify_add_watch` | `vfs.VirtualFilesystem`-liitostaulukon reititin (`fsimpl/erofs`, `fsimpl/ext4lite`, `fsimpl/hostfs` v2) | Kaksisuuntainen `pread`/`pwrite` yhdelle kiinnitetylle `.erofs`-kuvaajalle tai yhdelle `.ext4`-kuvaajalle taikka rajatut suhteelliset kulut `*os.Root`-kohteessa |
| **D. Verkko ja Netfilter** | `socket`, `bind`, `listen`, `connect`, `sendmsg`, `recvmsg`, `netlink`, `setsockopt(IPT_SO_SET_REPLACE)` | Käyttäjätilan `pkg/tcpip` (`lo`, `eth0`, `docker0`, `veth`, `vxlan`, `wireguard`, `ipset`, `iptables-legacy`) | Hiekkalaatikon sisäinen liikenne ei käytä **yhtään isäntäjärjestelmäkutsua**. Ulkoinen liikenne kuvautuu kohteisiin `net.Dial`/`net.Listen` (`-net=nat`) tai yhteen UDP-socketiin (`-net=wg`) |

Kun käsittelijä palauttaa arvot `(rval, ctrl, err)`, `Task.doSyscallInvoke()` muuntaa virheen negatiiviseksi Linux-`errno`-arvoksi (`-ExtractErrno(err, sysno)`), kirjoittaa paluuarvon takaisin jaettuun rekisterisivuun (`RAX` kohteessa `amd64`, `X0` kohteessa `arm64`) ja jatkaa vieraan suoritusta.

---

## Tallennus (`VFS2`) ja kaksiraiteinen käyttäjätilaverkko (`netstack`)

Kaikki vieraiden tiedostojen ja verkon toiminnot palvellaan Go-`Sentryn` sisällä kolmen `VFS2`-tiedostojärjestelmän ja kahden `pkg/netbackend`-raidan kautta:

![gvx VFS2-tallennusmoottorit ja kaksiraiteinen netstack](/assets/images/gvx/gvx-storage-netstack.png)

| Tallennusmoottori | Liitoksen rooli `gvx`:ssä | Taustalla oleva isäntäresurssi | Isännän `openat`- / `NtCreateFile`-kutsut ajonaikana | Windows Defenderin (`WdFilter.sys`) tiedostokohtaiset tarkistukset |
| :--- | :--- | :--- | ---: | ---: |
| **`fsimpl/erofs`** | Vain luku -tilassa olevat OCI-kuvan alemmat kerrokset | Yksi `<sha256>.erofs`-tiedosto kerrosta kohden | `0` | `0` |
| **`fsimpl/ext4lite`** | Nimetyt volyymit (`-v name:/path`) | Yksi `<name>.ext4`-tiedosto volyymiä kohden | `0` | `0` |
| **`fsimpl/hostfs` v2** | Isännän työtila (`-workspace`, `-v /host:/guest`) | Kiinnitetty `*os.Root`-isäntähakemisto | `O(depth)` jokaista välimuistittomaa avausta kohden | `1` jokaista isäntätiedoston sulkemista kohden |

### Miksi `ext4lite` on tärkeä Dockerille, tietokannoille ja pakettienhallinnoille

Kymmenien tuhansien konttitiedostojen purkaminen tai kirjoittaminen suoraan Windowsin NTFS- tai macOS:n APFS-tiedostojärjestelmään laukaisee virustorjunnan minifilter-tarkistuksia (`WdFilter.sys`), kirjainkokoherkkyystörmäyksiä ja puuttuvia POSIX-laajennettuja attribuutteja.

`pkg/sentry/fsimpl/ext4lite` toteuttaa puhtaasti Go-kielisen `ext4`-tiedostojärjestelmän yhdessä etukäteen avatussa isäntätiedostossa (`%LOCALAPPDATA%\gvx\cache\volumes\<name>.ext4` Windowsissa, `~/Library/Caches/gvx/volumes/<name>.ext4` macOS:ssä tai `~/.cache/gvx/volumes/<name>.ext4` Linuxissa), ja siinä on:

- **4 KiB:n lohkot ja 16 MiB:n dynaamiset lohkoryhmät (`meta_bg`)**: Kasvaa dynaamisesti ilman harvatiedostojen allokointiviiveitä (`fallocate` Linuxissa, `fcntl(F_PREALLOCATE)` macOS:ssä, `FileAllocationInfo` Windowsissa) ja tiivistää käyttämättömät lopulliset ryhmät puhtaan irrotuksen yhteydessä.
- **JBD2-järjestetyn tilan lokitiedosto (inode 8)**: Atomiset transaktioiden vahvistukset CRC-32-tarkistussummilla ja kumoituslohkoilla sekä `fsckLite`-palautus.
- **`overlayfs`-ylemmän kerroksen tuki**: Toteuttaa `trusted.overlay.*`- ja `security.capability`-laajennetut attribuutit, merkkilaitteiden poistomerkinnät (`0:0`), `d_type`-hakemistomerkintöjen raportoinnin ja `RENAME_EXCHANGE`-toiminnon.

---

## Käytännön työkuormat: Docker-moottori, Kubernetes (`k3s` + `Calico`) ja Go-SDK

### `rungv`-komennon asennus: SLSA-todennetut valmiit julkaisut tai `go install`

Voit ladata valmiin `rungv`-arkiston kohteille `linux/amd64`, `linux/arm64`, `darwin/arm64`, `windows/amd64` tai `windows/arm64` osoitteesta [GitHub Releases](https://github.com/gfire-sigs/gvx/releases) (jokainen rakennettu SLSA-julkaisuputkella Sigstore-alkuperätodistuksen ja `SHA256SUMS`-tiedoston kanssa) tai asentaa suoraan lähdekoodista komennolla `go install`:

```sh
# Vaihtoehto A: Lataa valmis julkaisu ja varmista SLSA-rakennuksen alkuperä
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

# Vaihtoehto B: Asenna suoraan Go-työkalulla (Linux / Windows)
CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest
```

> macOS:ssä (`darwin/arm64`) valmis julkaisuarkisto on jo allekirjoitettu `com.apple.security.hypervisor`-oikeudella (`xattr -d com.apple.quarantine rungv` poistaa selaimen karanteenimerkinnän). Jos rakennat binäärin paikallisesti macOS:ssä komennoilla `go install` tai `go build`, allekirjoita binääri komennolla `codesign --sign - --entitlements entitlements.plist --force $(which rungv)`.

### 1. Oikeudettoman Docker-moottorin ajaminen (`docker:dind`)

Noudattamalla ohjetta [`docs/docker-engine.md`](https://github.com/gfire-sigs/gvx/blob/main/docs/docker-engine.md) voit ajaa muuttamatonta `docker:dind`-konttia `rungv`-ajoympäristössä Windowsissa, macOS:ssä tai Linuxissa ja hallita sitä isäntäkoneen `docker`-komentorivityökalulla:

```sh
# 1. Luo isäntäkoneen hakemisto välitetylle Unix-socketille
mkdir -p ~/.gvx

# 2. Käynnistä docker:dind gvx-hiekkalaatikossa ext4lite-volyymillä
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
```

Toisessa päätteessä ohjaa isäntäkoneen `docker`-komentorivityökalu hiekkalaatikon socketiin:

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

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

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

### 2. Kubernetesin (`k3s` + `Calico`) ajaminen oikeudettomissa hiekkalaatikoissa

Koska `gvx` toteuttaa `/dev/kmsg`-laitteen, `cgroup` v2:n (`memory.max`-OOM-tappajan ja `cpu.max`-kaistanleikkauksen), `/proc/diskstats`-tiedoston, `wireguard`- ja `vxlan`-netlink-laitteet, `ipset`-toiminnon sekä `iptables-legacy`-toiminnon (`addrtype`, `conntrack`, `statistic`, `recent`), muuttamaton `rancher/k3s`-kuva saavuttaa tilan `Ready` yhden `rungv`-prosessin sisällä:

```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
```

Voit myös liittää useita `gvx`-solmuja WireGuardin kautta (`flannel-backend=wireguard-native` tai `wg0`-verkkomuodostelma) upotetulla `etcd`-korkean saatavuuden kokoonpanolla tai ajaa **Calico**-verkkoa (`calico-vxlan.yaml` asetuksella `FELIX_IPTABLESBACKEND=Legacy`) Kubernetesin `NetworkPolicy`-säännöjen täysimittaiseksi noudattamiseksi kokonaan käyttäjätilassa.

### 3. Linux-konttien upottaminen Go-ohjelmaan `z.gfire.dev/gvx/pkg/gvx`-paketin kautta

Go-sovellukset voivat upottaa Linux-kontteja suoraan ilman ulkoista konttidaemonia:

```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)
}
```

---

## Lisälukemista tästä sarjasta

1. **[gvx: Linux-konttien, Dockerin ja Kubernetesin ajaminen yhdessä oikeudettomassa prosessissa](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)** (tämä kirjoitus)
2. **[Docker-, docker build- ja docker compose -komentojen ajaminen ilman juurioikeuksia tai käyttäjänimiavaruuksia](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)**: Miten `docker:dind` käynnistetään lukituissa hiekkalaatikoissa, joissa `sudo`, `unshare(CLONE_NEWUSER)`, `mount(2)` ja `/dev/fuse` on estetty.
3. **[Docker-in-Docker gVisorin ja sisäkkäisten hiekkalaatikoiden sisällä gvx-työkalulla](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: Miksi `apt-get install docker.io` ja sisäkkäinen `runsc` epäonnistuvat `gVisorin` sisällä viiden ytimen esteen takia ja miten `gvx` ajaa sisäkkäistä `docker:dind`-ympäristöä jaetun muistin futex-silmukan avulla.
4. **[Nopeat eristetyt Docker-ympäristöt AI-agenttien RL-suorituksiin gvx-työkalulla](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: `SWE-bench`- ja agenttien vahvistusoppimisen suoritusten skaalaaminen sadoilla rinnakkaisilla oikeudettomilla `docker:dind`-instansseilla ja 100 millisekunnin kopioi-kirjoita-tilaan perustuvilla `.ext4`-volyymien nollauksilla.
