virtuakube

package module
v0.0.0-...-5de09cf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 8, 2019 License: Apache-2.0 Imports: 28 Imported by: 0

README

Virtuakube

This project is no longer being developed. I'm leaving it online for historical interest, but you should not expect it to work, and definitely not expect support, fixes, or features.

Virtuakube sets up virtual Kubernetes clusters for testing.

license GoDoc

It has several advantages compared to minikube or cloud clusters:

  • Support any number of nodes, limited only by system RAM.
  • Can run without root privileges (sort of - currently still requires docker privileges for image building).
  • Can run without internet access.
  • Because it emulates a full ethernet LAN, can be used to test networked systems.
  • After initial setup, can recreate a complex VM and network topology in <10s, ideal for running lots of unit tests.

It's a very young system, and is being built for the needs of testing MetalLB, but seems like it could be generally useful for both playing with Kubernetes and testing scenarios. However, as of now you should expect the API to change frequently. Users and contributions are welcome, but be aware you're using a very young piece of software.

Your host machine must have qemu, qemu-img, vde_switch and guestfish installed.

Example usage

The CLI under cmd/vkube is a quick way to get started. All resources in virtuakube live in a Universe. Within a universe there are three resources: Images are base disk images for VMs, VMs are machines that can talk to each other and the internet, and Clusters are Kubernetes clusters bootstrapped on VMs.

First, let's create a universe and build a VM base image inside it:

vkube newimage --universe ./my-test-universe --name base

This will create the my-test-universe directory to store universe state, and build a VM base disk that contains Kubernetes tools and prepulled control plane images. Building the image takes about 5 minutes.

Once we've done that, we can run a cluster in our universe:

vkube newcluster --universe ./my-test-universe --name example --image base

Bootstrapping a cluster takes a couple of minutes, but when done vkube will print something like:

Created cluster "example"
Done (took 1m32s). Resources available:

  Cluster "example": export KUBECONFIG="/home/dave/my-test-universe/cluster/example/kubeconfig"
  VM "example-controller": ssh -p50000 root@localhost
  VM "example-node1": ssh -p50003 root@localhost

Hit ctrl+C to shut down

From there you can use the cluster as you wish, or SSH into VMs to do more stuff. The VMs created here are ephemeral, so when you ctrl+C they will be deleted, and you'll have to run newcluster again to rebuild it.

If you want to suspend and resume your cluster instead of creating/deleting, just add --save to the commandline. With --save, all running VMs will be snapshotted to disk, and will all resume as if nothing happened the next time the universe is opened. To open a universe and resume whatever was saved, but without creating new resources, use the resume command:

vkube resume --universe ./my-test-universe

Assuming you created and saved a cluster previously, you'll get familiar output:

Done (took 791ms). Resources available:

  Cluster "example": export KUBECONFIG="/home/dave/my-test-universe/cluster/example/kubeconfig"
  VM "example-controller": ssh -p50000 root@localhost
  VM "example-node1": ssh -p50003 root@localhost

Hit ctrl+C to shut down

The cluster is back, but this time it took less than a second to come up (your mileage may vary, depending on disk and CPU performance - but it should be much faster than creating VMs from scratch).

All vkube commands accept --save to mean "resume from the current state next time, instead of reverting to the last savepoint. Saving is off by default for all commands except newimage (which is why the base image we created stuck around - vkube implicitly saved the universe after creating the image).

All vkube commands accept --wait. If --wait is true, vkube will pause after the requested command has executed, print the available resources (as above), and wait for ctrl+C before closing the universe (with or without saving, depending on --save). Waiting is on by default for all commands except newimage.

So, if you wanted to non-interactively create a universe, build a base image, build a cluster and then immediately save it for future use, you'd run:

vkube newimage --universe ./my-new-universe --name base
vkube newcluster --universe ./my-new-universe --name example --image base --save --wait=false

Then, later, play with your cluster:

vkube resume --universe ./my-new-universe

Documentation

Overview

Package virtuakube sets up virtual Kubernetes clusters for tests.

The top-level object is a Universe. Everything else exists within a Universe, and is cleaned up when the Universe is closed. Within a Universe, you can create either bare VMs (using universe.NewVM), or Kubernetes clusters (using universe.NewCluster).

Universes

A universe requires a directory on disk to store its state. You get a universe either by calling Create to make a new blank one, or by calling Open to reuse an existing one.

There are three ways of closing a universe. Calling Destroy wipes all the universe's state. Save snapshots and preserve all current resources, such that the next call to Open will resume the universe exactly as it was when last saved. Close preserves the universe, but rewinds its state to the last time it was saved, or to its pristine post-creation state if it was never saved.

A typical use of virtuakube in tests is to do expensive setup ahead of time: use Create to make a new universe, then create and configure resources within, and finally call Save to snapshot it. Then, tests can simply Open this universe to get a fully working system immediately. When each test is done, they can Close the universe to undo all the changes that happened during the test, ready for the next test to Open.

VMs

VMs have a preset form that can be customized somewhat, but not fundamentally changed.

Each VM has a single virtual disk, which is a copy-on-write fork of a base image. You can build base images with universe.NewImage.

