, ,

Installing OpenShift 4 on vSphere, IPI and UPI Compared (TKGI to OpenShift Series, Part 12)

IPI or UPI for the first OpenShift cluster beside your TKGI estate. A working install-config for vSphere, the three DNS records that decide the install, and the bootstrap failure that costs most teams two attempts.

TKGI to OpenShift Series · Part 12 of 26
Key takeaways: Installer provisioned infrastructure (IPI) is the correct default for a TKGI estate, because it keeps the Machine API, and the Machine API is what gives you MachineSets, autoscaling and automated node replacement. User provisioned infrastructure (UPI) hands back the virtual machine lifecycle you migrated in order to stop owning. Two virtual IP addresses and three DNS records carry the whole IPI install, and one of those records, api-int, is the one a network reviewer will delete as a duplicate. Ignition certificates expire 24 hours after openshift-install generates them, which quietly punishes slow hand builds. A standard cluster wants at least 800 GB of storage, and OpenShift 4.18 on vSphere documents 8.0 Update 1 or later. Headline command: openshift-install create cluster –dir=ocp-prod –log-level=info

INFO Install complete! landed in my terminal 38 minutes after I pressed enter, and the platform lead sitting beside me asked whether it had actually built anything. His scepticism was earned. Standing up a Tanzu Kubernetes Grid Integrated (TKGI) cluster in this estate meant a BOSH director, a Tanzu Operations Manager tile, an NSX-T principal identity and a change window measured in half days. OpenShift Container Platform 4 on vSphere replaces that machinery with one binary, one YAML file and a vCenter account that can create virtual machines.

Part 11 handed us a design: two clusters instead of three, 27 virtual machines, failure domains declared on day zero. This Part installs the first of them and settles the argument every TKGI team has in week one, which is whether to let openshift-install own the virtual machines or build them yourself.

Who this is for: A platform engineer holding the Part 11 design, a vCenter account and a change window. Terms defined on first use here: IPI is installer provisioned infrastructure, where openshift-install creates the virtual machines, the in cluster load balancing and the temporary bootstrap node; UPI is user provisioned infrastructure, where you create all of it; RHCOS is Red Hat Enterprise Linux CoreOS, the immutable node operating system; Ignition is the RHCOS first boot configuration format; a MachineSet is the OpenShift object that declares a pool of identically shaped nodes; VIP is a virtual IP address; CSR is a certificate signing request; OVN-Kubernetes is the default OpenShift network plugin.

Preflight, What to Prove Before openshift-install Runs

Every failed vSphere install I have sat through failed on something a five minute check would have caught. Run these from a jump host on the machine network the cluster will live on, not from a laptop across a VPN, because name resolution and reachability differ and that difference is exactly what breaks bootstrap.

# Tested against: OCP 4.18.21, openshift-install 4.18.21, oc 4.18.21, # vSphere 8.0 Update 3, govc 0.46, source estate TKGI 1.18 on NSX-T $ openshift-install version openshift-install 4.18.21 built from commit 6f2b2a4c1d9e0b7a3c85f1d2e4a6b8c0d2f4a6b8 release image quay.io/openshift-release-dev/ocp-release@sha256:9c1f… release architecture amd64 $ oc version –client Client Version: 4.18.21 Kustomize Version: v5.4.2 # three DNS records, resolved from the machine network $ dig +short api.ocp-prod.example.internal 10.24.60.10 $ dig +short api-int.ocp-prod.example.internal 10.24.60.10 $ dig +short console-openshift-console.apps.ocp-prod.example.internal 10.24.60.11 # vCenter reachable, credentials read from the environment, never from a file $ export GOVC_URL=https://vcsa01.example.internal/sdk $ export GOVC_USERNAME="$VSPHERE_USER" $ export GOVC_PASSWORD="$VSPHERE_PASSWORD" $ govc about Name: VMware vCenter Server Vendor: VMware, Inc. Version: 8.0.3 Build: 24322831 $ govc datastore.info vsanDatastore-prod | head -4 Name: vsanDatastore-prod Type: vsan Capacity: 40960.0 GB Free: 31204.7 GB

Two of those DNS records are obvious and one is not. api-int is the internal endpoint that control plane members and the bootstrap node use to reach the API server, and it resolves to the same VIP as api. Network reviewers delete it because it looks like a redundant alias of a record they already approved. It is not redundant, and the install dies at bootstrap without it. Note also that the apps entry must be a wildcard, so *.apps.ocp-prod.example.internal, rather than one record per route hostname.

