Skip to content

Repository files navigation

vnode-bridge

Virtual Kubelet provider that runs vcluster pods as real pods in a host Kubernetes cluster, typically using Kata Containers for isolation.

vnode-bridge implements the Virtual Kubelet PodLifecycleHandler and NodeProvider interfaces to register a virtual node inside a vcluster while offloading pod execution to a separate host cluster and namespace. Pods scheduled to the vnode in the vcluster are translated into real pods on the host cluster (with a configurable RuntimeClass) and their status is continuously synced back.


Features

  • Virtual Kubelet–based virtual node: Implements Virtual Kubelet provider interfaces so the vnode looks and behaves like a regular Kubernetes node from the vcluster’s perspective.
  • vcluster → host bridging: Pods scheduled onto the vnode in the vcluster are created as real pods in a configurable namespace on a host Kubernetes cluster.
  • Kata Containers support: Uses a configurable --runtime-class (default kata) to run host pods with Kata Containers or another RuntimeClass.
  • Status synchronization: Periodic sync loop keeps vcluster pod status aligned with the actual status of host pods.
  • Label-based observability: Adds clear labels to host pods and the vnode to trace workloads back to their originating vcluster pods and node.
  • Container-friendly distribution: Ships with a multi-stage Dockerfile that builds a minimal, non-root distroless image.

Architecture Overview

At a high level, vnode-bridge consists of:

  • CLI / daemon (cmd/vnode): Parses configuration, creates Kubernetes clients for both the vcluster and the host cluster, constructs the provider and translator, registers the virtual node, and runs Virtual Kubelet controllers.
  • Provider (internal/provider): Implements pod lifecycle and node provider logic using the host cluster client. It creates, updates, deletes, and lists pods in the host namespace and maintains a status cache reflected back into the vcluster.
  • Translator (internal/translator): Converts vcluster pod specs into host-cluster-ready pods:
    • Moves pods into the configured host namespace.
    • Applies the configured RuntimeClassName.
    • Strips vcluster-specific service account fields, projected volumes, and API token mounts.
    • Adds labels to map host pods back to their originating vcluster pods and vnode.
  • Pod controller (internal/provider/podcontroller.go): Watches vcluster pods whose spec.nodeName matches the vnode name, and feeds events into the provider.

The result is a virtual node in the vcluster whose pods are actually executed in another Kubernetes cluster/namespace.


Requirements

  • Go toolchain: Go 1.25+ to build from source (module targets go 1.25.7).
  • Kubernetes clusters:
    • A vcluster control plane where the virtual node will be registered.
    • A host Kubernetes cluster that will actually run the pods.
    • A namespace in the host cluster where vnode-bridge will create pods.
    • A RuntimeClass in the host cluster matching the value passed via --runtime-class (default: kata).
  • Permissions / RBAC:
    • In the vcluster: permissions to manage Nodes, Leases, Pods (list/watch), and Events in at least the default namespace.
    • In the host cluster: permissions to create, update, delete, and list/watch Pods in the configured host namespace.

Installation

Build from source

Clone the repository:

git clone https://github.com/kroderdev/vnode-bridge.git
cd vnode-bridge

Build the binary:

make build

This will compile the vnode binary from cmd/vnode.

Run tests:

make test

Run linters (if you have golangci-lint installed):

make lint

Build Docker image

To build a container image using the provided multi-stage Dockerfile:

make docker

By default this runs:

docker build -t kroderdev/vnode-bridge:dev .

You can change the tag or push the resulting image to your own registry.


Configuration

vnode-bridge is configured entirely via CLI flags. The most important flags are:

  • --node-name (required):
    Name of the virtual node that will appear in the vcluster.

  • --host-namespace (required):
    Namespace in the host cluster where translated pods will be created.

  • --cpu (default: 1000m):
    CPU capacity to advertise on the vnode.

  • --memory (default: 2Gi):
    Memory capacity to advertise on the vnode.

  • --runtime-class (default: kata):
    RuntimeClassName for pods on the host cluster (for example, a Kata Containers runtime class).

  • --kubeconfig-host:
    Path to the kubeconfig file for the host cluster. If omitted, vnode will try to use in-cluster configuration (suitable when running inside the host cluster).

  • --kubeconfig-vcluster:
    Path to the kubeconfig file for the vcluster.


