Deploy a VKS Cluster in VCF 9.1.1 and Test It with Nginx

I created a VMware vSphere Kubernetes Service (VKS) cluster manually in my VCF 9.1.1 home lab, then connected from Windows PowerShell and deployed an Nginx web server. This walkthrough covers Supervisor activation with VPC networking, namespace preparation, VKS cluster creation through the vSphere Client, kubeconfig access, and exposing an application through a LoadBalancer Service.

The cluster uses one control-plane node and one worker. Both use the best-effort-small VM class. This is a compact test configuration: a single control-plane node does not provide control-plane high availability.

Example configuration

The resource names below are generic examples. Substitute your own vCenter, Supervisor, namespace, storage policy, and cluster names. The software versions describe the tested deployment; select releases supported by your installed Supervisor and Kubernetes Service.

SettingExample / value to select
Workload vCenter / clustervcenter.example.com / workload-cluster
NSX Managernsx.example.com
Supervisorsupervisor-01
Supervisor versionv1.34.9+vmware.1-vsc9.1.1.0-25712839
Kubernetes Service3.7.0-embedded+v1.36
Local Consumption Interface9.1.2-embedded+fe6ddfd1
vSphere namespacevks-lab
VKS clustervks-demo
Kubernetes release in vCenterv1.36.2—vmware.2-vkr.3
Version reported by kubectlv1.36.2+vmware.2
Node configuration1 control-plane node + 1 worker; 2 vCPUs and 4 GB RAM each
Storage policyYour namespace storage policy
Supervisor API addressYour Supervisor API address
VKS API endpointEndpoint from your downloaded kubeconfig

The Supervisor and VKS cluster are separate Kubernetes environments. The Supervisor provides the platform used to provision the workload cluster. The downloaded VKS kubeconfig connects to the workload cluster where the Nginx application runs.

1. Prepare the Supervisor prerequisites

This walkthrough uses VCF Networking with VPC and a centralized Transit Gateway backed by NSX Edge. Start with an operational VCF workload domain, compatible vCenter and ESX versions, NSX host preparation, and sufficient compute and storage capacity. The distributed gateway and Foundation Load Balancer workflows have different prerequisites.

  1. Check the target cluster against the Supervisor requirements for VCF 9.1. Resolve cluster compatibility errors before activation, including host configuration, HA/DRS requirements, storage access, and NSX transport health.
  2. Prepare the placement model. For this example, use a single workload cluster and management zone. In vCenter, use vSphere Zones to prepare any required zone mapping; a three-zone design needs three eligible zones and a different placement plan.
  3. Create or select a storage policy with compatible shared storage for the Supervisor control-plane VMs. Confirm available capacity on the target datastore.
  4. Under Supervisor Management → Content Distribution, configure and assign the Supervisor release content library. Synchronize a compatible release through your supported online or offline depot workflow. Kubernetes node images for VKS are a separate content requirement.
  5. For the centralized networking path, prepare a healthy NSX Edge cluster, Tier-0 connectivity, and upstream routing. Confirm the intended NSX project and VPC connectivity profile, including its gateway connection, external IP block, private Transit Gateway pool, and Auto SNAT.
  6. Plan DNS, NTP, management IPs, workload address pools, and registry access. Reserve unused management addresses and verify that your workstation can route to the eventual Supervisor API endpoint.

These steps prepare existing infrastructure for Supervisor activation. Deploying the workload domain, NSX Edge appliances, and physical routing is a prerequisite rather than part of the activation wizard. For an offline environment, make both release content and required container images available before starting.

2. Check the VPC address plan

SettingExample / value to select
NSX projectDefault
Connectivity profileDefault VPC Connectivity Profile
External IP blockYour external IP block
Private Transit Gateway blockYour private Transit Gateway block
Private VPC CIDRYour private VPC CIDR
Supervisor Service CIDRYour Supervisor Service CIDR

These pools have different purposes. The external block supplies externally reachable addresses within the routed lab; it does not make a service public on the internet. The Supervisor Service CIDR is also separate from the workload cluster’s own Service network.

Keep the NSX transport networks, host and Edge TEP networks, Transit Gateway address pool, VPC ranges, and Kubernetes Service networks distinct. Check all allocations for overlap and verify routing, DNS, and Edge tunnel health. VLAN IDs and subnets must match your own network design.

3. Activate the Supervisor with VPC networking