Certificate window: Ignition config files produced by openshift-install carry certificates that expire 24 hours after generation. Generate them on a Friday, hand build twenty seven virtual machines across the weekend, and the nodes will refuse to join on Monday with an x509 error that looks like a clock problem and is not. Red Hat also asks you to keep a freshly installed cluster running and non degraded for 24 hours so the first automatic certificate rotation completes. Teams building by hand lose more clusters to this clock than to any networking mistake.

IPI and UPI Side by Side

Both methods produce an identical cluster. What differs is who owns the virtual machine lifecycle afterwards, and that question lands harder on a TKGI team than on anyone else, because BOSH trained them to own every VM in the estate. On OpenShift that instinct costs you the capability you migrated for.

flowchart TD
  A[Can openshift install reach the vCenter API] -->|No| U[Choose UPI]
  A -->|Yes| B[Does the design need custom NICs or non standard VM hardware]
  B -->|Yes| U
  B -->|No| C[Will you scale or replace nodes after go live]
  C -->|Yes| I[Choose IPI]
  C -->|No| D[Choose IPI anyway and revisit at first node failure]
Three questions decide the install method. Most TKGI estates answer them all in favour of IPI.
DimensionIPIUPIBetter here
Who creates the virtual machinesopenshift-install, through the vCenter APIYou, from an RHCOS OVA templateIPI
Machine API and MachineSetsPresent and populated at install timeExtra configuration required, and unavailable entirely if the platform type is noneIPI
Load balancing for api and ingressProvided in cluster against two VIPs, no external appliance neededExternal load balancer that you build, monitor and patchIPI
Adding a worker on day twooc scale machineset, roughly six minutes unattendedClone template, boot, approve CSRs by handIPI
disk.EnableUUID on nodesSet for youYour job, and forgetting it fails PVCs weeks laterIPI
Custom NICs, boot order, exotic VM hardwareLimited to what the installer modelsAnything vSphere can expressUPI
Installer denied access to the vCenter APINot possible, the API is the whole mechanismWorkable, VMs built by another team or pipelineUPI
Bootstrap nodeCreated and destroyed automaticallyYou build it and you remember to delete itIPI

Alongside the trade offs sit some fixed numbers that neither method negotiates. Print this second table and pin it above the change request, because three of these rows have started arguments in every design review I have run.

ItemDocumented value for OCP 4.18 on vSphere
Minimum vSphere version8.0 Update 1 or later, or VMware Cloud Foundation 5.0 or later
Control plane nodes3, on RHCOS, no exceptions
Compute nodes, minimum2
Cluster storage, minimum800 GB for a standard cluster
Static IP addresses consumed by IPI2, the api VIP and the ingress VIP, both inside networking.machineNetwork
DNS records you must create3, api, api-int and the *.apps wildcard
Ignition certificate lifetime24 hours from generation
Storage vMotion of cluster nodesNot supported, compute vMotion is generally supported
Engineer hours to a working cluster, by phase Measured on one nonprod cluster in the reference estate, seven nodes, single engineer, August 2026 IPI UPI Preflight and DNS 3.0 3.0 RHCOS template prep 0 6.0 Load balancer build 0 5.0 Install run and bootstrap 1.0 4.0 Node join and CSR approval 0 3.0 Day two scaling setup 0.5 7.0 Total: IPI 4.5 hours, UPI 28.0 hours
Both totals exclude the vCenter privilege request, which took 11 calendar days and is the genuine critical path.

Six of those UPI hours went on rediscovering disk.EnableUUID, a per virtual machine advanced setting that the vSphere CSI driver needs in order to match a Kubernetes volume to a VMDK. Set it to FALSE on a hand built template and everything installs perfectly, then persistent volume claims sit in Pending three weeks later when somebody finally migrates a database. Part 9 covered the storage side of that in detail, so this Part only flags where it bites during installation.

Scope note: Landing on VMware Kubernetes Service on VCF 9 rather than OpenShift is a different installer and a different series, covered in the TKGI to VKS guide. Everything below assumes OpenShift Container Platform 4 on vSphere.

Installing with IPI, Step by Step

Step 1. Render install-config.yaml from a template

