> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siderolabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# VMware

> Creating Talos Kubernetes cluster using VMware.

export const version_v1_13 = 'v1.13';

export const release_v1_13 = 'v1.13.1';

export const VersionWarningBanner = () => {
  const latestVersion = "v1.13";
  const [latestUrl, setLatestUrl] = useState(null);
  const [currentVersion, setCurrentVersion] = useState(null);
  const [isBeta, setIsBeta] = useState(false);
  const parseVersion = v => v.replace("v", "").split(".").map(Number);
  const isGreaterVersion = (a, b) => {
    const [aMajor, aMinor] = parseVersion(a);
    const [bMajor, bMinor] = parseVersion(b);
    if (aMajor > bMajor) return true;
    if (aMajor === bMajor && aMinor > bMinor) return true;
    return false;
  };
  useEffect(() => {
    if (typeof window === "undefined") return;
    const {pathname, hash, search} = window.location;
    const match = pathname.match(/\/talos\/(v\d+\.\d+)\//);
    if (!match) return;
    const detectedVersion = match[1];
    if (detectedVersion === latestVersion) return;
    setCurrentVersion(detectedVersion);
    if (isGreaterVersion(detectedVersion, latestVersion)) {
      setIsBeta(true);
    }
    const newPath = pathname.replace(`/talos/${detectedVersion}/`, `/talos/${latestVersion}/`);
    setLatestUrl(`${newPath}${search}${hash}`);
  }, []);
  if (!latestUrl || !currentVersion) return null;
  return <div className="not-prose sticky top-6 z-50 my-6">
      <div className="border border-yellow-500/30 bg-yellow-500/10 px-4 py-3 rounded-xl">
        <div className="text-sm">
          {isBeta ? <>
              ⚠️ You are viewing a <strong>beta version</strong> of Talos ({currentVersion}).
              This version may be unstable.
              <a href={latestUrl} className="ml-2 underline text-yellow-400 hover:text-yellow-300 font-medium">
                View latest stable version {latestVersion} →
              </a>
            </> : <>
              ⚠️ You are viewing an older version of Talos ({currentVersion}).
              <a href={latestUrl} className="ml-2 underline text-yellow-400 hover:text-yellow-300 font-medium">
                View the latest version {latestVersion} →
              </a>
            </>}
        </div>
      </div>
    </div>;
};

<VersionWarningBanner />

## Creating a cluster via the `govc` CLI

In this guide we will create an HA Kubernetes cluster with 2 worker nodes.
We will use the `govc` cli which can be downloaded [here](https://github.com/vmware/govmomi/tree/master/govc#installation).

## Prerequisites

This guide will use the virtual IP ("VIP") functionality that is built into Talos in order to provide a stable, known IP for the Kubernetes control plane.
This simply means the user should pick an IP on their "VM Network" to designate for this purpose and keep it handy for future steps.

The Talos OVA image uses the `vmx-15` hardware version, this requires a minimum of **ESXi 6.7U2**.
To check your version of ESXi refer to the following Broadcom
[KB article](https://knowledge.broadcom.com/external/article/316595/build-numbers-and-versions-of-vmware-esx.html).

More information regarding virtual machine hardware versions can be found in the following Broadcom
[KB article](https://knowledge.broadcom.com/external/article/315655/virtual-machine-hardware-versions.html).

## Create the machine configuration files

### Generating base configurations

Using the VIP chosen in the prereq steps, we will now generate the base configuration files for the Talos machines.
This can be done with the `talosctl gen config ...` command.
Take note that we will also use a JSON6902 patch when creating the configs so that the control plane nodes get some special information about the VIP we chose earlier, as well as a daemonset to install vmware tools on talos nodes.

First, download `cp.patch.yaml` to your local machine and edit the VIP to match your chosen IP.
You can do this by issuing:

<CodeBlock lang="sh">
  {`
    curl -fsSLO https://raw.githubusercontent.com/siderolabs/docs/main/static/talos/${version_v1_13}/vmware/cp.patch.yaml
    `}
</CodeBlock>

It's contents should look like the following:

```yaml theme={null}
- op: add
  path: /machine/network
  value:
    interfaces:
      - interface: eth0
        dhcp: true
        vip:
          ip: <VIP>
```

With the patch in hand, generate machine configs with:

```bash theme={null}
$ talosctl gen config vmware-test https://<VIP>:<port> --config-patch-control-plane @cp.patch.yaml
created controlplane.yaml
created worker.yaml
created talosconfig
```

At this point, you can modify the generated configs to your liking if needed.
Optionally, you can specify additional patches by adding to the `cp.patch.yaml` file downloaded earlier, or create your own patch files.

### Validate the configuration files

```bash theme={null}
$ talosctl validate --config controlplane.yaml --mode cloud
controlplane.yaml is valid for cloud mode
$ talosctl validate --config worker.yaml --mode cloud
worker.yaml is valid for cloud mode
```

> Note: Using VMXNET network interfaces in VMware will cause the default [Flannel CNI](https://github.com/flannel-io/flannel) backend (vxlan) to not work between nodes.
> To avoid this problem it is recommended to use Intel e1000 network interfaces or apply the patch below to [disable incompatible features](https://github.com/flannel-io/flannel/blob/master/Documentation/backends.md).

Add the following configuration to disable incompatible hardware acceleration features.

```yaml theme={null}
apiVersion: v1alpha1
kind: EthernetConfig
name: flannel.1
features:
  tx-checksum-ip-generic: false
```

## Set environment variables

`govc` makes use of the following environment variables

```bash theme={null}
export GOVC_URL=<vCenter url>
export GOVC_USERNAME=<vCenter username>
export GOVC_PASSWORD=<vCenter password>
```

> Note: If your vCenter installation makes use of self signed certificates, you'll want to export `GOVC_INSECURE=true`.

There are some additional variables that you may need to set:

```bash theme={null}
export GOVC_DATACENTER=<vCenter datacenter>
export GOVC_RESOURCE_POOL=<vCenter resource pool>
export GOVC_DATASTORE=<vCenter datastore>
export GOVC_NETWORK=<vCenter network>
```

## Choose install approach

As part of this guide, we have a more automated install script that handles some of the complexity of importing OVAs and creating VMs.
If you wish to use this script, we will detail that next.
If you wish to carry out the manual approach, simply skip ahead to the "Manual Approach" section.

### Scripted install

Download the `vmware.sh` script to your local machine.
You can do this by issuing:

<CodeBlock lang="sh">
  {`
    curl -fsSL "https://raw.githubusercontent.com/siderolabs/docs/main/static/talos/${version_v1_13}/vmware/cp.patch.yaml" | sed s/latest/${release_v1_13}/ > vmware.sh
    `}
</CodeBlock>

This script has default variables for things like Talos version and cluster name that may be interesting to tweak before deploying.

The script downloads VMWare OVA with `talos-vmtoolsd` from <a href={`https://factory.talos.dev/?arch=amd64&cmdline-set=true&extensions=-&extensions=siderolabs%2Fvmtoolsd-guest-agent&platform=vmware&target=cloud&version=${release_v1_13}`}>
Image Factory
</a> extension pre-installed.

#### Import OVA

To create a content library and import the Talos OVA corresponding to the mentioned Talos version, simply issue:

```bash theme={null}
./vmware.sh upload_ova
```

#### Create cluster

With the OVA uploaded to the content library, you can create a 5 node (by default) cluster with 3 control plane and 2 worker nodes:

```bash theme={null}
./vmware.sh create
```

This step will create a VM from the OVA, edit the settings based on the env variables used for VM size/specs, then power on the VMs.

You may now skip past the "Manual Approach" section down to "Bootstrap Cluster".

### Manual approach

#### Import the OVA into vCenter

A `talos.ova` asset is available from [Image Factory](https://www.talos.dev/latest/talos-guides/install/boot-assets/#image-factory).
We will refer to the version of the release as `$TALOS_VERSION` below.
It can be easily exported with `export TALOS_VERSION="v0.3.0-alpha.10"` or similar.

The download link already includes the `talos-vmtoolsd` extension.

```bash theme={null}
curl -LO https://factory.talos.dev/image/903b2da78f99adef03cbbd4df6714563823f63218508800751560d3bc3557e40/${TALOS_VERSION}/vmware-amd64.ova
```

Create a content library (if needed) with:

```bash theme={null}
govc library.create <library name>
```

Import the OVA to the library with:

```bash theme={null}
govc library.import -n talos-${TALOS_VERSION} <library name> /path/to/downloaded/talos.ova
```

#### Create the bootstrap node

We'll clone the OVA to create the bootstrap node (our first control plane node).

```bash theme={null}
govc library.deploy <library name>/talos-${TALOS_VERSION} control-plane-1
```

Talos makes use of the `guestinfo` facility of VMware to provide the machine/cluster configuration.
This can be set using the `govc vm.change` command.
To facilitate persistent storage using the vSphere cloud provider integration with Kubernetes, `disk.enableUUID=1` is used.

```bash theme={null}
govc vm.change \
  -e "guestinfo.talos.config=$(cat controlplane.yaml | base64)" \
  -e "disk.enableUUID=1" \
  -vm control-plane-1
```

#### Update hardware resources for the bootstrap node

* `-c` is used to configure the number of cpus
* `-m` is used to configure the amount of memory (in MB)

```bash theme={null}
govc vm.change \
  -c 2 \
  -m 4096 \
  -vm control-plane-1
```

The following can be used to adjust the [EPHEMERAL](../../learn-more/architecture#file-system-partitions) disk size.

```bash theme={null}
govc vm.disk.change -vm control-plane-1 -disk.name disk-1000-0 -size 10G
```

```bash theme={null}
govc vm.power -on control-plane-1
```

#### Create the remaining control plane nodes

```bash theme={null}
govc library.deploy <library name>/talos-${TALOS_VERSION} control-plane-2
govc vm.change \
  -e "guestinfo.talos.config=$(base64 controlplane.yaml)" \
  -e "disk.enableUUID=1" \
  -vm control-plane-2

govc library.deploy <library name>/talos-${TALOS_VERSION} control-plane-3
govc vm.change \
  -e "guestinfo.talos.config=$(base64 controlplane.yaml)" \
  -e "disk.enableUUID=1" \
  -vm control-plane-3
```

```bash theme={null}
govc vm.change \
  -c 2 \
  -m 4096 \
  -vm control-plane-2

govc vm.change \
  -c 2 \
  -m 4096 \
  -vm control-plane-3
```

```bash theme={null}
govc vm.disk.change -vm control-plane-2 -disk.name disk-1000-0 -size 10G

govc vm.disk.change -vm control-plane-3 -disk.name disk-1000-0 -size 10G
```

```bash theme={null}
govc vm.power -on control-plane-2

govc vm.power -on control-plane-3
```

#### Update settings for the worker nodes

```bash theme={null}
govc library.deploy <library name>/talos-${TALOS_VERSION} worker-1
govc vm.change \
  -e "guestinfo.talos.config=$(base64 worker.yaml)" \
  -e "disk.enableUUID=1" \
  -vm worker-1

govc library.deploy <library name>/talos-${TALOS_VERSION} worker-2
govc vm.change \
  -e "guestinfo.talos.config=$(base64 worker.yaml)" \
  -e "disk.enableUUID=1" \
  -vm worker-2
```

```bash theme={null}
govc vm.change \
  -c 4 \
  -m 8192 \
  -vm worker-1

govc vm.change \
  -c 4 \
  -m 8192 \
  -vm worker-2
```

```bash theme={null}
govc vm.disk.change -vm worker-1 -disk.name disk-1000-0 -size 10G

govc vm.disk.change -vm worker-2 -disk.name disk-1000-0 -size 10G
```

```bash theme={null}
govc vm.power -on worker-1

govc vm.power -on worker-2
```

#### Bootstrap cluster

In the vSphere UI, open a console to one of the control plane nodes.
You should see some output stating that etcd should be bootstrapped.
This text should look like:

```bash theme={null}
"etcd is waiting to join the cluster, if this node is the first node in the cluster, please run `talosctl bootstrap` against one of the following IPs:
```

Take note of the IP mentioned here and issue:

```bash theme={null}
talosctl --talosconfig talosconfig bootstrap -e <control plane IP> -n <control plane IP>
```

Keep this IP handy for the following steps as well.

#### Retrieve the `kubeconfig`

At this point we can retrieve the admin `kubeconfig` by running:

```bash theme={null}
talosctl --talosconfig talosconfig config endpoint <control plane IP>
talosctl --talosconfig talosconfig config node <control plane IP>
talosctl --talosconfig talosconfig kubeconfig .
```

#### Configure `talos-vmtoolsd`

The talos-vmtoolsd application was deployed as a daemonset as part of the cluster creation; however, we must now provide a talos credentials file for it to use.

Create a new talosconfig with:

```bash theme={null}
talosctl --talosconfig talosconfig -n <control plane IP> config new vmtoolsd-secret.yaml --roles os:admin
```

Create a secret from the talosconfig:

```bash theme={null}
kubectl -n kube-system create secret generic talos-vmtoolsd-config \
  --from-file=talosconfig=./vmtoolsd-secret.yaml
```

Clean up the generated file from local system:

```bash theme={null}
rm vmtoolsd-secret.yaml
```

Once configured, you should now see these daemonset pods go into "Running" state and in vCenter, you will now see IPs and info from the Talos nodes present in the UI.
