A bootstrapping template for a Talos Linux cluster (3 control plane + 3 workers) on VMware vSphere, with Cilium CNI and BGP load balancer integration.
This repo contains only the generic, reusable parts. Site-specific and sensitive files (machine configs, credentials, environment config) should be kept in a separate folder of your own choosing - outside this repo.
The scripts accept a -ConfigsPath parameter pointing to that folder:
.\Deploy-TalosCluster.ps1 -ConfigsPath "C:\path\to\your\configs"Your configs folder should contain:
configs/
controlplane.yaml # generated by talosctl gen config
worker.yaml # generated by talosctl gen config
talosconfig # generated by talosctl gen config
kubeconfig # written by Bootstrap-TalosCluster.ps1
environment.yaml # filled in from powershell/environment.example.yaml
The image is built from Image Factory with the following extensions:
customization:
systemExtensions:
officialExtensions:
- siderolabs/iscsi-tools
- siderolabs/util-linux-tools
- siderolabs/vmtoolsd-guest-agent- Schematic ID:
a28d86375cf9debe952efbcbe8e2886cf0a174b1f4dd733512600a40334977d7 - Talos version:
v1.13.2 - OVA: https://factory.talos.dev/image/a28d86375cf9debe952efbcbe8e2886cf0a174b1f4dd733512600a40334977d7/v1.13.2/vmware-amd64.ova
talosctlinstalled locallykubectlinstalled locally- PowerShell with
VCF.PowerCLIandpowershell-yamlmodules installed - A reserved VIP (Virtual IP) on your VM network for the control plane endpoint (e.g.
192.168.1.50) - 6 VM IP addresses planned (3 control plane, 3 workers) - DHCP or static
Copy powershell/environment.example.yaml to your configs folder as environment.yaml and fill in all values before running any scripts.
.\powershell\Upload-TalosOva.ps1 -ConfigsPath "C:\path\to\your\configs"This downloads the OVA from Image Factory and imports it into the content library defined in environment.yaml (default: TALOS).
Bumping the version in environment.yaml and re-running will upload the new version alongside the old one.
Generate the base configs (per-node networking and hostname are applied at deploy time via patches):
cd /path/to/your/configs
talosctl gen config vmware-cluster https://<VIP>:6443 \
--install-image factory.talos.dev/installer/<SCHEMATIC_ID>:<TALOS_VERSION>This produces controlplane.yaml, worker.yaml, and talosconfig directly in your configs folder.
.\powershell\Deploy-TalosCluster.ps1 -ConfigsPath "C:\path\to\your\configs"This creates VMs from the content library (3 control plane + 3 workers), injects the machine configs via guestinfo.talos.config, sets disk.enableUUID=TRUE, and powers them on. VM names match the hostnames defined in environment.yaml.
| Role | VMs | vCPU | RAM | Disk |
|---|---|---|---|---|
| Control plane | talos-cp-1, talos-cp-2, talos-cp-3 |
2 | 4 GB | 50 GB |
| Worker | talos-worker-1, talos-worker-2, talos-worker-3 |
4 | 8 GB | 100 GB |
.\powershell\Bootstrap-TalosCluster.ps1 -ConfigsPath "C:\path\to\your\configs"The script will:
- Read control plane IPs directly from
environment.yaml - Wait for the Talos API (port 50000) to be ready on all control plane nodes
- Bootstrap etcd on the first control plane node
- Wait for all control plane members to join
- Write
kubeconfigto the configs folder
Nodes will remain NotReady until a CNI is installed - this is expected.
helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium cilium/cilium --namespace kube-system --values helm/cilium/values.yamlCheck status of Cilium pods:
cilium status --waitTo upgrade Cilium later:
helm upgrade cilium cilium/cilium --namespace kube-system --values helm/cilium/values.yamlCopy exampleconfigs/bgp.yaml and fill in your values (<LOCAL_ASN>, <ROUTER_ASN>, <ROUTER_IP>, <LB_CIDR>, <ROUTER_NAME>), then apply it:
kubectl label nodes --all bgp-policy=default
kubectl apply -f bgp.yamlVerify peering is established:
cilium bgp peers$env:KUBECONFIG = "C:\path\to\your\configs\kubeconfig"
kubectl get nodesAll 6 nodes should appear Ready once Cilium is running.
Gateway API CRDs are required before Traefik can act as a Gateway controller:
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/latest/download/standard-install.yamlhelm repo add argo https://argoproj.github.io/argo-helm
helm repo update
helm install argocd argo/argo-cd --namespace argocd --create-namespace --values helm/argocd/values.yamlThe helm/argocd/values.yaml configures the server service as a LoadBalancer with BGP labels, so Cilium will assign it an IP from the pool and announce it to your router.
Get the initial admin password:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -dWhen a new Talos version is released, generate a new schematic at factory.talos.dev with the same extensions, then upgrade each node:
# Upgrade control plane nodes one at a time
talosctl upgrade -n <cp-1-ip> \
--image factory.talos.dev/installer/<new-schematic-id>:<new-version>
talosctl upgrade -n <cp-2-ip> \
--image factory.talos.dev/installer/<new-schematic-id>:<new-version>
talosctl upgrade -n <cp-3-ip> \
--image factory.talos.dev/installer/<new-schematic-id>:<new-version>
# Then worker nodes
talosctl upgrade -n <worker-1-ip> \
--image factory.talos.dev/installer/<new-schematic-id>:<new-version>
talosctl upgrade -n <worker-2-ip> \
--image factory.talos.dev/installer/<new-schematic-id>:<new-version>
talosctl upgrade -n <worker-3-ip> \
--image factory.talos.dev/installer/<new-schematic-id>:<new-version>Talos upgrades in-place with an A/B partition scheme - each node reboots into the new version without data loss.