Install Kube OVN
The Kube-OVN project is a Kubernetes Network Plugin that uses OVN as the network provider. It is a CNI plugin that provides a network solution for Kubernetes. It is a lightweight, scalable, and easy-to-use network solution for Kubernetes.
Prerequisites
The override values file for Kube-OVN can be found in /etc/genestack/helm-configs/kube-ovn/kube-ovn-helm-overrides.yaml
and should be setup-up before running the deployment. In a common production ready setup, the only values that will
likely need to be defined is the network interface that will Kube-OVN will bind to.
Example Kube-OVN Helm Overrides
In the example below, the IFACE and VLAN_INTERFACE_NAME are the only values that need to be defined and
are set to br-overlay. If you intend to enable hardware offloading, you will need to set the IFACE to the
a physical interface that supports hardware offloading.
For a full review of all the available options, see the Kube-OVN base helm overrides file.
Example Kube-OVN Helm Overrides
# Default values for kubeovn.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
---
global:
registry:
address: ghcr.io/rackerlabs/genestack-images
images:
kubeovn:
repository: kube-ovn
vpcRepository: vpc-nat-gateway
tag: v1.15.4
support_arm: true
thirdparty: true
image:
pullPolicy: IfNotPresent
replicaCount: 3
networking:
# NET_STACK defaults to ipv4
ENABLE_SSL: true
IFACE: "br-overlay"
vlan:
VLAN_INTERFACE_NAME: "br-overlay"
# VLAN_NAME: "ovn-vlan"
# VLAN_ID: "100"
ENABLE_EIP_SNAT: false
ENABLE_ECMP: true
# comma-separated string of nodelocal DNS ip addresses
PROBE_INTERVAL: 60000
OVN_NORTHD_PROBE_INTERVAL: 15000
OVN_LEADER_PROBE_INTERVAL: 15
OVN_REMOTE_PROBE_INTERVAL: 30000
OVN_NORTHD_N_THREADS: 4 # Number of threads for ovn-northd, default is 4 production environments could set it to a higher value.
ENABLE_COMPACT: true
func:
ENABLE_EXTERNAL_VPC: true
OVSDB_CON_TIMEOUT: 5
OVSDB_INACTIVITY_TIMEOUT: 30
ipv4:
POD_CIDR: "10.236.0.0/14"
POD_GATEWAY: "10.236.0.1"
SVC_CIDR: "10.233.0.0/18"
PINGER_EXTERNAL_ADDRESS: "208.67.222.222"
PINGER_EXTERNAL_DOMAIN: "opendns.com."
performance:
GC_INTERVAL: 360
INSPECT_INTERVAL: 300
OVS_VSCTL_CONCURRENCY: 150
Label Kube-OVN nodes
key |
type | value |
notes |
|---|---|---|---|
| kube-ovn/role | str | master |
Defines where the Kube-OVN Masters will reside |
| ovn.kubernetes.io/ovs_dp_type | str | kernel |
(Optional) Defines OVS DPDK mode |
Label all controllers as Kube-OVN control plane nodes
Deployment
To run the Kube-OVN deployment, run the following command commands or script.
Run the Kube-OVN deployment Script /opt/genestack/bin/install-kube-ovn.sh
#!/bin/bash
# Description: Fetches the version for SERVICE_NAME_DEFAULT from the specified
# YAML file and executes a helm upgrade/install command with dynamic values files.
# Disable SC2124 (unused array), SC2145 (array expansion issue), SC2294 (eval)
# shellcheck disable=SC2124,SC2145,SC2294
# Service
SERVICE_NAME_DEFAULT="kube-ovn"
SERVICE_NAMESPACE="kube-system" # Note: kube-ovn uses the kube-system namespace
# Helm
HELM_REPO_NAME_DEFAULT="kubeovn"
HELM_REPO_URL_DEFAULT="https://kubeovn.github.io/kube-ovn"
# Base directories provided by the environment
GENESTACK_BASE_DIR="${GENESTACK_BASE_DIR:-/opt/genestack}"
GENESTACK_OVERRIDES_DIR="${GENESTACK_OVERRIDES_DIR:-/etc/genestack}"
# Define service-specific override directories based on the framework
SERVICE_BASE_OVERRIDES="${GENESTACK_BASE_DIR}/base-helm-configs/${SERVICE_NAME_DEFAULT}"
SERVICE_CUSTOM_OVERRIDES="${GENESTACK_OVERRIDES_DIR}/helm-configs/${SERVICE_NAME_DEFAULT}"
# Define the Global Overrides directory used in the original script
GLOBAL_OVERRIDES_DIR="${GENESTACK_OVERRIDES_DIR}/helm-configs/global_overrides"
# Read the desired chart version from VERSION_FILE
VERSION_FILE="${GENESTACK_OVERRIDES_DIR}/helm-chart-versions.yaml"
if [ ! -f "$VERSION_FILE" ]; then
echo "Error: helm-chart-versions.yaml not found at $VERSION_FILE" >&2
exit 1
fi
# Extract version dynamically using the SERVICE_NAME_DEFAULT variable
SERVICE_VERSION=$(grep "^[[:space:]]*${SERVICE_NAME_DEFAULT}:" "$VERSION_FILE" | sed "s/.*${SERVICE_NAME_DEFAULT}: *//")
if [ -z "$SERVICE_VERSION" ]; then
echo "Error: Could not extract version for '$SERVICE_NAME_DEFAULT' from $VERSION_FILE" >&2
exit 1
fi
echo "Found version for $SERVICE_NAME_DEFAULT: $SERVICE_VERSION"
# --- Kube-OVN specific logic to determine masters and replica count ---
MASTER_NODES=$(kubectl get nodes -l kube-ovn/role=master -o json | jq -r '[.items[].status.addresses[] | select(.type == "InternalIP") | .address] | join(",")' | sed 's/,/\\,/g')
MASTER_NODE_COUNT=$(kubectl get nodes -l kube-ovn/role=master -o json | jq -r '.items[].status.addresses[] | select(.type=="InternalIP") | .address' | wc -l)
if [ "${MASTER_NODE_COUNT}" -eq 0 ]; then
echo "Error: No master nodes found labeled with 'kube-ovn/role=master'" >&2
echo "Be sure to label your master nodes with 'kube-ovn/role=master' before running this script." >&2
exit 1
fi
echo "Found $MASTER_NODE_COUNT master node(s) with IPs: ${MASTER_NODES//\\,/ }."
# --------------------------------------------------------------------
# Load chart metadata from custom override YAML if defined
for yaml_file in "${SERVICE_CUSTOM_OVERRIDES}"/*.yaml; do
if [ -f "$yaml_file" ]; then
HELM_REPO_URL=$(yq eval '.chart.repo_url // ""' "$yaml_file")
HELM_REPO_NAME=$(yq eval '.chart.repo_name // ""' "$yaml_file")
SERVICE_NAME=$(yq eval '.chart.service_name // ""' "$yaml_file")
break # use the first match and stop
fi
done
# Fallback to defaults if variables not set
: "${HELM_REPO_URL:=$HELM_REPO_URL_DEFAULT}"
: "${HELM_REPO_NAME:=$HELM_REPO_NAME_DEFAULT}"
: "${SERVICE_NAME:=$SERVICE_NAME_DEFAULT}"
# Determine Helm chart path
if [[ "$HELM_REPO_URL" == oci://* ]]; then
# OCI registry path
HELM_CHART_PATH="$HELM_REPO_URL/$HELM_REPO_NAME/$SERVICE_NAME"
else
# --- Helm Repository and Execution ---
helm repo add "$HELM_REPO_NAME" "$HELM_REPO_URL"
helm repo update
HELM_CHART_PATH="$HELM_REPO_NAME/$SERVICE_NAME"
fi
# Debug output
echo "[DEBUG] HELM_REPO_URL=$HELM_REPO_URL"
echo "[DEBUG] HELM_REPO_NAME=$HELM_REPO_NAME"
echo "[DEBUG] SERVICE_NAME=$SERVICE_NAME"
echo "[DEBUG] HELM_CHART_PATH=$HELM_CHART_PATH"
# Prepare an array to collect -f arguments
overrides_args=()
# Include all YAML files from the BASE configuration directory
# NOTE: Files in this directory are included first.
if [[ -d "$SERVICE_BASE_OVERRIDES" ]]; then
echo "Including base overrides from directory: $SERVICE_BASE_OVERRIDES"
for file in "$SERVICE_BASE_OVERRIDES"/*.yaml; do
# Check that there is at least one match
if [[ -e "$file" ]]; then
echo " - $file"
overrides_args+=("-f" "$file")
fi
done
else
echo "Warning: Base override directory not found: $SERVICE_BASE_OVERRIDES"
fi
# Include all YAML files from the GLOBAL configuration directory
# NOTE: Files here override base settings and are applied before service-specific ones.
if [[ -d "$GLOBAL_OVERRIDES_DIR" ]]; then
echo "Including global overrides from directory: $GLOBAL_OVERRIDES_DIR"
for file in "$GLOBAL_OVERRIDES_DIR"/*.yaml; do
if [[ -e "$file" ]]; then
echo " - $file"
overrides_args+=("-f" "$file")
fi
done
else
echo "Warning: Global override directory not found: $GLOBAL_OVERRIDES_DIR"
fi
# Include all YAML files from the custom SERVICE configuration directory
# NOTE: Files here have the highest precedence.
if [[ -d "$SERVICE_CUSTOM_OVERRIDES" ]]; then
echo "Including overrides from service config directory:"
for file in "$SERVICE_CUSTOM_OVERRIDES"/*.yaml; do
if [[ -e "$file" ]]; then
echo " - $file"
overrides_args+=("-f" "$file")
fi
done
else
echo "Warning: Service config directory not found: $SERVICE_CUSTOM_OVERRIDES"
fi
echo
# Collect all --set arguments, executing commands and quoting safely
set_args=(
--set "MASTER_NODES=${MASTER_NODES}"
--set "replicaCount=${MASTER_NODE_COUNT}"
)
helm_command=(
helm upgrade --install "$SERVICE_NAME_DEFAULT" "$HELM_CHART_PATH"
--version "${SERVICE_VERSION}"
--namespace="$SERVICE_NAMESPACE"
--timeout 120m
--create-namespace
"${overrides_args[@]}"
"${set_args[@]}"
# Post-renderer configuration
--post-renderer "$GENESTACK_OVERRIDES_DIR/kustomize/kustomize.sh"
--post-renderer-args "$SERVICE_NAME_DEFAULT/overlay"
"$@"
)
echo "Executing Helm command (arguments are quoted safely):"
printf '%q ' "${helm_command[@]}"
echo
# Execute the command directly from the array
"${helm_command[@]}"
Deployment Verification
Once the script has completed, you can verify that the Kube-OVN pods are running by running the following command
Output
NAME PROVIDER VPC PROTOCOL CIDR PRIVATE NAT DEFAULT GATEWAYTYPE V4USED V4AVAILABLE V6USED V6AVAILABLE EXCLUDEIPS U2OINTERCONNECTIONIP
join ovn ovn-cluster IPv4 100.64.0.0/16 false false false distributed 3 65530 0 0 ["100.64.0.1"]
ovn-default ovn ovn-cluster IPv4 10.236.0.0/14 false true true distributed 111 262030 0 0 ["10.236.0.1"]
Tip
After the deployment, and before going into production, it is highly recommended to review the Kube-OVN Backup documentation, from the operators guide for setting up you backups.
Upon successful deployment the Kubernetes Nodes should transition into a Ready state. Validate the nodes are ready by
running the following command.