Kibotos

Cluster and service metrics

This page explains how ctrl, node, the E2B gateway, and the Exposure gateway export Prometheus metrics, and how to collect, store, and view them in Grafana.

Overview

Each service can open a metrics listener that serves GET /metrics over plain HTTP in the Prometheus text format. Kibotos does not collect or store these metrics itself: the deployer runs a collector that scrapes them periodically and writes them to its own time series storage.

Besides its own process metrics, ctrl reads the state of the whole cluster when it is scraped: node status and resources, storage pools, Workspace and Volume counts, and in-flight commands.

These metrics are separate from instance metrics storage:

  • Instance metrics storage holds the CPU, memory, and disk readings of each Instance. Nodes and ctrl write them, and the E2B SDK queries them.
  • The metrics on this page describe the service processes and the cluster itself, and a collector scrapes them.

Keep them in separate stores. Do not write these metrics to the instance metrics storage, and do not let the E2B gateway query their store: the two differ in retention, readers, and access permissions.

The collector and the store must be reachable from the Kibotos hosts. Tenants must not reach them: the metrics contain node IDs, cluster size, and error rates.

These metrics may be lost and are not a usage record. Do not base billing, quotas, or any state decision on them.

Listener

ServiceConfigurationReference address
ctrllisten in the [telemetry] section of the configuration file127.0.0.1:18192
nodelisten in the [telemetry] section of the configuration file127.0.0.1:18191
E2B gatewayEnvironment variable KIBOTOS_E2B_TELEMETRY_LISTEN127.0.0.1:18195
Exposure gatewayEnvironment variable KIBOTOS_GW_TELEMETRY_LISTEN127.0.0.1:18197

Each reference port is the service's main port plus 100.

  • Without this configuration, no listener is opened, and an upgrade does not add a port.
  • The listener serves only /metrics, without authentication. Other paths return 404, and methods other than GET and HEAD return 405.
  • On a host, bind to the loopback address so that the collector on the same host scrapes it. In a container, bind to 0.0.0.0 and use a NetworkPolicy so that only the collector can connect to this port. See Kubernetes.
  • If the address is not in host:port form, configuration validation fails and the service does not start. If the port is already in use, the service fails to start and the log names the address. It does not skip the metrics listener and keep running.

Enabling the listener

For ctrl and node, add the following section to the configuration file, with 18192 for ctrl and 18191 for node. The example below is for node:

[telemetry]
listen = "127.0.0.1:18191"

For the two gateways, add a line to the environment file. For the Exposure gateway:

echo 'KIBOTOS_GW_TELEMETRY_LISTEN=127.0.0.1:18197' | sudo tee -a /etc/kibotos/gw/config.env >/dev/null

Then restart the service. The following commands restart the node and read its metrics once:

sudo systemctl restart kibotos-node.service
curl -s http://127.0.0.1:18191/metrics | grep '^kibotos_build_info'

Once the listener is open, the ctrl and node logs have a line metrics enabled, and the startup log lines of the two gateways, starting kibotos-e2b gateway and starting kibotos-gw, carry telemetry_address.

Exported metrics

The table below summarizes the metrics by prefix. Every metric with its type, labels, and description is listed in the metrics reference, generated from the source code.

