<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Raspberry-Pi on Roland Huß</title><link>https://ro14nd.de/tags/raspberry-pi/</link><description>Recent content in Raspberry-Pi on Roland Huß</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>© 2026 Roland Huß</copyright><lastBuildDate>Mon, 12 Mar 2018 00:00:00 +0000</lastBuildDate><atom:link href="https://ro14nd.de/tags/raspberry-pi/index.xml" rel="self" type="application/rss+xml"/><item><title>Dash2Alexa - Amazon Alexa Audio API Access</title><link>https://ro14nd.de/dash-2-alexa/</link><pubDate>Mon, 12 Mar 2018 00:00:00 +0000</pubDate><guid>https://ro14nd.de/dash-2-alexa/</guid><description>&lt;p&gt;Since I got my first Amazon Echo end of last year, I love it.
And although, as a typical German, I&amp;rsquo;m still a bit concerned about data privacy, at the end, convenience wins (as always :).
There are many things which work flawlessly, and to be honest, the most used feature for me is a simple timer.
But when it comes to aggregate actions, Alexa is still quite limited.
Ok, you can define your routines, but for only an insufficient set of fixed actions.
What I really would love to have is to start the radio when I get up in the morning, but this is not possible at the moment.&lt;/p&gt;
&lt;p&gt;So I remembered my last years Amazon Dash button hacks and thought it would be cool to combine both, the Dash button and Alexa.&lt;/p&gt;
&lt;p&gt;And here it is, my weekend hack &amp;hellip;..&lt;/p&gt;
&lt;iframe src="https://player.vimeo.com/video/259570045?byline=0&amp;portrait=0" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen&gt;&lt;/iframe&gt;
&lt;p&gt;In a nutshell, the setup looks like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure your router to not forward packets from your Dash Button.&lt;/li&gt;
&lt;li&gt;Spoof on ARP requests for the Dash button&amp;rsquo;s MAC.&lt;/li&gt;
&lt;li&gt;If found, call out to a text-to-speech service to convert configured Alexa commands to audio.&lt;/li&gt;
&lt;li&gt;Play the received audio output via RaspberryPi attached speakers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;rsquo;s it.
You can use this &lt;a href="https://github.com/rhuss/dash2alexa" target="_blank" rel="noreferrer"&gt;sample code&lt;/a&gt; for doing the dirty work, but maybe you are interested in some more details.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Amazon Dash Button
 &lt;div id="amazon-dash-button" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#amazon-dash-button" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Amazon_Dash" target="_blank" rel="noreferrer"&gt;Amazon Dash Button&lt;/a&gt; is part of Amazon&amp;rsquo;s consumer goods ordering service.
This button contains a Wifi sender and is quite inexpensive.
Each button is specific for a brand for which you can connect to a specific good.
When you press the button, this good is ordered (e.f. 24 cans of beer ;-)&lt;/p&gt;
&lt;p&gt;But this intended use case is not the only way how you can use this button.
In fact, it can be used just as a plain Wifi button for any purpose.&lt;/p&gt;
&lt;p&gt;First of all, you have to buy such a button e.g. 5 Euro here in Germany, but you can spend this five bucks for your first order.
You just configure it as described by Amazon and maybe order something to spend your credits.&lt;/p&gt;
&lt;p&gt;After this, you have to block the button in your home Wifi router for calling out to the internet.
For obvious reasons, this is &lt;strong&gt;very important&lt;/strong&gt; ;-)
When the button is blocked, it will flash red eventually when being pressed (in contrast to flashing green when an order is placed).&lt;/p&gt;
&lt;p&gt;When you press the button, it first asks via DHCP for an IP address.
The MAC address of the button is relevant, so its time to pick that up, e.g.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By looking into your DHCP servers log&lt;/li&gt;
&lt;li&gt;By trying &lt;code&gt;arp -a&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;By checking your Wifi Router&amp;rsquo;s admin UI&lt;/li&gt;
&lt;li&gt;Via Wireshark spoofing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This Mac address will be watched for later by spoofing ARP package traffic.
When &lt;a href="https://golang.org" target="_blank" rel="noreferrer"&gt;golang&lt;/a&gt; is your preferred programming language, then you can use directly &lt;a href="https://github.com/rhuss/dash" target="_blank" rel="noreferrer"&gt;rhuss/dash&lt;/a&gt; which is based on top of &lt;a href="https://github.com/google/gopacket" target="_blank" rel="noreferrer"&gt;gopacket&lt;/a&gt; to watch for certain ARP packages and trigger an action when received.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Amazon Polly API access
 &lt;div id="amazon-polly-api-access" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#amazon-polly-api-access" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;In our use case, when we detect that a button is pressed, then we want to send out some fixed, text-based audio.
