<?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: hatati</title>
    <description>The latest articles on DEV Community by hatati (@hatati).</description>
    <link>https://dev.to/hatati</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%2F226990%2F51f2b2b6-89a0-4985-a6f9-51bd91db2074.png</url>
      <title>DEV Community: hatati</title>
      <link>https://dev.to/hatati</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hatati"/>
    <language>en</language>
    <item>
      <title>Cook up a k3s cluster on Raspberry pies with Ansible</title>
      <dc:creator>hatati</dc:creator>
      <pubDate>Tue, 07 Mar 2023 21:49:00 +0000</pubDate>
      <link>https://dev.to/hatati/cook-up-a-k3s-cluster-on-raspberry-pies-with-ansible-4bb4</link>
      <guid>https://dev.to/hatati/cook-up-a-k3s-cluster-on-raspberry-pies-with-ansible-4bb4</guid>
      <description>&lt;p&gt;Cook up and scale a k3s Kubernetes cluster on Raspberry pies with a single command.&lt;/p&gt;

&lt;p&gt;All the code is available at my Github repo &lt;a href="https://github.com/hatati/PiClusterChef" rel="noopener noreferrer"&gt;PiClusterChef&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Install the Raspbian OS (64-bit) on your Raspberry Pies, connect them to your local network, give them a hostname, and enable their SSH servers. There is an excellent guide by w3Schools on how to do this &lt;a href="https://www.w3schools.com/nodejs/nodejs_raspberrypi.asp" rel="noopener noreferrer"&gt;here&lt;/a&gt;. (I prefer to use the official &lt;a href="https://www.raspberrypi.com/software/" rel="noopener noreferrer"&gt;Raspberry Pi Imager&lt;/a&gt; to flash the SD Cards instead of Etcher, which is used by w3schools, but you can use either.)&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://docs.ansible.com/ansible/latest/installation_guide/index.html" rel="noopener noreferrer"&gt;Ansible&lt;/a&gt; on your local machine. (I use the WSL 2 subsystem in Windows to run Ansible.)&lt;/li&gt;
&lt;li&gt;Install &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional&lt;/strong&gt;: Install &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Ansible setup and components
&lt;/h2&gt;

&lt;p&gt;To provision our cluster with ansible we need an &lt;em&gt;inventory&lt;/em&gt; file, &lt;em&gt;playbook&lt;/em&gt; file(s), and some initial SSH setup since ansible uses SSH to connect to nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inventory file
&lt;/h3&gt;

&lt;p&gt;In Ansible, the inventory file is a file that contains a list of target hosts or nodes that Ansible can manage. In this case, it will contain all our Raspberry Pis.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;workers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nerminworker1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ansible_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.66&lt;/span&gt;
      &lt;span class="na"&gt;ansible_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nermin&lt;/span&gt;

&lt;span class="na"&gt;masters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="c1"&gt;# This hostgroup is designed to only contains the initial bootstrap master node&lt;/span&gt;
&lt;span class="na"&gt;bootstrapMaster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nerminmaster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;ansible_host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;192.168.0.67&lt;/span&gt;
      &lt;span class="na"&gt;ansible_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nermin&lt;/span&gt;

&lt;span class="na"&gt;pies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;children&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;bootstrapMaster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;masters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;workers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vars&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;k3s_version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1.24.10+k3s1&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We have four groups in our setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bootstrapMaster&lt;/code&gt;: This is the first node that will get a k3s server and will create the token used by other nodes to register with the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;masters&lt;/code&gt;: These are the remaining k3s server nodes that will register themselves via the &lt;code&gt;bootstrapMaster&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;workers&lt;/code&gt;: These are the k3s worker/agent nodes that will run workloads in the cluster. They also register - themselves via the &lt;code&gt;bootstrapMaster&lt;/code&gt; and the generated k3s token.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;pies&lt;/code&gt;: This group contains all the masters and workers combined.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have two Raspberry Pis in my setup, even though the picture shows three. The third Raspberry Pi has another purpose not related to the k3s cluster. Both nodes have the user &lt;code&gt;nermin&lt;/code&gt;. &lt;code&gt;nermin&lt;/code&gt; is used to execute commands on each of the hosts. A single variable &lt;code&gt;k3s_version&lt;/code&gt; is used to determine which version of k3s we want to install.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSH connections
&lt;/h3&gt;

