---
id: e62d78ef5850c982dbddc9d3ff9134ae
author: Lemon Mint
title: 'gvx: 1つのUnprivileged Processで Linux Containers、Docker、Kubernetes を実行する'
description: gvxの技術概要：gVisorユーザー空間カーネルを基盤とする、セキュリティ強化されたクロスプラットフォーム対応のコンテナランタイムおよびGo SDKであり、Linuxコンテナ、Docker-in-Docker、そして複数ノードによる高可用性（HA）Kubernetesを、Windows、macOS、Linuxの各環境において、単一の非特権プロセス内で安全に実行します。
language: ja
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
---

## はじめに: root もホストデーモンも使用しないセキュリティ強化コンテナ

開発マシン、CI ランナー、またはマルチテナントのクラウドノード内で Linux コンテナ、`docker build`、または Kubernetes を実行する場合、通常は次のような不都合なセキュリティ上のトレードオフを強いられる:

- **Linux** では、標準的な OCI ランタイム（`runc`、`crun`、`runsc`）は、`root` 権限、ホストの `/var/run/docker.sock` の公開、`--privileged`（`CAP_SYS_ADMIN`）、またはホストのカーネル攻撃対象領域を拡大させるユーザー名前空間（`unshare(CLONE_NEWUSER)`）のいずれかを必要とする。
- **Windows** および **macOS** では、コンテナエンジン（`Docker Desktop`、`Podman Machine`、`Lima`、`OrbStack`）は、WSL2、Hyper-V、または `Virtualization.framework` 内で完全な Linux 仮想マシンカーネルを起動し、その VM 内で永続的なバックグラウンドデーモンを実行する。