Each VM gets two network interfaces. The first provides internet access, and the second connects to a virtual LAN shared by all VMs in the same Universe.

Network access to VMs from the host machine is only possible via port forwards, which are specified in the VM's configuration at creation time. Use vm.ForwardedPort to find out the local port to use to reach a given port on the VM.

The VM type provides some helpers for running commands and reading/writing files on the VM.

Kubernetes Clusters

Clusters consist of one control plane VM, and a configurable number of additional worker VMs. Once created, the Cluster type has helpers to retrieve a kubeconfig file to talk to the cluster, a Go kubernetes client connected to the cluster, and the port to talk to the in-cluster registry to push images.

VM Images

VM images belong to a universe, and can be created with NewImage. NewImage accepts customization functions to do things like install extra packages, or configure services that all VMs using the image will need.

If you customize your own VM image, it must conform to the following conventions for virtuakube to function correctly.

The VM should autoconfigure the first network interface (ens3) using DHCP. Other ens* network interfaces should be left unconfigured. The `ip` tool must be installed so that virtuakube can configure those other interfaces.

The VM should disable any kind of time synchronization, and rely purely on the VM's local virtual clock. VMs may spend hours or more suspended, and to avoid issues associated with timejumps on resume, virtuakube wants to maintain the illusion that no time has passed since suspend.

If you want to use NewCluster with your VM image, the VM must have docker, kubectl and kubeadm preinstalled. Dependencies and prerequisites must be satisfied such that `kubeadm init` produces a working single-node cluster. Virtuakube includes stock customization functions to install Kubernetes prerequisites, and to pre-pull the Docker images for faster cluster startup when NewCluster is called.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CustomizeInstallK8s

func CustomizeInstallK8s(v *VM) error

CustomizeInstallK8s is a build customization function that installs Docker and Kubernetes prerequisites, as required for NewCluster to function.

func CustomizePreloadK8sImages

func CustomizePreloadK8sImages(v *VM) error

CustomizePreloadK8sImages is a build customization function that pre-pulls all the Docker images needed to fully initialize a Kubernetes cluster.

func CustomizeScript

func CustomizeScript(path string) func(*VM) error

CustomizeScript is a build customization function that executes the script at path on a VM running the disk image being built.

Types

type Cluster

type Cluster struct {
	// contains filtered or unexported fields
}

Cluster is a virtual Kubernetes cluster.

func (*Cluster) ApplyManifest

func (c *Cluster) ApplyManifest(bs []byte) error

func (*Cluster) Controller

func (c *Cluster) Controller() *VM

Controller returns the VM for the cluster controller node.

func (*Cluster) Kubeconfig

func (c *Cluster) Kubeconfig() string

func (*Cluster) KubernetesClient

func (c *Cluster) KubernetesClient() *kubernetes.Clientset

KubernetesClient returns a kubernetes client connected to the cluster.

func (*Cluster) Name

func (c *Cluster) Name() string

func (*Cluster) Nodes

func (c *Cluster) Nodes() []*VM

Nodes returns the VMs for the cluster nodes.

func (*Cluster) NodesReady

func (c *Cluster) NodesReady() (bool, error)

NodesReady returns true if all nodes in the cluster are in the Ready state.

func (*Cluster) PushImages

func (c *Cluster) PushImages(images ...string) error

PushImages extracts the named images from the host's docker daemon, and pushes them to the docker daemons on all nodes in the cluster.

func (*Cluster) Start

func (c *Cluster) Start() error

Start starts the virtual cluster and waits for it to finish initializing.

func (*Cluster) WaitFor

func (c *Cluster) WaitFor(ctx context.Context, test func() (bool, error)) error

WaitFor invokes the test function repeatedly until it returns true, or the context times out.

type ClusterConfig

type ClusterConfig struct {
	Name string
	// NumNodes is the number of Kubernetes worker nodes to run.
	NumNodes int
	// The VMConfig template to use when creating cluster VMs. The
	// first configured VM network will be used for Kubernetes control
	// traffic.
	VMConfig *VMConfig
}

ClusterConfig is the configuration for a virtual Kubernetes cluster.

type Image

type Image struct {
	// contains filtered or unexported fields
}

Image is a VM disk base image.

type ImageConfig

type ImageConfig struct {
	Name           string
	CustomizeFuncs []ImageCustomizeFunc
	NoKVM          bool
}

ImageConfig is the build configuration for an Image.

type ImageCustomizeFunc

type ImageCustomizeFunc func(*VM) error

ImageCustomizeFunc is a function that applies customizations to a VM that's being built by NewImage.

type Network

type Network struct {
	// contains filtered or unexported fields
}

func (*Network) Close

func (n *Network) Close() error

type NetworkConfig

type NetworkConfig struct {
	Name string
}

type Universe

type Universe struct {
	// contains filtered or unexported fields
}

A Universe is a virtual sandbox and its associated resources.

func Create

func Create(dir string, runtimecfg *UniverseConfig) (*Universe, error)

Create creates a new empty Universe in dir. The directory must not already exist.

func Open

func Open(dir string, snapshot string, runtimecfg *UniverseConfig) (*Universe, error)