&lt;p&gt;Add your public SSH key to each Raspberry Pi to avoid being prompted for passwords when creating sessions.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-copy-id &amp;lt;user&amp;gt;@&amp;lt;host&amp;gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In this specific case:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-copy-id nermin@nerminmaster
&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-copy-id nermin@nerminworker1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can also use the IP address as the host instead of the hostname.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Make sure you have generated an SSH key pair in your WSL2 system. You can check by running:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; ~/.ssh/id_&lt;span class="k"&gt;*&lt;/span&gt;.pub


&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you don't see any files listed, you'll need to generate an SSH key pair. You can do this by running:&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-keygen


&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Follow the prompts to generate a new key pair. Make sure to keep your private key secure and do not share it with others.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Install Playbook
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;install-k3s-playbook.yaml&lt;/em&gt; file contains plays for installing k3s masters and workers on the Raspberry Pis. This includes enabling memory cgroups as required by the &lt;a href="https://docs.k3s.io/advanced#raspberry-pi" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. The playbook also retrieves the kubeconfig file from the bootstrap node and places it in the current directory with the name k3sconfig.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&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;Enable cgroups&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pies&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping hosts&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Check if cgroups are enabled&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cat /boot/cmdline.txt&lt;/span&gt;
    &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cmdlineContent&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;Enable cgroups&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sed -i -e 's/$/ cgroup_memory=1 cgroup_enable=memory/' /boot/cmdline.txt&lt;/span&gt;
    &lt;span class="na"&gt;when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;'cgroup_memory=1&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cgroup_enable=memory'&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;in&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;cmdlineContent.stdout"&lt;/span&gt;
    &lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Restart pi&lt;/span&gt;
  &lt;span class="na"&gt;handlers&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;Restart pi&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.reboot&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;Install k3s bootstrap server&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bootstrapMaster&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping host&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Install k3s bootstrap server&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION={{ k3s_version }} K3S_NODE_NAME={{ inventory_hostname }} K3S_KUBECONFIG_MODE="644" sh -s - server --cluster-init&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;Extract K3S_TOKEN from server output&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cat /var/lib/rancher/k3s/server/node-token&lt;/span&gt;
    &lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k3s_token&lt;/span&gt;
    &lt;span class="na"&gt;failed_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k3s_token is failed or k3s_token.stdout is undefined&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;Set K3S_TOKEN as a fact&lt;/span&gt;
    &lt;span class="na"&gt;set_fact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;k3s_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;k3s_token.stdout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&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;Install k3s servers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;masters&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping hosts&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Install k3s servers&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION={{ k3s_version }} K3S_URL=https://{{ hostvars['nerminmaster']['ansible_default_ipv4'].address }}:6443 K3S_TOKEN={{ hostvars['nerminmaster']['k3s_token'] }} K3S_NODE_NAME={{ inventory_hostname }} sh -s - server&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;Install k3s workers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;workers&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping hosts&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Install k3s workers&lt;/span&gt;
    &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION={{ k3s_version }} K3S_URL=https://{{ hostvars['nerminmaster']['ansible_default_ipv4'].address }}:6443 K3S_TOKEN={{ hostvars['nerminmaster']['k3s_token'] }} K3S_NODE_NAME={{ inventory_hostname }} sh -&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;Fetch k3s kubeconfig&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bootstrapMaster&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Fetch kubeconfig&lt;/span&gt;
    &lt;span class="na"&gt;fetch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/rancher/k3s/k3s.yaml&lt;/span&gt;
      &lt;span class="na"&gt;dest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k3sconfig&lt;/span&gt;
      &lt;span class="na"&gt;flat&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Uninstall Playbook
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;uninstall-k3s-playbook.yaml&lt;/em&gt; uninstalls the k3s services and scripts on each Raspberry Pi. This enables easy cleanup.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&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;Uninstall k3s on workers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;workers&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping hosts&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Uninstall k3s agent&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/k3s-agent-uninstall.sh&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;Uninstall k3s on servers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;masters&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping hosts&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Uninstall k3s server&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/k3s-uninstall.sh&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;Uninstall k3s on bootstrap servers&lt;/span&gt;
  &lt;span class="na"&gt;become&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bootstrapMaster&lt;/span&gt;
  &lt;span class="na"&gt;tasks&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;Ping hosts&lt;/span&gt;
    &lt;span class="na"&gt;ansible.builtin.ping&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;Uninstall k3s server&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/usr/local/bin/k3s-uninstall.sh&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Create the k3s cluster
