Intro

I’ve wanted a proper homelab for a long time. Somewhere I can break things without worrying about a cloud bill, or about messing something up at work. Over time I’ve ended up with a small pile of machines at home, and I finally decided to put them to real use.

This is the first post in a series where I write down how the whole thing comes together. I’ll start with the hardware I have, and then get into the one machine that’s actually doing something right now: a Dell OptiPlex 7070 running Proxmox, with a small Kubernetes cluster on top of it. In this part I’ll go through:

  1. The hardware, and what each piece does (or will do)
  2. Installing Proxmox VE on the OptiPlex 7070
  3. Creating two VMs, one for a Kubernetes control plane (master) node and one for a worker node
  4. Installing Talos Linux on both and bootstrapping the cluster

So why Talos? It’s a small, locked-down Linux distribution that exists only to run Kubernetes. There’s no SSH, no shell and no package manager. You manage everything through an API with a CLI called talosctl. I’ll admit that sounded a bit scary to me at first. But the more I thought about it, the more I liked it: there’s very little to configure, very little to patch, and not much I can accidentally break. That’s exactly what I want from something I don’t want to babysit.

Hardware

My homelab is a bit of a mixed bag. Here’s everything I have right now:

Device CPU RAM What it does right now
Dell OptiPlex 7070Intel Core i5-9500 (9th gen, 6 cores)24 GBProxmox, running the Kubernetes master and worker
Dell OptiPlex 7050 (×2)Intel Core i5 (7th gen)24 GB eachNothing yet, more on these in part 2
Old desktop PCIntel Core i5-2400 (upgrading to an i7-3770)32 GBNothing yet, also part 2
Raspberry Pi 1 Model B (2011.12 board)Single-core ARM11512 MBPi-hole, my DNS resolver and ad blocker
Raspberry Pi 5Quad-core Arm8 GBHome Assistant

The OptiPlex 7070

For now, this is the only machine with Proxmox on it, and it’s where the Kubernetes cluster lives. It’s small, quiet and doesn’t use much power, which matters when something is going to run 24/7.

24 GB of RAM turns out to be plenty for a two-node cluster. This is how I split it up:

VM vCPU RAM Disk
talos-cp-0124 GB20 GB
talos-wk-0148 GB50 GB
Proxmox host-~2 GB-

That still leaves around 10 GB free, so there’s room to try other things later.

The two Raspberry Pis

The old Raspberry Pi 1, a Model B with “2011.12” printed on the board, is the DNS server for the whole house. It runs Pi-hole, which answers DNS queries for everything on the network and blocks ads and trackers along the way. It’s been doing that job quietly for a long time.

The problem is that it’s old, and it runs off an SD card. SD cards don’t love constant writes, and one could die on me any day. When that happens, DNS goes down, and from the point of view of everyone else at home, “the internet is broken”.

The Raspberry Pi 5 runs Home Assistant. Home Assistant can run add-ons, and there’s one for Pi-hole. So the plan is to run a second Pi-hole on the Pi 5, right next to Home Assistant, and give both Pis out as DNS servers on the network. If the old Pi gives up one day, the Pi 5 keeps things running while I sort out a replacement.

The rest: two OptiPlex 7050s and an old desktop

The two OptiPlex 7050s and the old desktop aren’t doing anything yet. Between them there’s a lot of CPU and 80 GB of RAM sitting around, so they definitely won’t stay idle for long. The desktop is due for a CPU upgrade from the i5-2400 to an i7-3770 first. Both chips use the same socket (LGA 1155), so if the motherboard’s BIOS supports it, it should be a straight swap. I’ll get into what I’m doing with all three in part 2.

What you’ll need

If you want to follow along with the Proxmox and Talos setup, you’ll need:

  • A USB stick (8 GB or bigger) for the Proxmox installer
  • A monitor and keyboard, just for the first install
  • A laptop or desktop on the same network, with kubectl installed
  • Two free IP addresses on your network for the Talos VMs. It’s worth setting up DHCP reservations for them in your router, so they don’t move around.

Installing Proxmox VE

Step 1: Sort out the BIOS

Before installing anything, press F2 while the OptiPlex boots to get into the BIOS setup, and check these settings:

  • Virtualization Support → Virtualization: Enabled (Intel VT-x)
  • Virtualization Support → VT for Direct I/O: Enabled (VT-d). You’ll want this later if you ever pass a device through to a VM.
  • Storage → SATA/NVMe Operation: set it to AHCI/NVMe, not RAID On. A lot of OptiPlexes ship with RAID On, and with that setting the Proxmox installer might not see your NVMe drive at all.
  • Power Management → AC Recovery: set it to Power On, so the machine turns itself back on after a power cut.

Save and exit.

Step 2: Make a bootable USB stick

Grab the latest Proxmox VE ISO Installer from the Proxmox downloads page. Then write it to the USB stick with balenaEtcher, Rufus, or dd if you’re on Linux:

# Replace /dev/sdX with your USB stick. Double-check it, dd will happily wipe the wrong disk!
sudo dd if=proxmox-ve_*.iso of=/dev/sdX bs=4M status=progress conv=fsync

Step 3: Install Proxmox

Plug the USB stick into the OptiPlex, turn it on and press F12 for the one-time boot menu. Pick the USB stick, then Install Proxmox VE (Graphical).

The installer is pretty painless:

  • Target disk: your NVMe SSD. The default ext4 is fine for a single disk. ZFS (RAID0) gets you snapshots and compression, but ZFS likes to use a good chunk of RAM for caching, so keep that in mind.
  • Country, timezone and keyboard: whatever matches where you are
  • Password and email: this is the root password for the web UI and SSH
  • Management network:
    • Hostname (FQDN): something like pve.home.lan
    • IP address: a static IP outside your router’s DHCP range, e.g. 192.168.1.10/24
    • Gateway: your router, e.g. 192.168.1.1
    • DNS: your router, your Pi-hole, or a public resolver

Once it’s done, pull the USB stick out and let it reboot. You won’t need the monitor and keyboard anymore. Everything from here happens from your laptop at:

https://192.168.1.10:8006

Log in as root with the Linux PAM realm. You’ll see a certificate warning and a “No valid subscription” pop-up. Both are normal, so don’t worry about them.

Step 4: Switch to the free update repository

Out of the box, Proxmox gets its updates from the enterprise repository, which needs a paid subscription. For a homelab, the free no-subscription repository is all you need:

  1. In the web UI, click your node, then Updates → Repositories
  2. Select the pve-enterprise entry and click Disable. Do the same for the enterprise ceph entry.
  3. Click Add, choose No-Subscription, then Add

Then update everything from the node’s Shell:

apt update && apt full-upgrade -y
reboot

That’s it, Proxmox is ready for some VMs.

Getting Talos Linux ready

Step 1: Build an image with the QEMU guest agent

Since Talos has no package manager, anything extra has to be baked into the image itself. Talos calls these system extensions. On Proxmox you want the QEMU guest agent, so Proxmox can see each VM’s IP address and shut it down cleanly.

Head over to the Talos Image Factory and:

  1. Pick Bare-metal Machine
  2. Pick the latest Talos version
  3. Choose amd64
  4. Under system extensions, select siderolabs/qemu-guest-agent
  5. Click through the rest with the defaults

At the end you’ll get two things you need:

  • A link to the ISO (metal-amd64.iso)
  • The installer image, which looks like factory.talos.dev/installer/<schematic-id>:<version>. Copy this somewhere safe. You’ll need it later so the guest agent is still there after Talos installs itself to disk.

Step 2: Get the ISO into Proxmox

In Proxmox, go to local (pve) → ISO Images → Download from URL, paste the ISO link from the Image Factory, click Query URL and then Download.

Step 3: Install talosctl on your laptop

# Linux / macOS
curl -sL https://talos.dev/install | sh

# or with Homebrew
brew install siderolabs/tap/talosctl

Make sure your talosctl version matches the Talos version you picked in the Image Factory.

Creating the VMs

Create two VMs with the Create VM button in the top right of the Proxmox UI. Talos is fussy about a few settings, so here’s what I used:

Tab Setting Value
GeneralNametalos-cp-01 / talos-wk-01
OSISO imagethe Talos metal-amd64.iso
OSGuest OSLinux, 6.x - 2.6 Kernel
SystemQemu Agent✅ Enabled
SystemSCSI ControllerVirtIO SCSI single
DisksSize20 GB (control plane) / 50 GB (worker)
DisksDiscard / IO thread✅ / ✅
CPUCores2 (control plane) / 4 (worker)
CPUTypehost
MemoryMemory4096 MB (control plane) / 8192 MB (worker)
MemoryBallooning Device❌ Disabled
NetworkModelVirtIO (paravirtualized), bridge vmbr0

Two of these really matter:

  • CPU type = host: newer Talos releases need CPU features (x86-64-v2) that the old default kvm64 CPU type doesn’t have. Leave it on kvm64 and the VM might not boot, or might crash early.
  • Ballooning off: Kubernetes expects its memory to stay put, and Talos doesn’t support memory hot-plug. Give each VM a fixed amount and leave it at that.

Start both VMs. Each one boots the Talos ISO into maintenance mode and shows a little dashboard on the Proxmox console, with its IP address on it. Write both IPs down. For the rest of this post I’ll use:

  • Control plane: 192.168.1.21
  • Worker: 192.168.1.22

If you’re setting up DHCP reservations for the VMs (you can find their MAC addresses under Hardware → Network Device), reboot them now so they pick up the right IPs.

Bootstrapping the Kubernetes cluster

Step 1: Check the install disk

Talos is still running from the ISO at this point, so it needs to be told which disk to install to. In maintenance mode it’ll answer questions without any credentials, so you can just ask it:

talosctl get disks --insecure --nodes 192.168.1.21

With the VirtIO SCSI controller, the VM’s disk shows up as /dev/sda.

Step 2: Generate the machine configs

I like to set a few variables first so the commands are easier to read. Then generate the configs, using the installer image from the Image Factory instead of the default one:

export CLUSTER_NAME=homelab
export CP_IP=192.168.1.21
export WORKER_IP=192.168.1.22
export INSTALL_IMAGE=factory.talos.dev/installer/<schematic-id>:<version>

mkdir -p ~/homelab/talos && cd ~/homelab/talos

talosctl gen config $CLUSTER_NAME https://$CP_IP:6443 \
  --install-disk /dev/sda \
  --install-image $INSTALL_IMAGE

You’ll end up with three files:

  • controlplane.yaml: the config for the control plane node
  • worker.yaml: the config for worker nodes
  • talosconfig: the credentials talosctl uses to talk to your cluster

These files hold your cluster’s secrets and certificates. Keep them somewhere safe, like a password manager or an encrypted backup, and please don’t commit them to a public git repo.

Step 3: Apply the configs

Send each node its config. You only need --insecure this one time, because the nodes are still in maintenance mode and don’t have any certificates yet:

talosctl apply-config --insecure --nodes $CP_IP --file controlplane.yaml
talosctl apply-config --insecure --nodes $WORKER_IP --file worker.yaml

Each node installs Talos to /dev/sda and reboots. Once that’s done, go to Hardware → CD/DVD Drive for each VM in Proxmox and set it to Do not use any media, so they boot from the disk from now on.

Step 4: Point talosctl at the cluster

export TALOSCONFIG=~/homelab/talos/talosconfig

talosctl config endpoint $CP_IP
talosctl config node $CP_IP

Step 5: Bootstrap etcd

This is the step that’s easiest to forget. The control plane won’t start Kubernetes until you tell it to bootstrap etcd. Run this once, against one control plane node:

talosctl bootstrap

Then watch it come up. I really like Talos’s live dashboard for this:

talosctl dashboard

Give it a few minutes, then check that everything is healthy:

talosctl health

Step 6: Grab the kubeconfig

talosctl kubeconfig ~/.kube/config --merge
kubectl get nodes -o wide

You should see both nodes, and both should be Ready:

NAME            STATUS   ROLES           AGE   VERSION
talos-cp-01     Ready    control-plane   6m    v1.x.x
talos-wk-01     Ready    <none>          5m    v1.x.x

For a quick sanity check, run something on the worker:

kubectl create deployment hello --image=nginx
kubectl get pods -o wide

The pod should land on talos-wk-01. By default the control plane node has a taint that keeps regular workloads off it. Clean up with kubectl delete deployment hello when you’re done.

If something goes wrong

  • The Proxmox installer doesn’t see the NVMe drive: change the BIOS storage mode from RAID On to AHCI/NVMe.
  • A Talos VM crashes or hangs on boot: check that the CPU type is host and not kvm64.
  • apply-config times out: the node has probably picked up a different IP after rebooting. Check the Proxmox console for its current IP, and set up DHCP reservations so it doesn’t happen again.
  • A node boots back into maintenance mode after installing: the ISO is still attached and first in the boot order. Remove it from the CD/DVD drive.
  • kubectl get nodes just hangs: you most likely skipped talosctl bootstrap.
  • Proxmox can’t see the VM’s IP: the guest agent is missing. Check that you passed the Image Factory installer image to gen config.

What’s next

So that’s part 1. The OptiPlex 7070 is running Proxmox, and on top of it there’s a two-node Kubernetes cluster on Talos. It’s small, but it works, and it’s a good base to build on.

In part 2 I’ll get into what I’m planning for the two OptiPlex 7050s and the old desktop, and walk through how my Kubernetes cluster is actually set up.

Thanks for reading! If you have questions or ideas, find me on twitter.