vCluster Pro air-gapped install
This document details the prerequisites and steps to install vCluster Pro into
an air-gapped
Kubernetes cluster without the platform agent running on the host
cluster.
Prerequisites​
-
Administrator access to a Kubernetes cluster: See Accessing Clusters with kubectl for more information. Your current kube-context must have administrative privileges, which you can verify with
kubectl auth can-i create clusterrole -A
infoTo obtain a kube-context with admin access, ensure you have the necessary credentials and permissions for your Kubernetes cluster. This typically involves using
kubectl config
commands or authenticating through your cloud provider's CLI tools. -
helm
installed: Helm v3.10 is required for deploying the platform. Refer to the Helm Installation Guide if you need to install it. -
kubectl
installed: Kubernetes command-line tool for interacting with the cluster. See Install and Set Up kubectl for installation instructions.
-
docker
(check withdocker version
) -
An offline license key for vCluster Pro (provided by Loft)
infoContact sales@loft.sh to purchase an offline license key or request a trial license key for offline use.
-
Optionally: private docker registry that the installer computer and the air-gapped Kubernetes cluster can access (e.g. x-private-registry:5000 or gcr.io/x-team)
Example Local Registry Setup
Local Docker Registry Configuration​
It is easy to setup a private Docker registry for testing purposes using KIND cluster. The following steps show how to set up a Docker registry locally:
Basic Setup: Execute the setup script from the KIND webpage:
Verify & Use:
# Verify registry
curl http://localhost:5001/v2/_catalog
Download vCluster Helm chart​
Download the vCluster
Helm chart from the Loft Helm repository.
To retrieve all available versions of the vCluster Helm chart, run the following command:
helm repo update
helm search repo loft/vcluster --versions | grep "^loft/vcluster" | head
export CHART_VERSION="0.21.1" # Replace with the desired version
curl -O https://charts.loft.sh/charts/vcluster-"${CHART_VERSION}".tgz
The vCluster
Helm chart is a tarball that contains all the necessary images
to deploy the vCluster control plane.
Download and push required container images​
For clusters unable to pull images from Docker Hub, you need to push the
platform images to your private registry. Each vCluster release includes a
vcluster-images.txt
file that lists the necessary images.
When using virtual clusters in air-gapped environments, the
config.experimental.deploy.vcluster.helm
configuration setting does not work with external Helm repositories since they cannot be accessed. This means custom Helm charts from repositories like charts.bitnami.com
cannot be used for virtual cluster deployments.
Follow these instructions to download all vCluster images and import them to your private registry:
Set environment variables for the setup process:
Export environment variablesexport VCLUSTER_SERVICE="vcluster"
export VCLUSTER_NAMESPACE="vcluster"
export REGISTRY=ecr.io/myteam # This should be a prefix; do not include any LOFT_IMAGE paths- Existing vCluster Installation
- No vCluster Installation
Retrieve the vCluster version and set the
VERSION
variable:Retrieve and set VERSIONCHART=$(kubectl get service "${VCLUSTER_SERVICE}" -n "${VCLUSTER_NAMESPACE}" -o jsonpath={.metadata.labels.chart})
export VERSION=${CHART#vcluster-} # Remove 'vcluster-' prefixSet the
VERSION
variable to the latest vCluster version you want to install:Set VERSION variable for fresh installationexport VERSION=<latest-version> # e.g., "0.21.1"
Download the
vcluster-images.txt
file and the required scriptsdownload-images.sh
andpush-images.sh
, then make them executable.tipNote that the
vcluster-images.txt
contains all the distros and versions. You can edit the file and remove images you do not need. Each release also has a correspondingvcluster-images-k8s-[version].txt
file, use it to download k8s distro images for the desired version.Download and prepare scriptswget https://github.com/loft-sh/vcluster/releases/download/v"${VERSION}"/vcluster-images.txt
wget https://github.com/loft-sh/vcluster/releases/download/v"${VERSION}"/download-images.sh
wget https://github.com/loft-sh/vcluster/releases/download/v"${VERSION}"/push-images.sh
chmod +x ./download-images.sh
chmod +x ./push-images.shRun
download-images.sh
to download all images locally:Download images./download-images.sh --image-list vcluster-images.txt
tipThis creates a tarball with all the images and push them to your private registry.
Run
push-images.sh
to push all downloaded images to your private registry:Push images to private registry./push-images.sh --registry ${REGISTRY}
infovCluster prepends the image registry to all images used by vCluster, such as syncer and Kubernetes. For example,
registry.k8s.io/kube-apiserver:v1.30.2
becomesmy-private-registry:5000/vcluster/kube-apiserver:v1.30.2
.
Configure vCluster for air-gapped install​
The vcluster.yaml
file holds your vCluster configuration and allows overriding the vCluster Helm chart default values.
Edit your existing vcluster.yaml
file or create a new one with the following content:
To retrieve supported Kubernetes versions:
curl http://"${REGISTRY}"/v2/kube-controller-manager/tags/list
export KUBERNETES_VERSION="v1.31.1" # Replace with the desired version
cat <<EOF > vcluster.yaml
controlPlane:
advanced:
defaultImageRegistry: ${REGISTRY}
distro:
k8s:
version: ${KUBERNETES_VERSION}
EOF
If your REGISTRY
is set to ecr.io/myteam
, a fully formed registry path might look like:
ecr.io/myteam/ghcr.io/loft-sh/vcluster:0.21.0
The alpine
image may be replaced with any similar image with the following vcluster.yaml
configuration:
sync:
toHost:
pods:
rewriteHosts:
initContainer:
image: your-registry/your-image:1.0.0
The image that is used to replace the default image must be able to run the following command:
Command: []string{"sh"},
Args: []string{"-c", "sed -E -e 's/^(\\d+.\\d+.\\d+.\\d+\\s+)" + fromHost + "$/\\1 " + toHostnameFQDN + " " + toHostname + "/' /etc/hosts > /hosts/hosts"}
Optionally create image pull secret​
The imagePullSecrets
setting defines extra image pull secrets for the vCluster control plane ServiceAccount
.
This configuration is only necessary if your registry requires authentication.
controlPlane:
advanced:
serviceAccount:
imagePullSecrets:
- name-of-your-image-pull-secret
Configure API key​
The apiKey
provides a way to deploy vCluster with Pro features without the platform agent installed on the host cluster.
Although the config appears similar to when using the platform, the apiKey
secret's actual value is your air-gapped license key.
cat <<EOF > platform-api-key.yaml
external:
platform:
apiKey:
# The air-gapped license key provided by Loft has to be the data
# under the first key (name does not matter) of the secret.
secretName:
# Namespace to search for the secret. If undefined,
# it searches the namespace that the vCluster is deployed in.
# If different than the namespace of the vCluster deployment,
# then vCluster needs access to that namespace.
namespace:
# Default enabled to create the necessary RBAC roles
# and role bindings in order to find the secret
createRBAC: true
EOF
Deploy vCluster Pro​
License Setup
Create a Kubernetes
Secret
from the License Key provided by Loft in theNamespace
where you are installing the air-gapped vCluster instance:tipLicense secret is already
base64
encoded.Create Kubernetes Secret#!/bin/bash
# Set the license key as an environment variable (already base64 encoded)
export VCLUSTER_LICENSE_KEY="YOUR_BASE64_ENCODED_LICENSE_KEY_HERE"
# Optionally create the namespace
kubectl create namespace vcluster-ns
# Create secret
kubectl create -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: vcluster-platform-api-key
namespace: vcluster-ns
type: Opaque
data:
license: ${VCLUSTER_LICENSE_KEY}
EOFConfiguration File
At this point, you should have a
vcluster.yaml
file with the necessary configuration for your air-gapped vCluster Pro installation. It could look something like this:Create a
vcluster.yaml
file (Helm chart values file) based on the configuration examples from above:vcluster.yaml configurationcontrolPlane:
advanced:
defaultImageRegistry: my-private-registry:5000/vcluster/
serviceAccount:
imagePullSecrets:
- name-of-your-image-pull-secret
backingStore:
etcd:
embedded:
enabled: true
coredns:
embedded: true
external:
platform:
apiKey:
secretName: vcluster-platform-api-keyInstall vCluster Pro
Use Helm to install the vCluster Pro instance into the
namespace
where you installed the licensesecret
:Install vCluster Pro with Helmexport VCLUSTER_PRO_NAME="vcluster-pro"
export VCLUSTER_PRO_NAMESPACE="vcluster-ns"
helm upgrade --install "${VCLUSTER_PRO_NAME}" vcluster-${VERSION}.tgz \
--version ${VERSION} \
--values vcluster.yaml \
--namespace ${VCLUSTER_PRO_NAMESPACE} \
Air-gapped vCluster Pro with FIPS images​
To run vCluster in a FIPS compliant environment, the vcluster.yaml
needs to be configured to use the Loft GitHub Container Registry with the FIPS compliant images for the syncer (vCluster control plane StatefulSet
) and the Kubernetes distro images and configured to use the vCluster Pro embedded CoreDNS.
Refer to the FIPS configuration guide for more details.
The following is an example vcluster.yaml
configuration of air-gapped vCluster Pro with FIPS compliant images and assumes you have created a Secret
named vcluster-platform-api-key
with the air-gapped license key provided by Loft in the same Namespace
where you are deploying the vCluster instance
FIPS configuration
controlPlane:
advanced:
defaultImageRegistry: ghcr.io
virtualScheduler:
enabled: true
backingStore:
etcd:
embedded:
enabled: true
coredns:
embedded: true
distro:
k8s: # FIPS support is only available for the k8s distribution
version: v1.28.14
enabled: true
apiServer:
image:
repository: loft-sh/kubernetes-fips
controllerManager:
image:
repository: loft-sh/kubernetes-fips
scheduler:
image:
repository: loft-sh/kubernetes-fips
hostPathMapper:
enabled: true
statefulSet:
image:
repository: loft-sh/vcluster-pro-fips
resources:
limits:
cpu: 2
memory: 4Gi
requests:
cpu: 0
memory: 0
scheduling:
podManagementPolicy: OrderedReady
external:
platform:
apiKey:
secretName: license
policies:
limitRange:
enabled: false
podSecurityStandard: privileged
resourceQuota:
enabled: false
pro: true
external:
platform:
apiKey:
secretName: vcluster-platform-api-key