vSphere Kubernetes Service (VKS)
Big picture
Install Calico Enterprise as a Supervisor Service on vSphere Kubernetes Service (VKS), and deploy it to guest clusters.
Before you begin
This guide requires:
- VM Images: Ubuntu or Photon OVA images registered for a supported TKR version, with TKR in a healthy state. For Windows node pools, Windows Server OVA images are also required.
- vSphere Resources: Sufficient capacity to provision guest clusters with at minimum:
- 1 control plane node
- 3 Linux worker nodes
- OCI Registry: An OCI-compliant registry configured in vSphere for storing package manifests and container images.
- Tigera registry credentials for accessing the Tigera container registry (contact the Tigera team).
- VKS v3.8 and above
- vCenter - v9.1.1 and above
Networking
| Configuration | Dataplane | Encapsulation | BGP |
|---|---|---|---|
| Linux only (default) | IPTables | IPIP | Enabled |
How to
Setting up Calico Enterprise on VKS has two main phases: set it as a Supervisor Service (Part 1) in vSphere Client (one time), then deploy it to a guest cluster (Part 2). For Air-gapped environments follow the additional steps in the Air-gapped environment section.
Part 1: Set up the Supervisor Service (one time cluster admin setup)
-
In the vSphere Client - Container Registries page setup the Tigera container registry's credentials for pulling Calico Enterprise images from Tigera's private container registry.
- Use
quay.ioas the Registry host URL, and Username/Password provided by Tigera. For air-gapped installs, add the private registry that holds the Calico Enterprise images instead (see Air-gapped private container registry).
- Use
-
In the vSphere Client - Supervisor Management page:
- Create a new Supervisor Service (or add a new version to an existing one).
- Upload Supervisor service Package and PackageMetadata resources (example below) and complete the setup workflow.
- Register the Supervisor Service and set
registryNameto match the registry name configured for Tigera's private container registry.
---
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
name: calico-enterprise-svs.tigera.io.3.23.3
spec:
refName: calico-enterprise-svs.tigera.io
version: 3.23.3
template:
spec:
fetch:
- imgpkgBundle:
image: quay.io/tigera/calico-enterprise-svs:v3.23.3 #Change this to the registry where the carvel package is getting picked up
template:
- ytt:
paths:
- service
- kapp
- kbld:
paths:
- "-"
- .imgpkg/images.yml
- kbld/
deploy:
- kapp: {}
---
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: PackageMetadata
metadata:
name: calico-enterprise-svs.tigera.io
spec:
displayName: "Calico Enterprise SVS"
shortDescription: "Manages Calico Enterprise Addon Repository and Installation"
Part 2: Deploy a guest cluster with Calico Enterprise
Guest cluster prerequisites
- Tigera license file (contact the Tigera team).
- Dynamic PV provisioning via a StorageClass, required for Elasticsearch storage.
Step 1 (optional): Apply the AddonConfig
An AddonConfig is needed only if you want to change the default Calico Enterprise configuration, for example to create a cluster with Windows nodes. It is not required for a Linux-only cluster that uses the defaults.
The following example AddonConfig enables the Windows dataplane and disables policy recommendation.
Update the following fields before applying:
metadata.nameandmetadata.namespacespec.values.helmValues.installation.registryto use Calico Enterprise images from a private registry (for air-gapped installs). This should be the same registry where Calico Enterprise images are pushed to using Air-gapped private container registry of this doc. Optionallyspec.values.helmValues.installation.imagePathcan be set if the Calico Enterprise images were pushed to a specific folder within the private registry.
All Calico Enterprise features (logCollector, logStorage, manager, monitor, policyRecommendation) are optional. Only apiServer is required. Set any unwanted features to false.
kubectl apply -f ./addon-config.yaml
apiVersion: addons.kubernetes.vmware.com/v1alpha1
kind: AddonConfig
metadata:
name: <cluster-name>-calico-enterprise # The AddonConfig name has to be in this format eg. cluster1-calico-enterprise
namespace: <cluster-namespace>
spec:
values:
helmValues:
# Every option from tigera-helm-charts/tigera-operator/values.yaml may be
# set here. Anything not specified falls back to the default declared in
# the AddonConfigDefinition schema. The fields below are illustrative;
installation:
calicoWindowsDataplane:
enabled: true
policyRecommendation:
enabled: false
The Addon framework expects the AddonConfig name to use the format <cluster-name>-<addon-name>. If the name does not match this format, the framework ignores the AddonConfig and creates a new one with default values instead.
Step 2 (optional): Apply the Custom AddonInstall resource
A custom AddonInstall resource is needed only if you want to control which clusters get upgraded. It lets you upgrade clusters selectively. Use spec.clusters.selector.matchLabels to specify the labels that a cluster must have, and then add those labels to the Cluster resources you want to upgrade.
kubectl apply -f ./addon-install.yaml
apiVersion: addons.kubernetes.vmware.com/v1alpha1
kind: AddonInstall
metadata:
labels:
addon.kubernetes.vmware.com/addon-name: calico-enterprise
addon.kubernetes.vmware.com/addon-namespace: vmware-system-vks-public
addons.kubernetes.vmware.com/category: cni
name: <addon-install-name>
namespace: <cluster-namespace>
spec:
addonRef:
name: calico-enterprise
namespace: vmware-system-vks-public
clusters:
- selector:
matchLabels:
<AddonInstallLabelKey>: <AddonInstallLabelValue> # Eg. cluster-group: calico-group-1
constraints:
expression: cluster.cniRefName() = "calico-enterprise" && cluster.kubeProxyConfiguration().enabled == true
releaseFilter:
ref:
name: calico-enterprise.tigera.io.3.23.3
stopMatchingBehavior: Retain
Step 3: Apply the Cluster Resource
The following example creates a cluster with Linux and Windows node pools. To create a Linux-only cluster, remove the Windows node pool (windows-pool).
Update the following fields before applying:
metadata.nameandmetadata.namespacespec.topology.variables[].value.cniRef(name and namespace of the Calico Enterprise addon)- If you applied a custom AddonInstall in Step 2, add its label (
<AddonInstallLabelKey>: <AddonInstallLabelValue>) tometadata.labels. - Node pool configuration (VM class, storage class, replicas) as needed for your environment
kubectl apply -f ./cluster.yaml
apiVersion: cluster.x-k8s.io/v1beta2
kind: Cluster
metadata:
name: <cluster-name>
namespace: <cluster-namespace>
spec:
clusterNetwork:
pods: {cidrBlocks: [100.96.0.0/11]}
services: {cidrBlocks: [100.64.0.0/13]} # required for Windows (becomes serviceCIDRs)
serviceDomain: cluster.local
topology:
classRef: {name: builtin-generic-v3.8.0, namespace: vmware-system-vks-public}
version: v1.36.4+vmware.2-vkr.3
controlPlane:
replicas: 1
metadata: &ubuntu
annotations: {run.tanzu.vmware.com/resolve-os-image: "os-name=ubuntu,os-version=24.04"}
workers:
machineDeployments:
- {class: node-pool, name: linux-pool-1, replicas: 3, metadata: *ubuntu,
variables: {overrides: [{name: vmClass, value: best-effort-large}]}}
- {class: node-pool, name: linux-pool-2, replicas: 2, metadata: *ubuntu}
- class: node-pool
name: windows-pool
replicas: 2
metadata:
annotations: {run.tanzu.vmware.com/resolve-os-image: "os-name=windows,os-version=2022"}
variables: {overrides: [{name: vmClass, value: best-effort-xlarge}]}
variables:
- {name: bootstrapAddons, value: {cniRef: {name: calico-enterprise, namespace: vmware-system-vks-public}}}
- {name: vmClass, value: best-effort-xlarge}
- {name: storageClass, value: vsan-esa-default-policy-raid5}
- {name: vsphereOptions, value: {persistentVolumes: {defaultStorageClass: vsan-esa-default-policy-raid5}}}
- {name: kubernetes, value: {certificateRotation: {enabled: true, renewalDaysBeforeExpiry: 90}}}
# Must be cluster-level: the Calico ACD only reads spec.topology.variables.
- {name: osConfiguration, value: {windowsToolsConfig: {excludeNICs: ["cali*"]}}}
- name: node
value:
firewall:
inboundRules:
- {protocol: tcp, fromPort: 179, toPort: 179} # BGP
- {protocol: udp, fromPort: 4789, toPort: 4789} # VXLAN
- {protocol: tcp, fromPort: 5473, toPort: 5473} # Typha
- {protocol: udp, fromPort: 51820, toPort: 51820} # WireGuard
- {protocol: tcp, fromPort: 8444, toPort: 8444} # Linseed
- {protocol: tcp, fromPort: 9090, toPort: 9090} # Prometheus
- {protocol: tcp, fromPort: 9200, toPort: 9200} # Elasticsearch
- {protocol: tcp, fromPort: 9300, toPort: 9300} # Elasticsearch transport
- {protocol: tcp, fromPort: 9443, toPort: 9443} # Manager UI
Step 4: Retrieve the Guest Cluster Kubeconfig
Can be copied from the Supervisor.
Step 5: Wait for Core Components
Monitor the Tigera status until calico and apiserver report as Available:
kubectl get tigerastatus
At this point, all nodes should be in Ready state.
Step 6 (Windows only): Configure Windows nodes
Skip this step for Linux-only clusters.
-
After
apiserverreports asAvailable, setstrictAffinitytotruein the IPAM configuration:kubectl patch ipamconfigurations default --type merge -p '{"spec":{"strictAffinity":true}}'If the IPAM configuration does not exist yet, create it:
kubectl apply -f - <<EOFapiVersion: projectcalico.org/v3kind: IPAMConfigurationmetadata: {name: default}spec: {strictAffinity: true}EOF -
Install kube-proxy for Windows:
curl -L https://raw.githubusercontent.com/kubernetes-sigs/sig-windows-tools/master/hostprocess/calico/kube-proxy/kube-proxy.yml | sed "s/KUBE_PROXY_VERSION/<YOUR_KUBERNETES_VERSION>/g" | kubectl apply -f -Replace
<YOUR_KUBERNETES_VERSION>with the Kubernetes version of the guest cluster, for examplev1.36.4.💡 Tip: The K8s version can be retrieved with
kubectl version -o json | jq -r '.serverVersion.gitVersion'ℹ️ Note: If the version returned is of the form
v1.36.4+vmware.2, strip the+vmware.2suffix unless a VMware-provided kube-proxy image exists in thesigwindowstools/kube-proxyrepository. ℹ️ Note: For Air-gapped environments copy the kube-proxy.yaml to the air-gapped environment and make the changes.
Step 7: Apply the Tigera License
kubectl apply -f tigera-license.yaml
Step 8: Verify the Installation
Wait for all remaining components to become available:
kubectl get tigerastatus
kubectl get pods -A | grep -E 'tigera|calico'
Once all items in tigerastatus show Available, the installation is complete. You can now deploy workloads to validate networking.
Air-gapped environment
Air-gapped package registry
If the published bundles need to be moved into a private OCI registry (for example, an air-gapped install), follow these steps.
Air-gapped relocation prerequisites
imgpkgandyqavailable locally.- Network access to the source registry (or a tarball produced from it) and to the private registry.
- Credentials to push to the private registry (
imgpkgwill prompt or use the local docker config).
Step 1: Copy the Supervisor Service (SVS) bundles to a tarball (source side)
Run on a host that has access to the source registry:
imgpkg copy --bundle <source-registry>/calico-enterprise-svs:v3.23.3 --to-tar calico-enterprise-svs.tar
Direct registry-to-registry relocation is also supported. Replace --to-tar <file>.tar with --to-repo <private-registry>/<path> and skip Step 2.
Step 2: Push the SVS bundle into the private registry (destination side)
imgpkg copy --tar calico-enterprise-svs.tar --to-repo <customer-registry>/calico-enterprise-svs
Step 3: Patch Package Resource in calico-enterprise-svs.yaml
The only registry reference outside the bundles is the service-bundle pointer in the Package CR inside calico-enterprise-svs.yaml. This needs to be updated to the private registry:
yq eval '
(select(.kind == "Package") | .spec.template.spec.fetch[0].imgpkgBundle.image)
= "<private-registry>/calico-enterprise-svs:v3.23.3"
' -i calico-enterprise-svs.yaml
Content-pin to digest (optional): imgpkg copy --to-repo prints the destination digest of the relocated bundle on its last line. Substituting :v3.23.3 with @sha256:<that-digest> in the yq command above will make the reference immutable.
Step 4: Upload calico-enterprise-svs.yaml i.e. Package and PackageMetadata resource to the Supervisor
Upload the new Package and PackageMetadata to the vSphere Client - Supervisor Management as in Part 1, 2 and continue with the remaining steps to create a guest cluster.
What does not work
docker pull/docker pushon individual images. Re-tagging can change manifest digests, and the bundles'images.ymllock files are not rewritten — kapp-controller fetches will fail withmanifest unknown.- Not Copying the svs bundle during
imgpkg copyrun. The other 2 bundles are pulled by the svs package.
Air-gapped private container registry: Relocate Calico Enterprise private images to a private registry
Follow the steps in Push Calico Enterprise images to your private registry to pull Calico Enterprise images from Tigera's private image registry to your private registry.
Only steps 1, 2, 3, 4 — i.e. docker pull, docker tag and docker push for Linux only need to be performed.
Do not push Calico Enterprise private images to a public registry.
Next steps
Recommended
- Configure access to the Calico Enterprise web console
- Get started with Calico Enterprise tiered network policy
Recommended - Networking
- For all networking options, see Determine best networking option.