MetricFromContent
kibotos_build_infoAllValue 1, with the component, version, and VCS revision as labels
go_*, process_*AllGo runtime and process: goroutines, heap, GC, CPU, resident memory, file descriptors
kibotos_rpc_server_*ctrl, nodeCall count of each Connect method (by error code) and latency of unary calls
kibotos_http_server_*Both gateways; node's /v1/files and /v1/serviceRequest count of each route (by status code) and latency. WebSocket and proxied connections are timed over the whole connection
kibotos_cluster_*ctrlCluster state: status and unplaceable reasons of each node, placeable and allocated resources, host usage and PSI, clock skew and certificate expiry; capacity, reserved amount, and object count of storage pools; Workspace and Volume counts by state; in-flight commands and the age of the oldest one
kibotos_ctrl_*ctrlCommand settlements, attempt failures, and exhausted budgets; reasons control sessions ended; the database connection pool; cluster state read failures
kibotos_instance_metrics_*ctrl, nodeLength of the instance metrics write queue and dropped samples. The queue is 0 when instance metrics storage is not connected
kibotos_traces_dropped_totalAllSpans not pushed to trace storage, by reason reason: queue_full, export_failed, no_credential. It is 0 when trace storage is not connected. See Traces
kibotos_node_*nodekibotos_node_info; Instance counts by state; unresponsive guests and memory saturation, probe failures, and calls from the node to guests; Instances waiting for cleanup retries; control connections; whether storage pools are available; Template cache; in-flight data-plane streams and rejected credentials; lost guest logs and skipped samples
kibotos_gateway_*Both gatewaysFailed calls to ctrl or node (by operation and error code), authentication rejections, and proxied connections that ended abnormally
kibotos_gw_*Exposure gatewayIn-flight proxied connections, connections rejected by the concurrency limit, and bytes transferred
  • The only labels are node IDs, storage pool IDs, Connect method names and route patterns, error codes and HTTP status codes, the API method name that a command belongs to, the gateways' upstream operation names, and a few fixed values specific to each metric. IDs of objects such as Workspaces, Instances, and Volumes, Workspace labels, paths, addresses, credentials, and error messages never become labels, so the series count does not grow with the number of Workspaces.
  • Metrics that count over a fixed set output every value in the set. Values that never occurred are 0.
  • Cluster state (metrics starting with kibotos_cluster_) is read from the database when ctrl is scraped. Scrapes within 15 seconds share one read, and a read takes at most 5 seconds. After a read fails or times out, scrapes within the next 15 seconds do not output these metrics, and kibotos_ctrl_cluster_read_failures_total increases by one per read. All other metrics are output as usual.
  • The node outputs the metrics that carry its identity only after it joins the cluster and obtains an identity. kibotos_node_info has value 1, and its label node_id is the node ID. Use it to map node metrics scraped on a host to the node ID. See Common queries.

Common queries

To seeQuery (PromQL)
Processes that cannot be scrapedup == 0
Number of nodes by status; retired is the registration left after retirementsum by (status) (kibotos_cluster_node_status)
Unplaceable nodes and their reasonskibotos_cluster_node_unready == 1
The longest-backlogged commandsmax by (method) (kibotos_cluster_command_oldest_processing_seconds)
Command settlements in the last 5 minutes that did not succeedsum by (method, code) (increase(kibotos_ctrl_command_settlements_total{code!="ok"}[5m]))
Mapping node metrics scraped on hosts to node IDskibotos_node_instances * on (job, instance, host) group_left (node_id) kibotos_node_info

Reference deployment: vmagent, VictoriaMetrics, and Grafana

The reference deployment scrapes with vmagent, writes to a single-node VictoriaMetrics that stores only these metrics, and views them in Grafana. vmagent was chosen because it records up for each scrape target, so you can tell when a process cannot be scraped, and it supports discovering targets by Kubernetes Pod. Any collector that scrapes the Prometheus text format and any storage that offers the Prometheus query API can replace them.

The sections below set up the store and vmagent on hosts, on Kubernetes, and with Docker Compose. Grafana applies to all of them.

Capacity

Estimate capacity from the series count. The table below shows series counts measured on a KiboVM deployment after running through the lifecycle operations:

ProcessSeriesGrows with
nodeAbout 540 per nodeThe data-plane methods and guest methods that have been called
ctrlAbout 150, plus about 20 per registered nodeRegistered nodes and storage pools
E2B gatewayAbout 110The routes that have been accessed
Exposure gatewayAbout 100Essentially fixed

With 2000 nodes per cluster and a scrape every 30 seconds, that is about 1.1 million active series and about 37,000 samples per second, almost all from nodes. A scrape takes less than 100 ms. The longest is ctrl, because it reads the cluster state.

Hosts

On hosts, run VictoriaMetrics on one internal machine and one vmagent on every host that runs Kibotos services.

VictoriaMetrics on a host

This VictoriaMetrics stores only the metrics on this page and is deployed separately from the instance metrics storage. Flags:

