Skip to main content

K3s

Terraform clones a cloud-init template into Proxmox VMs that become k3s control-plane and worker nodes. Each VM gets a fixed IP, an SSH key, and Proxmox tags so k3s-ansible (or similar) can target it. After apply, you install k3s on those VMs with Ansible or another method. Placeholders such as <subnet> and <first-control-plane-ip> stand in for your network.

Overview
#

The layout is three control-plane VMs (API server and etcd) and two worker nodes. All five are full clones of the cloud-init template (VM ID 9999 in the examples). They share an SSH user and public key, and they carry tags k3s plus control-plane or node.

RoleVM namesCountIP range (example)Tags
Control planek3s-control-plane-01033<subnet>.201203/24k3s, control-plane
Nodek3s-node-01022<subnet>.211212/24k3s, node

Set the Proxmox host name in Terraform (for example proxmox-pve or a variable). Each VM uses one virtio NIC on a single bridge such as vmbr0, with your LAN gateway (for example <subnet>.1). Prefer host-local SSD (local-lvm) for guest OS disks when the cluster will run Longhorn, not NAS-backed boot disks, and not Ceph for this generation.

Replace <subnet> with your actual subnet (for example 192.168.1). Adjust IP ranges, node name, and bridge in the Terraform variables or in main.tf.

Prerequisites
#

You need a Proxmox VE host with API access (https://your-proxmox-host:8006), the cloud-init template VM (ID 9999; create it with the Proxmox cloud-init template guide), Terraform >= 1.0, and an SSH key pair for the cloud user (path in Terraform, for example ~/.ssh/<cloud-init-key>). The same key fetches kubeconfig and runs Ansible later. Authenticate to Proxmox with username and password; an API token works when the provider supports it.

File layout
#

The Terraform code lives in the homelab repo under kubernetes/terraform/:

FilePurpose
main.tfProxmox VM resources: k3s control-plane VMs and nodes (clone, CPU, memory, network, cloud-init)
providers.tfTerraform and Proxmox provider (bpg/proxmox) configuration
variables.tfInput variables: Proxmox endpoint, username, password
terraform.tfvars.exampleExample values; copy to terraform.tfvars and fill in

Provider and variables
#

The provider is bpg/proxmox (~> 0.66 in the snippet below). Authentication is the endpoint URL, username, and password (sensitive). A comment in the code notes a future switch to an API token.

VariableDescriptionExample
proxmox_endpointProxmox API URLhttps://your-proxmox-host:8006
proxmox_usernameProxmox userroot@pam or your-username@pam
proxmox_passwordProxmox password(sensitive)

Step-by-step usage
#

1. Clone the repo and enter the Terraform directory
#

cd /path/to/homelabs
cd kubernetes/terraform

2. Copy and edit tfvars
#

cp terraform.tfvars.example terraform.tfvars

Edit terraform.tfvars and set proxmox_endpoint to your Proxmox API URL (for example https://<proxmox-host>:8006), proxmox_username (for example root@pam), and proxmox_password. Do not commit terraform.tfvars; add it to .gitignore if needed.

3. Ensure the cloud-init template and SSH key exist
#

Template VM ID 9999 must exist and be a full-cloneable template (see Proxmox cloud-init template). Place the public key where Terraform file() expects it, or update that path in main.tf.

4. Initialize and apply
#

terraform init
terraform plan
terraform apply

Confirm when prompted. Terraform creates three control-plane VMs and two nodes on the configured Proxmox host.

5. Deploy k3s on the new VMs
#

Use your preferred method (for example k3s-ansible) with the same SSH user and key you provisioned on the VMs. The playbook inventory groups remain [master] for control-plane VMs and [worker] for nodes; those are the names the playbook expects.

After the playbooks run, copy kubeconfig from the first control-plane node (replace <first-control-plane-ip> with that VM’s IP):

scp -i ~/.ssh/<cloud-init-key> <ssh-user>@<first-control-plane-ip>:~/.kube/config ~/.kube/config

Then verify with kubectl get pods --all-namespaces.

For remote access with GitHub OIDC login (recommended), configure Dex OIDC and use homelabs-private/clusters/<cluster>/kubeconfig-oidc.yaml.template instead of relying on client certificates alone.

Destroying the VMs
#

To remove all Terraform-managed k3s VMs:

cd kubernetes/terraform
terraform destroy

Confirm when prompted. This does not remove the template VM (9999) or any resources not managed by this Terraform configuration.