Declarative Installation

This guide provides comprehensive instructions for deploying and managing Kubermatic Virtualization using the declarative apply command with YAML configuration files.

Overview

The Kubermatic Virtualization apply command enables declarative cluster management through infrastructure-as-code practices. This approach provides:

  • Version-controlled configurations stored in Git or other VCS
  • Idempotent operations that are safe to run repeatedly
  • Automated lifecycle management including installation, upgrades, and repairs
  • GitOps workflows for continuous delivery and reconciliation
  • Audit trails through configuration file history

Prerequisites

Before beginning, ensure you have:

  • A valid Kubermatic Virtualization license (contact sales@kubermatic.com)
  • Administrative access to target infrastructure
  • SSH connectivity to all designated cluster nodes
  • A text editor for creating YAML configuration files
  • Network planning documentation including CIDR blocks and IP ranges

Configuration File Structure

The declarative installation uses a YAML configuration file following the Kubermatic Virtualization API schema. This file serves as the single source of truth for your cluster’s desired state.

Image Pull Secret

KubeV images are hosted on a private registry, so registry credentials are required for every installation — the controller-manager is always deployed and pulls from it. A single secret covers all components (controller-manager, api-server, and the optional dashboard). Provide it in one of two ways:

Option 1 — the top-level imagePullSecret field in the config file (used in the examples below):

imagePullSecret: |
  {"auths":{"quay.io":{"auth":"<base64 of username:password>"}}}

Option 2 — environment variables before running kubev apply, so nothing is stored in the file:

export KUBEV_USERNAME=myuser
export KUBEV_PASSWORD=mypassword
kubev apply -f cluster.yaml

Minimal Configuration Example

apiVersion: virtualization.k8c.io/v1alpha1
kind: KubeVCluster

# required — see "Image Pull Secret" above
imagePullSecret: |
  {"auths":{"quay.io":{"auth":"..."}}}

networkConfiguration:
  dnsServerIP: "8.8.8.8"
  networkCIDR: "10.244.0.0/16"
  serviceCIDR: "10.96.0.0/12"
  gatewayIP: "10.244.0.1"

controlPlane:
  hosts:
    - address: "192.168.1.10"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/id_rsa"

loadBalancer:
  none: {}

storage:
  none: {}

Complete Configuration Example

apiVersion: virtualization.k8c.io/v1alpha1
kind: KubeVCluster

# required — see "Image Pull Secret" above
imagePullSecret: |
  {"auths":{"quay.io":{"auth":"..."}}}

# Network configuration defines the fundamental connectivity layer
networkConfiguration:
  # DNS server for name resolution
  dnsServerIP: "8.8.8.8"
  
  # Pod network CIDR (default: 10.244.0.0/16)
  networkCIDR: "10.244.0.0/16"
  
  # Service network CIDR (default: 10.96.0.0/12)
  serviceCIDR: "10.96.0.0/12"
  
  # Gateway IP for pod network (default: 10.244.0.1)
  gatewayIP: "10.244.0.1"

# Control plane configuration
controlPlane:
  hosts:
    - address: "192.168.1.10"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/cluster-key"

# Worker nodes configuration
staticWorkers:
  hosts:
    - address: "192.168.1.11"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/cluster-key"
    - address: "192.168.1.12"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/cluster-key"

# Load balancer configuration (exactly one option required)
loadBalancer:
  # Option 1: Enable MetalLB
  metallb:
    ipRange: "192.168.1.100-192.168.1.150"
  
  # Option 2: Disable load balancer (uncomment to use)
  # none: {}

# Storage configuration (exactly one option required)
storage:
  # Option 1: Enable Longhorn distributed storage
  longhorn: {}
  
  # Option 2: Disable managed storage (uncomment to use)
  # none: {}

KubeVirt

KubeVirt is deployed automatically as part of every KubeV installation. The kubevirt section is optional — when omitted, KubeVirt runs with its built-in defaults. You only need to set it if you want to enable specific feature gates or use software emulation.

kubevirt:
  developerConfiguration:
    featureGates:
      - "LiveMigration"
      - "Snapshot"
    useEmulation: false

LiveMigration and Snapshot are the most commonly enabled gates — live migration lets you move running VMs between nodes without downtime, and snapshots let you take point-in-time backups of VM disks. Only set useEmulation: true in development or nested-virtualization environments; it is 10–50× slower than KVM and must not be used in production.

Dashboard

The KubeV web dashboard is optional and disabled by default. Enable it by adding a dashboard section to your configuration file.

The dashboard supports three authentication modes: none, basic, and oidc. The simplest way to get started is none — the dashboard is accessible without a login, suitable for private networks during initial setup:

dashboard:
  enabled: true
  dashboardURL: "https://dashboard.example.com"
  auth:
    none: {}

For basic (username/password) or oidc (SSO via Keycloak, Dex, Azure AD, etc.), see the Configuration Guide.


Installation Procedure

Step 1: Create Configuration File

Create a YAML configuration file (e.g., cluster.yaml) with your cluster specifications:

# Create configuration file
cat > cluster.yaml <<EOF
apiVersion: virtualization.k8c.io/v1alpha1
kind: KubeVCluster

# required — see "Image Pull Secret" above
imagePullSecret: |
  {"auths":{"quay.io":{"auth":"..."}}}

