<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Pxe on inherent site</title>
		<link>https://inherently.xyz/tags/pxe/</link>
		<description>Recent content in Pxe on inherent site</description>
		<generator>Hugo</generator>
		<language>en-us</language>
			<lastBuildDate>Sat, 01 Mar 2025 19:00:33 +0200</lastBuildDate>
			<atom:link href="https://inherently.xyz/tags/pxe/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>PXE setup for Talos Linux with Matchbox</title>
				<link>https://inherently.xyz/blog/pxe-setup-for-talos-using-matchbox/</link>
				<pubDate>Sat, 01 Mar 2025 19:00:33 +0200</pubDate>
				<guid>https://inherently.xyz/blog/pxe-setup-for-talos-using-matchbox/</guid>
				<description>&lt;p&gt;Join my campaign of hate against installing operating systems interactively.&#xA;I usually wipe my homelab virtualization hosts every week or two.&#xA;This might sound insane but I&amp;rsquo;ve been working on automating their setup.&#xA;As explained in the previous post, friendship ended with ProxMox and kubernetes will take its place.&#xA;Specifically Talos Linux, a linux distro you can&amp;rsquo;t even SSH into.&#xA;ProxMox kind of notoriously doesn&amp;rsquo;t have a way to be sanely installed through PXE but Talos is kind of made for it.&#xA;However, PXE (and iPXE, we&amp;rsquo;ll discuss this later) is not perfectly documented and can be even harder to debug.&#xA;So in this post I&amp;rsquo;ll document what worked for me and talk about some pretty helpful resources.&lt;/p&gt;&#xA;&lt;h2 id=&#34;plan&#34;&gt;Plan&lt;/h2&gt;&#xA;&lt;h3 id=&#34;pxe&#34;&gt;PXE&lt;/h3&gt;&#xA;&lt;p&gt;So let&amp;rsquo;s start with a bit of background, then lay out what I wanted to achieve, why and what I considered &amp;ldquo;good enough&amp;rdquo;.&#xA;First off, PXE.&#xA;It stands for pre-boot execution environment and is mostly reliant on motherboards and network cards to be implemented on the client side.&#xA;It&amp;rsquo;s a stripped down environment before the computer is booted into an operating system.&#xA;Inside it, there are standards for getting information about what to execute, where to get it and what configuration to use.&#xA;PXE is the name of the general concept and the first version of the technology.&#xA;It allows booting a computer from the network by loading files from a TFTP server.&#xA;Later on, &lt;a href=&#34;https://ipxe.org/&#34;&gt;iPXE&lt;/a&gt; came around to fix some of its limitations.&#xA;One thing it&amp;rsquo;s useful for having a computer and being able to boot it from the network and install an operating system on it without having to have a USB stick on you.&#xA;With something like &lt;a href=&#34;https://syslinux.org/&#34;&gt;syslinux&lt;/a&gt; you can even create menus to be able to choose what to install and have a bunch of different options with different settings.&#xA;As computer installations grow larger, it&amp;rsquo;s easy to see how this becomes kind of essential as you can&amp;rsquo;t run around multiple datacenters any time something needs to be re-imaged.&#xA;A counter-point to that could be that servers have remote management features allowing us to load ISOs as if they&amp;rsquo;re DVDs but even then, iPXE has an advantage because you can fully automate the process.&#xA;Also my poor version of servers (read: used office PCs) do not have IPMI.&#xA;At any rate, that&amp;rsquo;s the general idea of PXE.&lt;/p&gt;&#xA;&lt;h3 id=&#34;talos&#34;&gt;Talos&lt;/h3&gt;&#xA;&lt;p&gt;How does that apply to my case then?&#xA;I want to be able to completely wipe all three systems and then effortlessly restore them.&#xA;As I plan to run kubernetes on it, the installation of applications to the cluster is taken care of using &lt;a href=&#34;https://fluxcd.io/&#34;&gt;FluxCD&lt;/a&gt; so I only really need to solve the installation part.&#xA;That&amp;rsquo;s where &lt;a href=&#34;https://www.talos.dev/&#34;&gt;Talos&lt;/a&gt; comes in.&#xA;Talos is an incredibly minimal linux distribution that is designed with the sole purpose of running kubernetes.&#xA;No SSH, no TTY, no nothing.&#xA;Sitting in front of the system only allows you to change kernel boot parameters and the network configuration.&#xA;Everyhing is done using the API which is accessible interactively through the &lt;code&gt;talosctl&lt;/code&gt; CLI utility.&#xA;This means that we can have our operating system and kubernetes configuration as code for the price of one config file.&#xA;Sign me up!&lt;/p&gt;&#xA;&lt;h3 id=&#34;matchbox&#34;&gt;Matchbox&lt;/h3&gt;&#xA;&lt;p&gt;Those are the ingredients but it can hardly be called a meal.&#xA;We need to get some kitchen utensils in this analogy to get the desired result.&#xA;Our PXE setup will need to have a little bit of logic in it so it knows what to install with what configuration.&#xA;See, Talos can be told to fetch a configuration file from an HTTP server using a kernel parameter.&#xA;A conditionally-rendered file would allow us to alter the response depending on who&amp;rsquo;s requesting it.&#xA;This is where &lt;a href=&#34;https://matchbox.psdn.io/&#34;&gt;matchbox&lt;/a&gt; slots in.&#xA;When matchbox gets a request it can see some information about the host requesting it and therefore make a determination about what to reply with.&#xA;We can then serve different options according to which system is asking such as what Talos configuration file to use.&#xA;This way the control-plane kubernetes nodes can receive the Talos &lt;code&gt;controlplane.yaml&lt;/code&gt; while worker nodes get the &lt;code&gt;worker.yaml&lt;/code&gt;.&#xA;So a brand-new host with an empty disk drives would boot up, skip the disks since they don&amp;rsquo;t have an operating system and then try booting using PXE.&#xA;Then the host would get its configuration, install the operating system, install kubernetes and become part of a cluster.&lt;/p&gt;&#xA;&lt;h3 id=&#34;definition-of-done&#34;&gt;Definition of Done&lt;/h3&gt;&#xA;&lt;p&gt;The ideal process when getting adding a host should look like:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;note down the MAC address and corresponding IP somewhere&lt;/li&gt;&#xA;&lt;li&gt;plug in the cables&lt;/li&gt;&#xA;&lt;li&gt;configure the boot device order&lt;/li&gt;&#xA;&lt;li&gt;save settings and exit&lt;/li&gt;&#xA;&lt;li&gt;play minecraft while waiting&lt;/li&gt;&#xA;&lt;li&gt;run one or zero commands&lt;/li&gt;&#xA;&lt;li&gt;host shows up in &lt;code&gt;kubectl get nodes&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;recreating it from scratch should be just as easy&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I don&amp;rsquo;t know if I can get exactly to that point but I&amp;rsquo;m willing to put in some effort into the setup so in the future I can avoid it to a greater extent.&#xA;Some compromise is acceptable since I don&amp;rsquo;t have any IPAM infrastructure in place already so this isn&amp;rsquo;t the full and proper way to go about it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;implementation&#34;&gt;Implementation&lt;/h2&gt;&#xA;&lt;h3 id=&#34;how-do-i-do-x-in-y-minutes&#34;&gt;How do I do X in Y minutes&lt;/h3&gt;&#xA;&lt;p&gt;Meat and potatoes first, for quick reference here is what I did (5-6 hours of suffering omitted for brevity):&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Installed &lt;code&gt;tftp-hpa&lt;/code&gt; on Arch&lt;/li&gt;&#xA;&lt;li&gt;Downloaded &lt;a href=&#34;http://boot.ipxe.org/undionly.kpxe&#34;&gt;undionly.kpxe&lt;/a&gt; and &lt;a href=&#34;http://boot.ipxe.org/ipxe.efi&#34;&gt;ipxe.efi&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Put them in &lt;code&gt;/srv/tftp&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Created &lt;code&gt;matchbox.ipxe&lt;/code&gt; with the following contents:&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#!ipxe&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chain http://10.0.20.50:8080/boot.ipxe&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Installed &lt;code&gt;matchbox&lt;/code&gt; using Docker by running the following command:&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;docker&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;net&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;host&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;matchbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lib&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;matchbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Z&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;etc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;matchbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;etc&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;matchbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Z&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ro&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;quay&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;poseidon&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;matchbox&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;10.0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;address&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;0.0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8080&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;level&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;debug&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Downloaded &lt;a href=&#34;https://github.com/siderolabs/talos/releases/download/v1.9.4/vmlinuz-amd64&#34;&gt;vmlinuz-amd64&lt;/a&gt; and &lt;a href=&#34;https://github.com/siderolabs/talos/releases/download/v1.9.4/initramfs-amd64.xz&#34;&gt;initramfs-amd64.xz&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;Put them in &lt;code&gt;/var/lib/matchbox/assets&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Download &lt;code&gt;talosctl&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Run &lt;code&gt;talosctl gen config homecluster https://10.0.50.69&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Edit &lt;code&gt;controlplane.yaml&lt;/code&gt; until it looks good&lt;/li&gt;&#xA;&lt;li&gt;Put &lt;code&gt;controlplane.yaml&lt;/code&gt; in &lt;code&gt;/var/lib/matchbox/assets&lt;/code&gt; as well&lt;/li&gt;&#xA;&lt;li&gt;Create &lt;code&gt;/var/lib/matchbox/profiles/control-plane.json&lt;/code&gt;:&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;control-plane&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;control-plane&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;boot&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;kernel&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;/assets/vmlinuz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;initrd&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/assets/initramfs.xz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;initrd=initramfs.xz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;init_on_alloc=1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;slab_nomerge&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;pti=on&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;console=tty0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;printk.devkmsg=on&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;talos.platform=metal&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;talos.config=http://10.0.20.50:8080/assets/controlplane.yaml&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;Create &lt;code&gt;/var/lib/matchbox/groups/control-plane.json&lt;/code&gt;:&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;kube01&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;kube01&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;profile&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;control-plane&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nt&#34;&gt;&amp;#34;selector&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;mac&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;18:03:73:2a:d8:a2&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;/li&gt;&#xA;&lt;li&gt;In &lt;a href=&#34;https://opnsense.home.inherently.xyz/services_dhcp.php?if=opt2&#34;&gt;OPNSense (link to my router)&lt;/a&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Under &lt;code&gt;DHCP Static Mappings for this interface.&lt;/code&gt; add the hosts&lt;/li&gt;&#xA;&lt;li&gt;Under &lt;code&gt;TFTP server&lt;/code&gt;:&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Set TFTP hostname: 10.0.20.50&lt;/li&gt;&#xA;&lt;li&gt;Set Bootfile: undionly.kpxe&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Under &lt;code&gt;Network booting&lt;/code&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Set next-server IP: 10.0.20.50&lt;/li&gt;&#xA;&lt;li&gt;Set default bios filename: undionly.kpxe&lt;/li&gt;&#xA;&lt;li&gt;Set iPXE boot filename: matchbox.ipxe&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Boot Optiplex&lt;/li&gt;&#xA;&lt;li&gt;Wait&lt;/li&gt;&#xA;&lt;li&gt;Watch text scroll on screen&lt;/li&gt;&#xA;&lt;li&gt;???&lt;/li&gt;&#xA;&lt;li&gt;No profit, I spent my whole weekend on this&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;explanation&#34;&gt;Explanation&lt;/h3&gt;&#xA;&lt;p&gt;PXE is an under-documented part of the common network services one can set up.&#xA;An amusing yet educational thing I found was a redditor&amp;rsquo;s 3-part descent into madness and consequently enlightenment:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/homelab/comments/1ahhhkh/why_does_pxe_feel_like_a_horribly_documented_mess/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&#34;&gt;part 1&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/homelab/comments/1b1qc05/a_followup_to_my_pxe_rant_standing_up_baremetal/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&#34;&gt;part 2&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.reddit.com/r/homelab/comments/1b3wgvm/uefipxeagents_conclusion_to_my_pxe_rant_with_a/?utm_source=share&amp;amp;utm_medium=web3x&amp;amp;utm_name=web3xcss&amp;amp;utm_term=1&amp;amp;utm_content=share_button&#34;&gt;part 3&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;The matchbox documentation was also very good at explaining both the general process and giving some specific recommendations:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://matchbox.psdn.io/network-booting/&#34;&gt;Network boot environments&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://matchbox.psdn.io/network-setup/&#34;&gt;Network setup&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;With those out of the way I&amp;rsquo;ll make an attemt at explaining it myself.&#xA;When a PXE client starts, it does the DHCP dance which tells it where the TFTP server is and what the name of the file it should execute is.&#xA;That file is a network boot program which can optionally load some configuration (also stored on the TFTP server).&#xA;So after all of that is figured out, the PXE client will pull the kernel and initramfs, again from the TFTP server.&#xA;In contrast, iPXE uses scripts stored on the TFTP server instead of plain configuration files so we can do fancier things with it.&#xA;However, my old desktop PCs do not have iPXE so I had to use an in-between thingy, undionly.kpxe.&#xA;What that does is load iPXE firmware (ipxe.efi) so we can access the cool new features without having to replace any hardware.&#xA;When that loads, it talks to the DHCP server as an iPXE client this time and gets told to grab the matchbox.ipxe file from the TFTP server.&#xA;That file is an iPXE script which tells the client to check the matchbox server.&#xA;When matchbox gets the request, it checks the groups it has registered and if there are any matches according to the &lt;code&gt;selector&lt;/code&gt; field, it uses the corresponding profile.&#xA;In this case, the profile is for control-plane Talos Linux nodes.&#xA;The kernel and initramfs listed in the profile are used alongside some specific kernel parameters.&#xA;The most important parameter is &lt;code&gt;talos.config=http://10.0.20.50:8080/assets/controlplane.yaml&lt;/code&gt; which tells the machine that is booting the operating system to fetch the configuration file listed there.&#xA;Of course, you will need to have generated the configuration (using &lt;code&gt;talosctl gen config homecluster https://10.0.50.69:6443&lt;/code&gt;) and moved it in the matchbox &lt;code&gt;assets&lt;/code&gt; directory (or in another HTTP server, matchbox is just convenient in this setup).&#xA;That configuration has some basic things like which disk and network settings to use.&#xA;When the machine gets this configuration, it installs Talos and then waits.&#xA;At this point the system is booted normally, no PXE involved.&lt;/p&gt;&#xA;&lt;p&gt;Following that, all we need to do is run &lt;code&gt;talosctl bootstrap --nodes 10.0.50.71 --endpoints 10.0.50.71&lt;/code&gt; and we get a kubernetes cluster.&#xA;To get the kubeconfig required to access the cluster, run &lt;code&gt;talosctl kubeconfig my-talos-kubeconfig --nodes 10.0.50.71 --endpoints 10.0.50.71&lt;/code&gt; and then check that it works by running &lt;code&gt;kubectl --kubeconfig my-talos-kubeconfig get nodes&lt;/code&gt;.&#xA;I&amp;rsquo;ve tested the whole process end-to-end twice now to ensure that nodes with blank disks and correct boot order will behave correctly and it&amp;rsquo;s almost magic.&#xA;True enough, after pressing the power button on all three systems, making some coffee, and then running the commands mentioned previously, I got this output:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ kubectl get nodes -o wide&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME     STATUS   ROLES           AGE     VERSION   INTERNAL-IP   EXTERNAL-IP   OS-IMAGE         KERNEL-VERSION   CONTAINER-RUNTIME&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kube01   Ready    control-plane   3h20m   v1.32.2   10.0.50.71    &amp;lt;none&amp;gt;        Talos (v1.9.4)   6.12.13-talos    containerd://2.0.2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kube02   Ready    control-plane   3h20m   v1.32.2   10.0.50.72    &amp;lt;none&amp;gt;        Talos (v1.9.4)   6.12.13-talos    containerd://2.0.2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kube03   Ready    control-plane   3h20m   v1.32.2   10.0.50.73    &amp;lt;none&amp;gt;        Talos (v1.9.4)   6.12.13-talos    containerd://2.0.2&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;And I guess that&amp;rsquo;s it.&#xA;It needed some effort and research and the approach should be adjusted according to the network situation (the matchbox docs saved the day here).&#xA;In the end though, I really like what I got working and it was a fun way to spend the weekend.&#xA;I can go from basically brand new computer with nothing on it to full cluster with a high availability control-plane using patience and a single command.&#xA;Two commands and I can install fluxcd on the cluster which will install all my applications.&#xA;Looking back at the definition of done I set in the beginning, I consider this a success.&lt;/p&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;As the proud owner of a Talos Linux kubernetes cluster installed in a fully automated way, I am quite happy.&#xA;I can get back into running services at home and live through the pain of using kubernetes daily again.&#xA;I have a couple of ideas in mind for how to use my new container running platform but that&amp;rsquo;s for another post.&#xA;Hopefully you got a better idea of what PXE is, how it works and how I used it in this instance.&#xA;If you weren&amp;rsquo;t familiar with any of this, maybe it&amp;rsquo;s time to get your hands dirty and prepare to throw away your USB drives.&#xA;Either way, that&amp;rsquo;s all for now.&lt;/p&gt;&#xA;</description>
			</item>
	</channel>
</rss>
