<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anthony Wales</title>
    <description>The latest articles on DEV Community by Anthony Wales (@anton2079).</description>
    <link>https://dev.to/anton2079</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F232324%2F67349926-1996-4ccf-af21-cbf6c7559105.jpg</url>
      <title>DEV Community: Anthony Wales</title>
      <link>https://dev.to/anton2079</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anton2079"/>
    <language>en</language>
    <item>
      <title>Breaking News! Startup develops stronger architectural foundation by gathering requirements first!</title>
      <dc:creator>Anthony Wales</dc:creator>
      <pubDate>Thu, 07 Nov 2019 21:50:22 +0000</pubDate>
      <link>https://dev.to/shirtctl/breaking-news-startup-develops-stronger-architectural-foundation-by-gathering-requirements-first-84e</link>
      <guid>https://dev.to/shirtctl/breaking-news-startup-develops-stronger-architectural-foundation-by-gathering-requirements-first-84e</guid>
      <description>&lt;p&gt;The start of any project is exciting, and &lt;code&gt;shirtctl&lt;/code&gt; is no different. Last month Blair and I &lt;a href="https://dev.to/shirtctl/all-your-shirt-are-belong-to-us-55ji"&gt;announced&lt;/a&gt; we’re working a brand new project to bring continuous delivery to tech tees.&lt;/p&gt;

&lt;p&gt;We set out with a goal to help tech brands create and ship cool t-shirts reliably to their fans at any time. 👕👚&lt;/p&gt;

&lt;p&gt;From our experience, we know just how easy it is to get carried away with building technology solutions before we even understand our requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wDjGaPMi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/Hix8VmG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wDjGaPMi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/Hix8VmG.png" alt="Solutioning/Requirements Comic"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This article is a summary of the principles we developed throughout first #shirtday hack, and how they  informed certain architecture decisions. And since we’re building &lt;code&gt;shirtctl&lt;/code&gt; in the open, expect to see more posts about how we implement these as our project develops. &lt;/p&gt;

&lt;h2&gt;
  
  
  Our Mission:
&lt;/h2&gt;