Credentials belong in the environment, not in a file that ends up in a ticket attachment. Keep a template under version control with placeholders, render it at run time, and remember that openshift-install consumes install-config.yaml when it creates manifests, so back it up first. Failure domains come straight from the Part 11 design, and declaring one now costs nothing while retrofitting zones after the control plane is placed costs a rebuild.

$ mkdir -p ocp-prod $ envsubst < install-config.tmpl.yaml > ocp-prod/install-config.yaml $ cp ocp-prod/install-config.yaml install-config.yaml.bak # install-config.tmpl.yaml apiVersion: v1 baseDomain: example.internal metadata: name: ocp-prod controlPlane: name: master replicas: 3 platform: vsphere: cpus: 8 coresPerSocket: 4 memoryMB: 32768 osDisk: diskSizeGB: 200 compute: – name: worker replicas: 4 platform: vsphere: cpus: 8 coresPerSocket: 4 memoryMB: 65536 osDisk: diskSizeGB: 200 networking: networkType: OVNKubernetes machineNetwork: – cidr: 10.24.60.0/24 clusterNetwork: – cidr: 10.128.0.0/14 hostPrefix: 23 serviceNetwork: – 172.30.0.0/16 platform: vsphere: apiVIPs: – 10.24.60.10 ingressVIPs: – 10.24.60.11 vcenters: – server: vcsa01.example.internal user: ${VSPHERE_USER} password: ${VSPHERE_PASSWORD} datacenters: – DC-PROD failureDomains: – name: fd-rack-a region: dc-prod zone: rack-a server: vcsa01.example.internal topology: datacenter: DC-PROD computeCluster: /DC-PROD/host/CL-PROD-A datastore: /DC-PROD/datastore/vsanDatastore-prod networks: – PG-OCP-PROD resourcePool: /DC-PROD/host/CL-PROD-A/Resources/rp-ocp pullSecret: ${PULL_SECRET} sshKey: ${SSH_PUBKEY}

Step 2. Create manifests, then run the install

Splitting manifest generation from the install gives you one chance to inject anything the installer cannot express, for example a custom certificate authority bundle or a chrony MachineConfig for a time source your security team mandates. Skip that step and you are editing a running cluster instead.

$ openshift-install create manifests –dir=ocp-prod INFO Credentials loaded from the "default" profile in file INFO Consuming Install Config from target directory INFO Manifests created in: ocp-prod/manifests and ocp-prod/openshift $ openshift-install create cluster –dir=ocp-prod –log-level=info INFO Consuming Common Manifests from target directory INFO Creating infrastructure resources… INFO Waiting up to 20m0s for the Kubernetes API at https://api.ocp-prod.example.internal:6443… INFO API v1.31.7 up INFO Waiting up to 30m0s for bootstrapping to complete… INFO Destroying the bootstrap resources… INFO Waiting up to 40m0s for the cluster at https://api.ocp-prod.example.internal:6443 to initialize… INFO Waiting up to 10m0s for the openshift-console route to be created… INFO Install complete! INFO To access the cluster as the system:admin user when using ‘oc’, run INFO export KUBECONFIG=/home/pjha/ocp-prod/auth/kubeconfig INFO Access the OpenShift web-console here: https://console-openshift-console.apps.ocp-prod.example.internal INFO Time elapsed: 38m11s

Step 3. Take the kubeadmin password out of the install directory

ocp-prod/auth holds a kubeconfig with cluster admin rights and a plaintext kubeadmin password. Move both into your secrets manager the same hour you finish, and plan to delete the kubeadmin user once an identity provider is wired, which is Part 15. Losing the rest of the install directory is worse than losing the password though, because metadata.json in there is what makes a clean teardown possible.

I prefer oc over kubectl throughout this series for one reason: oc understands OpenShift objects such as Route, Project and SecurityContextConstraints, and it carries subcommands like oc adm and oc debug that have no kubectl equivalent. Anything kubectl can do, oc does identically.

Verification and Rollback

Install complete is not the same as healthy. Four checks separate a cluster you can hand over from one that will page somebody at 03:00. Green looks like every cluster operator Available and neither Progressing nor Degraded, every node Ready, zero problems from the vSphere Problem Detector Operator, and a MachineSet whose ready count matches its desired count.