The following sequence follows Broadcom’s Deploy a Supervisor with VPC Networking procedure. All names are examples. If you already have a healthy Supervisor, skip activation and continue with the namespace steps.

  1. Open Menu → Supervisor Management in the vSphere Client and choose Get Started to launch activation. If Supervisors already exist, use the available activation action on that page.
  2. On vCenter Server and Network, select the workload vCenter and choose VCF Networking with VPC.
  3. On Supervisor location, select Cluster Deployment, enter a name such as supervisor-01, and select the intended datacenter and compatible cluster/management zone. Enable control-plane high availability for a resilient deployment. A single-control-plane configuration is a lab option where supported; it does not provide control-plane redundancy.
  4. Select the storage policy for the Supervisor control-plane VMs. Confirm that the intended datastore is compatible.
  5. On Management Network, select the management port group and IP assignment mode. For a static HA deployment, reserve the documented block of five unused management IPs for the control-plane VMs, floating address, and replacement capacity. Enter the requested IP range, subnet mask, gateway, DNS servers, DNS search domain, and NTP settings. Follow the address count shown for your selected topology. If using DHCP, configure stable assignments and the required client-identifier support.
  6. On Workload Network, select the NSX project and VPC connectivity profile prepared earlier. Review the external and private Transit Gateway IP blocks, enter the private VPC CIDR and Supervisor Service CIDR, and supply the workload DNS and NTP settings. Check the network plan in the previous section before continuing.
  7. Under Advanced Setting, choose the Supervisor control-plane size. Small provides 4 vCPUs and 16 GB RAM per control-plane VM; select a size appropriate for the expected workload. This is separate from the VKS node VM class. The documented sizing change supports scaling up, not down.
  8. Enter an API server DNS name, such as supervisor.example.com, if you intend to connect by name. This name is included in the generated certificate. Once the API address is known, configure DNS to resolve the name to that endpoint.
  9. Review the settings and use Export Configuration to retain the activation JSON securely. Click Finish to begin deployment.

Plan the management addresses carefully: changing the control-plane and floating IPs after activation is not supported. Do not point the API DNS name at an arbitrary control-plane VM; use the API endpoint reported for the Supervisor.

Validate the Supervisor and install the services

  1. Monitor the activation task under Supervisor Management → Supervisors. Wait for the configuration and host configuration to report Running; inspect the configuration status details if activation fails.
  2. Verify that the expected control-plane VMs are powered on, that the selected storage is healthy, and that the Supervisor API endpoint is reachable from your administration network. Check DNS resolution using the configured API name.
  3. Under Supervisor Management → Services, verify that Kubernetes Service and Local Consumption Interface (LCI) are installed and healthy on this Supervisor. If either is absent, select a compatible registered version and use its installation action to target this Supervisor. Registering a service in vCenter alone does not install it on a Supervisor.
  4. Associate the compatible Kubernetes release content library under the Supervisor’s Configure → General → Kubernetes Service settings. Verify that the release needed for the VKS cluster is available.
  5. Proceed to create the namespace, assign its storage policy and VM classes, then deploy the VKS cluster. A Running Supervisor is the platform prerequisite; the later Nginx test validates a workload on the VKS cluster.

If activation stalls: check the reported failure first. Common causes include an incomplete VPC connectivity profile, missing external address blocks or gateway connectivity, management IP conflicts, DNS/NTP failures, incompatible storage, and unavailable release content. Resolve the prerequisite and inspect the task again before attempting another activation.

4. Prepare the vSphere namespace

  1. Open Supervisor Management → Namespaces. Select your existing namespace or choose New Namespace and place it on the intended Supervisor and zone. Use an example namespace such as vks-lab.
  2. Assign the storage policy that will hold the node VMs. Select the storage policy assigned to your namespace.
  3. Under the namespace’s VM Service settings, associate the required VM classes. For example, associate best-effort-small, best-effort-medium, and best-effort-large; the VKS nodes use best-effort-small.
  4. Confirm your account has namespace permissions to create and manage VKS clusters. Check available compute, storage, and namespace quotas before proceeding.

My test namespace has no CPU, memory, or storage limit. That is a lab setting, not a requirement. Best-effort classes do not reserve the full configured CPU and memory. Guaranteed classes introduce reservation requirements that can prevent placement when the resource pool lacks capacity. See Broadcom’s VM class and placement guidance.

5. Create the VKS cluster through the UI

Open the namespace’s Resources tab and select the Kubernetes cluster creation workflow provided by LCI. Labels and field order can differ between LCI releases. The settings below describe a small example deployment.

  1. Enter a cluster name. For example, name it vks-demo; use a new name when deploying another cluster.
  2. Select the available Kubernetes release. My cluster uses v1.36.2---vmware.2-vkr.3.
  3. Configure one control-plane node using best-effort-small.
  4. Configure one worker node in a worker node pool, also using best-effort-small.
  5. Select the storage policy assigned to the namespace for the node storage settings. Review networking and any additional disk settings exposed by your release.
  6. Review the configuration and any generated YAML shown by the wizard, then submit the cluster creation request. Save an export for future reference if the UI offers one.

I created this cluster manually; there is no original cluster-creation YAML in this walkthrough. The YAML later in this post deploys the test application into the existing cluster.

Wait for the cluster to become Available. You can inspect it under namespace → Compute → Kubernetes clusters. My cluster shows Available = True and Worker Count = 1. Under Compute → Virtual Machines, both node VMs are powered on and use best-effort-small. VM power state alone is not sufficient validation; check Kubernetes readiness next.

