
2026/04/21 6:13
Show HN: Holos –QEMU/KVM を、Compose スタイルの YAML ファイル、GPU の利用、そしてヘルスチェック機能を備えた形で提供するプロジェクトです。
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
KVM 用の Docker Compose は、複雑な libvirt XML や Kubernetes コントロールプレーンの代わりに軽量な YAML ファイルを使用して、単一のホスト上で複数の VM を管理するための簡素化された方法を提供します。
holos.yaml ファイル内の単純なプリミティブ(レプリカ、バインドマウント、命名ボリュームなど)で完全に VM スタックを定義し、そこでサービス(イメージ、vCPU、メモリ)、cloud-init 構成、および依存関係を指定します。主要な CLI コマンドには holos up、holos down、holos ps、holos install/uninstall、SSH キーが自動的に生成される holos exec、holos images、および既存の libvirt ドメインを転換するための holos import が含まれます。サービスは QMP system_powerdown を使用したグレースフルシャットダウンをサポートし、SIGTERM/SIGKILL にフォールバックすることで対応します。また、VFIO を介した GPU パススルーをサポートしており、ホストの IOMMU および適切な BIOS/UEFI 設定と PCI バインディングが必要になります。ネットワーク機能は、ルートまたは手動ブリッジ構成を必要とせず、ソケットマルチキャストを使用して内部の 10.10.0.0/24 セグメント上で名前での VM 間通信を可能にします。人気のあるディストリビューション向けのビルトインイメージが自動的に引き出され、キャッシュされます。Dockerfile を使用して VM のプロビジョニングを行え、RUN/COPY/ENV 指示は cloud-init を介して実行されるシェルスクリプトへと変換されます。任意の QEMU 引数は extra_args フィールドを通じてサポートされます。ランタイムは Linux(/dev/kvm を必要とする)をターゲットとしており、macOS は validate および import のようなオフラインサブコマンドをサポートします。リリースは GoReleaser を使用して Git タグに基づいてビルドされ、Linux/macOS amd64/arm64 へのクロスコンパイルおよび SHA-256 チェックサムが実装されています。本文
Docker Compose 形式による KVM: はじめに
複数の仮想マシン(VM)のスタックを、libvirt や XML、分散制御プレーンを使用せず、単一の YAML ファイルで定義します。基本単位はコンテナではなく、すべてのワークロードインスタンスに対して独自のカーネル境界、独自の qcow2 オーバーレイ、そして独自の cloud-init シードを提供する「仮想マシン」が採用されています。
クイックスタート
holos.yaml を作成します:
name: my-stack services: db: image: ubuntu:noble vm: vcpu: 2 memory_mb: 1024 cloud_init: packages: - postgresql runcmd: - systemctl enable postgresql - systemctl start postgresql web: image: ubuntu:noble replicas: 2 depends_on: - db ports: - "8080:80" volumes: - ./www:/srv/www:ro cloud_init: packages: - nginx write_files: - path: /etc/nginx/sites-enabled/default content: | server { listen 80; location / { proxy_pass http://db:5432; } } runcmd: - systemctl restart nginx
起動するだけで済みます。これにより、ホスト上の同じ場所で、お互いの名前を使って通信し合う 2 つの Nginx VM と 1 つの PostgreSQL VM が立ち上がります。
コマンドラインインターフェース(CLI)
| コマンド | 説明 |
|---|---|
| すべてのサービスを開始する |
| すべてのサービスを停止および削除する |
| 実行中のプロジェクトをリストする |
| 停止中のサービスまたはすべてのサービスを開始する |
| サービスまたはすべてのサービスを停止する |
| インスタンスのシリアルコンソールに接続する |
| プロジェクトが生成したキーを使用して、インスタンス内へ SSH する |
| サービスのログを表示する |
| Compose ファイルを検証する |
| クラウドイメージをプルする(例:alpine, ubuntu:noble) |
| 利用可能なイメージをリストする |
| PCI デバイスおよび IOMMU グループをリストする |
| プロジェクトが再起動後も存続するように、systemd ユニットを生成する |
| で作成された systemd ユニットを削除する |
| virsh 定義済み VM を holos.yaml に変換する |
Compose ファイル構成
holos.yaml の形式は意図的に docker-compose と類似しています:
- services: 各サービスは、独自のイメージ、リソース、および cloud-init 設定を持つ VM です。
- depends_on: サービスは依存関係の順序に従って起動します。
- ports:
シNTAX を使用し、レプリカ間では自動増番されます。"ホスト:ゲスト" - volumes: バインドマウントには
、トップレベルの名前付きボリュームには./source:/target:ro
を使用します。name:/target - replicas: サービスを N インスタンス実行します。
- cloud_init: パッケージ、write_files、runcmd — 標準的な cloud-init の機能です。
- stop_grace_period: ACPI シャットダウン後に SIGTERM/SIGKILL を発行するまでの待ち時間(例:
、"30s"
);デフォルトは 30s です。"2m" - healthcheck: 依存項を制御するためのテスト、interval、retries、start_period、timeout です。
- トップレベルの volumes ブロック:
を実行しても持続する名前付きデータボリュームを宣言します。holos down
例:
name: demo services: db: image: ubuntu:noble stop_grace_period: 60s # ハード停止前に DB バッファをフラッシュする volumes: - pgdata:/var/lib/postgresql volumes: pgdata: size: 20G
データボリューム
トップレベルのボリュームは、
state_dir/volumes/<プロジェクト>/<名前>.qcow2 に存在する命名データストアを宣言し、各インスタンスの作業ディレクトリへのシンボリックリンクとして接続されます。これらは holos down でも生存します — プロジェクトのティアダウンではシンボリックリンクのみが削除され、ベースとなるファイルは決して削除されません。
name: demo services: db: image: ubuntu:noble volumes: - pgdata:/var/lib/postgresql volumes: pgdata: size: 20G
ボリュームは安定したシリアル番号
vol-<名前> を持つ virtio-blk デバイスとして接続され、ゲスト内では /dev/disk/by-id/virtio-vol-pgdata として表示されます。cloud-init は最初の起動時に冪等な mkfs.ext4 と /etc/fstab のフラグメントを実行するため、手動での設定は不要です。
ヘルスチェックと depends_on
ヘルスチェックを備えたサービスは、チェックが通るまで依存項の起動をブロックします。プローブは SSH(
holos exec で使用する同じキー)を使用して実行されます:
services: db: image: postgres-cloud.qcow2 healthcheck: test: ["pg_isready", "-U", "postgres"] interval: 2s retries: 30 start_period: 10s timeout: 3s api: image: api.qcow2 depends_on: [db] # db が健全になるまで待機する
test はリスト(exec フォーマット)または文字列(sh -c でラップされるもの)を受け取ります。実際のプローブをスキップするには HOLOS_HEALTH_BYPASS=1 を設定します — これ是客户環境でゲスト内の SSHD がない場合に便利です。
holos exec
各
holos up は、state_dir/ssh/<プロジェクト>/ 下でプロジェクト固有の SSH キーペアを自動生成し、公開鍵を cloud-init を介して注入します。各インスタンスに対してホストポートが割り当てられ、ゲストのポート 22 へフォワードされるため、以下の操作が可能です:
: インタラクティブなシェルholos exec web-0
: ワンショットコマンドholos exec db-0 -- pg_isready
-u <ユーザー> を指定することでログインユーザーをオーバーライドできます(デフォルトはサービスのカスタム設定の cloud_init.user、または ubuntu)。
再起動時の耐性
ホストが再起動した後にもプロジェクトが復元されるよう、systemd ユニットを生成します:
: ユーザー固有であり、sudo を必要としないholos install --enable
: ログイン前のシステム全体レベルholos install --system --enable
: ユニットを出力し終了するholos install --dry-run
ユーザーユニットは
~/.config/systemd/user/holos-<プロジェクト>.service 下に配置され、システムユニットは /etc/systemd/system/ 下になります。holos uninstall はこれを逆転します(冪等であり、2 回呼び出しても安全です)。
ネットワーキング
各サービスは名前で他のすべてのサービスに到達できます。その裏側では:
- 各 VM は 2 つの NIC を持っています:ユーザモード(ホストポートの転送用)とソケットマルチキャスト(VM 間での L2 通信用)。
- 静的 IP アドレスは、内部
セグメントで自動的に割り当てられます。10.10.0.0/24
は cloud-init を介して填充され、/etc/hosts
、db
、web-0
などすべてが解決されます。web-1- libvirt の使用はありません。ブリッジの設定も不要です。VM 間のネットワーキングに root アクセスは必要ありません。
GPU パススルー
VFIO を介して物理的な GPU(または任意の PCI デバイス)を直接 VM に渡します:
services: ml: image: ubuntu:noble vm: vcpu: 8 memory_mb: 16384 devices: - pci: "01:00.0" # GPU - pci: "01:00.1" # GPU オーディオ ports: - "8888:8888"
holos が担当する処理
- デバイスが存在する場合、UEFI 起動が自動的に有効になります(OVMF ファームウェア)。
- NVIDIA 互換性のためにマシンの
が設定されます。kernel-irqchip=on - 各 VM に独自の EFI 変数ストアを持つよう、インスタンスタイプごとの OVMF_VARS コピーを行います。
- カスタム VBIOS ROM 用のオプションの rom_file
ユーザーが担当する処理(ホストセットアップ)
- BIOS およびカーネルで IOMMU を有効にする(
またはintel_iommu=on
)。amd_iommu=on - GPU を vfio-pci ドライバーにバインドする。
- PCI アドレスと IOMMU グループを探すために
を実行する。holos devices --gpu
イメージ
独自の構築ではなく、事前に用意されたクラウドイメージを使用します:
services: web: image: alpine # 自動プルおよびキャッシュされる api: image: ubuntu:noble # 特定のタグ db: image: debian # デフォルトは debian:12
利用可能なもの:
alpine、arch、debian、ubuntu、fedora。すべてのタグを見るには holos images を実行します。
Dockerfile
VM のプロビジョニングに Dockerfile を使用します。RUN、COPY、ENV、WORKDIR 指令は、cloud-init が実行するシェルスクリプトに変換されます:
FROM ubuntu:noble ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y nodejs npm COPY server.js /opt/app/ WORKDIR /opt/app RUN npm init -y && npm install express
イメージが省略された場合、ベースイメージは Dockerfile の
FROM 行から取得されます。Dockerfile の指令は、すべての cloud_init.runcmd エントリより前に実行されます。
- サポートされているもの:FROM, RUN, COPY, ENV, WORKDIR
- サポートされていない指令(CMD, ENTRYPOINT, EXPOSE など)は静かにスキップされます。
- COPY のソースは Dockerfile のディレクトリ相対で解決され、ディレクトリではなくファイルである必要があります — ディレクトリマウントにはボリュームを使用してください。
追加の QEMU アーギュメント
extra_args を使用して、任意のフラグを直接 qemu-system-x86_64 に渡します:
services: gpu: image: ubuntu:noble vm: vcpu: 4 memory_mb: 8192 extra_args: - "-device" - "virtio-gpu-pci" - "-display" - "egl-headless"
アーギュメントは、holos が管理するすべてのフラグの後に付加されます。検証はありません — あなたの責任です。
リソースデフォルト
| フィールド | デフォルト |
|---|---|
| replicas | 1 |
| vm.vcpu | 1 |
| vm.memory_mb | 512 |
| vm.machine | q35 |
| vm.cpu_model | host |
| cloud_init.user | ubuntu |
| image_format | 拡張子から推測される |
libvirt からインポート
libvirt 下ですでに実行中の VM はありますか?
holos import は libvirt ドメイン XML を読み取り、既存のワークロードを holos へ移動させるためにすべてのフィールドを手入力することなく、同等の holos.yaml を出力します。
holos import web-prod db-prod # `virsh dumpxml` を介して holos import --all -o holos.yaml # 定義されたすべてのドメイン holos import --xml ./web.xml # オフラインで、virsh が不要 holos import --connect qemu:///system api # デフォルトではない libvirt URI
マッピングは、holos に直接相当するフィールドをカバーしています:
| libvirt | holos |
|---|---|
| |
/ | |
| (縮小済み) |
| |
| |
最初の | + |
| |
holos がきれいに変換できないもの — 追加のディスク、ブリッジ NIC、USB パススルー、カスタムエミュレーターなど — は stderr で警告として報告され、
holos up の前に何を見直す必要があるかを知るのに役立ちます。出力は -o を渡すまで標準出力に送出されるため、シェルリダイレクトと相性が良いです(holos import vm > holos.yaml)。
インストール
プリビルトの実行バイナリ(Linux および macOS、amd64 および arm64)は、すべての GitHub リリースに添付されています:
TAG=v0.1.0 curl -L https://github.com/zeroecco/holos/releases/download/$TAG/holos_${TAG#v}_Linux_x86_64.tar.gz \ | sudo tar -xz -C /usr/local/bin holos holos version
または、ソースから構築することもできます(下記参照)。
- Linux だけが実行目標です —
はholos up
および/dev/kvm
を必要とします。qemu-system-x86_64 - macOS のビルドは存在しており、オフラインサブコマンド(
、validate
、import
)がラップトップ上の Compose ファイル作成のために機能します。images
ビルド
go build -o bin/holos ./cmd/holos
リリースの作成
GoReleaser がすべての
v* git タグでリリースを生成します(.github/workflows/release.yml を参照):
git tag -a v0.1.0 -m "v0.1.0" git push origin v0.1.0
このワークフローでは 4 つのターゲットをクロスコンパイルし、LICENSE/NOTICE/README.md と一緒にパッケージ化し、SHA-256 チェックサムを計算し、コミットログからリリースノートドラフトを作成し、GitHub リリースを公開します。
ローカルで公開せずに練習するには:
goreleaser release --snapshot --clean --skip=publish ls dist/
ゲストイメージの構築(mkosi が必要)
ホスト要件
/dev/kvmqemu-system-x86_64qemu-img- cloud-localds、genisoimage、mkisofs のうちの一つ、または xorriso
- mkosi (ベースイメージの構築用のみ)
目的外(Non-Goals)
これは Kubernetes ではありません。解決しようとするものではありません:
- マルチホストクラスタリング
- ライブマイグレーション
- サービスメッシュ
- オーバーレイネットワーク
- スケジューラ、CRD、または制御プレーンのクォーラム
目標は、Kubernetes の運用形状を輸入することなく、シングルホストスタックに対して KVM を機能させることです。
ライセンス
Apache License Version 2.0 に基づいています。帰属については NOTICE を参照してください。