FlagExampleDescription
-storageDataPath/var/lib/victoria-metrics-telemetryData directory, on a local disk
-retentionPeriod30dRetention
-httpListenAddr10.0.0.7:8428Listen only on an internal address that the collectors and Grafana can reach
-httpAuth.username, -httpAuth.passwordkibotos, file:///etc/victoria-metrics/passwordAuthentication for writes and queries. The file:// form reads the password from a file, so it does not appear on the command line. If you need separate write and query permissions, put vmauth in front

vmagent on a host

Each host that runs Kibotos services runs one vmagent that scrapes the local metrics listeners:

  • vmagent.yml is the scrape configuration, with one job per service: kibotos-ctrl, kibotos-node, kibotos-e2b, kibotos-gw. Delete the services that this host does not run: a target that cannot be reached keeps up at 0, and vmagent logs a warning on every scrape.
  • kibotos-vmagent.service is the systemd unit. It adds a host label with the host name to every series: every host scrapes at 127.0.0.1, so without this label you cannot tell which host a series came from.
  • The password is in a file that only root can read. The unit passes it to vmagent with LoadCredential, so the password does not appear on the command line or in environment variables.

The following commands download vmagent, verify the checksum, and install it to /usr/local/bin/vmagent:

set -eu
version=v1.154.0
base="https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/$version"
curl -fsSLO "$base/vmutils-linux-amd64-$version.tar.gz"
curl -fsSLO "$base/vmutils-linux-amd64-${version}_checksums.txt"
sha256sum --check --ignore-missing "vmutils-linux-amd64-${version}_checksums.txt"
tar xzf "vmutils-linux-amd64-$version.tar.gz" vmagent-prod
sudo install -m 0755 vmagent-prod /usr/local/bin/vmagent

Run the following commands in the root of the source repository to install the scrape configuration, the password file, and the service unit. The two sudoedit commands let you write the password and change -remoteWrite.url in the unit to the VictoriaMetrics address. Also delete the jobs you do not need from the scrape configuration in /etc/vmagent/kibotos.yml:

set -eu
sudo install -d -m 0755 /etc/vmagent
sudo install -m 0644 deploy/metrics/vmagent.yml /etc/vmagent/kibotos.yml
sudo install -m 0600 /dev/null /etc/vmagent/remote-write-password
sudoedit /etc/vmagent/remote-write-password
sudo install -m 0644 deploy/metrics/kibotos-vmagent.service /etc/systemd/system/kibotos-vmagent.service
sudoedit /etc/systemd/system/kibotos-vmagent.service
sudo systemctl daemon-reload
sudo systemctl enable --now kibotos-vmagent.service

The vmagent status page listens only on the loopback address. The following command lists every target. state=up means the most recent scrape succeeded:

curl -s http://127.0.0.1:8429/targets

Kubernetes

On Kubernetes, a Helm chart installs the store, a manifest runs vmagent in the kibotos namespace, and the chart can also hand the data source and dashboards to Grafana's sidecar. vmagents on hosts outside the cluster can write to the same store.

VictoriaMetrics in the cluster

deploy/helm/kibotos-metrics/ installs this VictoriaMetrics into a Kubernetes cluster. Its structure is the same as the instance metrics storage chart:

  • Single-node VictoriaMetrics, running in a StatefulSet with its data on a persistent volume. It is reachable only inside the cluster, and a NetworkPolicy admits only the vmauth Pods.
  • vmauth in front for authentication. Write users can call only /api/v1/write, for vmagent. Read-only users can call only the Prometheus query API, for Grafana. All passwords are in Secrets that the deployer creates and reach vmauth through environment variables, so the chart never renders them.
  • A Service for vmauth. The vmagents on the hosts write through this address from outside the cluster. The Kibotos hosts must be able to reach it, and guests and the public internet must not. Use an internal load balancer or a NodePort, and do not give it a public address.
  • Optionally, a data source and dashboards for the Grafana sidecar to load. See Grafana sidecar.

Prerequisite: the cluster's CNI enforces NetworkPolicy. Otherwise any Pod in the same cluster can read and write VictoriaMetrics directly.