&lt;/h2&gt;

&lt;p&gt;Now for the fun part. Create the k3s cluster by executing the install playbook:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;ansible-playbook &lt;span class="nt"&gt;-i&lt;/span&gt; inventory.yaml install-k3s-playbook.yaml


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it! The output should look like this (my Raspberry Pis have cgroups enabled and are therefore skipping that task):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

PLAY &lt;span class="o"&gt;[&lt;/span&gt;Enable cgroups] &lt;span class="k"&gt;******************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;*****************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Ping hosts] &lt;span class="k"&gt;**********************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Check &lt;span class="k"&gt;if &lt;/span&gt;cgroups are enabled] &lt;span class="k"&gt;****************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]
changed: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Enable cgroups] &lt;span class="k"&gt;******************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
skipping: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]
skipping: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]

PLAY &lt;span class="o"&gt;[&lt;/span&gt;Install k3s bootstrap server] &lt;span class="k"&gt;****************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;*****************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Ping host] &lt;span class="k"&gt;***********************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Install k3s bootstrap server] &lt;span class="k"&gt;****************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Extract K3S_TOKEN from server output] &lt;span class="k"&gt;********************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Set K3S_TOKEN as a fact] &lt;span class="k"&gt;*********************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

PLAY &lt;span class="o"&gt;[&lt;/span&gt;Install k3s servers] &lt;span class="k"&gt;*************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
skipping: no hosts matched

PLAY &lt;span class="o"&gt;[&lt;/span&gt;Install k3s workers] &lt;span class="k"&gt;*************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;*****************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Ping hosts] &lt;span class="k"&gt;**********************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Install k3s workers] &lt;span class="k"&gt;*************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nerminworker1]

PLAY &lt;span class="o"&gt;[&lt;/span&gt;Fetch k3s kubeconfig] &lt;span class="k"&gt;************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;

TASK &lt;span class="o"&gt;[&lt;/span&gt;Gathering Facts] &lt;span class="k"&gt;*****************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
ok: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

TASK &lt;span class="o"&gt;[&lt;/span&gt;Fetch kubeconfig] &lt;span class="k"&gt;****************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
changed: &lt;span class="o"&gt;[&lt;/span&gt;nerminmaster]

PLAY RECAP &lt;span class="k"&gt;*****************************************************************************************************************************************************************************************************************************************************************************&lt;/span&gt;
nerminmaster               : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10   &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;rescued&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
nerminworker1              : &lt;span class="nv"&gt;ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;6    &lt;span class="nv"&gt;changed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;2    &lt;span class="nv"&gt;unreachable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;failed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;skipped&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1    &lt;span class="nv"&gt;rescued&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0    &lt;span class="nv"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The playbook downloaded the kubeconfig file from the bootstrap master to the current directory on the local machine with the name &lt;em&gt;k3sconfig&lt;/em&gt;. The file looks like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&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;clusters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;certificate-authority-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://127.0.0.1:6443&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;default&lt;/span&gt;
&lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;default&lt;/span&gt;
&lt;span class="na"&gt;current-context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;Config&lt;/span&gt;
&lt;span class="na"&gt;preferences&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;users&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;default&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;client-certificate-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;client-key-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Replace the localhost IP in the &lt;code&gt;server&lt;/code&gt; value with the IP or hostname of the bootstrap master node.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&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;clusters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;certificate-authority-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://nerminmaster:6443&lt;/span&gt;  &lt;span class="c1"&gt;# &amp;lt;----- This value here.&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;default&lt;/span&gt;
&lt;span class="na"&gt;contexts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cluster&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;default&lt;/span&gt;
&lt;span class="na"&gt;current-context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&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;Config&lt;/span&gt;
&lt;span class="na"&gt;preferences&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{}&lt;/span&gt;
&lt;span class="na"&gt;users&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;default&lt;/span&gt;
  &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;client-certificate-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;
    &lt;span class="na"&gt;client-key-data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Verify that the cluster is up and running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get nodes &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; k3sconfig
NAME            STATUS   ROLES                       AGE     VERSION
nerminmaster    Ready    control-plane,etcd,master   8m42s   v1.24.10+k3s1
nerminworker1   Ready    &amp;lt;none&amp;gt;                      8m7s    v1.24.10+k3s1


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Success.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional: Deploy rancher server to k3s
&lt;/h2&gt;

