k3s上でxpra + OpenboxのGUI Podを動かす設計
Posted:
k3s上でxpra + OpenboxのGUI Podを動かす設計
k3s 上で一時的な GUI desktop を動かしたい場合、xpra start-desktop と Openbox の組み合わせは小さく始めやすい。
目的は「Kubernetes 上に恒久的な VDI を作る」ではなく、検証用の軽量 desktop を 1 Pod で起動し、browser から操作できるようにすることである。
最小構成
flowchart LR
Browser["Browser"]
Ingress["Ingress or port-forward"]
Service["Service :10000"]
Pod["Pod"]
Xpra["xpra server + HTML5 client"]
Openbox["Openbox session"]
Tmp["emptyDir runtime dirs"]
Browser --> Ingress --> Service --> Pod
Pod --> Xpra --> Openbox
Pod --> Tmp
最初の PoC は次の範囲に絞る。
- 1 namespace
- 1 Deployment
- 1 ClusterIP Service
- HTML5 client
- Openbox session
/tmp、/var/tmp、/run/user/<uid>はemptyDir- audio / GPU / IME は後回し
この範囲なら、resource と security の切り分けがしやすい。
xpraの起動例
distro や xpra version によって option は調整が必要だが、考え方は次のようになる。
xpra start-desktop :100 \
--bind-tcp=0.0.0.0:10000 \
--html=on \
--mdns=no \
--notifications=no \
--webcam=no \
--printing=no \
--pulseaudio=no \
--start=openbox \
--no-daemon
不要な機能は最初から切る。特に audio、webcam、printing は container desktop の初期 PoC では複雑さの割に得るものが少ない。
image方針
最初は自前 image が扱いやすい。
理由:
- xpra、Openbox、Xvfb/Xdummy、font、dbus の依存を把握できる
- root 実行や password 埋め込みの既存 image を避けられる
- arm64 など target architecture を明示できる
- 不要 service を削れる
Debian / Ubuntu 系 image は GUI stack の package が揃いやすい。Gentoo image で揃えることもできるが、PoC では build 時間が長くなり判断が遅れる。
永続化の分け方
GUI Pod で最初に壊れやすいのは writable layer と cache である。
| パス | 推奨 |
|---|---|
/tmp | emptyDir |
/var/tmp | emptyDir |
/run/user/<uid> | emptyDir or memory-backed emptyDir |
| browser cache | emptyDir |
| user profile | 必要になってから PVC |
| downloads | 必要になってから PVC |
NFS PVC に browser cache を置くと、体感が悪くなることがある。永続化すべきものは config、profile、downloaded data であり、cache ではない。
resource設計
軽量 Openbox desktop でも、GUI image は通常の CLI Pod より大きい。
最初は控えめに始め、実測で増やす。
resources:
requests:
cpu: 250m
memory: 512Mi
limits:
memory: 2Gi
containerd の snapshot 展開先が小さい node では、image size と unpack 後サイズも見る。特に k3s の native snapshotter では、GUI 系 image の展開後サイズが効きやすい。
securityContext
初期値は non-root に寄せる。
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true は理想だが、xpra / X11 runtime の書き込み先をすべて tmpfs/PVC に逃がすまでは無理に有効化しなくてよい。
公開経路
初期 PoC は kubectl port-forward が一番安全である。
kubectl -n desktop-lab port-forward svc/xpra-openbox 10000:10000
Ingress 化する場合は、少なくとも次を入れる。
- TLS
- Basic Auth または xpra password auth
- source CIDR allowlist
- WebSocket 用 timeout
- NetworkPolicy
Ingress 側 Basic Auth は xpra image を変えずに前段で認証を置ける。家庭内検証では十分なことが多い。
複数 Web UI を同じ認証基盤で守りたい段階になったら、OIDC + oauth2-proxy などを検討する。
audioとGPUは後回し
audio forwarding は xpra で可能だが、PulseAudio / PipeWire / container device / permission の論点が増える。
GPU も同じで、DRM device、Mesa、権限、host library との整合が必要になる。
最初は software rendering で良い。Openbox と軽量 X11 app の PoC では、画面、keyboard、clipboard、reconnect を先に確認する。
よくある警告
xpra image を小さくすると、optional module の警告が出る。
| 警告 | 意味 | 初期 PoC での扱い |
|---|---|---|
paramiko 不足 | SSH socket upgrade 用 | 不要なら無視 |
uinput 不足 | pointer emulation | XTest fallback でよいことが多い |
python-xdg 不足 | desktop menu / application metadata | 必要になったら追加 |
| dbus helper 不足 | xdg-open や tray 系 | GUI app を増やす段階で検討 |
/run/xpra 作成不可 | system-wide socket dir | user socket に寄せる |
警告を全部消すより、使う機能に必要なものだけ足す方が image を保ちやすい。
GUI Podを重くしないコツ
- desktop environment ではなく window manager から始める
- browser を入れる前に xterm などで xpra の安定性を見る
- audio / webcam / printing / mDNS を切る
- cache は永続 PVC に置かない
- image は digest で検証し、tag cache による取り違えを避ける
- nodeSelector / taint で重い GUI workload の配置先を限定する
GUI Pod は便利だが、cluster の基盤 workload と同じ node に無制限で置くと調査が難しくなる。検証用 namespace と配置制約を分けるのが重要である。