The following commands generate the write password and Grafana's read-only password, create the namespace and the Secrets, and then install. The password files must not contain a newline: vmauth compares the Secret content verbatim as the password. The example uses the namespace kibotos-metrics and the internal load balancer annotation of Alibaba Cloud ACK. On other clusters, use the matching annotation, or use a NodePort instead:

set -eu
umask 077
openssl rand -hex 24 | tr -d '\n' > remote-write-password
openssl rand -hex 24 | tr -d '\n' > metrics-grafana-password
kubectl create namespace kibotos-metrics
kubectl -n kibotos-metrics create secret generic kibotos-metrics-writer --from-file=password=remote-write-password
kubectl -n kibotos-metrics create secret generic kibotos-metrics-grafana --from-file=password=metrics-grafana-password
cat > metrics.yaml <<EOF
vmauth:
  writers:
    - name: kibotos
      secretName: kibotos-metrics-writer
  readers:
    - name: grafana
      secretName: kibotos-metrics-grafana
  service:
    type: LoadBalancer
    annotations:
      service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: intranet
EOF
helm install kibotos-metrics deploy/helm/kibotos-metrics -n kibotos-metrics -f metrics.yaml --wait
kubectl -n kibotos-metrics get service kibotos-metrics-vmauth

The EXTERNAL-IP in the output of the last command is the storage address. The vmagent on each host sets -remoteWrite.url to http:// plus this address plus :8427/api/v1/write, with the username kibotos and the content of remote-write-password as the password. See vmagent on a host. A vmagent in the same cluster uses the in-cluster address http://kibotos-metrics-vmauth.kibotos-metrics.svc:8427/api/v1/write. See vmagent in the cluster.

The keys that the three Kibotos storage charts share, such as vmauth.readers, vmauth.tls.secretName, vmauth.service.*, and the storage size, are described in Common chart values. The keys and defaults specific to this chart:

KeyDescription
vmauth.writersWrite users for vmagent, each with name and secretName (key password). At least one is required. The username is name. Several vmagents can share one user, or each can have its own so that you can change their passwords separately
victoriaMetrics.retentionPeriod30d by default
victoriaMetrics.storage.size50Gi by default. Metrics from 200 nodes kept for 30 days take about 10 GB. Scale the estimate by node count
victoriaMetrics.resourcesBy default, a request of 1 GiB and a limit of 4 GiB memory. Memory grows with active series, about 1 KiB each. Raise it beyond a few hundred nodes
grafana.*Data source and dashboards for the Grafana sidecar, not rendered by default. See Grafana sidecar
  • vmauth's own /metrics, /flags, pprof, and config reload use the key key of the chart-generated Secret kibotos-metrics-vmauth-admin as authKey, and are not open to the network.
  • While vmauth restarts after a configuration change, writes fail for a few seconds. vmagent buffers the samples locally and writes them later.

vmagent in the cluster

  • kubernetes-vmagent.yaml runs one vmagent in the kibotos namespace. It discovers targets by Pod and scrapes only container ports named telemetry. job comes from the Pod's app.kubernetes.io/name label, matching the job names on hosts. host is the node the Pod runs on, and pod is the Pod name. Its ServiceAccount can read only the Pods in this namespace.

  • The example manifests ctrl.yaml, e2b.yaml, and gw.yaml all declare a port named telemetry. The ConfigMaps of the two gateways already set the listeners to 0.0.0.0:18195 and 0.0.0.0:18197. To open the ctrl listener, add the following section to ctrl's config.toml. Without it, the ctrl target keeps up at 0:

    [telemetry]
    listen = "0.0.0.0:18192"
  • Each of the three manifests includes a NetworkPolicy: the service ports stay open as usual, and only the vmagent Pod may connect to the telemetry port. The cluster must enforce NetworkPolicy. Otherwise any Pod in the same cluster can read these metrics.

  • The Services do not expose the telemetry port. vmagent connects to the Pods directly.

The -remoteWrite.url in the manifest is the in-cluster address after installing VictoriaMetrics in the cluster as in the example, with the username kibotos. If the storage is elsewhere, change it to that address. Put the write password in a Secret, then apply:

set -eu
kubectl -n kibotos create secret generic kibotos-vmagent --from-file=password=./remote-write-password
kubectl apply -f deploy/metrics/kubernetes-vmagent.yaml
kubectl -n kibotos rollout status deploy/kibotos-vmagent --timeout=5m

The vmagent status page listens only inside the Pod. The following command forwards it to your machine. Then open http://127.0.0.1:8429/targets to see the scrape status:

kubectl -n kibotos port-forward deploy/kibotos-vmagent 8429:8429

Grafana sidecar

When Grafana runs on Kubernetes with its sidecars enabled, the kibotos-metrics chart can render the data source and dashboards, so you do not have to add and import them by hand:

  • grafana.datasource.enabled: renders a ConfigMap labeled grafana_datasource: "1" that contains the provisioning file of a Prometheus data source named Kibotos 指标 with uid kibotos-metrics. It queries through vmauth as the read-only user named by grafana.datasource.reader. The password is not written into the ConfigMap. The file contains $__env{KIBOTOS_METRICS_GRAFANA_PASSWORD}, which Grafana reads from its own environment variables.
  • grafana.dashboards.enabled: renders one ConfigMap labeled grafana_dashboard: "1" for each of the two dashboards. The dashboards' data source variable preselects the data source whose uid is grafana.datasource.uid, so when the same Grafana also has other Prometheus data sources, such as the instance metrics storage, the dashboards query this store by default. If you add the data source by hand, set its uid to the same value.
  • grafana.namespace: the namespace of the ConfigMaps, by default the chart's namespace. Grafana's sidecar must search this namespace. You can change the labels and the dashboard annotations with grafana.datasource.labels, grafana.dashboards.labels, and grafana.dashboards.annotations.

The following example uses the grafana chart from grafana-community, with Grafana installed in the namespace monitoring. First, put the read-only password in a Secret in Grafana's namespace:

kubectl -n monitoring create secret generic kibotos-metrics-grafana --from-file=password=metrics-grafana-password

In Grafana's values, turn on both sidecars, pass the password to Grafana as an environment variable, and create folders from the annotation grafana_folder:

envValueFrom:
  KIBOTOS_METRICS_GRAFANA_PASSWORD:
    secretKeyRef:
      name: kibotos-metrics-grafana
      key: password
sidecar:
  datasources:
    enabled: true
  dashboards:
    enabled: true
    folderAnnotation: grafana_folder
    provider:
      foldersFromFilesStructure: true

Add the following to the kibotos-metrics values in the metrics.yaml from earlier:

grafana:
  namespace: monitoring
  datasource:
    enabled: true
  dashboards:
    enabled: true
    annotations:
      grafana_folder: Kibotos

Then run helm upgrade kibotos-metrics deploy/helm/kibotos-metrics -n kibotos-metrics -f metrics.yaml. A few seconds later, the data source Kibotos 指标 and the two dashboards in the folder Kibotos appear in Grafana.

  • Data sources and dashboards loaded by the sidecar are read-only. Changes made in Grafana cannot be saved. To change a dashboard, change its JSON in deploy/metrics/, then run helm upgrade. The two dashboards in the chart are symbolic links to these files.
  • If the storage has TLS enabled with a certificate issued by a private CA, Grafana must trust that CA, or you add the data source by hand and provide the CA.

Docker Compose

compose.yaml already opens the metrics listeners of the two gateways. They are reachable only inside the Compose network and are not published to the host. To open the ctrl listener, set listen = "0.0.0.0:18192" in the [telemetry] section of ctrl/config.toml; it stays unpublished as well.

Add a vmagent service to the same Compose project to scrape them. Write its scrape configuration based on vmagent.yml, with the target addresses changed to ctrl:18192, e2b:18195, and gw:18197:

  vmagent:
    image: docker.io/victoriametrics/vmagent:v1.154.0@sha256:2a939a9df9c8591aa5447efcd21af8c4f2ecc60ca6a8e742ffd46b9c76ef7f17
    restart: unless-stopped
    command:
      - -promscrape.config=/etc/vmagent/kibotos.yml
      - -remoteWrite.url=http://10.0.0.7:8428/api/v1/write
      - -remoteWrite.basicAuth.username=kibotos
      - -remoteWrite.basicAuth.passwordFile=/etc/vmagent/remote-write-password
      - -remoteWrite.label=host=docker-a
      - -remoteWrite.tmpDataPath=/var/lib/vmagent
    volumes:
      - ./vmagent/kibotos.yml:/etc/vmagent/kibotos.yml:ro
      - ./vmagent/remote-write-password:/etc/vmagent/remote-write-password:ro
      - vmagent-data:/var/lib/vmagent