&lt;p&gt;It would be nice if we had a UI we could use to view and manage our cluster. Rancher server comes with this UI!&lt;/p&gt;

&lt;p&gt;To deploy the Rancher server, execute the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="c"&gt;## CERT MANAGER&lt;/span&gt;

&lt;span class="c"&gt;# Add jetstack helm repo&lt;/span&gt;
helm repo add jetstack https://charts.jetstack.io
helm repo update

&lt;span class="c"&gt;# Create cert-manager namespace&lt;/span&gt;
kubectl create namespace cert-manager &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; k3sconfig

&lt;span class="c"&gt;# Install cert-manager&lt;/span&gt;
helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; cert-manager jetstack/cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; v1.8.2 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;installCRDs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; k3sconfig


&lt;span class="c"&gt;## RANCHER SERVER&lt;/span&gt;

&lt;span class="c"&gt;# Create cattle-system namespace&lt;/span&gt;
kubectl create ns cattle-system &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; k3sconfig

&lt;span class="c"&gt;# Add rancher-latest helm repo&lt;/span&gt;
helm repo add rancher-latest https://releases.rancher.com/server-charts/latest
helm repo update

&lt;span class="c"&gt;# Install rancher&lt;/span&gt;
helm upgrade &lt;span class="nt"&gt;--install&lt;/span&gt; rancher rancher-latest/rancher &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--version&lt;/span&gt; 2.7.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; cattle-system &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nb"&gt;hostname&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;nermin.cluster &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;replicas&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;rancherImageTag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;v2.7.2-rc5-linux-arm64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; k3sconfig


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Create a record in your hosts file that points to a worker node's IP. On Windows, this file is located at &lt;code&gt;C:/Windows/System32/drivers/etc/hosts&lt;/code&gt;. In the file, add the record:&lt;/p&gt;

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

192.168.0.66   nermin.cluster


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Notice that this domain is the same as the &lt;code&gt;hostname&lt;/code&gt; value in the Rancher chart.&lt;/p&gt;