&lt;p&gt;We make it super easy for companies to build their brand and connect with the community by harnessing the awesome power of t-shirts.  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How:&lt;/strong&gt;  Our MVP: For &lt;code&gt;shirtctl&lt;/code&gt; to work, we need to be able to join brands and fans together for the reliable transfer of merchandise. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bkzO7kDc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/dYQBw5I.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bkzO7kDc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/dYQBw5I.png" alt="Process Flow"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With our MVP defined, we had everything we need to consider what high level platform architecture decisions we would need to make to build a strong technology foundation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Requirement Principles:
&lt;/h2&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    * [Flexibility](#Flexibility)
    * [Relentless Focus](#Relentless-Focus)
    * [Security in Depth](#Secure)
    * [Frugal by Design](#Frugal-Architecture)
    * [Easy to Consume](#Easy-to-Consume)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Flexibility
&lt;/h3&gt;

&lt;p&gt;We are going to make mistakes. Our path, like any startup, is unclear. Recognising that we are only a small team, we have to live and breath the fail-fast approach to bring &lt;code&gt;shirtctl&lt;/code&gt; to life as soon as possible.&lt;/p&gt;

&lt;p&gt;If we need to change directions, we need to be able to do so quickly without having to rebuild from scratch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H-6Bc4py--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1200/1%2AJZ9i7JzobVeZbhoOODuPyA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H-6Bc4py--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1200/1%2AJZ9i7JzobVeZbhoOODuPyA.png" alt="Fail Fast"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://medium.com/@jocatorres/fail-fast-vs-learn-fast-f7912fdc12e4"&gt;Image Source&lt;/a&gt;



&lt;p&gt;&lt;strong&gt;Adopting Architectures:&lt;/strong&gt;&lt;br&gt;
Hybrid Cloud Architecture provides:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Rapid deployment.&lt;/li&gt;
&lt;li&gt;Horizontally scalable.&lt;/li&gt;
&lt;li&gt;Heavily automated.&lt;/li&gt;
&lt;li&gt;Standardisation.&lt;/li&gt;
&lt;li&gt;Minimum commitment (some services are billed per 100ms).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Continuous Delivery Architecture (Continuous Integration with Continuous Delivery):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Short software deployment cycles releasing software with greater speed and frequency.&lt;/li&gt;
&lt;li&gt;Incremental updates for patching and feature enhancement.&lt;/li&gt;
&lt;li&gt;Software release governance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Relentless Focus
&lt;/h3&gt;

&lt;p&gt;We know our main goal is to connect tech brands and their fans, not to host and manage infrastructure. We don’t have time to do the Design, Build and Run of a new infrastructure and platform service. In addition, the management overhead of a single tenancy wouldn't be time or cost effective. We are trying to shift as much as possible to managed services so we can worry just about &lt;code&gt;shirtctl&lt;/code&gt; and leave the rest to the to the infrastructure experts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dnqAOv2e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stxnext.com/media/filer_public_thumbnails/filer_public/64/0d/640d7abe-4899-4e28-8763-267737ef7737/serverless-architecture-comparisonpng__1920x1080_.png__680x383_q85_crop_subsampling-2_upscale.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dnqAOv2e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://stxnext.com/media/filer_public_thumbnails/filer_public/64/0d/640d7abe-4899-4e28-8763-267737ef7737/serverless-architecture-comparisonpng__1920x1080_.png__680x383_q85_crop_subsampling-2_upscale.jpg" alt="Serverless"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://stxnext.com/blog/2017/12/06/serverless-computing-explained-comparing-features-and-pricing-saas-iaas-paas/"&gt;Image Source&lt;/a&gt;



&lt;p&gt;&lt;strong&gt;Adopting Architectures:&lt;/strong&gt;&lt;br&gt;
Managed Cloud Architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Responsibility abstraction (just worry about the code, 'Serverless').&lt;/li&gt;
&lt;li&gt;Consumption based billing.&lt;/li&gt;
&lt;li&gt;Pre-architected building blocks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Serverless Architecture provides; outsourcing as much responsibility as possible so we can just worry about the code.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Security in Depth
&lt;/h3&gt;

&lt;p&gt;With cyberattacks on the rise, and increasing consumer awareness of the risks of personal information being exposed, we need a modern approach to security that is simple and effective. We want to keep &lt;code&gt;shirtctl&lt;/code&gt; free of traditional approaches to security that are prone to failure and costly to design, build and manage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5zbpQ3Vw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JETPq5E.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5zbpQ3Vw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/JETPq5E.png" alt="Secure"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://www.actiac.org/system/files/ACT-IAC%20Zero%20Trust%20Project%20Report%2004182019.pdf"&gt;Image Source&lt;/a&gt;



&lt;p&gt;&lt;strong&gt;Adopting Architectures:&lt;/strong&gt;&lt;br&gt;
Zero Trust Security Model:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An alternative security model to not trust anything remediating the rudimentary fault in traditional strategies to only protect from the outside.  In this architecture, every pillar is verified.&lt;/li&gt;
&lt;li&gt;All communication paths need to be encrypted especially for micro-services.&lt;/li&gt;
&lt;li&gt;Validation and authentication are performed between all services.&lt;/li&gt;
&lt;li&gt;Low cost with minimal special tooling required.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Frugal by Design
&lt;/h3&gt;

&lt;p&gt;As a super interesting side-project, &lt;code&gt;shirtctl&lt;/code&gt; has no funding to splurge on unnecessary expenses. Just like a 1990’s startup using the garage as an office, we’re using modern architectures for their opportunities to save big on cost and time. As a public cloud consumer, we’re capitalising on the opportunities that cloud presents to pay for only what we consume.&lt;/p&gt;

&lt;p&gt;We don’t expect to ever have to invest big in infrastructure development projects to enable our data lake or deployment pipeline, and just like we see the biggest disruptors changing their markets, we’re hoping it works for tech tees too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hwrGeQ4C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://solutionsreview.com/data-integration/files/2018/10/oie_wFhUpS8vKVmY.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hwrGeQ4C--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://solutionsreview.com/data-integration/files/2018/10/oie_wFhUpS8vKVmY.jpg" alt="Frugal Architecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://solutionsreview.com/data-integration/consumption-based-pricing-why-2019-will-be-the-year-to-align-value-with-investment/"&gt;Image Source&lt;/a&gt;



&lt;p&gt;&lt;strong&gt;Adopting Architectures:&lt;/strong&gt;&lt;br&gt;
Public Cloud Architectures:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Consumption based billing with some products such as serverless allowing you to only pay for the CPU/RAM cycles used to run the code not the OS and below.&lt;/li&gt;
&lt;li&gt;Free tier pricing for certain services to help get you started allowing for experimentation with different technologies ensuring you pick the best one.&lt;/li&gt;
&lt;li&gt;Startup credits to be used on any service allowing you to try services that have costs associated.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Easy to Consume
&lt;/h3&gt;

&lt;p&gt;With our small team and non-existant budget, we need &lt;code&gt;shirtctl&lt;/code&gt; to be usable by as many people as possible. So we’re starting out with a web app at &lt;a href="https://shirtctl.com"&gt;https://shirtctl.com&lt;/a&gt;. We think you’ll like it when ready. A lot.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zePexxXM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/600/0%2AQCqRjzCc_QPux8C7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zePexxXM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/600/0%2AQCqRjzCc_QPux8C7.png" alt="Multiplatform"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;a href="https://blog.kotlin-academy.com/lessons-from-my-first-multiplatform-kotlin-project-d4e311f15874?gi=af3e85f95689"&gt;Image Source&lt;/a&gt;



&lt;p&gt;&lt;strong&gt;Adopting Architectures:&lt;/strong&gt;&lt;br&gt;
Web App Architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Availability to be accessed over the internet.&lt;/li&gt;
&lt;li&gt;Compatibility with many different platforms and devices.&lt;/li&gt;
&lt;li&gt;Very low time to get your product into the hands of your potential consumers.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>devops</category>
      <category>startup</category>
      <category>architecture</category>
      <category>requirements</category>
    </item>
    <item>
      <title>Kubernetes (K8s) Private Cloud with Raspberry Pi 4s</title>
      <dc:creator>Anthony Wales</dc:creator>
      <pubDate>Mon, 23 Sep 2019 23:43:32 +0000</pubDate>
      <link>https://dev.to/anton2079/kubernetes-k8s-private-cloud-with-raspberry-pi-4s-k0d</link>
      <guid>https://dev.to/anton2079/kubernetes-k8s-private-cloud-with-raspberry-pi-4s-k0d</guid>
      <description>&lt;p&gt;Deploying a Kubernetes cluster on a public cloud provider is easy, but what if you want a private bare-metal deployment?  This walk-through will go through the steps I took (and why we need to do them) in order to have a private Kubernetes cluster at home.&lt;/p&gt;

&lt;p&gt;Kubernetes enables you to have the flexibility to move your workload where it is best suited.  The most common reasons I hear are; latency, performance (special hardware requirements) and security (regulation or data governance).  This compliments the hybrid cloud story and in my career it has become more apparent that my customers see this as well to help them resolve issues like; cost, availability and compliance.  In parallel software vendors are starting to embrace containers as a standard deployment model leading to a recent increase in requests for container solutions.&lt;/p&gt;

&lt;p&gt;As you can see in the workflow comparison below, there is greater room for error when deploying on-premises.  Public clouds provide the automation and reduces the risk of error as less steps are required.  But as mentioned above, private cloud provides you more options when you have unique requirements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fnd7PEe4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fnd7PEe4.png" alt="Deployment Steps"&gt;&lt;/a&gt;&lt;/p&gt;
Workflow comparison for deploying Kubernetes on or off premises



&lt;p&gt;To help people understand some of the pitfalls and challenges with on-premises Kubernetes/Container deployments, below is a guide to help you build your own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F2OheyZE.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F2OheyZE.png" alt="Main Picture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"A cloud you can touch!"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  What you will need
&lt;/h4&gt;

&lt;p&gt;Compute:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.raspberrypi.org/products/raspberry-pi-4-model-b/" rel="noopener noreferrer"&gt;4 x Raspberry Pi 4 - 2GB RAM&lt;/a&gt; &lt;em&gt;[2GB+ RAM is recommended as we are deploying K8s not K3s]&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Storage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.sandisk.com.au/home/memory-cards/microsd-cards/extreme-microsd" rel="noopener noreferrer"&gt;4 x 32GB High Speed Sand-disk Micro-SD Cards&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Network:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.raspberrypi.org/products/poe-hat/" rel="noopener noreferrer"&gt;4 x Raspberry Pi POE HAT&lt;/a&gt; &lt;em&gt;[Optional if you don't want to provide USB power to the Raspberry Pi]&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;1 x Network Switch &lt;em&gt;[POE Capability is only required if using Raspberry Pi POE HAT]&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;1 x Network Router&lt;/li&gt;
&lt;li&gt;5 x Ethernet Cables&lt;/li&gt;
&lt;li&gt;1 x Keyboard, HDMI, Mouse (for initial setup only)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Other:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DNS Server &lt;em&gt;[Optional if you want to provide round robin infrastructure resiliency]&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Walk Through
&lt;/h1&gt;

&lt;h4&gt;
  
  
  Initial Raspberry Pi Configuration
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Flash Raspbian&lt;br&gt;
Refer to the Raspbian Installation guide by Raspberry Pi Foundation&lt;br&gt;
&lt;a href="https://www.raspberrypi.org/documentation/installation/installing-images/README.md" rel="noopener noreferrer"&gt;https://www.raspberrypi.org/documentation/installation/installing-images/README.md&lt;/a&gt;&lt;br&gt;
In short:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Download image from the link above&lt;/li&gt;
&lt;li&gt;Use balenaEtcha to flash image onto micro-SD card&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Perform Initial Setup on Boot on startup screen (this will require keyboard, video and mouse to be connected)&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.raspberrypi.org%2Fapp%2Fuploads%2F2018%2F06%2Fpiwiz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.raspberrypi.org%2Fapp%2Fuploads%2F2018%2F06%2Fpiwiz.gif" alt="Welcome to Raspberry Pi"&gt;&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;
Source: RaspberryPi.org



&lt;ul&gt;
&lt;li&gt;Choose Country, Language, Timezone&lt;/li&gt;
&lt;li&gt;Define new password for user 'pi'&lt;/li&gt;
&lt;li&gt;Connect to WiFi or skip if using ethernet&lt;/li&gt;
&lt;li&gt;Skip update software (this caused my Raspberry Pi to hang, not sure if there's currently a bug.  We will perform this activity manually later).&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose restart later&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure Additional Settings
Click the Raspberry Pi icon (top left of screen) &amp;gt; Preferences &amp;gt; Raspberry Pi Configuration
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fvvn5QWc.jpg" alt="Configure Raspberry Pi System"&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;System&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure Hostname&lt;/li&gt;
&lt;li&gt;Boot: To CLI&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Interfaces&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH: Enable&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Choose restart later&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Configure Static Network
Perform one of the following:&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Define Static IP on Raspberry Pi: Right Click the arrow logo top right of screen and select 'Wireless &amp;amp; Wired Network Settings'&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Define Static IP on DHCP Server: Configure your DHCP server to define a static IP on the Raspberry Pi Mac Address.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reboot and Test SSH&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Username: pi&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Password: Defined in step 2 above&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;On Terminal: &lt;code&gt;ssh pi@[IP Address]&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fk3aIf01.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fk3aIf01.gif" alt="SSH Login GIF"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Repeat steps for all of the Raspberry Pis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Kubernetes Cluster Preparation (via SSH)
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Perform Updates

&lt;ul&gt;
&lt;li&gt;apt-get update: Updates the package indexes&lt;/li&gt;
&lt;li&gt;apt-get upgrade: Performs the upgrades
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  sudo apt-get update
  sudo apt-get upgrade
  sudo reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Configure Net.IP4.IP configuration
Edit &lt;code&gt;sudo vi /etc/sysctl.conf&lt;/code&gt;, uncomment &lt;code&gt;net.ipv4.ip_forward = 1&lt;/code&gt; and add &lt;code&gt;net.ipv4.ip_nonlocal_bind=1&lt;/code&gt;.

&lt;ul&gt;
&lt;li&gt;Note: This is required to allow for traffic forwarding, for example Node Ports from containers to/from non-cluster devices.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FVD3DIgQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FVD3DIgQ.png" alt="Example sysctl.conf"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Install Docker
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -sSL get.docker.com | sh &amp;amp;&amp;amp; sudo usermod pi -aG docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Disable Swap

&lt;ul&gt;
&lt;li&gt;You can verify this before/after reboot with the &lt;code&gt;top&lt;/code&gt; command, on the top left corner next to MiB Swap should be 0.0.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo systemctl disable dphys-swapfile.service
sudo reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYjJ4Ih4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FYjJ4Ih4.png" alt="Top Output"&gt;&lt;/a&gt;&lt;/p&gt;
SSH Session Screen after `top` command



&lt;ul&gt;
&lt;li&gt;Install Kubernetes

&lt;ul&gt;
&lt;li&gt;Currently forcing the previous version (1.15.3), ran into compatibility issues with the most recent version (1.16).&lt;/li&gt;
&lt;li&gt;There shouldn't be any errors, however during my installation the repos were down and I had to retry in a few hours.
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | \
sudo apt-key add - &amp;amp;&amp;amp; echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" | \
sudo tee /etc/apt/sources.list.d/kubernetes.list &amp;amp;&amp;amp; sudo apt-get update -q

sudo apt-get install -qy kubelet=1.15.3-00 kubectl=1.15.3-00 kubeadm=1.15.3-00
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Repeat steps for all of the Raspberry Pis.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Kubernetes Master Node Configuration
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Note: You only need to do this for the master node (in this deployment I recommend only 1 master node).  Each Raspberry Pi is a node.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initiate Master Node
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo kubeadm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Enable Connections to Port 8080

&lt;ul&gt;
&lt;li&gt;Without this Kubernetes services won't work
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add Container Network Interface (CNI)

&lt;ul&gt;
&lt;li&gt;I've chosen to use Weaver, however you can get others working such as Flannel (I've verified this works with this cluster)
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCh4WCqZ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FCh4WCqZ.png" alt="Apply Weaver"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Get Join Command

&lt;ul&gt;
&lt;li&gt;This will be used in the next section to join the worker nodes to the cluster.  It will return something like: &lt;code&gt;kubeadm join 192.168.0.101:6443 --token X.Y     --discovery-token-ca-cert-hash sha256:XYZ&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubeadm token create --print-join-command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Kubernetes Worker Node Configuration
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Note: You only need to do this for the worker nodes (in this deployment I recommend 3 worker node).&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Join Cluster

&lt;ul&gt;
&lt;li&gt;Use the join command provided at the end of the previous section
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo kubeadm join 192.168.0.101:6443 --token X.Y \
--discovery-token-ca-cert-hash sha256:XYZ 
#Example Only
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Verify Node Added Successfully (SSH on Master Node)

&lt;ul&gt;
&lt;li&gt;Should have status ready after ~30 seconds
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get nodes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjEB2Nmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjEB2Nmv.png" alt="Get Nodes View"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  First Deployment and Service
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Note: We will perform the deployment via SSH on the Master Node.  Below are two ways to deploy the deployment and service; using either YAML or single line commands.  YAML allows for easier complex actions while single line commands can be used for simple actions but for this example it will be the same outcome.&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deploy NGINX (Option A: Simple)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create deployment nginx --image=nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deploy NGINX (Option B: YAML)

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl apply -f nginx.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#nginx.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-deployment&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Testing NGINX
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnVN129E.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnVN129E.png" alt="Get Deployments Screenshot"&gt;&lt;/a&gt;&lt;/p&gt;
List of running deployments



&lt;ul&gt;
&lt;li&gt;Deploy Node Port Service (Option A: Simple)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create service nodeport nginx --tcp=80:80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Deploy Node Port Service (Option B: YAML)

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl apply -f nginxservice.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#nginxservice.yaml&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Testing Node Port Service
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FFvTkpIn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FFvTkpIn.png" alt="Get Services"&gt;&lt;/a&gt;&lt;/p&gt;
List of running services



&lt;ul&gt;
&lt;li&gt;Testing Nginx (from your laptop or anything with connectivity to the cluster)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl [IP address of any node (RPi)]:[Port by the Node Port]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FejWZeBq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FejWZeBq.png" alt="Get HTML Curl"&gt;&lt;/a&gt;&lt;/p&gt;
Result of curl request.



&lt;h4&gt;
  
  
  DNS A Round Robin
&lt;/h4&gt;

&lt;p&gt;As a form of load balancer, I chose to use DNS A Record Round Robbin.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added entries for a shared hostname and pointed it to all the IP addresses of the nodes.

&lt;ul&gt;
&lt;li&gt;Note: The CNI creates a VXLAN network that allows all hosts to redirect to the container which hosts the container via the defined Node Port.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  A Few Lessons Learnt
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Require sandpits for testing

&lt;ul&gt;
&lt;li&gt;Without proper testing prior to deploying, updating any of the container components might fail.  I saw this with the incompatibility of Kubernetes v1.16 with Weaver (hence the v1.15.3 install).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Auxiliary/Supporting Services requires additional effort

&lt;ul&gt;
&lt;li&gt;Public clouds provide ready to go managed supporting services such as load balancing, DNS, container registries, user authentication etc.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Additional work arounds required

&lt;ul&gt;
&lt;li&gt;Not just one click deployment, workarounds maybe required depending on the infrastructure.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>raspberrypi</category>
      <category>cluster</category>
      <category>raspbian</category>
    </item>
  </channel>
</rss>