For converting text coming from a configuration, a text-to-speech service is used.&lt;/p&gt;
&lt;p&gt;There are several such services available.
For our purpose, we are using &lt;a href="https://aws.amazon.com/polly/developers/?nc1=h_ls" target="_blank" rel="noreferrer"&gt;Amazon Polly&lt;/a&gt;, which offers a free tier for the first 12 months (including 5 million characters per month, fair enough for a handful of buttons ;-) and then 4 $ per one million of chars.&lt;/p&gt;
&lt;p&gt;A short cost calculation beyond the free tier: 100 characters for Alexa commands per button press (which is already quite a mouthful) costs ~ 0.4 cents.
Or the other way round, for five bucks you can press the button 1.250 times: Three times a day per yeare for 5 $
Well, for me that&amp;rsquo;s worth the fun ;-)&lt;/p&gt;
&lt;p&gt;You need an &lt;a href="https://portal.aws.amazon.com/billing/signup" target="_blank" rel="noreferrer"&gt;AWS account&lt;/a&gt; to access the speech API.
The access and secret token can be either that of your &lt;a href="https://console.aws.amazon.com/iam/home#/security_credential" target="_blank" rel="noreferrer"&gt;root AWS account&lt;/a&gt;, or you probably should create a dedicated &lt;a href="https://console.aws.amazon.com/iam/home#/users" target="_blank" rel="noreferrer"&gt;IAM User&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Of course, you can also use different text-to-speech tool.
Maybe even the good old Unix &lt;code&gt;speak&lt;/code&gt; will do it ?
Not tried it yet, but will check that for sure very soonish.
For now, the Polly voices are recognised quite well by my echo so that I won&amp;rsquo;t change it right now.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Raspberry Pi Audio
 &lt;div id="raspberry-pi-audio" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#raspberry-pi-audio" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The final jigsaw piece is the hardware on which to run the watcher.
For my use case, a Raspberry Pi 2 with some &lt;a href="https://www.amazon.de/gp/product/B00JRW0M32/" target="_blank" rel="noreferrer"&gt;inexpensive speakers&lt;/a&gt; was totally good enough.&lt;/p&gt;

&lt;h2 class="relative group"&gt;dash2alexa command
 &lt;div id="dash2alexa-command" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#dash2alexa-command" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/rhuss/dash2alexa" target="_blank" rel="noreferrer"&gt;dash2alexa&lt;/a&gt; command actually takes a configuration file (defautl: &lt;code&gt;~/.dash2alexa.yml&lt;/code&gt;)&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Sample configuration file for dash2alexa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Adapt and copy it to ~/.dash2alexa.yml&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Access and secret for accessing the services&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;access&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;..........&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;secret&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;..........&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Network interface to listen for ARP requests when a Dash button is pressed&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;interface&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;wlan0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Language (&amp;#34;de&amp;#34; or &amp;#34;en&amp;#34;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;language&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;de&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Gender which can be either &amp;#34;male&amp;#34; or &amp;#34;female&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;gender&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;male&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Keyword to use for alexa&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;keyword&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Alexa&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Player to use when playing an mp3 sound file&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;player&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;mpeg123&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# List of Dash Buttons with associated Alexa command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;buttons&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Symbolic name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;heineken&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Mac adress of Dash button&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;mac&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ac:63:be:00:11:22&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# How many seconds to wait between Alexa commands&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;wait&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# Messages to talk&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;messages&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;Lautstärke 4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - &lt;span style="color:#e6db74"&gt;&amp;#34;Spiele Bayern 3&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There&amp;rsquo;s not much documentation yet, but some will follow soon.
Feel free to adapt the code, and I&amp;rsquo;m happy to integrate any pull requests.
Also, as I&amp;rsquo;m a bloody golang greenhorn still, would be curious whether things could be done better.&lt;/p&gt;