**[gvx](https://github.com/gfire-sigs/gvx)**（`rungv` CLI および `z.gfire.dev/gvx/pkg/gvx` Go SDK）は、**安全でゼロ特権の代替手段**を提供する。Google の **gVisor** のユーザー空間 Linux カーネル（`Sentry`）およびユーザー空間ネットワークスタック（`netstack`）の、アップストリームに追従可能なフォークとして構築された `gvx` は、Windows、macOS、Linux 上の**単一の非特権かつ自己ロックされたホストプロセス内**で、変更されていない `linux/amd64` および `linux/arm64` の ELF64 バイナリおよび OCI コンテナを直接実行する。

> **セキュリティ保証（三重リング多層防御）**: `gvx` はホスト OS のセキュリティ境界を弱めることは決してなく、カーネルドライバをインストールすることもなく、ホスト上で `root`、`sudo`、`--privileged`、または `CLONE_NEWUSER` を必要とすることも決してない。ゲスト命令を1つも実行する前に、`gvx` は自身のホストプロセスを、Windows Restricted Tokens と Job Objects、macOS Seatbelt（`deny default`）、または Linux の `PR_SET_NO_NEW_PRIVS` と BPF `seccomp` を用いてロックダウンする。すべてのゲストシステムコール、仮想 `UID 0` 権限、マウント（`VFS2`）、およびネットワークテーブル（`netstack`）は、メモリ安全な Go 言語製の `Sentry` カーネル内に厳密に閉じ込められる。

| ランタイム                 | ホスト OS                                             |   コールドスタート | メモリフットプリント | 管理者権限または `sudo` の必要性 | バックグラウンド VM デーモン | OCI イメージの直接実行 |
| :------------------------- | :---------------------------------------------------- | -----------------: | -------------------: | :------------------------------- | :--------------------------- | :--------------------- |
| **`gvx` (`whpx` / `hvf`)** | Windows (`amd64`, `arm64`) & macOS (`arm64`)          |          `~20 ms` |        `~30 MiB` | いいえ                           | いいえ                       | はい                   |
| **`gvx` (`systrap`)**      | Windows (`amd64`, `arm64`) & Linux (`amd64`, `arm64`) |    `~25 to 65 ms` |        `~31 MiB` | いいえ                           | いいえ                       | はい                   |
| **WSL2 / Docker Desktop**  | Windows & macOS                                       |  `800 to 2500 ms` |      `> 512 MiB` | はい（初回セットアップ時）       | はい                         | デーモンが必要         |
| **QEMU (Full System)**     | Windows & macOS                                       | `1500 to 4000 ms` |      `> 256 MiB` | いいえ                           | いいえ                       | ディスクイメージが必要 |

Windows および macOS 上で Linux VM カーネルは起動しない。ホスト上でバックグラウンドデーモンは実行されない。ホスト OS において、`root`、`sudo`、ユーザー名前空間（`CLONE_NEWUSER`）、`mount(2)`、`TUN`/`TAP` ドライバ、または `CAP_NET_ADMIN` 権限は一切必要としない。その非特権プロセス内で、`gvx` は **Docker-in-Docker（`docker:dind`）**、`docker build`、`docker compose`、および**多ノード構成の高可用性 Kubernetes（埋め込み `etcd` と `Calico` CNI を備えた `k3s`）**を実行する。

---

## コンテナのライフサイクルと三重リングによるホストロックダウン

すべての `gvx` サンドボックスは1つの非特権ホストプロセス内で実行され、3段階のライフサイクルを適用する。すなわち、必要なすべてのホストファイルディスクリプタおよびソケットの事前オープン、`pkg/hostlockdown` によるホスト OS プロセスのロックダウン、そしてプロセス内の `Sentry` 実行ループへの移行である。

![gvx コンテナのライフサイクルとホスト自己ロックダウン](/assets/images/gvx/gvx-lifecycle-lockdown.png)

最初のゲスト命令へ制御を移す前に、`gvx` はキャッシュ済みの `.erofs` イメージレイヤーのディスクリプタ、`.ext4` ボリュームのファイルディスクリプタ、`/workspace` の `*os.Root` ハンドル、およびホストのネットワークソケットを事前にオープンし、その後 `hostlockdown.Apply()` を呼び出す:

1. **Windows NT（`lockdown_windows.go`）**: `AdjustTokenPrivileges` を `SE_PRIVILEGE_REMOVED` とともに呼び出して権限をその場で剥奪し、Low 整合性レベル（`S-1-16-4096`）の `DISABLE_MAX_PRIVILEGE` 制限付き偽装トークンを割り当て、プロセスを `JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1` を設定した無名の Job Object に割り当てて（子プロセスの生成をすべてブロックする）、`SetProcessMitigationPolicy` を介して `DisallowWin32kSystemCalls = 1` を有効化する。
2. **macOS XNU（`lockdown_darwin.go`）**: `RLIMIT_NPROC = 0` を設定し、`(version 1)(deny default)` から始まり `process-fork`、`process-exec*`、およびすべての新規ホストファイルオープンをブロックする Seatbelt プロファイル（`sandbox_init_with_parameters`）を適用する。
3. **Linux（`lockdown_linux.go` + `pkg/gvx/syscallfilter_linux.go`）**: `PR_SET_NO_NEW_PRIVS` を設定し、すべてのスレッドに対して（`SECCOMP_FILTER_FLAG_TSYNC`）Sentry の BPF `seccomp` 許可リストを導入し、`execve`、`execveat`、`clone`、`openat`、`socket` に対して明示的な `EPERM` ルールを設ける。

---

## クロスプラットフォームのシステムコール傍受と 4 KB ページング（`pkg/sentry/platform`）

Linux の ELF64 バイナリは、`mmap(MAP_FIXED)` によるセグメントマッピングにおいて、4 KB（`0x1000`）のメモリページ粒度を前提とする。しかしながら、Windows の `VirtualAlloc` および `MapViewOfFile3` は 64 KB（`0x10000`）のアライメントを強制し、Apple Silicon の macOS（`darwin/arm64`）は 16 KB（`0x4000`）のホストページを使用する。さらに、各 OS は、Linux VM を起動することなく、Linux の `SYSCALL`（`amd64`）および `SVC #0`（`arm64`）命令を傍受するために、それぞれ異なるメカニズムを必要とする。

`gvx` は、`pkg/sentry/platform.Context` を実装する4つの実行バックエンドを通じて、これら両方の問題を解決する:

![gvx プラットフォームのシステムコール傍受と 4KB ページングの仕組み](/assets/images/gvx/gvx-platform-syscalls.png)

### 1. Windows ハードウェアエンジン: `platform/whpx`（`WinHvPlatform.dll`）

`windows/amd64` および `windows/arm64` 上では、`platform/whpx` がゲスト OS カーネルを起動することなく、`WHvCreatePartition` を介して軽量なハイパーバイザパーティションを作成する:

- **64 KB から 4 KB へのページングデカップラ**: `whpx` は、`pgalloc.MemoryFile` の各 64 MiB アリーナを、`WHvMapGpaRange` を介して一度だけパーティションに登録する。その後の `MapFile` および `Unmap` の呼び出しは、パーティション内のゲストページテーブルのみを変更し、Windows の 64 KB 割り当て粒度にもかかわらず、正確な 4 KB 単位の `R/W/X` 権限を強制する。
- **`CommPage` を介したゼロ API のレジスタ交換**:
  - `amd64` では、ゲストの Ring-3 `SYSCALL` がパーティション内の Ring-0 `MSR_LSTAR` スタブ（`stubgen_x86.go`）に入る。このスタブは高速パスのシステムコール用 GPR（`RAX, RDI, RSI, RDX, R10, R8, R9, RIP, RSP`）を共有の 4 KB `CommPage` に退避させ、`HLT` を実行して `WHvRunVirtualProcessor` から脱出する。
  - `arm64` では、ゲストの EL0 `SVC #0` が EL1 ベクタ（`stubgen_a64.go`）に入り、`X0..X8, SP_EL0, ELR_EL1, PSTATE` を `CommPage` に退避させ、バックされていない GPA ゼロからロードすることでメモリ例外を発生させ、Sentry へ戻る。

### 2. macOS ハードウェアエンジン: `platform/hvf`（`Hypervisor.framework`）

Apple Silicon（`darwin/arm64`）上では、`platform/hvf` が `Hypervisor.framework` の vCPU（`hv_vm_create`、`hv_vcpu_run`）内でコンテナのスレッドを実行する:

- **2段階の 4 KB over 16 KB MMU 変換**: Stage-2（`hv_vm_map`）は、1 GiB のメモリファイルチャンクを、`HV_MEMORY_READ | HV_MEMORY_WRITE | HV_MEMORY_EXEC` を伴い、16 KB のホストページ粒度で中間物理アドレス（IPA）空間へ一度だけマップする。vCPU 内では、EL1 の `bluepill` スタブ（`bluepill_arm64.go`）が `TTBR0_EL1` において `TCR_EL1.TG0 = 0b00`（4 KB granule）を設定し、正確な `R-X` または `RW-`（`UXN=1`）権限を持つ 4 KB の Stage-1 ページテーブルエントリを配置する。ARM64 MMU は Stage-1 と Stage-2 の権限の共通部分を強制するため、ハードウェアは正確な 4 KB 境界で権限フォルトをトラップする。
- **システムコールのトラップ**: ゲストの EL0 `SVC #0` は EL1 の `VBAR_EL1` へトラップし、レジスタを共有 4 KB `CommPage` に退避させ、`HVC #0` を実行して `hv_vcpu_run` から Go の Sentry スレッドへ戻る。

### 3. Windows ユーザーモードフォールバック: `platform/systrap`（`winsystrap`）

ハードウェア仮想化が利用できない場合（ネストされたクラウド VM 内など）、`winsystrap` は `windows/amd64` および `windows/arm64` 上でユーザーモードにおいてゲストコードを実行する:

- **ハードウェアの `CR3` / `TTBR0_EL1` 分離**: ゲストスレッドは、生成された 1 KB の実行可能ファイル（`stubimage_xplat.go`）から起動された隔離されたスタブサブプロセス内で実行され、Low 整合性トークンおよび Job Object によって閉じ込められる。
- **その場でのバイナリパッチングと `winSysmsg` IPC**: `amd64` では、パッチャ（`patcher_amd64_xplat.go`）が2バイトの `syscall`（`0f 05`）命令を、5バイトの `jmp rel32` ジャンプ（5バイトの領域が利用できない場合は `CC 90` ブレークポイントトラップ）に置き換え、高速パスのアイランドへ飛ばす。`arm64` では、`svc #0` がアイランドスロットへの `B` 分岐にパッチされる。アイランドは共有 `winSysmsg` ページにレジスタを退避させ、`WaitOnAddress` および `WakeByAddressSingle` を介して Sentry と同期する。一方、パッチされていないトラップおよびページフォルトは Windows Debug Object（`WaitForDebugEventEx`）上で停止する。

### 4. Linux ユーザーモードエンジン: `platform/systrap`

`linux/amd64` および `linux/arm64` 上では、`systrap` は、`SECCOMP_RET_TRAP`（`SIGSYS`）を介してゲストのシステムコールをトラップし、`syscall` 箇所を `SYS_FUTEX` によって同期される共有メモリのトランポリン（`sysmsg`）へバイナリパッチするゲストスレッド（`sysmsg`）を実行する。一方、スタブである `syscallThread`（`syscall_thread.go`）は、`SECCOMP_RET_USER_NOTIF`（`_RUN_SECCOMP_LOOP`）を介してアドレス空間の操作（`mmap`、`munmap`、`clone`）を実行する。`gvx` が、単一の `SECCOMP_FILTER_FLAG_NEW_LISTENER` スロットが `EBUSY` を返す外側の `gVisor`（`runsc`）サンドボックス内で実行される場合、`gvx` は自動的に `syscallThread` を共有メモリのフュテックスループ（`_RUN_SYSCALL_LOOP`）へ切り替える。詳細は[本シリーズの第3部](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)で述べる。

---

## gvx がゲストの Linux システムコールを仮想サブシステムおよびホストハンドルへ対応付ける仕組み

プラットフォームエンジンがゲストの `SYSCALL`（`amd64`）または `SVC #0`（`arm64`）命令をトラップし、ゲストのレジスタを 4 KB の共有ページ（`CommPage`、`sysmsg`、または `winSysmsg`）に書き込むと、制御は Go の `Sentry` タスクゴルーチン（`pkg/sentry/kernel/task_syscall.go`）へ戻る。Linux のシステムコールを基盤となるホスト OS カーネルへ転送する代わりに、`Task.doSyscall()` は元のレジスタ状態（`SyscallSaveOrig()`）を保存し、ゲスト内の BPF `seccomp` フィルタおよび `ptrace` 停止を評価した上で、`linux.AMD64` または `linux.ARM64`（`pkg/sentry/syscalls/linux/linux64.go`、約370個の Linux システムコールを網羅）を通じてシステムコール番号を発送し、4つの内部ドメインへ振り分ける:

![gvx がゲストの Linux システムコールをサブシステムおよびホスト OS へ対応付ける仕組み](/assets/images/gvx/gvx-syscall-mapping.png)

| システムコールドメイン | 代表的なゲスト Linux システムコール | 内部 `gvx` サブシステム（`pkg/sentry`） | ホスト OS 境界との相互作用（`hostlockdown` 適用後） |
| :--- | :--- | :--- | :--- |
| **A. プロセス、名前空間、マウント、同期** | `clone`, `execve`, `unshare`, `setns`, `mount`, `umount2`, `pivot_root`, `setuid`, `capset`, `futex`, `epoll_wait`, `pipe2` | `kernel.Task`、仮想資格情報、フュテックステーブル、およびインメモリの `VFS2`（`procfs`、`sysfs`、`cgroupfs` v2、`tmpfs`、`overlayfs`） | **ホストへのシステムコールはゼロ**（100% インメモリの Go 状態であり、ホスト OS からは完全に不可視） |
| **B. 仮想メモリ（`MM`）** | `mmap`, `munmap`, `mremap`, `mprotect`, `brk`, `madvise`, `memfd_create` | `mm.MemoryManager`（4 KB VMA ツリー）および `pgalloc.MemoryFile` | `WHvMapGpaRange`、`hv_vm_map` + `TTBR0_EL1`、またはスタブの `mmap`/`mprotect` を介した双方向の 4 KB ページテーブル更新 |
| **C. ファイルおよびストレージ（`VFS2`）** | `openat`, `pread64`, `pwrite64`, `getdents64`, `statx`, `renameat2`, `setxattr`, `mknod`, `inotify_add_watch` | `vfs.VirtualFilesystem` のマウントテーブルルーター（`fsimpl/erofs`、`fsimpl/ext4lite`、`fsimpl/hostfs` v2） | 1つの固定された `.erofs` FD または1つの `.ext4` FD に対する双方向の `pread`/`pwrite`、もしくは `*os.Root` 上の範囲限定された相対走査 |
| **D. ネットワークおよび Netfilter** | `socket`, `bind`, `listen`, `connect`, `sendmsg`, `recvmsg`, `netlink`, `setsockopt(IPT_SO_SET_REPLACE)` | ユーザー空間の `pkg/tcpip`（`lo`、`eth0`、`docker0`、`veth`、`vxlan`、`wireguard`、`ipset`、`iptables-legacy`） | サンドボックス内のトラフィックはホストへのシステムコールをゼロとして処理され、外部トラフィックは `net.Dial`/`net.Listen`（`-net=nat`）または1つの UDP ソケット（`-net=wg`）に対応付けられる |

ハンドラが `(rval, ctrl, err)` を返すと、`Task.doSyscallInvoke()` は任意のエラーを負の Linux `errno`（`-ExtractErrno(err, sysno)`）に変換し、戻り値を共有レジスタページ（`amd64` では `RAX`、`arm64` では `X0`）に書き戻し、ゲストの実行を再開する。

---

## ストレージ（`VFS2`）およびデュアルトラックのユーザー空間ネットワーク（`netstack`）

ゲストのすべてのファイルおよびネットワーク操作は、3つの `VFS2` ファイルシステムと2つの `pkg/netbackend` トラックを通じて、Go の `Sentry` 内で処理される:

![gvx VFS2 ストレージエンジンとデュアルトラック netstack](/assets/images/gvx/gvx-storage-netstack.png)

| ストレージエンジン | gvx におけるマウントの役割 | 背後のホストリソース | 実行時のホストにおける `openat` / `NtCreateFile` 呼び出し | Windows Defender（`WdFilter.sys`）によるファイル単位のスキャン |
| :--- | :--- | :--- | ---: | ---: |
| **`fsimpl/erofs`** | 読み取り専用の OCI イメージ下位レイヤー | レイヤーごとに単一の `<sha256>.erofs` ファイル | `0` | `0` |
| **`fsimpl/ext4lite`** | 名前付きボリューム（`-v name:/path`） | ボリュームごとに単一の `<name>.ext4` ファイル | `0` | `0` |
| **`fsimpl/hostfs` v2** | ホストのワークスペース（`-workspace`、`-v /host:/guest`） | 固定された `*os.Root` ホストディレクトリ | キャッシュされていない open ごとに `O(depth)` | ホストファイルのクローズごとに `1` |

### Docker、データベース、およびパッケージマネージャにおいて `ext4lite` が重要である理由

数万にのぼるコンテナファイルを Windows NTFS または macOS APFS へ直接展開または書き込むと、アンチウイルスのミニフィルタによるスキャン（`WdFilter.sys`）、大文字小文字の区別による衝突、および POSIX 拡張属性の欠落が発生する。

`pkg/sentry/fsimpl/ext4lite` は、事前にオープンされた1つのホストファイル（Windows では `%LOCALAPPDATA%\gvx\cache\volumes\<name>.ext4`、macOS では `~/Library/Caches/gvx/volumes/<name>.ext4`、Linux では `~/.cache/gvx/volumes/<name>.ext4`）内に、純粋な Go 言語による `ext4` ファイルシステムを実装し、以下の機能を備える:

- **4 KiB ブロックおよび 16 MiB の動的ブロックグループ（`meta_bg`）**: スパースファイルの割り当て停止を伴わずに動的に拡張し（Linux では `fallocate`、macOS では `fcntl(F_PREALLOCATE)`、Windows では `FileAllocationInfo`）、クリーンなアンマウント時に未使用の末尾グループを圧縮する。
- **JBD2 ordered-mode ジャーナル（inode 8）**: CRC-32 チェックサムおよび revoke ブロックを伴う原子的なトランザクションのコミットに加え、`fsckLite` による回復を備える。
- **`overlayfs` のアッパーレイヤー対応**: `trusted.overlay.*` および `security.capability` の拡張属性、キャラクタデバイスのホワイトアウト（`0:0`）、`d_type` によるディレクトリエントリの報告、および `RENAME_EXCHANGE` を実装する。

---

## 実用的なワークロード：Docker Engine、Kubernetes（`k3s` + `Calico`）、および Go SDK

### `rungv` のインストール：SLSA 認証済みのビルド済みリリースまたは `go install`

`linux/amd64`、`linux/arm64`、`darwin/arm64`、`windows/amd64`、または `windows/arm64` 向けのビルド済み `rungv` アーカイブは [GitHub Releases](https://github.com/gfire-sigs/gvx/releases) からダウンロードできる（各アーカイブは SLSA リリースパイプラインによってビルドされ、Sigstore の provenance バンドルおよび `SHA256SUMS` を伴う）。あるいは、`go install` によってソースから直接インストールすることもできる:

```sh
# オプション A：ビルド済みリリースをダウンロードし、SLSA ビルドの provenance を検証する
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

# オプション B：Go を介して直接インストールする（Linux / Windows）
CGO_ENABLED=0 go install z.gfire.dev/gvx/cmd/rungv@latest
```

> macOS（`darwin/arm64`）では、ビルド済みリリースのアーカイブは既に `com.apple.security.hypervisor` エンタイトルメントで署名されている（`xattr -d com.apple.quarantine rungv` によりブラウザの隔離属性が解除される）。macOS 上で `go install` または `go build` によってローカルでビルドする場合は、`codesign --sign - --entitlements entitlements.plist --force $(which rungv)` でバイナリに署名すること。

### 1. 非特権 Docker Engine（`docker:dind`）の実行

[`docs/docker-engine.md`](https://github.com/gfire-sigs/gvx/blob/main/docs/docker-engine.md) に従うことで、Windows、macOS、または Linux 上の `rungv` 内で変更されていない `docker:dind` コンテナを実行し、ホストの `docker` CLI から制御できる:

```sh
# 1. 転送される Unix ソケット用のホストディレクトリを作成する
mkdir -p ~/.gvx

# 2. ext4lite ボリュームを伴う gvx サンドボックス内で docker:dind を起動する
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
```

2つ目のターミナルで、ホストの `docker` CLI をサンドボックスのソケットに向ける:

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

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

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

### 2. 非特権サンドボックスにおける Kubernetes（`k3s` + `Calico`）の実行

`gvx` が `/dev/kmsg`、`cgroup` v2（`memory.max` による OOM killer および `cpu.max` による帯域制限）、`/proc/diskstats`、`wireguard` および `vxlan` の netlink デバイス、`ipset`、ならびに `iptables-legacy`（`addrtype`、`conntrack`、`statistic`、`recent`）を実装しているため、変更されていない `rancher/k3s` イメージは、単一の `rungv` プロセス内で `Ready` に到達する:

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

埋め込み `etcd` による高可用性構成で、複数の `gvx` ノードを WireGuard（`flannel-backend=wireguard-native` または `wg0` メッシュ）を介して結合することもできる。あるいは、**Calico**（`FELIX_IPTABLESBACKEND=Legacy` を伴う `calico-vxlan.yaml`）を実行し、Kubernetes の `NetworkPolicy` をユーザー空間内で完全に適用することもできる。

### 3. `z.gfire.dev/gvx/pkg/gvx` を介した Go への Linux コンテナの埋め込み

Go アプリケーションは、外部のコンテナデーモンを必要とせずに、Linux コンテナを直接埋め込むことができる:

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

---

## 本シリーズのさらなる読書案内

1. **[gvx: 1つの非特権プロセスで Linux コンテナ、Docker、および Kubernetes を実行する](/blog/posts/gvx-cross-platform-linux-containers-z48916d01)**（本記事）
2. **[root またはユーザー名前空間を用いずに Docker、docker build、および docker compose を実行する](/blog/posts/run-docker-without-root-or-userns-gvx-z48916d02)**: `sudo`、`unshare(CLONE_NEWUSER)`、`mount(2)`、および `/dev/fuse` がブロックされたロックダウン済みのサンドボックスにおいて、`docker:dind` をブートストラップする方法。
3. **[gvx を用いた gVisor およびネストされたサンドボックス内での Docker-in-Docker の実行](/blog/posts/docker-in-docker-inside-gvisor-with-gvx-z48916d03)**: `apt-get install docker.io` およびネストされた `runsc` が、`gVisor` 内で5つのカーネル上の障壁によりなぜ失敗するのか、また `gvx` がどのようにして共有メモリのフュテックスループを用いてネストされた `docker:dind` を実行するのかについて。
4. **[gvx を用いた AI エージェントの RL ロールアウトのための高速な隔離 Docker 環境](/blog/posts/fast-docker-environments-for-agent-rl-rollouts-z48916d04)**: 数百の並列な非特権 `docker:dind` インスタンスおよび100ミリ秒のコピーオンライト `.ext4` ボリュームリセットを用いて、`SWE-bench` およびエージェントの強化学習ロールアウトを拡張する。