Set host to the name of this Docker host, and add vmagent-data to the volumes at the end of the file.

Grafana

Add a Prometheus data source: set the URL to the VictoriaMetrics address http://10.0.0.7:8428, turn on Basic auth, and enter the username and password. If you installed the storage with the chart, set the URL to vmauth (inside the cluster, http://kibotos-metrics-vmauth.kibotos-metrics.svc:8427) and use the username and password of a read-only user. Then import the two dashboards below, selecting this data source when you import:

DashboardContent
grafana-cluster.json "Kibotos 集群概览" (cluster overview)Status and unplaceable reasons of nodes; placeable and allocated CPU and memory, with per-node detail; the few hosts with the worst available memory, CPU idle, and PSI; clock skew and certificate expiry; capacity and reserved amount of storage pools; Workspace and Volume counts by state; in-flight commands, the age of the oldest one, and command settlements
grafana-services.json "Kibotos 服务" (services)up and version of each target; request rate, non-ok ratio, and p95 latency of Connect methods; requests, 5xx, and latency of HTTP routes; gateway upstream failures, authentication rejections, and proxied connections; node Instances, guests, control connections, storage pools, Template cache, and data plane; the instance metrics write queue and drops; ctrl's database connection pool and control sessions; Go runtime, CPU, memory, and file descriptors of each process

The instance metrics storage has two more dashboards, "Kibotos 实例概览" (instance overview) and "Kibotos Workspace", whose data source points to that storage. See Instance metrics storage dashboards.

"Kibotos 服务" narrows the scope with three variables: job, host, and node. Its node panels use kibotos_node_info to map the series scraped on hosts to node IDs and filter by node.

Troubleshooting

SymptomCauseResolution
up is 0 for a targetThe service has no metrics listener configured, is not running, or the collector cannot reach itcurl /metrics once on the service's host, and look for telemetry_address in the service log
The service fails to start, and the log has listen for metrics onThe metrics port is already in useUse another port, or stop the process that holds it
The service fails to start, and the log mentions telemetry.listen, KIBOTOS_E2B_TELEMETRY_LISTEN, or KIBOTOS_GW_TELEMETRY_LISTENThe address is not in host:port formWrite it like 127.0.0.1:18191
Panels of the cluster overview have gaps at the same time while the service dashboard is normalDuring those scrapes, ctrl could not read the cluster state, usually because the database was unavailable or slowCheck kibotos_ctrl_cluster_read_failures_total and the cluster metrics read failed records in the ctrl log
The node panels have no data, but the node's up is 1The node has not obtained an identity yet and does not output kibotos_node_infoComplete the join as described in Install node
Series from different hosts are mixed togetherThe vmagent on the host does not add the host labelAdd -remoteWrite.label=host=%H as in the reference unit
On Kubernetes, up is 0 and the error is a connection timeoutThe NetworkPolicy does not admit it: the vmagent Pod label is not app.kubernetes.io/name: kibotos-vmagentUse the label from the reference manifest, or change all three NetworkPolicies
vmagent writes keep failing while /targets is normal, and the log shows 401 from the remoteThe write password does not match vmauth's, usually because the password in the Secret has a newlineRemove the newline with tr -d '\n', recreate the Secret, then run kubectl -n kibotos-metrics rollout restart deploy/kibotos-metrics-vmauth
Testing the Kibotos 指标 data source in Grafana returns 401Grafana lacks the KIBOTOS_METRICS_GRAFANA_PASSWORD environment variable, or the password differs from the read-only user'sAdd the environment variable to Grafana as described in Grafana sidecar

Next steps

On this page