&lt;p&gt;Go to the domain &lt;a href="//nermin.cluster"&gt;&lt;code&gt;nermin.cluster&lt;/code&gt;&lt;/a&gt;. There is not a trusted certificate, so the browser will warn us against an untrusted site. Press &lt;em&gt;Advanced&lt;/em&gt; and then &lt;em&gt;Continue to nermin.cluster (unsafe)&lt;/em&gt;. Now, you will enter the login page.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F520sf8vro5ejqnxwzfr1.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F520sf8vro5ejqnxwzfr1.png" alt="Rancher front page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To acquire the bootstrap password, run:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; cattle-system bootstrap-secret &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; go-template&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{{.data.bootstrapPassword|base64decode}}{{"\n"}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--kubeconfig&lt;/span&gt; k3sconfig

qstl5v7n4j6tmmr89rnhhb6qcf69krfljnwxm96sds2xpgbm4zp4zf


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Copy and paste the password into the input field, and you will be allowed to enter the Rancher server UI.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuinkz3m4es8pa6tgwron.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%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuinkz3m4es8pa6tgwron.png" alt="Rancher workloads"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Clean up
&lt;/h2&gt;

&lt;p&gt;Run the &lt;em&gt;uninstall-k3s-playbook&lt;/em&gt; to remove k3s from all the nodes:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;p&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ansible-playbook &lt;span class="nt"&gt;-i&lt;/span&gt; inventory.yaml uninstall-k3s-playbook.yaml&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Remarks&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;This setup allows easy scaling of the cluster up and down by only adding or removing master and worker nodes from the inventory file. However, there are some important points to be aware of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic IPs&lt;/strong&gt;: The Raspberry Pis have dynamic IPs on the local network, meaning that their IPs can change when their current IP lease expires. This can disrupt the execution of the playbook. Consider assigning static IPs to the nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local domain&lt;/strong&gt;: Because the &lt;code&gt;nermin.cluster&lt;/code&gt; domain has been defined in the hosts file, it can be resolved but only on the local machine. This is good for testing purposes, but if the cluster needs to be available to others on the same network, a real domain should be purchased and used.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Untrusted certificate&lt;/strong&gt;: The &lt;code&gt;nermin.cluster&lt;/code&gt; domain is only resolvable on the local machine. No certificate has been signed by a trusted party for this domain, and therefore, it isn't trusted by the browser. If you plan on allowing access to other users, you should change the domain and acquire a certificate. The &lt;a href="https://cert-manager.io/docs/" rel="noopener noreferrer"&gt;cert-manager&lt;/a&gt; chart can help you get free Let's Encrypt certificates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardcoded values&lt;/strong&gt;: In order to acquire information from the bootstrap node like its IP address and the k3s token, we reference them by hardcoding the hostname in the hostvars dict &lt;code&gt;hostvars['nerminmaster']&lt;/code&gt;. This means that a change to the hostname in the &lt;code&gt;bootstrapMaster&lt;/code&gt; group will make the playbook fail. A change in any of the places requires a change in both the &lt;em&gt;inventory.yaml&lt;/em&gt; and &lt;em&gt;install-k3s-playbook.yaml&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ansible</category>
      <category>k3s</category>
      <category>kubernetes</category>
      <category>rancher</category>
    </item>
    <item>
      <title>Automate working environment startup</title>
      <dc:creator>hatati</dc:creator>
      <pubDate>Sun, 24 Apr 2022 11:41:53 +0000</pubDate>
      <link>https://dev.to/hatati/automate-working-environment-startup-2635</link>
      <guid>https://dev.to/hatati/automate-working-environment-startup-2635</guid>
      <description>&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;It's 8 am and the working day has begun. You turn on your computer, open your mail program, open teams/skype, open your Notes, open your favorite IDE, open a text editor, and open terminals to different repos. You decide to grab a quick coffee, meanwhile, your colleague asks for help on a project, and you tell them you'll be right there as soon as your computer is ready. You open the browser and all the tabs that you need. The time registration software also needs to start. The boss asks about the progress on the crucial task he assigned you and you tell him that you'll get on it in a minute. You open up the company's issue tracker system and now you are finally ready to start working, and it's only 9 am! You go to help your colleague, but he says he is busy with meetings and that you can look at it together over lunch. Your boss asks why you are not at your desk and gives you are warning for slacking off at a crucial time for the company. You go back to your desk and can't wait to go home.&lt;/p&gt;

&lt;p&gt;Exaggeration? Yes. But while we can't easily automate the morning coffee we can automate our working environment. &lt;/p&gt;

&lt;h2&gt;
  
  
  How?
&lt;/h2&gt;

&lt;p&gt;Here's how to make your windows laptop automatically open Google Chrome, Outlook, Notepad++, a VS Code workspace, and a windows terminal with 2 tabs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Press &lt;code&gt;Win + r&lt;/code&gt; and type &lt;code&gt;shell:startup&lt;/code&gt;. This opens up the &lt;code&gt;C:\Users\&amp;lt;user&amp;gt;\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup&lt;/code&gt;. Shortcuts and scripts in this folder will be executed at startup.&lt;/li&gt;
&lt;li&gt;Copy shortcuts for Google Chrome, Outlook, and Notepad++ into the startup folder&lt;/li&gt;
&lt;li&gt;Create a &lt;code&gt;Startup.bat&lt;/code&gt; batch script that will open the terminal and VS Code Workspace and put it in the startup folder. Here's the code for this example:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;start wt -d C:\temp\project1 ; new-tab -d C:\temp\project2
code C:\temp\test-workspace.code-workspace
exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Startup folder now looks like this:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YNkZtgm4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6rq3l5rnxrayw42z38c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YNkZtgm4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p6rq3l5rnxrayw42z38c.png" alt="The Startup folder" width="871" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the next windows startup, all the files in the Startup folder will be executed automatically, making you ready to work immediately. By using batch files you can customize the startup process to fit your needs exactly:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cVdbnNgA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4c5j2fxnbnlvwlcjda0k.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cVdbnNgA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4c5j2fxnbnlvwlcjda0k.gif" alt="Windows Startup" width="800" height="450"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Note:
&lt;/h3&gt;

&lt;p&gt;A lot of application comes prebuilt with a &lt;em&gt;Run on startup&lt;/em&gt; feature that you should prefer instead of using the &lt;code&gt;Startup&lt;/code&gt; folder. You can see a list of all the applications that come with this feature under &lt;code&gt;Settings -&amp;gt; Apps -&amp;gt; Startup&lt;/code&gt;&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>windows</category>
      <category>efficiency</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