Getting Started

  1. Prepare kubeconfigs and clusters

    • Ensure you have a working vcluster and a host Kubernetes cluster.
    • Create or choose a namespace in the host cluster where vnode-bridge will create pods (for example, vcluster-workloads).
    • Make sure a RuntimeClass (e.g. kata) is available in the host cluster.
  2. Run vnode as a binary

    vnode \
      --node-name=vnode-01 \
      --host-namespace=vcluster-workloads \
      --cpu=2000m \
      --memory=4Gi \
      --runtime-class=kata \
      --kubeconfig-host=/path/to/host.kubeconfig \
      --kubeconfig-vcluster=/path/to/vcluster.kubeconfig

    This process:

    • Registers a virtual Node named vnode-01 in the vcluster.
    • Watches pods in the vcluster whose spec.nodeName is vnode-01.
    • Translates those pods into host cluster pods in vcluster-workloads.
    • Periodically syncs host pod status back to the corresponding vcluster pods.
  3. Run vnode as a container

    After building and pushing an image (or using a prebuilt one), you can run it with Docker:

docker run --rm \
  -v /path/to/host.kubeconfig:/host.kubeconfig:ro \
  -v /path/to/vcluster.kubeconfig:/vcluster.kubeconfig:ro \
  kroderdev/vnode-bridge:dev \
    --node-name=vnode-01 \
    --host-namespace=vcluster-workloads \
    --kubeconfig-host=/host.kubeconfig \
    --kubeconfig-vcluster=/vcluster.kubeconfig

In a real deployment, you would typically run vnode as a Deployment or DaemonSet in either the host cluster or the vcluster, mounting appropriate kubeconfigs or using in-cluster credentials.


Labels and Observability

vnode-bridge adds labels to host pods and the vnode to help correlate workloads and debug issues:

  • Host pods created by vnode-bridge include labels such as:

    • app.kubernetes.io/managed-by = kroderdev-vnode-bridge
    • vnode.kroderdev.io/node-name = <vnode name>
    • vnode.kroderdev.io/vcluster-pod-name = <original vcluster pod name>
    • vnode.kroderdev.io/vcluster-pod-namespace = <original vcluster pod namespace>
  • The virtual Node in the vcluster includes labels such as:

    • type = virtual
    • kubernetes.io/role = agent
    • node.kubernetes.io/instance-type = vnode
    • vnode.kroderdev.io/managed = "true"

This makes it easy to discover which pods are managed by vnode-bridge and trace them back to their originating vcluster pods.


How It Works (Detailed)

  1. Startup

    • The vnode process parses CLI flags to build a configuration.
    • It creates Kubernetes clients for both the vcluster and the host cluster using the provided kubeconfigs (or in-cluster config).
    • It constructs:
      • A Translator that knows the host namespace, runtime class, and vnode name.
      • A Provider that uses the host client and translator to manage host pods and maintain an in-memory pod cache.
      • A virtual Node object representing the vnode in the vcluster, including capacity and labels.
  2. Virtual Kubelet controllers

    • A node controller registers the vnode in the vcluster and keeps node status up to date.
    • A pod controller in the vcluster watches pods assigned to the vnode and sends events (create, update, delete) to the Provider.
  3. Pod lifecycle

    • When a pod is scheduled onto the vnode in the vcluster:
      • The Provider calls the Translator to produce a host pod spec.
      • The host pod is created in the configured host namespace, with the configured RuntimeClassName and labels linking it back to the original vcluster pod.
    • Updates to vcluster pods are propagated to host pods by re-translating relevant parts of the spec.
    • Deletions in the vcluster trigger deletions in the host cluster; the Provider marks the vcluster pod as Succeeded with reason ProviderTerminated.
  4. Status sync

    • A periodic sync loop lists host pods matching the vnode’s labels and updates the Provider’s cache.
    • The pod controller then uses this cache to serve up-to-date status for pods in the vcluster.

Contributing

Contributions, bug reports, and feature requests are welcome.

If you plan to contribute:

  • Run make test and make lint before submitting changes.
  • Try to add or update tests alongside your code changes.
  • Keep commit messages and pull request descriptions focused and clear.

License

This project is licensed under the terms of the license found in the LICENSE file.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages