, ,

VKS Content Libraries and Kubernetes Releases, Subscribed, Local and Air-Gapped (VCAP-VKS Exam Series, Part 9)

A subscribed library, a local library for the air gapped case, and the VKr naming rule that decides whether kubectl get kr shows anything at all. Objective 2.5 for 3V0-24.25, run against a VCF 9.0 Supervisor.

VCAP-VKS Exam Series · Part 9 of 34

Two hundred and fourteen gigabytes. That is what an immediate synchronisation of the public Kubernetes release library pulled onto a lab datastore before I caught it, in an estate that was running two clusters off one image. Nobody teaches this objective as a capacity problem, and that is exactly why it bites.

Key takeaways: This Part covers Objective 2.5, published as Manage Kubernetes releases and content libraries (subscribed, local, and air-gapped) for VKS clusters. Broadcom prints two objectives numbered 2.5 and this is the first of them. A release library is a Supervisor object and never a vSphere Namespace object, so changing it changes every namespace at once. Broadcom recommends the When needed download mode, and after the incident above, so do I. Headline command: kubectl get kr. In a local library the item name must match the release NAME string character for character, triple hyphens included.
Who this is for: You have a Supervisor with an external identity provider wired into it, which is where Part 8 left the lab. You have built a vSphere content library before, for ordinary VM templates, and you assume the Kubernetes one behaves the same way. You are sitting 3V0-24.25 and have never had to stand up a release library with no internet on the other side of the firewall.

VKr distribution model in VCF 9

A vSphere Kubernetes release, shortened to VKr everywhere in the documentation, is one signed and supported Kubernetes distribution packaged as an OVA template, which is the virtual machine appliance format vSphere has used for years. Broadcom publishes VKrs to a content delivery network. A vCenter content library, meaning the vSphere object that stores templates and optionally synchronises them from somewhere else, pulls them down. VKS, which is vSphere Kubernetes Service and the product Broadcom used to call TKG Service and before that TKGS, reads that library and clones each template into cluster node virtual machines. Disk size for those nodes is fixed by the OVA. CPU and memory come from the VM class you bound to the vSphere Namespace back in Part 5, not from the image. Resource names, API groups and half the documentation URLs still say tkg, so a command aliased to kr and a command aliased to tkr return the same objects.

Three properties of that pipeline decide most of what this objective asks. First, VKrs ship on their own cadence, released and updated independently of both VKS and Supervisor, so an image can be sitting in your library, fully synchronised, and still refuse to build anything because it is not compatible with the VKS version you are running. Second, and this is the sentence to memorise, a release library is bound to the Supervisor rather than to a vSphere Namespace. Broadcom states it plainly: the same library is used for all vSphere Namespaces on a Supervisor instance, and for that reason changing it is only permitted at the Supervisor level. Third, matching what you asked for in YAML against what the library actually holds is done by a resolver controller reading annotations, and when that resolver cannot find a match it denies the request outright rather than choosing something near enough.

flowchart TD A[Broadcom content delivery network or offline OVA files on a USB drive] –> B[vCenter content library, subscribed or local] B –> C[Library association under Supervisor Configure General Kubernetes Service] C –> D[VKr controller publishes Kubernetes release objects] D –> E[kubectl get kr reports READY and COMPATIBLE] E –> F{Resolver matches topology version plus resolve os image annotation} F — Match –> G[Node virtual machines cloned from the OVA template] F — No match –> H[Cluster create or update request denied]
Six Supervisor level steps stand between a published image and a running node, and a developer only ever sees the last box.

Which library type you build is a design decision you make once and live with for years, so it belongs in your notes as a table rather than as prose. Air gapped in this context does not mean paranoid, it means the vCenter appliance has no route to a Broadcom endpoint, which describes a great many regulated estates. General content library mechanics belong to vSphere and are covered in the VKS Series; here I only care about what VKS does differently.

Library typeUse it whenHow images arriveMain cost
Subscribed, When neededvCenter can reach the depot or the public repository. Default choice.Metadata syncs automatically, image files download on first useFirst cluster of a new version waits for a template pull
Subscribed, ImmediatelyProvisioning latency matters more than datastore capacity, and only thenMetadata and every image file sync on scheduleLarge, growing datastore footprint, plus orphaned files after upstream deletions
Local, air gappedvCenter has no route out. Regulated, classified or offline sites.You download OVA files on a connected host and import them by handManual naming discipline, and a human step on every patch
Local, published to a subscriberSeveral offline vCenters behind one internal distribution pointOne local library publishes, remote sites subscribe internallyAn internal endpoint and certificate you now own and must renew

Preflight and version record

Four conditions gate this work. Your Supervisor must be Ready, because association triggers a reconcile that a busy Supervisor will accept and then quietly defer. You need vSphere 9.0 or later with VKS 3.3 or later installed if you want more than one library attached at a time, which is the capability that makes a mixed subscribed and local arrangement possible at all. You need enough free capacity on the chosen datastore, and I mean measured rather than assumed. And you need the correct subscription endpoint, which differs depending on whether your estate runs a Software Depot, the VCF component that caches Broadcom binaries locally.

# Reference estate for this Part, recorded before any change # VCF 9.0, vCenter 9.0.0.0, Supervisor 1.32.0, VKS 3.3.1 # kubectl v1.32.3, kubectl-vsphere plugin 9.0.0, VCF CLI v1.5.0, govc v0.48.1 # Three vSphere Zones, NSX VPC networking, vSAN backed storage policies $ export GOVC_URL=https://vcenter.lab.local $ export GOVC_USERNAME=administrator@vsphere.local $ export GOVC_PASSWORD=$(cat ~/.vc-pass) # read from a file, never inline $ govc library.ls # no output, nothing exists yet $ kubectl get kr No resources found # Correct at this stage. VKS has no library attached, so no releases are published.

Note how uninformative that last result is. An empty kubectl get kr has at least four distinct causes: no library exists, a library exists but is not associated with the Supervisor, a library is associated but has never synchronised, or a library synchronised and every item failed OVF certificate validation. Candidates who treat empty as one symptom rather than four lose time on the troubleshooting objectives later in the blueprint, and they lose it in the lab too. Learn to reach for govc library.ls before kubectl, because it splits those four causes into two groups in one command.

Subscribed library, from subscription URL to a ready VKr

Step 1, obtain the correct subscription URL

Two answers exist and picking the wrong one is a silent failure, not an error. Estates without a Software Depot, which includes most VMware vSphere Foundation deployments, use the standard Broadcom public repository at https://wp-content.broadcom.com/v2/latest/lib.json. Estates that do run a Software Depot must build the URL from their own depot: log in to vCenter, open Developer Center, then API Explorer, issue a GET against the lcm/depot/services API, and assemble the returned depot address and base path into a URL ending /PROD/COMP/VKR/lib.json. Use the public repository against a depot backed estate and you will pull images your lifecycle tooling does not know about.

Step 2, create the subscribed library

$ export VKR_SUB_URL=https://wp-content.broadcom.com/v2/latest/lib.json $ govc library.create –sub=$VKR_SUB_URL –sub-autosync=true –sub-ondemand=true –ds=vsanDatastore –thumbprint=$(govc about.cert –u=$VKR_SUB_URL –thumbprint | awk ‘{print $2}’) vkr-subscribed $ govc library.ls /vkr-subscribed $ govc library.ls /vkr-subscribed/* | head -4 /vkr-subscribed/v1.31.4—vmware.3-fips-vkr.1 /vkr-subscribed/v1.32.0—vmware.6-fips-vkr.2 /vkr-subscribed/v1.32.4—vmware.2-fips-vkr.1 /vkr-subscribed/v1.33.1—vmware.1-fips-vkr.1

That –sub-ondemand=true flag is the CLI equivalent of choosing When needed in the New Content Library wizard, and it is the recommended setting in Broadcom documentation for one blunt reason: metadata is small and images are not. On my lab the metadata for the full catalogue landed in under 3 GB and six minutes. Choosing Immediately instead has a second cost people forget about. When items are deleted from the published library upstream, their contents stay in your subscribed library storage and you have to delete them by hand. That is how a datastore quietly fills with Kubernetes versions nobody can even provision any more.

Step 3, associate the library with the Supervisor

No supported CLI exists for this and it is a vSphere Client action, which is precisely why it turns up as a point and click item. Navigate to Supervisor Management, then Supervisors, select your Supervisor instance, open Configure, then General, and find the Kubernetes Service card. On vSphere 9.0 with VKS 3.3 or later you get Add and Remove buttons and can attach more than one library. On vSphere 8.x and earlier you get a single Content Library field with an EDIT link and one library only. Add your subscribed library, then wait for it to appear in the list before you navigate away, because the write is asynchronous.

Step 4, confirm releases are published and usable

$ kubectl get kr NAME VERSION READY COMPATIBLE CREATED v1.31.4—vmware.3-fips-vkr.1 v1.31.4+vmware.3-fips-vkr.1 True True 4m v1.32.0—vmware.6-fips-vkr.2 v1.32.0+vmware.6-fips-vkr.2 True True 4m v1.32.4—vmware.2-fips-vkr.1 v1.32.4+vmware.2-fips-vkr.1 True True 4m v1.33.1—vmware.1-fips-vkr.1 v1.33.1+vmware.1-fips-vkr.1 False False 4m # READY True plus COMPATIBLE True is what green looks like. # The v1.33.1 row is COMPATIBLE False because VKS 3.3.1 does not support it yet. # A synced image is not the same thing as a usable image. # Now the failure that costs people an afternoon: $ kubectl apply -f cluster-payments.yaml Error from server: admission webhook denied the request: could not resolve VKr for version v1.32.0+vmware.6-fips-vkr.2, os image query os-name=photon # Cause: the manifest carried the VERSION string, which uses a plus sign. # Fix: topology.version must carry the NAME string, with three hyphens. $ sed –in-place ‘s/v1.32.0+vmware.6-fips-vkr.2/v1.32.0—vmware.6-fips-vkr.2/’ cluster-payments.yaml $ kubectl apply -f cluster-payments.yaml cluster.cluster.x-k8s.io/payments created

Two strings, one image, and only one of them works. On the v1alpha3 API you put the NAME string in tkr.reference.name. On v1beta1 and v1beta2 you put it in topology.version. Broadcom prints VERSION in the same table for human readability and it is the wrong value to copy every single time. If your team pastes cluster manifests from a wiki, this is worth a lint rule rather than a training session.

Trap worth a whole callout: vSphere presents a second content library field on the VM Service tile, and it looks like the same setting. It is not. Broadcom documentation says directly that the library referenced by VM Service can be used only with standalone virtual machines, and that you must not add the VKS content library to the VM Service tile. Doing it does not throw an error. It gives you two places that appear configured, one of which does nothing for your clusters, and a colleague who now believes the job is done.

Local library for an air-gapped estate

Here is the war story, because it is short and it cost me real time. Building the offline half of this lab, I created a local library, downloaded the OVA on a jump host, carried it across, and imported it with the item name taken straight from the VERSION column, plus sign and all. Import succeeded. Library showed one item. And kubectl get kr returned nothing, for ninety minutes, while I checked the Supervisor, the storage policy, the zones and eventually the Pinniped pods, because at that point I was guessing. Broadcom documents the rule in one sentence: if you are using a local content library, make sure the name you give the VKr matches the NAME string. The subscribed library does that naming for you, which is exactly why nobody who has only ever run subscribed libraries knows the rule exists. I reversed my decision to import by hand and wrote a four line script instead.

# On the connected jump host: download the OVA for each release you need. # On the air gapped vCenter, create a plain local library: $ govc library.create –ds=vsanDatastore –d=Offline VKr library vkr-local $ govc library.ls /vkr-local /vkr-subscribed # WRONG, and it fails silently: $ govc library.import –n=v1.32.0+vmware.6-fips-vkr.2 /vkr-local ./photon-ova-v1.32.0.ova $ kubectl get kr No resources found # RIGHT: derive the item name from the file, never from the VERSION column. $ VKR_NAME=v1.32.0—vmware.6-fips-vkr.2 $ govc library.import –n=$VKR_NAME /vkr-local ./photon-ova-v1.32.0.ova $ govc library.ls /vkr-local/* /vkr-local/v1.32.0—vmware.6-fips-vkr.2 $ kubectl get kr v1.32.0—vmware.6-fips-vkr.2 NAME VERSION READY COMPATIBLE CREATED v1.32.0—vmware.6-fips-vkr.2 v1.32.0+vmware.6-fips-vkr.2 True True 52s

One warning about running both libraries at once, which VKS 3.3 lets you do and which is genuinely useful for testing an offline path beside a live one. If two attached libraries hold the same image, matching on Kubernetes version, name, VKr version and architecture, the resolver finds multiple candidates and denies the request rather than choosing. Broadcom documents an annotation on the cluster specification to nominate a library and break the tie. Plan for that before you attach the second library, not after somebody reports that cluster creation broke for no reason.

Datastore consumed by library mode, same catalogueMeasured on the reference lab, vSAN datastore, VCF 9.0 with VKS 3.3.1Subscribed, Immediately214 GBWhen needed, two releases pulled41 GBWhen needed, metadata only3 GBSame catalogue, same Supervisor. Only the download mode differs.
A seventy fold difference in footprint for an estate that ran exactly two Kubernetes versions.

Verification, rollback and a failure lookup

Three checks prove the work, and they should be run in this order because each one narrows the search space for the next. Confirm the library exists and holds items with govc library.ls. Confirm the Supervisor publishes them with kubectl get kr, reading both boolean columns rather than just the first. Then confirm the resolver agrees with your manifest by inspecting a cluster that already exists, since a successful resolution stamps the cluster with a label naming the release it picked.

$ kubectl get cluster payments -n team-payments -o jsonpath='{.metadata.labels.run.tanzu.vmware.com/tkr}{"n"}’ v1.32.0—vmware.6-fips-vkr.2 # What green looks like: the label names the release the resolver actually chose, # which is not always the one you thought you asked for. $ kubectl get cluster payments -n team-payments -o jsonpath='{.status.conditions[?(@.type=="UpdatesAvailable")].message}’ [v1.32.4—vmware.2-fips-vkr.1] # Empty here with newer releases visible in kubectl get kr is usually the # resolve-os-image annotation: updatesAvailable honours it, so a Photon cluster # will never list an Ubuntu only release as an available upgrade.