6. Download kubeconfig and connect from PowerShell

Open the cluster’s details in the LCI workflow and download its kubeconfig. Treat that file as a credential and keep it out of public repositories. Install a compatible kubectl client, then point the current PowerShell session at the downloaded file:

$env:KUBECONFIG = "$env:USERPROFILE\Downloads\vks-demo-kubeconfig.yaml"
kubectl config current-context
kubectl get --raw=/readyz
kubectl get nodes -o wide
kubectl get pods -A
kubectl get storageclass

Replace the path with your own download location. Confirm that the current context belongs to the intended VKS cluster. The readiness check should return ok, and both nodes should report Ready. Use the API endpoint and authentication information provided in the downloaded kubeconfig.

Confirm that the StorageClasses made available by your assigned storage policy appear in the output. Listing them confirms availability, but does not itself prove a persistent volume can be provisioned.

7. Deploy the Nginx test application

Create an application namespace inside the VKS cluster. This nginx-demo namespace is different from the vks-lab vSphere namespace that contains the cluster.

kubectl create namespace nginx-demo

Skip creation if that namespace already exists. Save the following as web.yaml. It contains the Deployment and a LoadBalancer Service:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: nginx-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 101
        seccompProfile:
          type: RuntimeDefault
      containers:
        - name: nginx
          image: nginxinc/nginx-unprivileged:stable-alpine
          ports:
            - containerPort: 8080
          securityContext:
            allowPrivilegeEscalation: false
            capabilities:
              drop:
                - ALL
---
apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: nginx-demo
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
  type: LoadBalancer

The initial standard Nginx deployment was blocked by the namespace’s restricted Pod Security policy. This version uses an unprivileged image listening on port 8080, runs as a non-root user, disables privilege escalation, drops Linux capabilities, and selects the runtime’s default seccomp profile. See the Kubernetes security context documentation.

The worker must be able to pull the image. If your environment is offline, mirror it into an accessible registry and update the image reference and registry trust configuration first. The tag shown here matches the lab example; it can change over time.

kubectl apply -f .\web.yaml
kubectl rollout status deployment/web -n nginx-demo --timeout=120s
kubectl get pods -n nginx-demo
kubectl get service web -n nginx-demo --watch

8. Verify access through the LoadBalancer

Wait for the web pod to show 1/1 Running and for the Service to receive an external address. Press Ctrl+C to stop the watch once the address appears. Use the address returned by your own Service on TCP port 80:

$webIP = kubectl get service web -n nginx-demo -o jsonpath="{.status.loadBalancer.ingress[0].ip}"
Test-NetConnection -ComputerName $webIP -Port 80
Invoke-WebRequest -Uri "http://$webIP"

Open the same HTTP address in a browser to check the Nginx welcome page. A TCP test checks connectivity; the HTTP response verifies the application. The Service forwards port 80 to port 8080 in the container.

For a temporary local test, you can also run kubectl port-forward service/web 8080:80 -n nginx-demo and browse to http://localhost:8080. Port forwarding ends when you close that command. The Deployment and LoadBalancer Service remain in the cluster when you close PowerShell.

This example does not use a PersistentVolumeClaim. It validates cluster access, pod scheduling, image retrieval, and application exposure. A separate PVC test is needed to validate persistent application storage.

Troubleshooting from this lab

Resources tab missing or blank: confirm LCI is installed on the correct Supervisor, check its service health and browser connectivity, and refresh the vSphere session. The native Compute tab can still show existing clusters while you investigate the embedded Resources view.

LCI capability or networking errors: confirm the Supervisor uses the intended network stack. In my setup, the management DVPG is valid alongside NSX VPC workload networking. An earlier VDS setup without a load balancer did not provide the required service capabilities. Also verify the VPC connectivity profile’s Auto SNAT and address-block prerequisites.

Node placement failure: check namespace limits, host capacity, storage policy availability, and VM class reservations. For clusters created through LCI, make topology changes through the vSphere Client, as described in the Broadcom placement guidance linked above.

Deployment exists but no pod starts: inspect events. In this lab, the ReplicaSet reported restricted Pod Security violations. The corrected manifest above resolved the missing security settings.

kubectl get events -n nginx-demo --sort-by=.metadata.creationTimestamp
kubectl describe deployment web -n nginx-demo
kubectl get pods -n nginx-demo
kubectl logs deployment/web -n nginx-demo

External IP stays pending: inspect kubectl describe service web -n nginx-demo and the platform’s service/network provisioning. If an IP is allocated but unreachable, check client routing, return routing, and firewall access to TCP 80. Do not assume an allocated address proves end-to-end connectivity.

What this test established

The manual VKS deployment produced an available two-node cluster, and kubeconfig authentication and API readiness checks succeeded. The Nginx test supplied a repeatable application manifest and a LoadBalancer endpoint. It also exposed a useful lesson: a successful cluster deployment is only the first check; security policy and network access still need validation with a real workload.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.