Hyper's native API is BEAM-native (Elixir/Erlang processes calling Hyper.*).
The gRPC interface puts that same machine lifecycle behind a language-agnostic
contract, so consumers in any language -- and off-BEAM services -- can
create, stop, locate, and list microVMs.
v0 -- unstable. The contract may change without notice during early development. Pin to a commit if you depend on it.
No authentication
The gRPC API has no authentication. Any client that can reach the port can
create and stop VMs and load images. It is off by default (grpc.enabled = false). When you enable it, bind it to loopback or a trusted network, or put
it behind a proxy that terminates TLS and authenticates callers. TLS (cred)
encrypts the channel but does not authenticate the client. Authentication is
planned for a later release; the v0 contract is UNSTABLE.
Configuration
By default, the gRPC interface is disabled. The simplest way to enable it
is the [grpc] table of /etc/hyper/config.toml:
[grpc]
enabled = true
port = 50051
cred = { cert = "/path/to/cert.pem", key = "/path/to/key.pem" }Alternatively, configure Hyper.Cfg.Grpc from Elixir — in the operator config
file /etc/hyper/config.exs (loaded at runtime), or in your own application's
config/runtime.exs when you embed Hyper as a dependency. Application env
takes precedence over the TOML table:
config :hyper, Hyper.Cfg.Grpc,
enabled: true,
port: 50_051,
cred: GRPC.Credential.new(
ssl: [certfile: "/path/to/cert.pem", keyfile: "/path/to/key.pem"]
)Omit cred to serve plaintext gRPC.
No authentication
The gRPC API currently has no authentication or authorization: any
client that can reach the port has full VM lifecycle control (create, stop,
load images). TLS (cred) encrypts the transport but does not
authenticate callers. Only enable the interface on a network you trust —
bind it to a private interface or firewall the port so that just your own
services can reach it.
Client Usage
With Hyper running, you can create a new gRPC client in your favorite
language. We will be using Python here:
import grpc
from google.protobuf import empty_pb2
from hyper.grpc.v0 import hyper_pb2, hyper_pb2_grpc
# Plaintext. For TLS, pass grpc.ssl_channel_credentials(ca_pem) to
# grpc.aio.secure_channel(...) instead.
client = hyper_pb2_grpc.HyperStub(grpc.aio.insecure_channel("localhost:50051"))Loading Images
Before you can create a VM you need an image in the cluster. LoadImage pulls an
OCI image, builds its rootfs, and records it -- returning the img_id you pass to
CreateVm. It blocks until the load finishes (this can take minutes), so set a
generous deadline.
loaded = await client.LoadImage(
hyper_pb2.LoadImageRequest(
image_ref="docker.io/library/alpine:3.19",
# label is optional; defaults to image_ref.
)
)
print(loaded.img_id) # pass this to CreateVmCreating VMs
You can create new VMs with the CreateVm RPC.
created = await client.CreateVm(
hyper_pb2.CreateVmRequest(
img_id=loaded.img_id,
instance_type=hyper_pb2.INSTANCE_TYPE_DECI,
arch=hyper_pb2.ARCHITECTURE_X86_64,
# boot_args is optional; omit it for the default kernel cmdline.
)
)
print(created.vm_id, created.node)Listing VMs
You can list running virtual machines with ListVms, which takes a
google.protobuf.Empty:
listed = await client.ListVms(empty_pb2.Empty())
for vm in listed.vms:
print(vm.vm_id, vm.node)Getting VM Info
You can query a VM with GetVm, which returns the node it runs on:
info = await client.GetVm(hyper_pb2.GetVmRequest(vm_id=created.vm_id))
print(info.vm_id, info.node)Reading VM Usage
You can read a VM's metered compute with GetVmUsage. It reports the
cumulative CPU time the VM has actually executed — measured from its
cgroup, so an idle VM accrues (almost) nothing. This is the counter to bill
on: compute performed, not compute allocated. Stopped VMs report their
recorded lifetime total. A VM that never accrued any compute (for example,
created and stopped while fully idle) has no recorded usage and returns
NOT_FOUND.
usage = await client.GetVmUsage(hyper_pb2.GetVmUsageRequest(vm_id=created.vm_id))
print(f"{usage.vm_id} consumed {usage.cpu_usec / 1e6:.2f} CPU-seconds")Under the hood, usage is persisted once a minute as append-only windows in
the vm_usage Postgres table (vm_id, window_start, window_end,
cpu_usec), so billing pipelines can also aggregate ranges with SQL directly.
Stopping a VM
You can stop a running VM with StopVm, which returns a
google.protobuf.Empty:
await client.StopVm(hyper_pb2.StopVmRequest(vm_id=created.vm_id))For full documentation, please read the documentation in the
.proto
file.