&lt;h2 class="relative group"&gt;tl;dr
 &lt;div id="tldr" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#tldr" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This little hack uses Amazon Echo via its &amp;lsquo;Audio API&amp;rsquo; to perform specific action on a button press.
It&amp;rsquo;s entirely suited for a situation when its calm around, like putting the button right beside the bed for getting started even when your Echo is out of sight.&lt;/p&gt;
&lt;p&gt;And finally, it&amp;rsquo;s just pure fun ;-) Enjoy!&lt;/p&gt;
&lt;p&gt;P.S. Let me know in the comments whether you tried it out, too and how it works for you.&lt;/p&gt;</description></item><item><title>RasPi 3 Kubernetes Cluster - An Update</title><link>https://ro14nd.de/k8s-on-pi-update/</link><pubDate>Wed, 05 Apr 2017 00:00:00 +0000</pubDate><guid>https://ro14nd.de/k8s-on-pi-update/</guid><description>&lt;p&gt;Our Ansible Playbooks for installing Kubernetes on a Raspberry Pi Cluster have been constantly updated and are now using the awesome &lt;a href="https://github.com/kubernetes/kubeadm" target="_blank" rel="noreferrer"&gt;kubeadm&lt;/a&gt;. The update to Kubernetes 1.6. was a bit tricky, though.&lt;/p&gt;
&lt;p&gt;Recently I had the luck to meet Mr. &lt;a href="https://twitter.com/kubernetesonarm" target="_blank" rel="noreferrer"&gt;@kubernetesonarm&lt;/a&gt; Lucas Käldström at the&lt;a href="https://devops-gathering.io/" target="_blank" rel="noreferrer"&gt; DevOps Gathering&lt;/a&gt; where he demoed his multi-arch cluster. That was really impressing. Lucas really squeezes out the maximum what is possible these days with Raspberry Pis and other SOC devices on the Kubernetes platform. Please follow his &lt;a href="https://github.com/luxas/kubeadm-workshop" target="_blank" rel="noreferrer"&gt;Workshop&lt;/a&gt; on GitHub for a multi-platform setup with ingress controller, persistent volumes, custom API servers and more.&lt;/p&gt;
&lt;p&gt;Needless to say that after returning home one of the first task was to update our &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3" target="_blank" rel="noreferrer"&gt;Ansible playbooks&lt;/a&gt; for updating to Kubernetes 1.6 on my RasPi cluster. The goal of these playbooks are a bit different than Lucas workshop setup: Instead of living at the edge, the goal here is to provide an easy, automated and robust way to install a standard Kubernetes installation on a Raspberry Pi 3 cluster. &lt;code&gt;kubeadm&lt;/code&gt; is a real great help and makes many things so much easier. However there are still some steps to do in addition.&lt;/p&gt;
&lt;p&gt;After following the &lt;a href="https://github.com/luxas/kubeadm-workshop/blob/master/README.md" target="_blank" rel="noreferrer"&gt;workshop instructions&lt;/a&gt; it turned out soon, that it was probably not the best time for the update. Kubernetes 1.6. has just been released and it turned out that last minute pre-release changes &lt;a href="https://github.com/kubernetes/kubeadm/issues/212" target="_blank" rel="noreferrer"&gt;broke kubeadm 1.6.0&lt;/a&gt;. Luckily these were fixed quickly with 1.6.1. However the so called &lt;em&gt;self hosted&lt;/em&gt; mode of kubeadm broke, too (and is currently still &lt;a href="https://github.com/luxas/kubeadm-workshop/issues/8" target="_blank" rel="noreferrer"&gt;broken&lt;/a&gt; in 1.6.1 but should be fixed soon). So the best bet for the moment is to use a standard install (with external processes for api-server et. al).&lt;/p&gt;
&lt;p&gt;Also this time I wanted to use &lt;a href="https://github.com/weaveworks/weave" target="_blank" rel="noreferrer"&gt;Weave&lt;/a&gt; instead of Flannel as the overlay network. In turned out that this didn&amp;rsquo;t worked on my cluster because every of my nodes got the same virtual Mac address assigned by Weave. That&amp;rsquo;s because this address is &lt;a href="https://github.com/weaveworks/weave/blob/916ff7aa3979fced84fceef1635ab8c868d71e25/net/uuid.go#L26" target="_blank" rel="noreferrer"&gt;calculated&lt;/a&gt; based on &lt;code&gt;/etc/machine-id&lt;/code&gt;. And guess what. All my nodes had the &lt;em&gt;same machine id&lt;/em&gt; &lt;code&gt;9989a26f06984d6dbadc01770f018e3b&lt;/code&gt;. This it what the base Hypriot 1.4.0 system decides to install (in fact it is derived by &lt;code&gt;systemd-machine-id-setup&lt;/code&gt; from &lt;code&gt;/var/lib/dbus/machine-id&lt;/code&gt;). And every Hypriot installation out there has this very same machine-id ;-) For me it wasn&amp;rsquo;t surprising, that this happened (well, developing bugs is our daily business ;-), but I was quite puzzled that this hasn&amp;rsquo;t been a bigger &lt;a href="https://github.com/hypriot/image-builder-rpi/issues/167" target="_blank" rel="noreferrer"&gt;issue&lt;/a&gt; yet, because I suspect that especially in cluster setups (may it be Docker Swarm or Kubernetes) at some point the nodes need their unique id. Of course most of the time the IP and hostname is enough. But for a more rigorous UUID &lt;code&gt;/etc/machine-id&lt;/code&gt; is normally good fit.&lt;/p&gt;
&lt;p&gt;After knowing this and re-creating the UUID on my own (with &lt;code&gt;dbus-uuidgen &amp;gt; /etc/machine-id&lt;/code&gt;) everything works smoothly now again, so that I have a base Kubernetes 1.6 cluster with DNS and proper overlay network again. Uff, was quite a mouthful of work :)&lt;/p&gt;
&lt;p&gt;You find the installation instructions and the updated playbooks at &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3" target="_blank" rel="noreferrer"&gt;https://github.com/Project31/ansible-kubernetes-openshift-pi3&lt;/a&gt;. If your router is configured properly, it takes not much more than half an hour to &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3#ansible-playbooks" target="_blank" rel="noreferrer"&gt;setup the full cluster&lt;/a&gt;. I did it several times now since last week, always starting afresh with flashing the SD cards. I can confirm that its reproducible and idempotent now ;-)&lt;/p&gt;
&lt;p&gt;The next steps are to add persistent volumes with &lt;a href="https://github.com/rook/rook" target="_blank" rel="noreferrer"&gt;Rook&lt;/a&gt;, &lt;a href="https://traefik.io/" target="_blank" rel="noreferrer"&gt;Træfik&lt;/a&gt; as ingress controller and an own internal registry.&lt;/p&gt;
&lt;p&gt;Feel free to give it a try and open many &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3/issues/new" target="_blank" rel="noreferrer"&gt;issues&lt;/a&gt; ;-)&lt;/p&gt;</description></item><item><title>A Raspberry Pi 3 Kubernetes Cluster</title><link>https://ro14nd.de/kubernetes-on-raspberry-pi3/</link><pubDate>Wed, 27 Apr 2016 00:00:00 +0000</pubDate><guid>https://ro14nd.de/kubernetes-on-raspberry-pi3/</guid><description>&lt;p&gt;Let&amp;rsquo;s build a Raspberry Pi Cluster running Docker and Kubernetes. There has been already a handful of good recipes, however this howto is a bit different and provides some unique features.&lt;/p&gt;
&lt;img src="https://ro14nd.de/images/kubernetes-on-raspberry-pi3/pi_cluster.jpg" style="float:right; margin: 50px 0px 20px 30px"/&gt;
&lt;p&gt;My main motivation for going the Raspberry Pi road for a Kubernetes cluster was that I wanted something fancy for my &lt;a href="https://github.com/rhuss/jax-kubernetes-2016" target="_blank" rel="noreferrer"&gt;Kubernetes talk&lt;/a&gt; to show, shamelessly stealing the idea &lt;a href="https://opensource.com/life/16/2/build-a-kubernetes-cloud-with-raspberry-pi" target="_blank" rel="noreferrer"&gt;from&lt;/a&gt; &lt;a href="https://www.youtube.com/watch?time_continue=4&amp;amp;v=AAS5Mq9EktI" target="_blank" rel="noreferrer"&gt;others&lt;/a&gt; (kudos to &lt;code&gt;@KurtStam&lt;/code&gt;, &lt;code&gt;@saturnism&lt;/code&gt;, &lt;code&gt;@ArjenWassink&lt;/code&gt; and &lt;code&gt;@kubernetesonarm&lt;/code&gt; for the inspiration ;-)&lt;/p&gt;
&lt;p&gt;I.e. the following Pi-K8s projects already existed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/Project31/kubernetes-installer-rpi" target="_blank" rel="noreferrer"&gt;kubernetes-installer-rpi&lt;/a&gt;&lt;/strong&gt; : A set up shell scripts and precompiled ARM binaries for running Kubernetes by &lt;a href="https://twitter.com/KurtStam" target="_blank" rel="noreferrer"&gt;@KurtStam&lt;/a&gt; on top of the Hypriot Docker Image for Raspberry Pi.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/luxas/kubernetes-on-arm" target="_blank" rel="noreferrer"&gt;Kubernetes on ARM&lt;/a&gt;&lt;/strong&gt; : An opinionated approach by &lt;a href="https://twitter.com/kubernetesonarm" target="_blank" rel="noreferrer"&gt;@kubernetesonarm&lt;/a&gt; with an own installer for setting up Kubernetes no only for the Pi but also for other ARM based platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/awassink/k8s-on-rpi" target="_blank" rel="noreferrer"&gt;K8s on Rpi&lt;/a&gt;&lt;/strong&gt; : Another shell based installer for installing a Kubernetes cluster by &lt;a href="https://twitter.com/ArjenWassink" target="_blank" rel="noreferrer"&gt;@ArjenWassink&lt;/a&gt; and &lt;a href="https://twitter.com/saturnism" target="_blank" rel="noreferrer"&gt;@saturnism&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When there are already multiple recipes out there, why then trying yet another approach ?&lt;/p&gt;
&lt;p&gt;My somewhat selfish goals were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using (and learning on the way) Ansible for not only a one-shot installation but also maintainance and upgrades.&lt;/li&gt;
&lt;li&gt;Learning myself how to setup a Kubernetes cluster. This setup includes flannel as an overlay network, the SkyDNS extension and soon also a registry. Using Ansible helps me to incrementally add on top of things already installed.&lt;/li&gt;
&lt;li&gt;Want to use WiFi for connecting the cluster. See below for the reason.&lt;/li&gt;
&lt;li&gt;Get &lt;a href="https://github.com/openshift/origin" target="_blank" rel="noreferrer"&gt;OpenShift Origin&lt;/a&gt; running and be able to switch between Ansible and OpenShift via Ansible.&lt;/li&gt;
&lt;li&gt;Create a demonstration platform for my favourite development and integration platform &lt;a href="http://fabric8.io" target="_blank" rel="noreferrer"&gt;fabric8&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As it turns out the whole experience was very enlightening to me. Its one thing to start Kubernetes on a single node within a VM (because multiple VM-based nodes kill soon your machine resourcewise) or having a small bare metal cluster, which blinks red and green and where you can plug wires at will. Not to mention the the geek factor :)&lt;/p&gt;

&lt;h2 class="relative group"&gt;Shopping List
 &lt;div id="shopping-list" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#shopping-list" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s my shopping list for a Raspberry Pi 3 cluster, along with (non-affiliate) links to (German) shops, but I&amp;rsquo;m sure you can find them elswhere, too.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Amount&lt;/th&gt;
 &lt;th&gt;Part&lt;/th&gt;
 &lt;th&gt;Price&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.watterott.com/de/Raspberry-Pi-3" target="_blank" rel="noreferrer"&gt;Raspberry Pi 3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;4 * 38 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B013UDL5RU" target="_blank" rel="noreferrer"&gt;Micro SD Card 32 GB&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;4 * 11 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00XPUIDFQ" target="_blank" rel="noreferrer"&gt;WLAN Router&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;22 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B016BEVNK4" target="_blank" rel="noreferrer"&gt;USB wires&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;9 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00PTLSH9G" target="_blank" rel="noreferrer"&gt;Power Supply&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;30 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00NB1WPEE" target="_blank" rel="noreferrer"&gt;Case&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;10 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;&lt;a href="http://www.amazon.de/dp/B00NB1WQZW" target="_blank" rel="noreferrer"&gt;Intermediate Case Plate&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;3 * 7 EUR&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All in all, a 4 node Pi cluster for &lt;strong&gt;288 EUR&lt;/strong&gt; (as of April 2016). Not so bad.&lt;/p&gt;
&lt;p&gt;Some remarks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using WiFi for the connection has the big advantage that the Raspberry Pi 3 integrated BCM43438 WiFi chip doesn&amp;rsquo;t go over USB and saves valuable bandwidth used for IO in general. That way you are able to to get ~ 25 MB/s for disk IO and network traffic, respectively. And also less cables, of course. You can alway plug the power wire for demos, too ;-)&lt;/li&gt;
&lt;li&gt;A class 10 Mirco SD is recommended but it doesn&amp;rsquo;t have to be the fastest on the world as the USB bus only allows around 35 MB/s anyway.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;Initial Pi Setup
 &lt;div id="initial-pi-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#initial-pi-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Most of the installation is automated by using &lt;a href="https://www.ansible.com/" target="_blank" rel="noreferrer"&gt;Ansible&lt;/a&gt;. However the initial setup is a bit more involved. It certainly can be improved (e.g. automatic filesystem expanding of the initial Raspian setup). If you have ideas how to improve this, please open issues and PRs on &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3" target="_blank" rel="noreferrer"&gt;Project31/ansible-kubernetes-openshift-pi3&lt;/a&gt;. Several base distributions has been tried out. It turned out that the most stable setup is based on a stock Raspian. Unfortunately it doesn&amp;rsquo;t provide a headless WLAN setup as it is possible with the latest &lt;a href="https://github.com/hypriot/image-builder-rpi/releases/latest" target="_blank" rel="noreferrer"&gt;Hypriot&lt;/a&gt; images, but for the moment it much more stable (I had strange kernel panics and 200% CPU load issues with the Hypriot image for no obvious reasons). Since this is a one time effort, let&amp;rsquo;s use Raspbian. If you want to try out the Hypriot image, there&amp;rsquo;s an &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3/tree/hypriot" target="_blank" rel="noreferrer"&gt;experimental branch&lt;/a&gt; for the Ansible playbooks which can be used with Hypriot. I will retry Hypriot OS for sure some times later.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Download the latest Raspian image and store it as &lt;code&gt;raspbian.zip&lt;/code&gt; :&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; curl -L https://downloads.raspberrypi.org/raspbian_lite_latest \
 -o raspbian.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install Hypriots&amp;rsquo; &lt;a href="https://github.com/hypriot/flash" target="_blank" rel="noreferrer"&gt;flash&lt;/a&gt; installer script. Follow the directions on the installation page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Insert you Micro-SD card in your Desktop computer (via an adapter possibly) and run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; flash raspbian.zip
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will be asked to which device to write. Check this carefully, otherwise you could destroy your Desktop OS if selecting the the wrong device. Typically its something like &lt;code&gt;/dev/disk2&lt;/code&gt; on OS X, but depends on the number of hard drives you have.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Insert the Micro SSD card into your Raspberry Pi and connect it to a monitor and keyboard. Boot up. Login in with &lt;em&gt;pi&lt;/em&gt; / &lt;em&gt;raspberry&lt;/em&gt;. Then:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; raspi-config --expand-rootfs
 vi /etc/wpa_supplicant/wpa_supplicant.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and then add your WLAN credentials&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; network={
 ssid=&amp;quot;MySSID&amp;quot;
 psk=&amp;quot;s3cr3t&amp;quot;
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reboot&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Repeat step 2. to 5. for each Micro SD card.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;Network Setup
 &lt;div id="network-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#network-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;It is now time to configure your WLAN router. This of course depends on which router you use. The following instructions are based on a &lt;a href="http://www.tp-link.com/en/products/details/cat-9_TL-WR802N.html" target="_blank" rel="noreferrer"&gt;TP-Link TL-WR802N&lt;/a&gt; which is quite inexepensive but still absolutely ok for our purposes since it sits very close to the cluster and my notebook anyway.&lt;/p&gt;
&lt;p&gt;First of all you need to setup the SSID and password. Use the same credentials with which you have configured your images.&lt;/p&gt;
&lt;p&gt;My setup is, that I span a private network &lt;code&gt;192.168.23.0/24&lt;/code&gt; for the Pi cluster which my MacBook also joins via its integrated WiFi.&lt;/p&gt;
&lt;p&gt;The addresses I have chosen are :&lt;/p&gt;
&lt;p&gt;| &lt;code&gt;192.168.23.1&lt;/code&gt; | WLAN Router |
| &lt;code&gt;192.168.23.100&lt;/code&gt; | MacBook&amp;rsquo;s WLAN |
| &lt;code&gt;192.168.23.200&lt;/code&gt; &amp;hellip; &lt;code&gt;192.168.23.203&lt;/code&gt; | Raspberry Pis |&lt;/p&gt;
&lt;p&gt;The MacBook is setup for NAT and forwarding from this private network to the internet. This &lt;a href="https://github.com/Project31/ansible-kubernetes-openshift-pi3/blob/master/tools/setup_nat_on_osx.sh" target="_blank" rel="noreferrer"&gt;script&lt;/a&gt; helps in setting up the forwarding and NAT rules on OS X.&lt;/p&gt;
&lt;p&gt;In order to configure your WLAN router you need to connect to it according to its setup instructions. The router is setup in &lt;strong&gt;Access Point&lt;/strong&gt; mode with DHCP enabled. As soon as the MAC of the Pis are known (which you can see as soon as they connect for the first time via WiFi), I configured them to always use the same DHCP lease. For the TL-WR802N this can be done in the configuration section &lt;em&gt;DHCP -&amp;gt; Address Reservation&lt;/em&gt;. In the &lt;em&gt;DHCP -&amp;gt; DHCP-Settings&lt;/em&gt; the default gateway is set to &lt;code&gt;192.168.23.100&lt;/code&gt;, which my notebook&amp;rsquo;s WLAN IP.&lt;/p&gt;
&lt;p&gt;Startup all nodes, you should be able to ping every node in your cluster. I added &lt;code&gt;n0&lt;/code&gt; &amp;hellip; &lt;code&gt;n3&lt;/code&gt; to my notebook&amp;rsquo;s &lt;code&gt;/etc/hosts&lt;/code&gt; pointing to &lt;code&gt;192.168.23.200&lt;/code&gt; &amp;hellip; &lt;code&gt;192.168.23.203&lt;/code&gt; for convenience.&lt;/p&gt;
&lt;p&gt;You should be able to ssh into every Pi with user &lt;em&gt;pi&lt;/em&gt; and password &lt;em&gt;raspberry&lt;/em&gt;. Also, if you set up the forwarding on your desktop properly you should be able to ping from within the pi to the outside world.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Ansible Playbooks
 &lt;div id="ansible-playbooks" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ansible-playbooks" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;After this initial setup is done, the next step is to initialize the base system with Ansible. You will need Ansible 2 installed on your desktop (e.g. &lt;code&gt;brew install ansible&lt;/code&gt; when running on OS X)&lt;/p&gt;

&lt;h3 class="relative group"&gt;Ansible Configuration
 &lt;div id="ansible-configuration" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#ansible-configuration" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Checkout the Ansible playbooks:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; git clone https://github.com/Project31/ansible-kubernetes-openshift-pi3.git k8s-pi
 cd k8s-pi
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy over &lt;code&gt;hosts.example&lt;/code&gt; and adapt it to your needs&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cp hosts.example hosts
 vi hosts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are three Ansible groups which are refered to in the playbooks:&lt;/p&gt;
&lt;p&gt;| &lt;strong&gt;pis&lt;/strong&gt; | All cluster node | &lt;code&gt;n0&lt;/code&gt;, &lt;code&gt;n1&lt;/code&gt;, &lt;code&gt;n2&lt;/code&gt;, &lt;code&gt;n3&lt;/code&gt; |
| &lt;strong&gt;master&lt;/strong&gt; | Master node | &lt;code&gt;n0&lt;/code&gt; |
| &lt;strong&gt;nodes&lt;/strong&gt; | All nodes which are not master | &lt;code&gt;n1&lt;/code&gt;, &lt;code&gt;n2&lt;/code&gt;, &lt;code&gt;n3&lt;/code&gt;|&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Copy over the configuration and adapt it.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cp config.yml.example config.yml
 vi config.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should at least put in your WLAN credentials, but you are also free to adapt the other values.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 class="relative group"&gt;Basic Node Setup
 &lt;div id="basic-node-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#basic-node-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;If you have already created a cluster with these playbooks and want to start a fresh, please be sure that you cleanup your &lt;code&gt;~/.ssh/known_hosts&lt;/code&gt; from the old host keys. You should be able to ssh into each of the nodes without warnings. Also you must be able to reach the internet from the nodes.&lt;/p&gt;
&lt;p&gt;In the next step the basic setup (without Kubernetes) is performed. This is done by&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -k -i hosts setup.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you are prompted for the password, use &lt;em&gt;raspberry&lt;/em&gt;. You will probably also need to confirm the SSH authentity for each host with &lt;em&gt;yes&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The following steps will be applied by this command (which may take a bit):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Docker will be installed from the Hypriot repositories&lt;/li&gt;
&lt;li&gt;Your public SSH key is copied over to &lt;em&gt;pi&amp;rsquo;s&lt;/em&gt; authenticated_keys and the users password will be taken from &lt;code&gt;config.yml&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Some extra tools are installed for your convenience and some benchmarking:
&lt;ul&gt;
&lt;li&gt;hdparm&lt;/li&gt;
&lt;li&gt;iperf&lt;/li&gt;
&lt;li&gt;mtr&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Hostname is set to the name of the node configured. Also &lt;code&gt;/etc/hosts&lt;/code&gt; is setup to contain all nodes with their short names.&lt;/li&gt;
&lt;li&gt;A swapfile is enabled (just in case)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this basic setup you have already a working Docker environment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Now its time to reboot the whole cluster since some required boot params has been added. Plug the wire.&lt;/strong&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;Kubernetes Setup
 &lt;div id="kubernetes-setup" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#kubernetes-setup" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;The final step for a working Kubernetes cluster is to run&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -i hosts kubernetes.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will install one master at n0 and threed additional nodes n1, n2, n3.&lt;/p&gt;
&lt;p&gt;The following features are enabled:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;etcd&lt;/code&gt;, &lt;code&gt;flanneld&lt;/code&gt; and &lt;code&gt;kubelet&lt;/code&gt; are installed as systemd services on the master&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubelet&lt;/code&gt; and &lt;code&gt;flanneld&lt;/code&gt; are installed as systemd services on the nodes&lt;/li&gt;
&lt;li&gt;Docker is configured to use the Flannel overlay network&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kubectl&lt;/code&gt; is installed (and an alias &lt;code&gt;k&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If there are some issues when restarting services in the master, don&amp;rsquo;t worry. However you should best restart the master node n0 when this happens, because when setting up the other nodes the would fail if not all services are running on the master.&lt;/p&gt;
&lt;p&gt;After an initial installation it may take a bit until all infrastructure docker images has been loaded. Eventually should be able to use &lt;code&gt;kubectl get nodes&lt;/code&gt; from e.g. &lt;code&gt;n0&lt;/code&gt;. When this wotks but you see only one node, please reboot the cluster since some services may have not been started on the nodes (plug the cables when &lt;code&gt;n0&lt;/code&gt; is ready).&lt;/p&gt;

&lt;h3 class="relative group"&gt;Install SkyDNS
 &lt;div id="install-skydns" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#install-skydns" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;For service discovery via DNS you should finally install the SkyDNS addon, but only when the cluster is running, i.e. the master must be up and listening. For this final step call:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ansible-playbook -i hosts skydns.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 class="relative group"&gt;Wrap Up
 &lt;div id="wrap-up" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#wrap-up" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This has become a rather long recipe. I re-did everything from scratch within 60 minutes, so this could be considered as a lower boundary (because I already did it several times :). The initial setup might be a bit flaky, but should be easy to fix. I&amp;rsquo;d love to hear your feedback on this, and maybe we get it more stable afterwards. Remember, that&amp;rsquo;s my first Ansible playbook :)&lt;/p&gt;
&lt;p&gt;Now go out, buy and setup your Kubernetes cluster and have fun :-)&lt;/p&gt;</description></item></channel></rss>