## Requirements
Per [Broadcom's requirements](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-supervisor/8-0/vsphere-supervisor-concepts-and-planning/requirements-for-enabling-a-single-cluster-supervisor/requirements-for-cluster-supervisor-deployment-with-vds-networking-and-haproxy-load-balancer.html)
:
| System | Minimum Deployment Size | CPU | Memory | Storage |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | -------------- | -------------- |
| vCenter Server<br><br>8.0 | Small | 2 | 21 GB | 290 GB |
| ESXi hosts 8.0 | Without vSAN: 3 ESXi hosts with 1 static IP per host.<br><br>With vSAN: 4 ESXi hosts with at least 2 physical NICs.<br><br>The hosts must be joined in a cluster with vSphere DRS and HA enabled. vSphere DRS must be in Fully Automate or Partially Automate mode.<br><br>Make sure that the names of the hosts that join the cluster use lower case letters. Otherwise, the enablement of the cluster for Workload Management might fail. | 8 | 64 GB per host | Not applicable |
| Kubernetes control plane VMs | 3 | 4 | 16 GB | 16 GB |
In my Setup I deployed the Cluster Supervisor with HAProxy & VDS with 3 ESXi hosts & vSAN.
During the Setup inside vCenter, it will check for the requirements, although they are different from Broadcom's official requirements:
![[Pasted image 20250418103036.png||625]]
### Network
| VLAN | Subnet | Description | Assignments |
| ---- | --------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 005 | 192.168.5.0/24 | Management VLAN | 192.168.5.1 = Gateway<br>192.168.5.90 = DNS<br>192.168.5.70 = vCenter<br>192.168.5.115 = lb-01.lab.sponar.de(AVI LB Management Interface)<br>192.168.5.116 = lb-01.lab.sponar.de(AVI LB Managemenet vIP)<br>192.168.5.120-125 = Supervisor control plane VMs<br>192.168.5.126-140 = AVI LB Service Engine IP Pool<br>192.168.5.201-204 = Supervisor Node IPs<br>192.168.5.205 = Supervisor vIP |
| 052 | 192.168.52.0/24 | Workload Network | 192.168.52.1 = Gateway<br>192.168.52.10-200 = Supervisor Workload IP Pool |
| 053 | 192.168.53.0.24 | Data Network | 192.168.53.1 = Gateway<br>192.168.53.100-200 = AVI LB vIP/Service Engine IP Pool |
| 054 | 192.168.54.0/24 | Workload Network 2 | 192.168.54.1 = Gateway |
## Setup
The setup procedure is explained in great detail in [Broadcom's official documentation](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-supervisor/8-0/installing-and-configuring-vsphere-supervisor/deploy-a-one-zone-supervisor/deploy-a-supervisor-with-vds-networking.html)
### Installing HAProxy (depreceated)
HAProxy seems to be no longer in development looking at the last commits, it is highly recommended using VMware AVI Loadbalancer instead.
see [Broadcom HAProxy Installation gudie](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-supervisor/8-0/installing-and-configuring-vsphere-supervisor/networking-for-vsphere-with-tanzu/install-and-configure-the-haproxy-load-balancer.html)
Before starting the Appliance after deployment, we need to set an advanced option to allow for the VM to boot.
see [Broadcom KB](https://knowledge.broadcom.com/external/article?articleId=377393)
Advanced Option:
```
guest_rpc.auth.cloud-init.set=FALSE
```
![[Pasted image 20250418115525.png||425]]
### Installing VMware AVI Load Balancer
Currently only certain versions of AVI Load balancer allow for licensing through the Tanzu basic tier.
In the future VMUG will also receive keys for Enterprise/Basic, for now we need to install an older version.
Known to work version: `controller-22.1.7-9093`
Deploy the OVA inside your vSphere Environment and fill out the necessary values for your environment.
After the deployment is done, start the VM. This will usually take ~10 minutes.
Open the AVI Load balancer webinterface (reachable over :443)
Set your admin credentials and login.
#### Switching the License
Navigate to licensing and ensure to switch over to the essentials tier for Tanzu
![[image-1.webp|| 800]]
![[image-2.webp|800]]
#### Configure SSL Certificate
Navigate to `Templates -> Security -> SSL/TLS Certificates -> Create -> Controller Certificate`
![[image-3.webp]]
Choose to either create a CSR or import a certificate/private key from your CA
![[image-4.webp| 800]]
Navigate to `Administration -> System Settings` and click on `Edit`
![[image-6.webp| 800]]
Navigate to the `Access Section` and remove all default certificates inside the `SSL/TLC Certificate Selection`, then replace it with your imported certificate.
![[image-7.webp]]
After you force refresh the site, it should use your imported certificate for the webinterface.
#### Configure Cloud
Navigate to `Infrastructure -> Clouds` and edit the `Default-Cloud`
![[image-9.webp|800]]
for `Type` select `VMware vCenter/vSphere ESX`. For `Template Service Engine Group` the `Default-Group`. Scroll down and click on `Set Credentials`. Check the box for `Prefer Static Routes vs Directly Connected Network for Virtual Service Placement`
![[Pasted image 20250608102527.png||800]]
Enter your information and confirm with pressing `Connect`
![[Pasted image 20250607213227.png]]
Select your Datacenter for the deployment and the content Library. Click on `Save & Relaunch` to proceed.
![[Pasted image 20250607213422.png||800]]
Scroll down to the Management Network section and enter your Management Network details
![[Pasted image 20250607213924.png||800]]
Now for the last step inside the cloud config, scroll down to `IPAM/DNS` and create a new Profile
![[Pasted image 20250607214031.png||800]]
Give the Profile a name, select the Default Cloud and add your `Data Network` Portgroup, click on `Save`
![[Pasted image 20250607214305.png||800]]
Click on `Save` again to exit the Cloud Config, the Status of the `Default-Cloud` should switch to green after a few seconds
![[Pasted image 20250607214531.png||800]]
#### Configure Network
Navigate to `Infrastructure -> Cloud Resources -> Networks` and edit the Network Profile for your `Data Network`
![[Pasted image 20250607214906.png]]
Click on `Add` in the Subnet Section
![[Pasted image 20250607214957.png||800]]
Enter the `Subnet Prefix` and an `IP Range` for the vIPs and Service Engines
![[Pasted image 20250607215345.png||800]]
Click on `Save` Once more to exit the Network Settings.
Navigate to `VRF Context` and edit the `Global` Context
![[Pasted image 20250607220854.png]]
Add a static routes, for your `Workload Network`, pointing to your `Data Network` Gateway, like shown below, click on `Save` to confirm.
![[Pasted image 20250608103237.png||800]]
## Kubectl-vsphere Commands
```bash
# login to server
kubectl-vsphere login --insecure-skip-tls-verify --server 192.168.54.101
```
```bash
# get current Versions of kubernetes available in namespace
kubectl get virtualmachineimages
```
```bash
# get current Versions of kubernetes availabile in namespace with better formating
kubectl get tanzukubernetesreleases \
-o custom-columns="NAME:.metadata.name,VERSION:.spec.version,READY:.status.phase"
```
```bash
# Get current context
kubectl config current-context
```
```bash
# Get versioned ClusterClasses
kubectl get clusterclass -n osn-namespace
```
Available ClusterClasses:
```
NAME AGE
builtin-generic-v3.1.0 12h
builtin-generic-v3.2.0 12h
builtin-generic-v3.3.0 12h
tanzukubernetescluster 12h
```
```bash
# Get Clusters
kubectl get clusters -n osn-namespace
```
```bash
# Get Machines
kubectl get machines -n osn-namespace
```
## Creating CAPI-styled TKG Cluster
### Cluster Classes
with TKG 3.2.0 and later they introduced Custom ClusterClasses.
To use those Cluster Classes we will need to translate some variables and add our Tanzu Cluster deployment yaml file.
```bash
# Get currently available Cluster classes
kubectl -n osn-namespace get clusterclasses
```
```bash
# Example Output
NAME AGE
builtin-generic-v3.1.0 2d18h
builtin-generic-v3.2.0 2d18h
builtin-generic-v3.3.0 2d18h
tanzukubernetescluster 2d18h
```
As you can see in the example output we still have the old Clusterclass `tanzukubernetescluster` available to us.
It is generally advised to us the new versioned clusterlasses `builtin-generic-v*` by either creating a ClusterClass yourself or just using the generic one.
Example using the `builtin-generic-v3.3.0` clusterClass
```yaml
apiVersion: cluster.x-k8s.io/v1beta1
kind: Cluster
metadata:
name: tanzu-cluster-1
namespace: osn-namespace
spec:
clusterNetwork:
services:
cidrBlocks: ["198.53.100.0/16"]
pods:
cidrBlocks: ["192.0.5.0/16"]
serviceDomain: "lab.sponar.de"
topology:
class: builtin-generic-v3.3.0
version: v1.32.0---vmware.6-fips-vkr.2
controlPlane:
replicas: 3
workers:
machineDeployments:
- class: node-pool
name: node-pool-1
replicas: 3
variables:
- name: vmClass
value: best-effort-medium
- name: storageClass
value: k8s
- name: vsphereOptions
value:
persistentVolumes:
defaultStorageClass: k8s
```
### Setup
login to the supervisor:
```bash
# login to server
kubectl-vsphere login --insecure-skip-tls-verify --server 192.168.40.194
```
Apply the yml
```bash
kubectl apply -f Tanzu-Cluster-1/tanzu-k8s-cluster.yaml
```
Wait for the deployment to finish, check the Status:
```bash
kubectl get clusters -n osn-namespace
```
```bash
# Example output, Cluster is deployed, see Phase = Provisioned:
NAME CLUSTERCLASS PHASE AGE VERSION
tanzu-cluster-1 builtin-generic-v3.3.0 Provisioned 18m v1.32.0+vmware.6-fips
```
### login to cluster with kubectl-vsphere
```bash
# login with the cluster as argument
kubectl-vsphere login --insecure-skip-tls-verify --server 192.168.54.101 --tanzu-kubernetes-cluster-name tanzu-cluster-1 --tanzu-kubernetes-cluster-namespace osn-namespace
```
### Login to TKG Cluster with kubeconfig
Get kubeconfig secret:
```bash
kubectl get secrets -n osn-namespace
```
```bash
# Look for the following line:
tanzu-cluster-1-kubeconfig Opaque 1 5m
```
extract kubeconfig secret:
```
kubectl get secret tanzu-cluster-1-kubeconfig \
-n osn-namespace \
-o jsonpath='{.data.value}' | base64 -d > tanzu-cluster-1.kubeconfig
```
export the kubeconfig path
```bash
export KUBECONFIG=~/Documents/Git/homelab/Tanzu/Tanzu-Cluster-1/tanzu-cluster-1.kubeconfig
```
check if the Kubeconfig works by checking for available namespaces and switching the context:
```bash
kubectl config get-contexts
```
```bash
# Example Output:
CURRENT NAME CLUSTER AUTHINFO NAMESPACE
* tanzu-cluster-1-admin@tanzu-cluster-1 tanzu-cluster-1 tanzu-cluster-1-admin
```
## Create Storageclass with Retain
Per default the Storageclass that is created when the Cluster is deployed will have the `reclaimPolicy` to be `Delete`.
This can cause issues when deploying services and accidentatelly deleting the pvc.
To allow for pvcs to be retained even when deleting the pvc, we will copy the existing Storage Class and create a new one with `reclaimPolicy` to be Retain.
```bash
# Output current available storage Classes
kubectl get sc
# Output:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
k8s (default) csi.vsphere.vmware.com Delete Immediate true 13h
k8s-latebinding csi.vsphere.vmware.com Delete WaitForFirstConsumer true 13h
k8s-retain (default) csi.vsphere.vmware.com Retain Immediate true 5s
```
```bash
# Copy existing "k8s" storage Class into a new yaml file
kubectl get storageclass k8s -o yaml > sc-retain.yaml
```
```bash
# edit the exported yaml
vim sc-retain.yaml
```
```yaml
allowVolumeExpansion: true
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
storageclass.kubernetes.io/is-default-class: "true"
creationTimestamp: "2025-06-08T19:45:50Z"
labels:
isSyncedFromSupervisor: "yes"
name: k8s-retain # Change the Name of the SC to prevent duplicate naming
resourceVersion: "309"
uid: 6095be7a-aad7-4909-b1a8-8382e1edcbec
parameters:
svStorageClass: k8s
provisioner: csi.vsphere.vmware.com
reclaimPolicy: Retain # Change from Delete to Retain
volumeBindingMode: Immediate
```
```bash
# Apply the new sc yaml
kubectl apply -f sc-retain.yaml
```
## Example Deployment of nginx
create a new deployment file for nginx, example:
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: bitnami/nginx:latest
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
ports:
- containerPort: 80
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
env:
- name: NGINX_HTTP_PORT_NUMBER
value: "8080"
- name: NGINX_LISTEN_ADDRESS
value: "0.0.0.0"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: default
spec:
type: LoadBalancer
loadBalancerIP: 192.168.54.200
selector:
app: nginx
ports:
- port: 8080
targetPort: 8080
protocol: TCP
```
apply the yaml file:
```bash
kubectl apply -f nginx-test.yaml
```
Check for the deployment status
```bash
kubectl get deployments
```
Troubleshooting:
```bash
# Get logs of deployment
kubectl describe deployment nginx -n default
# Get logs of default namespace
kubectl get events -n default
```
Get Pods:
```bash
kubectl get pods -n default
```
## Example Helm Deployment of Netbox
Before starting we will create a new namespace for Netbox
```bash
# create Namespace for netbox
kubectl create namespace netbox
```
Then we will install helm and add the netbox helm repository
```bash
# Install helm, for example using brew
brew install helm
```
```bash
# Add netbox repository to helm
helm repo add netbox https://charts.netbox.oss.netboxlabs.com/
helm repo update
```
## Concepts
| Concept | Role |
| ------------- | ---------------------------------------------------------------- |
| Namespace | Resource boundary + access control in Supervisor (or K8s itself) |
| K8s Cluster | Made of control plane + worker nodes; runs your apps |
| Control Plane | Brain of the cluster; manages everything |
| Worker Node | Muscles of the cluster; actually runs the apps (pods) |
| TKG Cluster | A guest Kubernetes cluster deployed within a vSphere Namespace |
## đź”—Resources
### Broadcom vSphere Supervisor Resources
- [[Broadcom)](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-supervisor/8-0/installing-and-configuring-vsphere-supervisor/deploy-a-one-zone-supervisor/deploy-a-supervisor-with-vds-networking.html|Supervisor deployment guide (Broadcom)]]
- https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-supervisor/8-0/using-tkg-service-with-vsphere-supervisor/provisioning-tkg-service-clusters/using-the-cluster-v1beta1-api/v1beta1-example-default-cluster.html
### HAProxy
- [HAProxy Installation Guide](https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere-supervisor/8-0/installing-and-configuring-vsphere-supervisor/networking-for-vsphere-with-tanzu/install-and-configure-the-haproxy-load-balancer.html)
- [Broadcom KB IP boot fix](https://knowledge.broadcom.com/external/article?articleId=377393)
### Installation Guides
- https://vtam.nl/2022/10/23/vsphere-with-tanzu-on-vds-with-haproxy/
- https://little-stuff.com/2023/05/06/creating-a-tanzu-kubernetes-cluster-in-vsphere-8-with-tanzu/