Rollback is where the sharp edge lives. Backing out a library change means selecting it under Configure, General, Kubernetes Service and clicking Remove, and existing clusters keep running because their nodes were cloned long ago. Do it in that order. If somebody deletes the library from vCenter first, it stays linked to VKS as a dangling reference, and you then cannot add or remove any other library until you unlink the deleted one, with an error message telling you so. I have watched a change window burn twenty minutes on exactly that sequence. Remove from VKS, then delete from vCenter, never the reverse.

SymptomCauseRemediation
kubectl get kr returns No resources foundNo library associated, or association never reconciledCheck govc library.ls first, then re-add under Configure, General, Kubernetes Service
Library has items but no releases publishLocal library item name does not match the VKr NAME stringRename the item to the triple hyphen NAME form and wait for the controller
could not resolve VKr for version, on applyManifest carries the VERSION string with a plus signReplace with the NAME string in topology.version or tkr.reference.name
Release listed but COMPATIBLE is FalseVKr newer than the installed VKS version supportsUpgrade VKS, or pick a release whose COMPATIBLE column reads True
Release READY False, reason deactivatedSuperseded by a newer patch after a critical bug was foundMove to the superseding patch. Deactivated is intentional, not a sync fault.
Apply denied with multiple matching imagesTwo attached libraries hold the identical releaseAnnotate the cluster to nominate one library, or detach the duplicate
Item tagged Verification Failed after syncOVF signing certificate rejected by the applied security policyMetadata is kept but files will not sync. Fix trust, then resynchronise the item.
Cannot add or remove any libraryA library was deleted from vCenter while still linked to VKSUnlink the deleted library from VKS first, then repeat the operation

Exam focus for objective 2.5

Objective 2.5, Manage Kubernetes releases and content libraries (subscribed, local, and air-gapped) for VKS clusters: What this objective expects you to be able to do is choose a library type for a stated constraint, build it, attach it at the right scope, and read a release listing well enough to say why a cluster will or will not provision. Expect it in multiple selection items about which download mode suits a described estate, in matching items pairing a symptom to a cause, in point and click or hot area items on the Kubernetes Service card under Supervisor Configure, and in build list items ordering the offline workflow. The trap that catches experienced admins is scope again, in a new costume: they reason about the release library as a per namespace or per cluster setting, because every other Kubernetes platform they have run attaches images per cluster. It is one Supervisor wide association, and editing it from within a namespace view edits it for every namespace on that Supervisor. A quieter second trap is the two strings. Anything that asks you to complete a manifest wants the NAME form with three hyphens, and the VERSION form with a plus sign will be sitting right next to it as a distractor.

Objective checkpoint

Original practice questionAnswer and reasoning
An administrator changes the release content library while viewing a single vSphere Namespace. Which namespaces are affected?All of them on that Supervisor. The association is not namespace scoped, which is why the change is only permitted at Supervisor level in the first place.
A local library contains one imported OVA, yet kubectl get kr reports nothing. What is checked first?Item name. In a local library it must match the release NAME string exactly, including the triple hyphen separator. Subscribed libraries generate that name for you, local libraries do not.
A release appears in the listing with READY True and COMPATIBLE False. Can a cluster be provisioned from it?No. Releases are versioned independently of VKS, so an image can be fully synchronised and still be unusable until VKS itself is upgraded.

Library plan for the reference estate

My recommendation for this lab, and for most connected estates that resemble it, is one subscribed library set to When needed, attached at the Supervisor, with a second local library attached only while you are rehearsing the offline workflow and detached immediately afterwards. Avoid the pattern that most tutorials still teach, which is Immediately for the sake of faster first provisioning. Broadcom recommends on demand, my own numbers put the difference at 214 GB against 3 GB for an identical catalogue, and the eleven minutes you save on a first cluster is not worth a datastore you have to garbage collect by hand. Avoid, equally, leaving two libraries attached permanently unless you have already written the disambiguating annotation into your cluster templates.

Tonight, in your own lab, run kubectl get kr and then run govc library.ls against the same Supervisor, and reconcile the two lists by hand. Any item present in vCenter and absent from Kubernetes is either misnamed, incompatible, deactivated or failed verification, and working out which one takes about ten minutes and teaches this objective better than any amount of reading. Part 10 carries the second objective printed as 2.5, covering CNIs, NSX networking objects and TLS certificates, and it assumes the library you built here.

VCAP-VKS Exam Series · Part 9 of 34
« Previous: Part 8  |  Guide  |  Next: Part 10 »

References

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