networkConfiguration:
  dnsServerIP: "8.8.8.8"
  networkCIDR: "10.244.0.0/16"
  serviceCIDR: "10.96.0.0/12"
  gatewayIP: "10.244.0.1"

controlPlane:
  hosts:
    - address: "192.168.1.10"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/id_rsa"

staticWorkers:
  hosts:
    - address: "192.168.1.11"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/id_rsa"

loadBalancer:
  metallb:
    ipRange: "192.168.1.100-192.168.1.150"

storage:
  longhorn: {}
EOF

Step 2: Review Installation Plan

Run the apply command to see what will be installed:

kubev apply -f cluster.yaml

The command will display:

INFO[12:01:02 CET] ╔══════════════════════════════════════════════════════════════╗ 
INFO[12:01:02 CET] ║                                                              ║ 
INFO[12:01:02 CET] ║          KubeV - Kubermatic Virtualization Platform          ║ 
INFO[12:01:02 CET] ║                                                              ║ 
INFO[12:01:02 CET] ╚══════════════════════════════════════════════════════════════╝ 
INFO[12:01:02 CET]                                              
INFO[12:01:02 CET] Starting cluster apply process                configFile=cluster.yaml
INFO[12:01:02 CET] Loading configuration file                    file=cluster.yaml
INFO[12:01:02 CET] Configuration loaded and validated successfully  loadBalancer=metallb masterNodes=1 storage=longhorn workerNodes=2
Do you want to proceed (yes/no): 

Step 3: Confirm and Install

Confirm the installation by typing y and pressing Enter. The installation will proceed through multiple phases:

[KubeV] Identifying the operating system...
[KubeV] Setting up required software components...
[KubeV] Creating configuration files...
[KubeV] Performing initial system checks...
...
[KubeV] Configuring virtualization support...

[KubeV] ✓ Cluster installation completed successfully

Cluster Lifecycle Management

The apply command is not just for initial installation—it manages your cluster’s entire lifecycle.

Adding Worker Nodes

Add new nodes to staticWorkers section and apply:

staticWorkers:
  hosts:
    - address: "192.168.1.11"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/id_rsa"
    - address: "192.168.1.12"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/id_rsa"
    # New node
    - address: "192.168.1.13"
      sshUsername: "ubuntu"
      sshPrivateKeyFile: "/home/user/.ssh/id_rsa"
kubev apply -f cluster.yaml

Repairing Unhealthy Clusters

If a node becomes unhealthy or is removed from the cluster, simply run apply again:

kubev apply -f cluster.yaml

The command will:

  1. Detect unhealthy or missing nodes
  2. Determine if repair is safe (no etcd quorum risk)
  3. Rejoin nodes automatically
  4. Restore cluster to healthy state

Checking Cluster Status

To check current cluster state without making changes:

kubev apply -f cluster.yaml --verbose

This shows detailed information about:

  • Current node health
  • Component versions
  • Service status
  • Any detected issues

Troubleshooting

Configuration Validation Errors

Error: configuration validation failed: invalid IP address

Solution: Verify all IP addresses are valid IPv4 addresses:

controlPlane:
  hosts:
    - address: "192.168.1.10"  # ✓ Valid
    # - address: "192.168.1"    # ✗ Invalid

Error: SSH key file does not exist

Solution: Ensure SSH key paths are absolute and files exist:

# Check key file exists
ls -la /home/user/.ssh/id_rsa

# Fix permissions if needed
chmod 600 /home/user/.ssh/id_rsa

Error: exactly one load balancer option must be specified

Solution: Set either metallb or none, not both:

# Choose one:
loadBalancer:
  metallb:
    ipRange: "192.168.1.100-192.168.1.150"
  # OR
  # none: {}

Connection Issues

Error: failed to connect to host: connection refused

Solutions:

  1. Verify SSH connectivity:

    ssh -i /home/user/.ssh/id_rsa ubuntu@192.168.1.10
    
  2. Check firewall rules allow SSH (port 22)

  3. Verify SSH service is running on target nodes:

    systemctl status sshd
    

Upgrade Issues

Error: repair and upgrade are not supported simultaneously

Solution: This occurs when trying to upgrade while nodes are unhealthy. First repair the cluster:

# Step 1: Repair cluster with current version
kubev apply -f cluster.yaml

# Step 2: After repair completes, upgrade
# (update version in cluster.yaml)
kubev apply -f cluster.yaml

Log Analysis

Detailed logs are available at /tmp/kubermatic-virtualization.log:

# View recent logs
tail -f /tmp/kubermatic-virtualization.log

# Search for errors
grep -i error /tmp/kubermatic-virtualization.log

Post-Installation

After successful installation, verify cluster health and begin workload deployment.

Verify Installation

# Set KUBECONFIG
export KUBECONFIG=kubev-cluster-kubeconfig

# Check nodes
kubectl get nodes

# Expected output:
# NAME    STATUS   ROLES           AGE   VERSION
# node1   Ready    control-plane   5m    v1.33.0
# node2   Ready    <none>          4m    v1.33.0

# Check system pods
kubectl get pods --all-namespaces

# Check storage (if Longhorn enabled)
kubectl get pods -n longhorn-system

# Check load balancer (if MetalLB enabled)
kubectl get pods -n metallb-system

Support and Resources

For production deployments, enterprise support, or licensing inquiries, contact Kubermatic at sales@kubermatic.com.