Open opens the existing Universe in dir, and resumes from snapshot.

func (*Universe) Close

func (u *Universe) Close() error

Close closes the universe, discarding all changes since the last call to Save.

func (*Universe) Cluster

func (u *Universe) Cluster(name string) *Cluster

Cluster returns the Cluster with the given name, or nil if no such Cluster exists in the universe.

func (*Universe) Clusters

func (u *Universe) Clusters() []*Cluster

Clusters returns a list of all Clusters in the universe.

func (*Universe) Command

func (u *Universe) Command(command string, args ...string) *exec.Cmd

func (*Universe) Destroy

func (u *Universe) Destroy() error

Destroy closes the universe and recursively deletes the universe directory.

func (*Universe) ImportImage

func (u *Universe) ImportImage(name, path string) error

func (*Universe) NewCluster

func (u *Universe) NewCluster(cfg *ClusterConfig) (*Cluster, error)

NewCluster creates an unstarted Kubernetes cluster with the given configuration.

func (*Universe) NewImage

func (u *Universe) NewImage(cfg *ImageConfig) error

NewImage builds a VM disk image using the given config.

func (*Universe) NewNetwork

func (u *Universe) NewNetwork(cfg *NetworkConfig) error

func (*Universe) NewVM

func (u *Universe) NewVM(cfg *VMConfig) (*VM, error)

NewVM creates an unstarted virtual machine with the given configuration.

func (*Universe) Save

func (u *Universe) Save(snapshotName string) error

Save snapshots the current state of VMs and clusters, then closes the universe.

func (*Universe) Snapshots

func (u *Universe) Snapshots() []string

func (*Universe) VM

func (u *Universe) VM(name string) *VM

VM returns the VM with the given name, or nil if no such VM exists in the universe.

func (*Universe) VMs

func (u *Universe) VMs() []*VM

VM returns a list of all VMs in the universe.

func (*Universe) Wait

func (u *Universe) Wait(ctx context.Context) error

Wait waits for the universe to be Closed, Saved or Destroyed.

type UniverseConfig

type UniverseConfig struct {
	// If non-nil, all commands executed on VMs and during image
	// building are logged to this writer, along with their
	// stdout/stderr.
	CommandLog io.Writer
	// Whether VMs should have a GUI. Useful for debugging Virtuakube
	// itself.
	VMGraphics bool
	// Make subprocesses immune to ^C, to enable interactive control.
	Interactive bool
	// Don't use any privileged hardware acceleration for VMs. Will
	// run much slower, but 100% in userspace.
	NoAcceleration bool
}

UniverseConfig contains the ephemeral runtime settings for the universe. A nil UniverseConfig is equivalent to the zero value.

type VM

type VM struct {
	// contains filtered or unexported fields
}

VM is a virtual machine.

func (*VM) Close

func (v *VM) Close() error

Close shuts down the VM, reverting all changes since the universe was last saved.

func (*VM) Dial

func (v *VM) Dial(network, addr string) (net.Conn, error)

Dial connects to the given destination, through the VM.

func (*VM) ForwardedPort

func (v *VM) ForwardedPort(dst int) int

ForwardedPort returns the port on localhost that maps to the given port on the VM.

func (*VM) Hostname

func (v *VM) Hostname() string

Hostname returns the configured hostname of the VM. It might be different from the VM's actual hostname if its hostname was changed after boot by something other than virtuakube.

func (*VM) IPv4

func (v *VM) IPv4(network string) net.IP

IPv4 returns the LAN IPv4 address of the VM.

func (*VM) IPv6

func (v *VM) IPv6(network string) net.IP

IPv6 returns the LAN IPv6 address of the VM.

func (*VM) Networks

func (v *VM) Networks() []string

Networks returns the networks to which the VM is connected.

func (*VM) ReadFile

func (v *VM) ReadFile(path string) ([]byte, error)

ReadFile reads path from the VM and returns its contents.

func (*VM) Run

func (v *VM) Run(command string) ([]byte, error)

Run runs the given shell command as root on the VM, and returns its output.

func (*VM) RunMultiple

func (v *VM) RunMultiple(commands ...string) error

RunMultiple runs all given commands sequentially. It stops at the first unsuccessful command and returns its error.

func (*VM) RunWithInput

func (v *VM) RunWithInput(command string, stdin io.Reader) ([]byte, error)

func (*VM) Start

func (v *VM) Start() error

Start starts the virtual machine and waits for it to finish booting.

func (*VM) Wait

func (v *VM) Wait(ctx context.Context) error

Wait waits for the VM to shut down.

func (*VM) WriteFile

func (v *VM) WriteFile(path string, bs []byte) error

WriteFile writes bs to the given path on the VM.

type VMConfig

type VMConfig struct {
	Name         string
	Image        string
	MemoryMiB    int
	Networks     []string
	PortForwards map[int]bool
	// contains filtered or unexported fields
}

VMConfig is the configuration for a virtual machine.

Directories

Path Synopsis
cmd
internal
assets
Package assets contains asset files for virtuakube.
Package assets contains asset files for virtuakube.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL