<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TinyComputers.io (Posts about cluster computing)</title><link>https://tinycomputers.io/</link><description></description><atom:link href="https://tinycomputers.io/categories/cluster-computing.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Original site content © 2022–2026 Tiny Machines Workshop, LLC, except where otherwise noted. Some rights reserved.</copyright><lastBuildDate>Sat, 26 Sep 2026 18:52:25 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Raspberry Pi Kubernetes Cluster</title><link>https://tinycomputers.io/posts/raspberry-pi-kubernetes-cluster.html?utm_source=feed&amp;utm_medium=rss&amp;utm_campaign=rss</link><dc:creator>A.C. Jokela</dc:creator><description>&lt;div class="audio-widget"&gt;
&lt;div class="audio-widget-header"&gt;
&lt;span class="audio-widget-icon"&gt;🎧&lt;/span&gt;
&lt;span class="audio-widget-label"&gt;Listen to this article&lt;/span&gt;
&lt;/div&gt;
&lt;audio controls preload="metadata"&gt;
&lt;source src="https://tinycomputers.io/raspberry-pi-kubernetes-cluster_tts.mp3" type="audio/mpeg"&gt;
&lt;/source&gt;&lt;/audio&gt;
&lt;div class="audio-widget-footer"&gt;8 min · AI-generated narration&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src="https://tinycomputers.io/images/rpi-cluster-nodes-IMG_0779.jpg.webp" loading="lazy"&gt;&lt;/p&gt;
&lt;p&gt;So, you find your with about nineteen Raspberry Pi 4b single board computers, and you want to run &lt;a href="https://go.tinymachines.io/hzcDAR"&gt;Kubernetes&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Over the course of 2022, I slowly assembled the requisite number of Raspberry Pis, despite the fact that all things Raspberry Pi were in short supply.  Basically, I used technology to pay attention to sites selling Pis.  It was as simple as that.  No automatic buying or the like; I would get a text message and then I would have to act quickly.&lt;/p&gt;
&lt;p&gt;Why nineteen when there are clearly only eighteen in the above photo?  There needs to be a control node (call it &lt;code&gt;master&lt;/code&gt; or &lt;code&gt;controlplane&lt;/code&gt;).  This is the node that orchestrates the building of the cluster.&lt;/p&gt;
&lt;p&gt;Now that you have all of your nodes assembled and in a very &lt;a href="https://go.tinymachines.io/PWtaCa"&gt;nice 2U rack mount assembly&lt;/a&gt;, it is time to provision things.&lt;/p&gt;
&lt;p&gt;We will be using &lt;a href="https://go.tinymachines.io/bYg3kQ"&gt;Ansible&lt;/a&gt; for provisioning and it will handle around 95% of the work.  The other 5% is manual setup.  The manual task is getting a public ssh key onto all of the nodes.  If I had been smart, I would have added this into the imaging process with &lt;a href="https://go.tinymachines.io/yuZs7y"&gt;Imager&lt;/a&gt;, but I did not.  When imaging, if you are not setting initial ssh key within Imager, make sure to set the password on all nodes the same.  Ideally, you would want to set the ssh key during imaging; doing so, will take out a small portion of the needed manually tasks.&lt;/p&gt;
&lt;h4&gt;Pre-game Setup&lt;/h4&gt;
&lt;p&gt;We will be executing from the &lt;code&gt;controlplane&lt;/code&gt; or &lt;code&gt;master&lt;/code&gt; node. Before we get into that, let's establish our base parameters and assumptions.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All nodes, including &lt;code&gt;master&lt;/code&gt; will be running Raspberry Pi OS 64bit&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;master&lt;/code&gt; node will be named &lt;code&gt;rpi-cluster-master&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Each worker node will be named &lt;code&gt;rpi-cluster-[1-18]&lt;/code&gt;; e.g. &lt;code&gt;rpi-cluster-1&lt;/code&gt; and so one&lt;/li&gt;
&lt;li&gt;Each node, &lt;code&gt;master&lt;/code&gt; and &lt;code&gt;workers&lt;/code&gt; will have IP addresses ranging from &lt;code&gt;10.1.1.100&lt;/code&gt; to &lt;code&gt;10.1.1.18&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;You are using &lt;em&gt;ethernet&lt;/em&gt; and &lt;strong&gt;not&lt;/strong&gt; &lt;em&gt;wifi&lt;/em&gt;.  &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;This is important because the &lt;a href="https://go.tinymachines.io/cQGG8f"&gt;Ansible playbooks&lt;/a&gt; that we are going to use assume there is &lt;code&gt;eth0&lt;/code&gt; and not &lt;code&gt;wlan0&lt;/code&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;If you are wanting to insert the ssh key during imaging, run the following command, and then copy the contents of &lt;code&gt;.ssh/id_rsa.pub&lt;/code&gt; from the &lt;code&gt;master&lt;/code&gt;node to the Advanced section of the setup in &lt;code&gt;Imager&lt;/code&gt; where it says ""&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, let's distribute our public ssh key.  As the user &lt;code&gt;pi&lt;/code&gt; on &lt;code&gt;rpi-cluster-master&lt;/code&gt;, run the following:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;ssh-keygen
&lt;/pre&gt;&lt;/div&gt;

&lt;h6&gt;If needing to transfer the public key manually, make the following script (saved as 'dist-key.sh') on &lt;code&gt;master&lt;/code&gt;&lt;/h6&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="ch"&gt;#!/bin/bash&lt;/span&gt;

ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.101
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.102
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.103
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.104
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.105
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.106
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.107
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.108
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.109
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.110
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.111
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.112
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.113
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.114
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.115
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.116
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.117
ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.1.1.118
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Execute!&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;dist-key.sh
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Assuming you set the default password for the &lt;code&gt;pi&lt;/code&gt; user when using &lt;code&gt;Imager&lt;/code&gt;, you will be prompted eighteen times to accept the connection and then the enter in your password.&lt;/p&gt;
&lt;h6&gt;If you are smart and, unlike me, you put your id_rsa.pub key into &lt;code&gt;Imager&lt;/code&gt;, it should look like:&lt;/h6&gt;
&lt;p&gt;&lt;img alt="" src="https://tinycomputers.io/images/rpi-imager-advanced-setup.png.webp"&gt;&lt;/p&gt;
&lt;p&gt;And then you will not have to dink-around with transferring your key, individually, to each node.&lt;/p&gt;
&lt;p&gt;Now, let's &lt;a href="https://go.tinymachines.io/9hZV9f"&gt;install &lt;code&gt;ansible&lt;/code&gt;&lt;/a&gt;on our &lt;code&gt;master&lt;/code&gt; node; we will be following &lt;a href="https://go.tinymachines.io/9hZV9f"&gt;this&lt;/a&gt;.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;update
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;ansible&lt;span class="w"&gt; &lt;/span&gt;sshpass
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deb http://ppa.launchpad.net/ansible/ansible/ubuntu trusty main"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
-a&lt;span class="w"&gt; &lt;/span&gt;/etc/apt/sources.list
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;dirmngr&lt;span class="w"&gt; &lt;/span&gt;-y
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-key&lt;span class="w"&gt; &lt;/span&gt;adv&lt;span class="w"&gt; &lt;/span&gt;--keyserver&lt;span class="w"&gt; &lt;/span&gt;keyserver.ubuntu.com&lt;span class="w"&gt; &lt;/span&gt;--recv-keys&lt;span class="w"&gt; &lt;/span&gt;93C4A3FD7BB9C367
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;update
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;ansible
pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;ansible&lt;span class="w"&gt; &lt;/span&gt;--version
ansible&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.10.8
&lt;span class="w"&gt;  &lt;/span&gt;config&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;None
&lt;span class="w"&gt;  &lt;/span&gt;configured&lt;span class="w"&gt; &lt;/span&gt;module&lt;span class="w"&gt; &lt;/span&gt;search&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'/home/pi/.ansible/plugins/modules'&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'/usr/share/ansible/plugins/modules'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;ansible&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;module&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/lib/python3/dist-packages/ansible
&lt;span class="w"&gt;  &lt;/span&gt;executable&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/usr/bin/ansible
&lt;span class="w"&gt;  &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.9.2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;default,&lt;span class="w"&gt; &lt;/span&gt;Feb&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;28&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2021&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;:03:44&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;GCC&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;.2.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20210110&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you have made it to this point, you should have eighteen nodes with the &lt;code&gt;master&lt;/code&gt; node's public ssh key install.  You should also have &lt;code&gt;ansible&lt;/code&gt; installed.&lt;/p&gt;
&lt;h4&gt;Let's get Ansible'ing&lt;/h4&gt;
&lt;p&gt;Now, we will be following the steps outlined in &lt;a href="https://go.tinymachines.io/cQGG8f"&gt;this&lt;/a&gt; git repo.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;https://github.com/ajokela/rpi-k8s-ansible.git
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Change directory into &lt;code&gt;rpi-k8s-ansible&lt;/code&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;pi@rpi-cluster-master:~&lt;span class="w"&gt; &lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;rpi-k8s-ansible
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, if you want to customize your list of nodes, this is the time.  Edit &lt;code&gt;cluster.yml&lt;/code&gt;; if you only have sixteen nodes, comment out the two you do not have; there are a couple spots where each node is mentioned.&lt;/p&gt;
&lt;p&gt;On to provisioning!  These steps are fairly intelligent at being atomic and repeatable without causing issues.  In provisioning the cluster in the picture (above), some of the steps had to be repeated because of lost ssh connections and other mysterious errors.  Let's first see if we have our basic configuration in working order.  &lt;strong&gt;The following assumes you are in the directory &lt;code&gt;~/rpi-k8s-ansible&lt;/code&gt; on your &lt;code&gt;master&lt;/code&gt; node.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;ansible&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;cluster.yml&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;ping
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will execute a simple &lt;code&gt;ping&lt;/code&gt;/&lt;code&gt;pong&lt;/code&gt; between your &lt;code&gt;master&lt;/code&gt; node and the &lt;code&gt;worker&lt;/code&gt; nodes.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="err"&gt;rpi&lt;/span&gt;&lt;span class="mi"&gt;-&lt;/span&gt;&lt;span class="err"&gt;clus&lt;/span&gt;&lt;span class="kc"&gt;ter&lt;/span&gt;&lt;span class="mf"&gt;-1.&lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SUCCESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;rpi&lt;/span&gt;&lt;span class="mi"&gt;-&lt;/span&gt;&lt;span class="err"&gt;clus&lt;/span&gt;&lt;span class="kc"&gt;ter&lt;/span&gt;&lt;span class="mf"&gt;-2.&lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SUCCESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;rpi&lt;/span&gt;&lt;span class="mi"&gt;-&lt;/span&gt;&lt;span class="err"&gt;clus&lt;/span&gt;&lt;span class="kc"&gt;ter&lt;/span&gt;&lt;span class="mf"&gt;-3.&lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SUCCESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="err"&gt;rpi&lt;/span&gt;&lt;span class="mi"&gt;-&lt;/span&gt;&lt;span class="err"&gt;clus&lt;/span&gt;&lt;span class="kc"&gt;ter&lt;/span&gt;&lt;span class="mf"&gt;-16.&lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SUCCESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;rpi&lt;/span&gt;&lt;span class="mi"&gt;-&lt;/span&gt;&lt;span class="err"&gt;clus&lt;/span&gt;&lt;span class="kc"&gt;ter&lt;/span&gt;&lt;span class="mf"&gt;-17.&lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SUCCESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="err"&gt;rpi&lt;/span&gt;&lt;span class="mi"&gt;-&lt;/span&gt;&lt;span class="err"&gt;clus&lt;/span&gt;&lt;span class="kc"&gt;ter&lt;/span&gt;&lt;span class="mf"&gt;-18.&lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;SUCCESS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"changed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;"ping"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pong"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you get an error, double you have your nodes correctly named in &lt;code&gt;cluster.yml&lt;/code&gt; if all looks good, try Googling the error.&lt;/p&gt;
&lt;h5&gt;Update all Your Nodes' Packages&lt;/h5&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;cluster.yml&lt;span class="w"&gt; &lt;/span&gt;playbooks/upgrade.yml
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As we start to run ansible playbooks, this is where you just might have to rerun a playbook to get beyond an error.  The most common error I ran into was peer connections dropped.  It is a bit of a mystery why; the aforementioned cluster is connected via a managed HP gigabit switch.&lt;/p&gt;
&lt;h5&gt;Install Kubernetes&lt;/h5&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Bootstrap the master and all slaves&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;cluster.yml&lt;span class="w"&gt; &lt;/span&gt;site.yml
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;This will reboot your cluster nodes&lt;/strong&gt; This might cause issues and force you to repeat this step.  After my initial execution of that command, I followed it up with:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# When running again, feel free to ignore the common tag as this will reboot the rpi's&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;cluster.yml&lt;span class="w"&gt; &lt;/span&gt;site.yml&lt;span class="w"&gt; &lt;/span&gt;--skip-tags&lt;span class="w"&gt; &lt;/span&gt;common
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will run everything except the &lt;code&gt;reboot&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;If you want to only rerun a single node and the master node, you can do something like the following:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Bootstrap a single slave (rpi-cluster-5) and the master node&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;cluster.yml&lt;span class="w"&gt; &lt;/span&gt;site.yml&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;rpi-cluster-master.local,rpi-cluster-5.local
&lt;/pre&gt;&lt;/div&gt;

&lt;h5&gt;Copy over the .kube/config and verification&lt;/h5&gt;
&lt;p&gt;We need to copy over your kubernetes configuration file.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# Copy in your kube config&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;cluster.yml&lt;span class="w"&gt; &lt;/span&gt;playbooks/copy-kube-config.yml

&lt;span class="c1"&gt;# Set an alias to make it easier&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;kubectl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'docker run -it --rm -v ~/.kube:/.kube -v $(pwd):/pwd -w /pwd bitnami/kubectl:1.21.3'&lt;/span&gt;

&lt;span class="c1"&gt;# Run kubectl within docker&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;version
Client&lt;span class="w"&gt; &lt;/span&gt;Version:&lt;span class="w"&gt; &lt;/span&gt;version.Info&lt;span class="o"&gt;{&lt;/span&gt;Major:&lt;span class="s2"&gt;"1"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;Minor:&lt;span class="s2"&gt;"21"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GitVersion:&lt;span class="s2"&gt;"v1.21.3"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GitCommit:&lt;span class="s2"&gt;"ca643a4d1f7bfe34773c74f79527be4afd95bf39"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GitTreeState:&lt;span class="s2"&gt;"clean"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;BuildDate:&lt;span class="s2"&gt;"2021-07-15T21:04:39Z"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GoVersion:&lt;span class="s2"&gt;"go1.16.6"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;Compiler:&lt;span class="s2"&gt;"gc"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;Platform:&lt;span class="s2"&gt;"linux/arm64"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
Server&lt;span class="w"&gt; &lt;/span&gt;Version:&lt;span class="w"&gt; &lt;/span&gt;version.Info&lt;span class="o"&gt;{&lt;/span&gt;Major:&lt;span class="s2"&gt;"1"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;Minor:&lt;span class="s2"&gt;"21"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GitVersion:&lt;span class="s2"&gt;"v1.21.14"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GitCommit:&lt;span class="s2"&gt;"0f77da5bd4809927e15d1658fb4aa8f13ad890a5"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GitTreeState:&lt;span class="s2"&gt;"clean"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;BuildDate:&lt;span class="s2"&gt;"2022-06-15T14:11:36Z"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;GoVersion:&lt;span class="s2"&gt;"go1.16.15"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;Compiler:&lt;span class="s2"&gt;"gc"&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;Platform:&lt;span class="s2"&gt;"linux/arm64"&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's get a little information about the cluster:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt;  &lt;/span&gt;cluster-info
Kubernetes&lt;span class="w"&gt; &lt;/span&gt;control&lt;span class="w"&gt; &lt;/span&gt;plane&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;running&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;https://10.1.1.100:6443
CoreDNS&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;running&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;https://10.1.1.100:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

To&lt;span class="w"&gt; &lt;/span&gt;further&lt;span class="w"&gt; &lt;/span&gt;debug&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;diagnose&lt;span class="w"&gt; &lt;/span&gt;cluster&lt;span class="w"&gt; &lt;/span&gt;problems,&lt;span class="w"&gt; &lt;/span&gt;use&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'kubectl cluster-info dump'&lt;/span&gt;.
&lt;/pre&gt;&lt;/div&gt;

&lt;h6&gt;Helm&lt;/h6&gt;
&lt;p&gt;If you need to &lt;a href="https://go.tinymachines.io/DGvsn2"&gt;install &lt;code&gt;helm&lt;/code&gt;&lt;/a&gt;; Helm is a package manager for Kubernetes: &lt;em&gt;Helm is the best way to find, share, and use software built for &lt;a href="https://go.tinymachines.io/hzcDAR"&gt;Kubernetes&lt;/a&gt;&lt;/em&gt; - follow these instructions:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;curl&lt;span class="w"&gt; &lt;/span&gt;https://baltocdn.com/helm/signing.asc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gpg&lt;span class="w"&gt; &lt;/span&gt;--dearmor&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;/usr/share/keyrings/helm.gpg&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
/dev/null
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;apt-transport-https&lt;span class="w"&gt; &lt;/span&gt;--yes
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"deb [arch=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;dpkg&lt;span class="w"&gt; &lt;/span&gt;--print-architecture&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt; signed-by=/usr/share/keyrings/helm.gpg] \&lt;/span&gt;
&lt;span class="s2"&gt;https://baltocdn.com/helm/stable/debian/ all main"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;/etc/apt/sources.list.d/helm-stable-debian.list
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;update
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;helm
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you do not have &lt;code&gt;gpg&lt;/code&gt; installed, you will need to install it.&lt;/p&gt;
&lt;p&gt;Here is a more in depth look at &lt;a href="https://go.tinymachines.io/ZKXCu7"&gt;helm&lt;/a&gt; and its role within kubernetes.&lt;/p&gt;
&lt;p&gt;This is going to be anticlimactic, but we will start to run our first container on our shiny new kubernetes cluster in our next posting.&lt;/p&gt;</description><category>cluster computing</category><category>kubernetes</category><category>raspberry pi</category><guid>https://tinycomputers.io/posts/raspberry-pi-kubernetes-cluster.html</guid><pubDate>Tue, 03 Jan 2023 00:14:22 GMT</pubDate></item></channel></rss>