$ export KUBECONFIG=$PWD/ocp-prod/auth/kubeconfig $ oc get clusteroperators | grep -v ‘True *False *False’ NAME VERSION AVAILABLE PROGRESSING DEGRADED SINCE MESSAGE $ oc get nodes NAME STATUS ROLES AGE VERSION ocp-prod-9k4mt-master-0 Ready control-plane,master 41m v1.31.7 ocp-prod-9k4mt-master-1 Ready control-plane,master 41m v1.31.7 ocp-prod-9k4mt-master-2 Ready control-plane,master 41m v1.31.7 ocp-prod-9k4mt-worker-0-h7x2q Ready worker 29m v1.31.7 ocp-prod-9k4mt-worker-0-m4kdz Ready worker 29m v1.31.7 ocp-prod-9k4mt-worker-0-t9plc Ready worker 28m v1.31.7 ocp-prod-9k4mt-worker-0-w6rnb Ready worker 28m v1.31.7 $ oc logs deployment/vsphere-problem-detector-operator -n openshift-cluster-storage-operator | tail -4 CheckNodeDiskUUID:node ocp-prod-9k4mt-worker-0-h7x2q passed CheckFolderPermissions:passed CheckDefaultDatastore:passed Checks completed, 0 problems found $ oc get machineset -n openshift-machine-api NAME DESIRED CURRENT READY AVAILABLE AGE ocp-prod-9k4mt-worker-0 4 4 4 4 42m

That last object is the whole argument in four lines of output. A MachineSet exists, it knows the vSphere folder, datastore, port group and template, and oc scale machineset ocp-prod-9k4mt-worker-0 –replicas=6 adds two nodes without anyone opening vCenter. On a UPI build that object is absent, and adding a node is a clone, a boot and a round of CSR approvals.

Rollback during installation means destroy and retry, and IPI makes that cheap enough to be worth doing rather than debugging in place. openshift-install destroy cluster reads metadata.json from the install directory and removes every virtual machine, folder and tag it created, including the bootstrap node. Guard that directory. Without it you are deleting objects by hand in vCenter, matching them on the random infrastructure ID embedded in each VM name.

$ openshift-install create cluster –dir=ocp-prod –log-level=info INFO Waiting up to 30m0s for bootstrapping to complete… ERROR Bootstrap failed to complete: timed out waiting for the condition ERROR Failed to wait for bootstrapping to complete. This error usually happens ERROR when there is a problem with control plane hosts that prevents the control ERROR plane operators from creating the control plane. $ openshift-install gather bootstrap –dir=ocp-prod –bootstrap 10.24.60.31 –master 10.24.60.32 INFO Pulling debug logs from the bootstrap machine INFO Bootstrap gather logs captured here ocp-prod/log-bundle-20260812.tar.gz $ tar xzf ocp-prod/log-bundle-20260812.tar.gz $ grep -m1 api-int log-bundle-20260812/bootstrap/journals/bootkube.log failed to get https://api-int.ocp-prod.example.internal:6443/version: dial tcp: lookup api-int.ocp-prod.example.internal on 10.24.10.5:53: no such host $ openshift-install destroy cluster –dir=ocp-prod –log-level=info INFO Destroyed VirtualMachine ocp-prod-9k4mt-bootstrap INFO Destroyed VirtualMachine ocp-prod-9k4mt-master-0 INFO Destroyed Folder /DC-PROD/vm/ocp-prod-9k4mt INFO Time elapsed: 2m14s

Install Failures and Remediation

Seven failures account for nearly every stalled vSphere install I have been handed. Keep this table beside the runbook, because each row maps a literal error string to a cause you can act on in minutes rather than an afternoon of guessing.

Error you seeCauseFix
Bootstrap failed to complete: timed out waiting for the condition, and bootkube.log shows lookup api-int … no such hostapi-int A record missingCreate api-int pointing at the api VIP, destroy, reinstall
level=fatal … ServerFaultCode: Permission to perform this operation was deniedvCenter role lacks privileges on the folder, datastore or resource poolApply the documented privilege set at each object type, propagate, then rerun
Waiting up to 20m0s for the Kubernetes API … never returns and the VIP never answers pingapiVIP sits outside networking.machineNetworkMove both VIPs inside the machine network CIDR, they cannot be routed in from elsewhere
PVC stuck Pending, events show failed to provision volume with StorageClass thin-csidisk.EnableUUID is FALSE on the node VMs, common on hand built UPI templatesSet disk.EnableUUID TRUE on the template and replace the nodes
Nodes booted but never appear in oc get nodes on a UPI buildPending CSRs waiting for approvaloc get csr, then oc adm certificate approve, twice per node
x509: certificate has expired or is not yet valid during node joinIgnition configs older than 24 hoursRegenerate the Ignition configs, reserve the nodes and boot them the same day
Install completes, console route returns 503Wildcard record missing or pointing at the api VIPPoint *.apps at the ingress VIP, then oc get co ingress to confirm recovery

