{"id":3099,"date":"2022-01-27T18:52:38","date_gmt":"2022-01-27T06:52:38","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=3099"},"modified":"2022-01-28T10:36:32","modified_gmt":"2022-01-27T22:36:32","slug":"kubernetes-home-vagrant-nodes","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/3099\/","title":{"rendered":"Kubernetes @ Home: Vagrant Nodes"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">8<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>\n<p>The first significant practical step in establishing my Bare Metal Kubernetes cluster was to provision 4 VM&#8217;s.  At this point it is worth mentioning that actually installing Kubernetes is almost trivial once you have the necessary hardware in place.  Since my &#8216;hardware&#8217; was going to be virtual, this meant that provisioning the VM&#8217;s was by far the biggest job so after an initial manual install, so I set about automating as much of this process as I could.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-task\">The Task<\/h2>\n\n\n\n<p>Having settled on 4 VM&#8217;s to provide my 4 nodes, I had 4 VM&#8217;s to be configured and 4 installations of Ubuntu Server 20.04 to be performed.<\/p>\n\n\n\n<p>I had already previously established a working Kubernetes cluster by manually creating and configuring each VM and installing Ubuntu Server on them all.  Although not complicated, this was tedious and I foresaw much frustration if\/when I ever needed to rebuild the cluster so looked for something to automate this repetitive and fiddly business.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-vagrant-mis-step\">The &#8216;Vagrant&#8217; Mis-Step<\/h2>\n\n\n\n<p><a href=\"https:\/\/www.vagrantup.com\/\" data-type=\"URL\" data-id=\"https:\/\/www.vagrantup.com\/\">Vagrant<\/a> appeared to offer a perfect solution.<\/p>\n\n\n\n<p>Though not related to Kubernetes, <strong>Vagrant<\/strong> employs a similar approach, using a declarative mechanism rather than imperative.  That is, <strong>Vagrant<\/strong> takes a description of a VM (or VM&#8217;s) and compares it to the current &#8220;real world&#8221;, making whatever changes are required to bring the real world into line with the declared desired state.<\/p>\n\n\n\n<p><strong>Vagrant<\/strong> supports a number of virtual machine platforms with <strong>VirtualBox<\/strong> being the default.  Crucially, it offered support for <strong>Hyper-V<\/strong>.<\/p>\n\n\n\n<p>It initially appeared that all I needed was a <code>VagrantFile<\/code> describing the 4 VM&#8217;s for my nodes, something similar to:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-ruby\">Vagrant.configure(&quot;2&quot;) do |config|\n  # This is a multi-machine VagrantFile.\n  # These settings are applied to all VM&#039;s\n  config.vm.box = &quot;deltics\/focal64&quot;\n\n  config.vm.network &quot;public_network&quot;\n\n  config.vm.provider &quot;hyperv&quot; do |vm|\n    vm.cpus = 4\n    vm.memory = &quot;8192&quot;\n    vm.vlan_id = 2\n  end\n\n  # The remaining settings are applied individually\n  # to each separate machine that is defined\n\n  config.vm.define &quot;master&quot; do |node|\n    node.hostname = &quot;master&quot;\n    \n    node.vm.provider &quot;hyperv&quot; do |vm|\n      vm.vmname = &quot;k8s.master&quot;\n      vm.mac = &quot;ffffffffff00&quot;\n    end\n  end \n  \n  config.vm.define &quot;worker1&quot; do |node|\n    node.hostname = &quot;worker1&quot;\n    \n    node.vm.provider &quot;hyperv&quot; do |vm|\n      vm.vmname = &quot;k8s.worker1&quot;\n      vm.mac = &quot;ffffffffff01&quot;\n    end\n  end \n  \n  config.vm.define &quot;worker2&quot; do |node|\n    node.hostname = &quot;worker2&quot;\n    \n    node.vm.provider &quot;hyperv&quot; do |vm|\n      vm.vmname = &quot;k8s.worker2&quot;\n      vm.mac = &quot;ffffffffff02&quot;\n    end\n  end \n  \n  config.vm.define &quot;worker3&quot; do |node|\n    node.hostname = &quot;worker3&quot;\n    \n    node.vm.provider &quot;hyperv&quot; do |vm|\n      vm.vmname = &quot;k8s.worker3&quot;\n      vm.mac = &quot;ffffffffff03&quot;\n    end\n  end \nend<\/code><\/pre>\n\n\n\n<p>A <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> is specified in a project (folder).  It may describe a single VM or a number of them.  In the context of that project (i.e. folder), when the command <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vagrant up<\/mark> is performed, <strong>Vagrant<\/strong> examines the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> and compares it against the state of the virtual machines currently established in that project, the VM&#8217;s themselves being created in a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">.vagrantd<\/mark> subfolder.<\/p>\n\n\n\n<p>The first time the command is run, for example, there are no actual VM&#8217;s that exist at all, so <strong>Vagrant<\/strong> will apply the configuration described in the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> and create the specified VM&#8217;s in that <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">.vagrantd<\/mark> folder.  If changes are made to the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark>, those changes are applied to any existing VM&#8217;s the next time <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">vagrant up<\/mark> is performed.<\/p>\n\n\n\n<p>The &#8220;2&#8221; in the initial <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">configure<\/mark> statement indicates the desired Vagrant API Version and is nothing to do with the number of VM&#8217;s defined by the file.<\/p>\n\n\n\n<p class=\"has-luminous-vivid-amber-background-color has-background\">A quick note on <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> syntax.  Although it <em>looks<\/em> like a declarative configuration file such as <strong>yaml<\/strong> or <strong>json<\/strong>, it is in fact a Ruby program; the <strong>Vagrant<\/strong> Api is specifically designed to make it <em>appear<\/em> as declarative as possible.<\/p>\n\n\n\n<p>Almost everything needed for my VM&#8217;s could be specified in a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark>, as illustrated above.<\/p>\n\n\n\n<p><em><strong>Almost<\/strong><\/em> everything.<\/p>\n\n\n\n<p>As illustrated above, my project required a &#8220;<a href=\"https:\/\/www.vagrantup.com\/docs\/multi-machine\" data-type=\"URL\" data-id=\"https:\/\/www.vagrantup.com\/docs\/multi-machine\">Multi-Machine<\/a>&#8221; file, with basic configuration that applied to all machines and further configuration specific to each individual machine (which in turn identifies those machines as needing to be created).  In addition, whilst many properties of a VM are configurable through generic <strong>Vagrant<\/strong> properties, some are specific to the particular provider being used, in my case <strong>Hyper-V<\/strong>.   <a href=\"https:\/\/www.vagrantup.com\/docs\/providers\/hyperv\/configuration\" data-type=\"URL\" data-id=\"https:\/\/www.vagrantup.com\/docs\/providers\/hyperv\/configuration\">Provider-specific properties<\/a> are accessible using the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">&#8230;vm.provider &#8220;hyperv&#8221; do |vm|<\/mark> configuration blocks.<\/p>\n\n\n\n<p>Properties common to all VM&#8217;s in the project are specified at the &#8220;top level&#8221;.  VM-specific settings are then provided within a nested configuration block that <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">define<\/mark>s each VM.  For example, this block defines and configures the VM for the <strong>master<\/strong> node, including the hostname supported by the general <strong>Vagrant Api<\/strong> and the <strong>Hyper-V provider-specific<\/strong> configuration for the name of the VM (as identified in <strong>Hyper-V<\/strong> itself) and MAC address:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-ruby\">  config.vm.define &quot;master&quot; do |node|\n    node.hostname = &quot;master&quot;\n    \n    node.vm.provider &quot;hyperv&quot; do |vm|\n      vm.vmname = &quot;k8s.master&quot;\n      vm.mac = &quot;ffffffffff00&quot;\n    end\n  end <\/code><\/pre>\n\n\n\n<p>In my case, <strong>Hyper-V<\/strong> provider-specific properties are required both in the common section and in each VM-specific section.<\/p>\n\n\n\n<p>We can see that the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> specifies the same amount of RAM for each VM as well as the CPU count and VLAN ID since these are consistent across all VM&#8217;s:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-ruby\">  config.vm.network &quot;public_network&quot;\n\n  config.vm.provider &quot;hyperv&quot; do |vm|\n    vm.cpus = 4\n    vm.memory = &quot;8192&quot;\n    vm.vlan_id = 2\n  end<\/code><\/pre>\n\n\n\n<p>The network specification here seems to be more for Vagrant&#8217;s purposes than for configuring the VM&#8217;s themselves as it has no bearing on or relation to the <strong>Network Switch<\/strong> settings of the VM&#8217;s that I can determine.<\/p>\n\n\n\n<p>Then, as we&#8217;ve seen, a number of VM&#8217;s are <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">define<\/mark>d with configuration specific to each, including:<\/p>\n\n\n\n<ul><li>The VM name (as identified in HyperV)<\/li><li>The Hostname (by which the VM is known on the network)<\/li><li>The MAC address<\/li><\/ul>\n\n\n\n<p>The MAC addresses in this file are not accurate but illustrate the use of a consecutive range.<\/p>\n\n\n\n<p>Some key things are missing from this specification:<\/p>\n\n\n\n<ul><li>Secure Boot configuration (i.e. disabled)<\/li><li><em><strong>Any<\/strong><\/em> form of HDD specification<\/li><li>The network switch to use (&#8220;Kubernetes Switch&#8221;)<\/li><\/ul>\n\n\n\n<p>The first two of these are actually provided by the &#8220;<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">box<\/mark>&#8221; declaration at the very top of the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-ruby\">  # This is a multi-machine VagrantFile.\n  # These settings are applied to all VM&#039;s\n  config.vm.box = &quot;deltics\/focal64&quot;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"what-s-in-a-vagrant-box\">What&#8217;s In A (Vagrant) Box?<\/h2>\n\n\n\n<p>A &#8220;<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">box<\/mark>&#8221; is a pre-prepared image of a virtual machine that serves as a &#8220;template&#8221; for a VM specified in a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark>.  In a multi-machine <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> each VM could be based on a different <strong>box<\/strong>.  In my case, the VM&#8217;s all use the same <strong>box<\/strong>, hence this is specified in the <em>global<\/em> section of the file and identifies a custom <strong>box<\/strong> that I created.<\/p>\n\n\n\n<p>This highlights the first, relatively minor, problem with <strong>Vagrant<\/strong>.<\/p>\n\n\n\n<p>To use <strong>Vagrant<\/strong> to provision my nodes, I had to go through the process of configuring and installing the OS on a VM which would then provide the template for my <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark> specified machines.  This includes specifying a HDD (on which to install the OS).<\/p>\n\n\n\n<p>i.e. the HDD of a VM provisioned using <strong>Vagrant<\/strong> is determined by the <strong>box<\/strong> used (though <em>additional<\/em> drives can be added, using an experimental feature).  The same applies to BIOS\/Firmware configuration and additional devices such as virtual DVD drive etc.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"here-be-dragons\">Here Be Dragons&#8230;<\/h2>\n\n\n\n<p>I decided I needed to prepare a <strong>box<\/strong>, on which point the Vagrant documentation is not particularly clear.  It all makes sense once you figure out how things are supposed to be organised, but IMHO it is not very clearly described.<\/p>\n\n\n\n<p>For those planning to experiment with <strong>Hyper-V<\/strong> box creation, this is the process:<\/p>\n\n\n\n<ol><li>Configure and prepare your VM (see below)<\/li><li>Export your <strong>Hyper-V<\/strong> VM.  I recommend ensuring that your exported VM has no checkpoints, so that the <strong>Snapshots<\/strong> folder created during export will be empty and can simply be removed as it won&#8217;t be required.<\/li><li>Create a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">metadata.json<\/mark> file in the folder containing the exported VM.  At a minimum this metadata file needs to include a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">provider<\/mark> property, set to <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-green-cyan-color\">hyperv<\/mark> (for a <strong>Hyper-V<\/strong> VM)<\/li><li>Create a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-orange-color\">tar<\/mark> archive of the folder, giving the archive a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">.box<\/mark> extension.  Compression is a good idea if you intend to publish the box to a catalogue, but otherwise is unnecessarily time consuming if you only intend using it &#8216;locally&#8217;, making sure to include only contents of the folder with the metadata file, and not the folder itself<\/li><\/ol>\n\n\n\n<p>So you should end up with a folder (and an archive) that contains two folders and your metadata file:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?ssl=1\"><img decoding=\"async\" loading=\"lazy\" width=\"640\" height=\"85\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?resize=640%2C85&#038;ssl=1\" alt=\"\" class=\"wp-image-3123\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?resize=1024%2C136&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?resize=300%2C40&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?resize=768%2C102&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?resize=380%2C50&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?w=1400&amp;ssl=1 1400w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/A-valid-box-folder.png?w=1280&amp;ssl=1 1280w\" sizes=\"(max-width: 640px) 100vw, 640px\" data-recalc-dims=\"1\" \/><\/a><\/figure>\n\n\n\n<p>Note that the pluralised names on these folders (created by the <strong>Export<\/strong> process) are not significant.  In the case of a VM with a single HDD, there is only <strong>one<\/strong> virtual machine and only <strong>one<\/strong> virtual hard disk in those folders.<\/p>\n\n\n\n<p>Once packaged, your custom box is made available for (local) use by adding it to the local registry of boxes:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">vagrant box add --name my-box \/path\/to\/the\/new.box --provider hyperv<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"stand-on-the-shoulders-of-giants-others\">Stand On The Shoulders of <s>Giants<\/s> Others<\/h2>\n\n\n\n<p>Preparing a custom box is considered &#8220;advanced&#8221; use of Vagrant, with the recommendation being to use <a href=\"https:\/\/app.vagrantup.com\/boxes\/search\" data-type=\"URL\" data-id=\"https:\/\/app.vagrantup.com\/boxes\/search\">a pre-prepared box from the <strong>Vagrant<\/strong> community<\/a> where possible.<\/p>\n\n\n\n<p>This is great advice, except that the catalogue of such boxes contains a <strong><em>lot<\/em><\/strong> of boxes with little to no documentation explaining what each box is, contains or is good for, beyond identifying the OS and the providers that the box supports.<\/p>\n\n\n\n<p>Since a <strong>box<\/strong> is a template VM, the VM image format in a box also determines which provider it may be used with.  Though a <strong>box<\/strong> may contain templates for <em>multiple<\/em> providers most boxes in the public catalogues only seem to support the (default) <strong>VirtualBox<\/strong> provider; very few support <strong>Hyper-V<\/strong>.  In particular, there was no <em>official<\/em> Ubuntu 20.04 (aka &#8220;focal&#8221;) box for <strong>Hyper-V<\/strong>.<\/p>\n\n\n\n<p>Unable to vouch for the content of public boxes or be certain of how the templated VM they contained were configured, I opted to create my own box.<\/p>\n\n\n\n<p>Apart from anything else, this presented another learning opportunity!  \\o\/<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"preparing-a-vm-to-be-boxed\">Preparing a VM to be Boxed<\/h2>\n\n\n\n<p>To enable <strong>Vagrant<\/strong> to work its magic, the OS in <a href=\"https:\/\/www.vagrantup.com\/docs\/boxes\/base\" data-type=\"URL\" data-id=\"https:\/\/www.vagrantup.com\/docs\/boxes\/base\">the template VM has to be prepared in a <em>very<\/em> precise manner<\/a>.<\/p>\n\n\n\n<p>Briefly:<\/p>\n\n\n\n<p>First, a specific user account must be configured with a prescribed password and provided with password-less <strong>sudo<\/strong> (in the case of Linux VMs).<\/p>\n\n\n\n<p>Secondly, additional networking components are required to be installed to enable <strong>Vagrant<\/strong> to inspect the internals of the machine and to determine that the network stack in the VM has been provisioned correctly.  Again, the documentation on this point is incomplete and inaccurate when it comes to Ubuntu 20.04 and it took me some time trawling through duckduckgo search results to figure out the solution to that!<\/p>\n\n\n\n<p class=\"has-luminous-vivid-amber-background-color has-background\">The solution I eventually found was in <a href=\"https:\/\/stackoverflow.com\/a\/67481445\/123487\" data-type=\"URL\" data-id=\"https:\/\/stackoverflow.com\/a\/67481445\/123487\">this answer on Stack Overflow<\/a>.  I followed the answer entirely, though a commenter had suggested that only installing the additional packages (<code>linux-virtual<\/code>, <code>linux-cloud-tools-virtual<\/code> and <code>linux-tools-virtual<\/code>) was required.<\/p>\n\n\n\n<p>There are additional\/alternate considerations when preparing boxes containing VM&#8217;s with an OS other than Linux (or different flavours of Linux).<\/p>\n\n\n\n<p>Simply put, preparing a VM box is more complicated than simply installing the OS you want to use in a configured VM template.<\/p>\n\n\n\n<p>And every time a problem with provisioning a VM is determined to be due to an issue with the &#8220;box&#8221;, the template VM has to be reconfigured or fixed and the box re-exported and re-packaged.  This is not necessarily difficult but was both time-consuming and frustrating.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"good-not-great\">Good, Not Great<\/h2>\n\n\n\n<p>Even when everything was working, <strong>Vagrant<\/strong> still did not present a fully automated solution.<\/p>\n\n\n\n<p>Particularly annoying was the inability to specify the desired network switch in the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-purple-color\">VagrantFile<\/mark>, with <strong>Vagrant<\/strong> instead <em>interactively prompting<\/em> for a switch to be selected as <em>each<\/em> VM was created.<\/p>\n\n\n\n<p>The VM creation process would also prompt &#8211; again, for <em>each<\/em> VM &#8211; for host OS credentials to mount the project folder into each guest VM.  Since I didn&#8217;t need this, I could perhaps have disabled this behaviour, but I didn&#8217;t research that as I had to give up on <strong>Vagrant<\/strong> entirely for a different reason. <\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-vagrant-deal-breaker\">The Vagrant Deal-Breaker<\/h2>\n\n\n\n<p>After a lot of trouble to get Vagrant &#8220;working&#8221; I then discovered that my preferred VLAN configuration was going to cause a problem.<\/p>\n\n\n\n<p>With a couple of test VM&#8217;s and the host OS on the same VLAN, everything worked well.  <strong>Vagrant<\/strong> would create and configure my VM&#8217;s (after I answered the prompts) and report once they were operating correctly.<\/p>\n\n\n\n<p>But this does <strong>not<\/strong> appear to work when a VM is on a different VLAN than the host OS, as was the case with my actual Kubernetes node VMs!  I simply could not get Vagrant to acknowledge (and therefore fully configure) the VM&#8217;s when configured on a separate VLAN.<\/p>\n\n\n\n<p>The VLAN was determined to be the cause by moving the host system onto the same VLAN as the VM&#8217;s, at which point <strong>Vagrant<\/strong> was once again happy.<\/p>\n\n\n\n<p>I don&#8217;t understand why this is the case, since the Unifi Security Gateway is configured to allow routing of traffic between VLAN&#8217;s and I don&#8217;t otherwise have any problem with machines communicating across VLANs.  In particular, with my initial manual install of Kubernetes with the same VLAN separation, there was no issue with the nodes, Kubernetes networking or my ability to communicate with them or the host.<\/p>\n\n\n\n<p>This left me with three issues:<\/p>\n\n\n\n<ol><li>Being aware that networking is one of the more complicated aspects of Kubernetes, I was concerned that this issue might be symptomatic of a bigger networking problem-berg lurking with a <strong>Vagrant<\/strong>-based approach<\/li><li>Despite all the work involved in preparing a box, <strong>Vagrant<\/strong> was unable to <em>completely<\/em> configure my VM&#8217;s, at least not fully automatically.<\/li><li>The degree of automation that <em>was<\/em> provided by <strong>Vagrant<\/strong> was significantly offset by the amount of up-front work required to prepare a box, not to mention the &#8220;fussiness&#8221; of that work<\/li><\/ol>\n\n\n\n<p>So I decided to explore an alternative automation solution.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"the-alternative-powershell\">The Alternative: PowerShell<\/h2>\n\n\n\n<p>The alternative I switched to was simple PowerShell scripting, which I&#8217;ll cover in the next post, along with the actual creation of the Kubernetes cluster.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\">8<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span> The first significant practical step in establishing my Bare Metal Kubernetes cluster was to provision 4 VM&#8217;s. At this point it is worth mentioning that actually installing Kubernetes is almost trivial once you have the necessary hardware in place. Since my &#8216;hardware&#8217; was going to be virtual, this meant that provisioning the VM&#8217;s was by [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":3111,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"The next post in the Kubernetes @ Home series, describing my attempt to automate the provisioning of the VM's for my cluster using Vagrant, and why I ultimately abandoned that idea.","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":[]},"categories":[324,4,321],"tags":[356,352,355],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/kubernetes-banner.png?fit=1171%2C416&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-NZ","jetpack_sharing_enabled":true,"jetpack-related-posts":[{"id":3148,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/3148\/","url_meta":{"origin":3099,"position":0},"title":"Kubernetes @ Home: PowerShell VM&#8217;s","date":"01 Feb 2022","format":false,"excerpt":"Following the Vagrant experiment (reminding me of a Bill Bailey metaphor... \"a long walk down a windy beach to a cafe that was closed\") I next set about automating my VM creation using PowerShell, with greater success. Though still not perfect, the final gap to full automation is something I\u2026","rel":"","context":"In &quot;automation&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/kubernetes-banner.png?fit=1171%2C416&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":3076,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/3076\/","url_meta":{"origin":3099,"position":1},"title":"A Kubernetes Cluster @ Home","date":"26 Jan 2022","format":false,"excerpt":"I set myself a new challenge for the New Year: Stand Up a Kubernetes cluster of my own. At home. I have reasons (long term costs being [potentially] lower than cloud-hosted alternatives being just one of them) but honestly since Kubernetes is a dominant presence in my day-to-day work these\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/kubernetes-banner.png?fit=1171%2C416&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":3291,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/3291\/","url_meta":{"origin":3099,"position":2},"title":"Kubernetes @ Home: Load Balancer","date":"11 Feb 2022","format":false,"excerpt":"In the previous post we installed the Kubernetes Dashboard and saw how we could access the dashboard service which itself runs in the Kubernetes cluster. We also saw how clunky that was and I promised a better way, which we turn to now. Kubernetes Services and IP Addresses To this\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/kubernetes-banner.png?fit=1171%2C416&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":3233,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/3233\/","url_meta":{"origin":3099,"position":3},"title":"Kubernetes @ Home: Dashboard","date":"07 Feb 2022","format":false,"excerpt":"At the end of the previous post in this series, we reached the point where I had my Kubernetes cluster up and running, including a Dashboard service. As I mentioned, this Dashboard is not part of a default installation. Taking a look at how I got this up and running\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/kubernetes-banner.png?fit=1171%2C416&ssl=1&resize=350%2C200","width":350,"height":200},"classes":[]},{"id":1757,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1757\/","url_meta":{"origin":3099,"position":4},"title":"Parallels 9 and VM&#8217;s on External Drives","date":"25 Sep 2013","format":false,"excerpt":"Not a Delphi or even Pascal related post on this occasion, but an experience that may interest any developer running Windows in a VM on a Mac. I have been using Parallels desktop virtualisation solution to run Windows on my iMac since the day I got it (or I should\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":1766,"url":"https:\/\/www.deltics.co.nz\/blog\/posts\/1766\/","url_meta":{"origin":3099,"position":5},"title":"VM&#8217;s on External Drives &#8211; Update Redux","date":"28 Sep 2013","format":false,"excerpt":"My previous post declaring a successful resolution to the problems I was experiencing with Parallels 9 VM's stored on an external USB HDD proved premature. The apparent success of being able to start \/ suspend \/ resume \/ shutdown \/ restart etc, something that had previously been impossible, was sadly\u2026","rel":"","context":"In &quot;Delphi&quot;","img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/3099"}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=3099"}],"version-history":[{"count":8,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/3099\/revisions"}],"predecessor-version":[{"id":3137,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/3099\/revisions\/3137"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/3111"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=3099"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=3099"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=3099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}