Two of those rows exist only on UPI, which is a cost worth naming out loud. Here are the commands behind them, neither of which an IPI operator ever types.

# UPI only, set before first boot on every node template $ govc vm.change -vm /DC-PROD/vm/ocp-upi/worker-0 -e disk.EnableUUID=TRUE # UPI only, and repeated every time a node joins $ oc get csr | grep Pending | wc -l 8 $ oc get csr -o name | xargs oc adm certificate approve certificatesigningrequest.certificates.k8s.io/csr-4x9lm approved certificatesigningrequest.certificates.k8s.io/csr-h2vqp approved certificatesigningrequest.certificates.k8s.io/csr-r8dwn approved

Field Note from a Bootstrap That Never Completed

First attempt on this estate died at 30 minutes with the timeout above. Everyone in the room blamed the installer, because in TKGI a stalled deployment usually meant a BOSH task you could tail and reason about. I gathered the bootstrap bundle, grepped for api-int, and found a DNS lookup failure on a record I had personally requested three weeks earlier. Network review had removed it, with a comment that a second name resolving to the same address was noise.

Cost of that lesson: two failed installs, one destroy that took 2 minutes 14 seconds, roughly three hours of my afternoon, and a stalled change window. Adding the record took the DNS team four minutes. Second attempt completed in 38 minutes and has not been reinstalled since.

Second thing I got wrong, and this one is more embarrassing. We had originally planned a UPI build, on the reasoning that a regulated estate should never grant an installer write access to vCenter. Security agreed with us for eleven days while the privilege request sat in a queue. Then somebody asked the obvious question, which was what happens when a worker node dies at 02:00 in month four. On UPI the answer is a human clones a template. On IPI the answer is a MachineHealthCheck deletes the Machine and the MachineSet builds a replacement. We reversed the decision, and the same privileges got approved in two days once the request said node self healing instead of installer automation.

Pick IPI for This Estate, and Reserve UPI for One Case

Verdict: install both clusters from the Part 11 design with IPI. Common advice inside VMware shops points the other way, because owning every virtual machine feels like operational maturity and because a BOSH background makes an opinionated installer feel like a loss of control. On OpenShift that reasoning inverts. Node lifecycle is a platform capability delivered through the Machine API, and choosing UPI switches it off at install time to buy flexibility that a standard three tier estate will never use. Reserve UPI for exactly one case: the installer genuinely cannot reach the vCenter API, or the design needs VM hardware the installer does not model, such as a second NIC on a storage VLAN.

A clean result looks like this. Every cluster operator Available, Progressing False, Degraded False. Seven nodes Ready on v1.31.7. Zero problems from the vSphere Problem Detector Operator. One MachineSet with ready matching desired. Kubeadmin credentials moved out of the install directory, and the install directory itself archived somewhere you can find it in a year. Cluster left running and non degraded for 24 hours so the first certificate rotation completes before anyone declares victory.

Monday action, and it takes ten minutes on your own estate: run dig against api, api-int and the apps wildcard for the cluster name you intend to build, from a host on the target machine network. If api-int does not resolve, you have just found the failure that would have cost you an afternoon, and you found it before booking a change window. Part 13 takes the cluster this Part installed and turns to cluster networking, OVN-Kubernetes, Routes and load balancing, which is where the NSX-T habits from Part 8 finally meet running configuration.

TKGI to OpenShift Series · Part 12 of 26
« Previous: Part 11  |  Guide  |  Next: Part 13 »

References

Red Hat, Installer-provisioned infrastructure, Installing on VMware vSphere, OpenShift Container Platform 4.18

Red Hat, User-provisioned infrastructure, Installing on VMware vSphere, OpenShift Container Platform 4.18

Red Hat, Using the vSphere Problem Detector Operator, OpenShift Container Platform 4.18

About The Author


Discover more from Journal of Intelligent Infrastructure

Subscribe to get the latest posts sent to your email.

Leave a Reply

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

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure

Subscribe now to keep reading and get access to the full archive.

Continue reading