<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>– Code Blind Blog</title><link>https://codeblind-ai.github.io/blog/</link><description>Recent content in Code Blind Blog on</description><generator>Hugo -- gohugo.io</generator><language>en</language><atom:link href="https://codeblind-ai.github.io/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Blog: ↩️ Securing communication in Transit</title><link>https://codeblind-ai.github.io/blog/2024/04/02/%EF%B8%8F-securing-communication-in-transit/</link><pubDate>Tue, 02 Apr 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/04/02/%EF%B8%8F-securing-communication-in-transit/</guid><description>
&lt;p>Greetings tech enthusiasts and developers! Today, we continue our journey to secure services running on our Mighty Pi Cloud. This post digs into the details of ensuring we keep private communication private introducing CloudFlare using Let&amp;rsquo;s Encrypt certificates into our setup.&lt;/p>
&lt;style>
aside {
width: 40%;
padding-left: 0.5rem;
margin-left: 0.5rem;
float: right;
box-shadow: inset 5px 0 5px -5px #29627e;
font-style: italic;
color: #29627e;
}
aside > p {
margin: 0.5rem;
}
summary {
font-weight: bold;
font-size: 1.1em;
}
details > summary {
list-style-type: 'ℹ️ ';
color: #666666;
}
details[open] > summary {
list-style-type: 'ℹ️ ';
color: #333333;
}
table {
margin-left: 30px;
}
&lt;/style>
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/eaves-dropping.jpeg" alt="Home Lab" style="width: 50%; display: block; margin-left: auto; margin-right: auto;">
&lt;br/>
&lt;p>The journey to secure our services running on our RPi5 MicroK8s cluster is both nostalgic and illuminating. Back in my college days, a group of us experimented with network sniffers using libpcap, a groundbreaking technology at the time. Security was a whimsical concept then — or should I say really nonexistent. Placing a computer Network Interface Card (NIC) in &lt;a href="https://www.blumira.com/glossary/promiscuous-mode/#:~:text=Promiscuous%20mode%20is%20a%20type,adapters%20operating%20in%20this%20mode.">promiscuous mode&lt;/a> allowed us to listen to all traffic on the Local Area Network (LAN). If you can believe, most internet traffic traversed using Hypertext Transfer Protocol (HTTP), with sites often employing Basic Authentication for username and password login — essentially transmitting sensitive information in plain text across the network and around the globe! It was interesting times indeed! 😱&lt;/p>
&lt;p>Fortunately, the landscape evolved, and HTTPS (Hypertext Transfer Protocol Secure) emerged as the de facto standard for web communication, with major pushes for its adoption beginning in the mid-2000s. In July of 2018 Google released &lt;a href="https://www.thesslstore.com/blog/google-chrome-68-https-mandatory/">Chrome 68&lt;/a>, which marked all HTTP only sites as &lt;code>&amp;quot;Not Secure&amp;quot;&lt;/code> in the browser&amp;rsquo;s address bar. This embarrassment applied significant pressure on website owners to transition to HTTPS.&lt;/p>
&lt;p>Today, ensuring that our services support HTTPS and Transport Layer Security (TLS) is monitory. HTTPS adds an essential layer of security to the standard HTTP protocol by encrypting data exchanged between clients (such as web browsers) and servers (such as websites), safeguarding sensitive information such as login credentials, credit card details, and personal healthcare information.&lt;/p>
&lt;p>In this post, we explore how we enhance the CIA of our environment, but using Let&amp;rsquo;s Encrypt certificates for TLS, and improve our security posture by adding Cloudflare in front our our platform.&lt;/p>
&lt;h3 id="cloud-cia-confidentiality-integrity-and-availability">Cloud CIA: Confidentiality, Integrity, and Availability&lt;/h3>
&lt;p>Before we proceed, let&amp;rsquo;s touch on the fundamental principles of information security — &lt;code>Confidentiality&lt;/code>, &lt;code>Integrity&lt;/code>, and &lt;code>Availability&lt;/code> (CIA). These principles guide the design, implementation, and maintenance of secure systems.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Confidentiality&lt;/strong>: focuses on ensuring that sensitive information remains accessible only to authorized individuals or systems, preventing unauthorized access or disclosure.&lt;/li>
&lt;li>&lt;strong>Integrity&lt;/strong>: focuses on maintaining the accuracy and trustworthiness of data throughout its lifecycle, protecting it from unauthorized modification or corruption.&lt;/li>
&lt;li>&lt;strong>Availability&lt;/strong>: focuses on ensuring that information and resources are accessible and usable when needed by authorized users, emphasizing system uptime, reliability, and recovery in the situation of massive disaster (like burning down the house).&lt;/li>
&lt;/ul>
&lt;h3 id="transport-layer-security-tls-in-action">Transport Layer Security (TLS) in Action&lt;/h3>
&lt;p>TLS is a cryptographic protocol at the heart of secure communication over networks, playing a pivotal role in keeping our data secret while in transit. It ensures privacy, data integrity, and authentication between communicating applications. Let&amp;rsquo;s break down its key components and functionalities:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Encryption&lt;/strong>: TLS encrypts data exchanged between clients and servers, preventing unauthorized parties from intercepting and reading sensitive information.&lt;/li>
&lt;li>&lt;strong>Data Integrity&lt;/strong>: It verifies that data remains unchanged during transmission, using cryptographic hash functions to detect any tampering attempts.&lt;/li>
&lt;li>&lt;strong>Authentication&lt;/strong>: TLS allows both parties to authenticate each other&amp;rsquo;s identities, mitigating the risk of man-in-the-middle attacks.&lt;/li>
&lt;li>&lt;strong>Session Establishment&lt;/strong>: Before data exchange, TLS establishes a secure session, negotiating cryptographic algorithms and other parameters.&lt;/li>
&lt;/ul>
&lt;h3 id="why-use-cloudflare">Why use Cloudflare?&lt;/h3>
&lt;p>Using Cloudflare can significantly enhance the availability aspect of the CIA (Confidentiality, Integrity, and Availability) security triad in several ways:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>DDoS Protection&lt;/strong>: Cloudflare provides robust Distributed Denial of Service (DDoS) protection, which helps ensure the availability of our services by mitigating large-scale attacks that could otherwise overwhelm your infrastructure. By leveraging Cloudflare, we can maintain the availability of our services even under heavy attack.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>DNS Management:&lt;/strong> Cloudflare&amp;rsquo;s DNS management services provide advanced features such as DNSSEC (Domain Name System Security Extensions) and Anycast routing, which improve the availability and security of the DNS infrastructure. This helps us mitigate DNS-related attacks, such as DDoS attacks and DNS spoofing.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Cloudflare&amp;rsquo;s had a much larger, comprehensive suite of security and performance solutions - however for the purpose of this article, these two features help us achieve the CIA level protection we need.&lt;/p>
&lt;h1 id="rpi5-cloud-saas-lab-design-overview">RPi5 Cloud SaaS Lab: Design Overview&lt;/h1>
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/basic-overview.png" alt="Home Lab" style="width: 80%; display: block; margin-left: auto; margin-right: auto;">
&lt;p>Currently, our &amp;ldquo;Might RPi Cloud Lab&amp;rdquo; looks a lot like the diagram above. It is a cluster of Raspberry Pi5 nodes running Kubernetes - with Load Balancer support provided by MetalLB.&lt;/p>
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/detailed-overview.png" alt="Lab Design Plan" style="width: 80%; display: block; margin-left: auto; margin-right: auto;">
&lt;p>In the diagram above, we define the plan of this blog - which is a little intimidating to look at - so lets break it down.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Users&lt;/strong> will gain access to the system by visiting a platform application at &lt;code>app.codeblind.ai&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Cloudflare&lt;/strong> provides DNS resolution for the users, and provides the platform with DDoS protection, DNS management, Content Delivery Network (CDN), Web Application Firewall (WAF), SSL/TLS encryption, and analytics. This enables us to secure our communication and gain insights into our website traffic effortlessly.&lt;/li>
&lt;li>&lt;strong>Github&lt;/strong> provides hosting for our frontend(s) which are designed as static SPA sites so they are fast, and don&amp;rsquo;t require server side rendering.&lt;/li>
&lt;li>&lt;strong>Home Router&lt;/strong> provides the cluster access to the internet, and provides a firewall for isolating the cluster network from the internet. We will configure a single port forwarding rule to allow HTTPS communications to hit any of our Kubernetes services hosted in our cluster.&lt;/li>
&lt;li>&lt;strong>Let&amp;rsquo;s Encrypt (LE)&lt;/strong> is used to provide us free x802.11 certificates for TLS encryption tied to our domain names.&lt;/li>
&lt;li>&lt;strong>Certificate Issuer&lt;/strong> (or Issuers) are Kubernetes resources (CRD) that represent certificate authorities (CAs) that are able to generate signed certificates and honor certificate signing requests. Together with the &lt;code>cert-manager&lt;/code> we can ensure the certificates are rotated automatically as we - saving us from performing the task manually.&lt;/li>
&lt;li>&lt;strong>Acme&lt;/strong> is the LE extension to the Certificate Issuer which will handle the LE interaction for us.&lt;/li>
&lt;li>&lt;strong>DSN-01&lt;/strong> is the extension in the Certificate Issuer which will add TXT records to the DNS management system in Cloudflare as we add new services with real domain names.&lt;/li>
&lt;li>&lt;strong>Certificate&lt;/strong> is a persistent resource request for a certificate from one of the system Issuers (LE in this case). This certificate will be bound with our domain name.&lt;/li>
&lt;li>&lt;strong>Ingress&lt;/strong> is point of incoming traffic, and the TLS termination endpoint for HTTPS requests. It decrypts the data and forwards it internally as HTTP traffic. In an ideal world, we would want the traffic encrypted until it reaches the target service (or musting mutual TLS between services). However that is a much more complicate setup which we will get to later.&lt;/li>
&lt;li>&lt;strong>Service&lt;/strong> s a logical abstraction for a deployed group of pods in a cluster (which all perform the same function). Since pods are ephemeral, a service enables a group of pods, which provide specific functions (web services, image processing, etc.) to be assigned a name and unique IP address (Read IP in our case thanks to &lt;a href="https://metallb.universe.tf/">MetalLB&lt;/a>).&lt;/li>
&lt;li>&lt;strong>Deployment (Pods)&lt;/strong> A Deployment provides declarative updates for Pods and ReplicaSets. A ReplicaSet&amp;rsquo;s purpose is to maintain a stable set (number) of Pods running at any given time. It is often used to guarantee the availability of a service. A Pod is a group of one or more containers, with shared storage and network resources, and a specification for how to run the containers.&lt;/li>
&lt;/ul>
&lt;p>Putting this all together, we should be able to provide a secure and highly available API service for the frontend SPA. Let&amp;rsquo;s get building.&lt;/p>
&lt;h2 id="private-saas-cloud-lets-build-something">Private SaaS Cloud: Let&amp;rsquo;s build something!&lt;/h2>
&lt;h3 id="1-dns-provisioning">1. DNS Provisioning&lt;/h3>
&lt;p>To realize the architecture above we first need to start at the CloudFlare and our Domain Name Provider.&lt;/p>
&lt;p>If you don&amp;rsquo;t have an account, create one - it is free for hobby projects (❤️ Thank you cloudflare). Next you need to configure CloudFlare to provide DNS resolution for your domain name. They have a &lt;a href="https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/">fantastic guide in their documentation&lt;/a> which has specialized instructions for most Domain Name Registrars; so I won&amp;rsquo;t repeat it here.&lt;/p>
&lt;p>Hurry and complete that configuration&amp;hellip; I will wait 😊&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong> this setup assumes you have already deployed a static site on github pages. During that process you mapped your DNS to point to your site at the registrar, and in github pages for a custom domain name (codeblind.ai in my case). When we configure SSL on Cloudflare - we would normally set &lt;code>full or strict&lt;/code> mode to ensure no &lt;a href="https://developers.cloudflare.com/ssl/troubleshooting/too-many-redirects/#:~:text=Redirect%20loops%20will%20occur%20if,configured%20at%20your%20origin%20server">routing loops&lt;/a>). However when using our private cloud we will run into a few issues which we resolve later. You have been warned&amp;hellip;&lt;/p>
&lt;/blockquote>
&lt;h3 id="2-define-port-forwarding-in-your-home-router">2. Define Port Forwarding in your Home Router&lt;/h3>
&lt;p>Any guide I provide here is likely to not work for your specific case. I recommend looking at your router, and hopefully admin login information is available on a sticker on the router itself.&lt;/p>
&lt;p>Once you login, with a bit of luck you will find two things:&lt;/p>
&lt;ol>
&lt;li>The Dynamic Host Configuration Protocol (&lt;strong>DHCP&lt;/strong>) Classless Inter-Domain Routing (&lt;strong>CIDR&lt;/strong>) &lt;strong>range&lt;/strong>. Also known as the DHCP IP ranges assigned to your home network. In the earlier post when configuring metallb, you would have reduced the range so that metalLB can own a segment.&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong> this guide assume you have that configured correctly. Since this is our first service, metalLB will chose the first address in the reserved range.&lt;/p>
&lt;/blockquote>
&lt;ol start="2">
&lt;li>&lt;strong>Port forwarding or Firewall Configuration&lt;/strong>. Here you will make sure to port forward to the first expected IP address assigned by metalLB, and allow port 80 and 443 to pass through from any address.&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;strong>Note&lt;/strong> from a security standpoint, and operations standpoint this is not ideal. We don&amp;rsquo;t want to have to isolate ranges of IPs, nor open up firewall rules for each service we deploy. In a later post we will remove this burden by using &lt;code>Cloudflare Tunnels&lt;/code>. However that will have to wait, we are busy learning after all&amp;hellip;&lt;/p>
&lt;/blockquote>
&lt;h3 id="3-installing-cert-manager-on-microk8s-to-automate-certificate-management">3. Installing cert-manager on MicroK8s to automate certificate management&lt;/h3>
&lt;p>Our MicroK8s cluster provides us the ability to start applications, but until now we have not needed to secure communication.&lt;/p>
&lt;p>In Kubernetes, &lt;a href="https://cert-manager.io/docs/">cert-manager&lt;/a> can be used to automate the creation of certificates for TLS workloads in our Kubernetes cluster &lt;em>and renews the certificates before they expire.&lt;/em>&lt;/p>
&lt;p>&lt;code>cert-manager&lt;/code> setup on MicroK8s is a breeze, simple run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>microk8s &lt;span style="color:#204a87">enable&lt;/span> cert-manager
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Alternatively (note I did this), you could use the official installation by running:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.14.4/cert-manager.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>This command fetches the YAML manifest for cert-manager from the official &lt;a href="https://github.com/jetstack/cert-manager">Jetstack GitHub repository&lt;/a> and applies it to your Kubernetes cluster. Find the latest release version available, on the releases page, and replace it in URL (eg. &lt;code>v1.14.4&lt;/code>) before running the command.This way you don&amp;rsquo;t have to worry about an old version supplied by MicroK8S.&lt;/p>
&lt;/blockquote>
&lt;h3 id="4-enabling-nginx-ingress-controller-for-routing-traffic-to-our-services">4. Enabling NGINX Ingress controller for routing traffic to our services.&lt;/h3>
&lt;p>MicroK8s provides a ready to use NGINX &lt;code>Ingress&lt;/code> controller. You can enable it by running:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>microk8s &lt;span style="color:#204a87">enable&lt;/span> ingress
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Using the built in &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/">ingress&lt;/a> gives you a well configured NGINX ingress controller and a compatible internal dns configuration for network communication between pods. Note there are many different &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/">ingress controllers available&lt;/a>, but NGINX will work find for what we need to accomplish today.&lt;/p>
&lt;h3 id="5-configuring-a-clusterissuer-and-certificate-resource-for-lets-encrypt-integration">5. Configuring a ClusterIssuer and Certificate resource for Let&amp;rsquo;s Encrypt integration.&lt;/h3>
&lt;p>&lt;strong>So far, setup has hopefully been very easy. Now the fun begins&lt;/strong>. 🙈&lt;/p>
&lt;p>We first need to create a &lt;code>ClusterIssuer&lt;/code>. A ClusterIssuer is a microservice in the cluster which another service can use to &lt;em>allocate&lt;/em> a certificate.&lt;/p>
&lt;p>We will use Let&amp;rsquo;s Encrypt (LE) so we get trusted certificates for free. There are two ways to get verified before a certificate is issued:&lt;/p>
&lt;ol>
&lt;li>HTTP challenge - which means LE must be able to hit the address requesting the certificate. We could use this since we have the github page, but I don&amp;rsquo;t want to tie that to the backend.&lt;/li>
&lt;li>&lt;a href="https://letsencrypt.org/docs/challenge-types/">DNS-01 challenge&lt;/a>. This challenge asks us to prove that we control the DNS for the domain name by putting a specific value in a TXT record under that domain name. With the correct configuration, we can have our Certificate Issuer add this TXT value itself - managing the DNS records at Cloudflare.&lt;/li>
&lt;/ol>
&lt;h4 id="51-getting-your-cloudflare-api-token">5.1 Getting your CloudFlare API Token&lt;/h4>
&lt;p>To allow the &lt;code>ClusterIssuer&lt;/code> to modify records at Cloudflare, we must provide it with an API Key with enough permissions to modify the DNS records for the domain.&lt;/p>
&lt;ol>
&lt;li>Go to your &lt;a href="https://dash.cloudflare.com/profile/api-tokens/">domain dashboard&lt;/a>&lt;/li>
&lt;li>Select Create Token.&lt;/li>
&lt;li>Select &amp;ldquo;Edit Zone DNS template&amp;rdquo;
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/token-creation-1.png">&lt;/li>
&lt;li>Configure &lt;code>Zone:DNS:Edit&lt;/code> and &lt;code>Include:Specific Zone:{your domain name}&lt;/code>
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/token-creation-2.png">&lt;/li>
&lt;li>Select Continue to summary&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;strong>IMPORTANT&lt;/strong> save this token somewhere safe. You will need it in the next step&lt;/p>
&lt;/blockquote>
&lt;h4 id="52-create-a-kubernetes-secret-for-the-certificateissuer">5.2 Create a Kubernetes Secret for the CertificateIssuer&lt;/h4>
&lt;p>Assuming you are going to place the Certificate Issuer in the &lt;code>cert-manager&lt;/code> namespace, do the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl create secret &lt;span style="color:#4e9a06">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">&lt;/span> -n cert-manager &lt;span style="color:#4e9a06">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">&lt;/span> generic cloudflare-api-key-secret &lt;span style="color:#4e9a06">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">&lt;/span> --dry-run&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>client &lt;span style="color:#4e9a06">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">&lt;/span> -o yaml &lt;span style="color:#4e9a06">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">&lt;/span> --from-literal&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>api-key&lt;span style="color:#ce5c00;font-weight:bold">={&lt;/span>YOUR API KEY GOES HERE&lt;span style="color:#ce5c00;font-weight:bold">}&lt;/span> &lt;span style="color:#000;font-weight:bold">|&lt;/span> tee issuer-secret.yaml &lt;span style="color:#000;font-weight:bold">|&lt;/span> kubectl apply -f -
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;details>
&lt;summary>Whats going on here&lt;/summary>
&lt;ol>
&lt;li>
&lt;p>&lt;code>--dry-run&lt;/code> flag prepares the secret (encodes it to base64) and then the &lt;code>-o yaml&lt;/code> outputs the yaml file configuration.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>by piping to &lt;code>tee&lt;/code> we are saving the secret for cleanup later.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>by piping the output of &lt;code>tee&lt;/code> to &lt;code>kubectl apply&lt;/code>, we create the secret&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Note, later we will reference the secret by the name &lt;code>cloudflare-api-key-secret&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Additionally, Notice it is added to &lt;code>cert-manager&lt;/code> namespace. This is because _secrets are only accessible from the namespace that they are stored in. Since this is needed by the &lt;code>cluster issuer&lt;/code>, and we place it in the &lt;code>cert-manager&lt;/code> namespace. However you can place the secret and issuer in any namespace you like.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;/details>
&lt;details>
&lt;summary>Troubleshooting Commands&lt;/summary>
&lt;ol>
&lt;li>To add the secret now, you can run:
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl apply -f cloudflare-secret.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>To list the secrets run:
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n cert-manager get secrets
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>To list general configuration details of the secret run:
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n cert-manager describe secret cloudflare-api-key-secret
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>To decode or inspect the details of the secret run:
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n cert-manager get secret cloudflare-api-key-secret -o yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;/details>
&lt;h4 id="53-create-the-certificate-issuer">5.3 Create the Certificate Issuer&lt;/h4>
&lt;p>Finally, we will create a &lt;code>Certifcate Issuer&lt;/code>. Create a file called &lt;code>cluster-issuer.yaml&lt;/code> with the following contents:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">cert-manager.io/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ClusterIssuer&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">letsencrypt-dns01-issuer &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># name for the issuer (for use when creating ingresses)&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">cert-manager &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># it will live in the cert-manager namespace&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">acme&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">email&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">your.cert.registration.email@example.com&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># The email associated with allocated certificates&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">privateKeySecretRef&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">letsencrypt-dns01-private-key &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># key used to allow access to the issuer during certificate resource creation (used later)&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">server: https://acme-staging-v02.api.letsencrypt.org/directory # NOTE: changeThis is staging - for production change to&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">https://acme-v02.api.letsencrypt.org/directory&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">solvers&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">dns01&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">cloudflare&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">email&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">your.cloudflare.email@example.com &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># the email address we use to login to cloudflare&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiTokenSecretRef&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">cloudflare-api-key-secret The secret we created earlier with our cloudflare API key&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">key&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">api-key&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>Make sure to update your &lt;code>email addresses&lt;/code> as outlined.&lt;/strong>&lt;/p>
&lt;/blockquote>
&lt;p>Then apply the configuration to kubernetes:&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl apply -f cluster-issuer.yaml
&lt;/code>&lt;/pre>&lt;details>
&lt;summary>Troubleshooting Commands&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl get clusterissuer -n cert-manager
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME READY AGE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>letsencrypt-dns01-issuer True 10h
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/details>
&lt;h3 id="6-create-ou-certificate-">6. Create ou Certificate 🎉&lt;/h3>
&lt;p>Now for the moment of truth&amp;hellip; Let&amp;rsquo;s create a real certificate (resource) which we will use in our backend ingress for HTTPS and TLS.&lt;/p>
&lt;p>Since our service &lt;em>must&lt;/em> be tied to our domain name, in the Certificate definition, we must specify the domain and sub-domains for which we intend to use in the certificate. For my purposes, I am using &lt;code>codeblind.ai&lt;/code>, and a few other sub-domains. Create a similar file names &lt;code>certificate.yaml&lt;/code> using the guidance below:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">cert-manager.io/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Certificate&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-cert &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># some name you choose for the certificate&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># the namespace where I want to use the certificate&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">secretName&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-tls-secret&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Output secret location where the certificate will be places after creation&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">commonName&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind.ai &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># our top level domain&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">dnsNames&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#000">backend.codeblind.ai &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># backend sub-domain&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#4e9a06">&amp;#39;*.backend.codeblind.ai&amp;#39;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># wildcards for future endpoints. &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">issuerRef&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">letsencrypt-dns01-issuer&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># the reference to the issuer we defined earlier&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ClusterIssuer &lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># and the issuers `kind`&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Note, if you don&amp;rsquo;t have the namespace yet for your app, you can create it now by running:&lt;/p>
&lt;p>&lt;code>kubectl create namespace &amp;lt;add-namespace-here&amp;gt; --dry-run=client -o yaml | tee namespace.yaml | kubectl apply -f -&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;p>Now create the certificate:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl apply -f certificate.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;details>
&lt;summary>Troubleshooting Commands&lt;/summary>
&lt;ol>
&lt;li>
&lt;p>Validate the certificate is created&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl get certificate -n codeblind
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME READY SECRET AGE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>codeblind-cert True codeblind-tls-secret 9s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>If &lt;code>READY&lt;/code> is not true - we might have a configuration issue. What I normally do is look at the &lt;code>cert-manager&lt;/code> logs:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>List the pods&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl -n cert-manager get pods
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME READY STATUS RESTARTS AGE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cert-manager-webhook-7f9f8648b9-bz7vx 1/1 Running &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span> 44h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cert-manager-cainjector-5c5695d979-sx47r 1/1 Running &lt;span style="color:#0000cf;font-weight:bold">6&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>26h ago&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span> 44h
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>cert-manager-67c98b89c8-lhbbk 1/1 Running &lt;span style="color:#0000cf;font-weight:bold">0&lt;/span> 22h
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Inspect the logs&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl -n cert-manager logs -f cert-manager-67c98b89c8-lhbbk
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>Check the status of the certificate (describe):&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl -n codeblind describe certificate codeblind-cert
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Name: codeblind-cert
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Namespace: codeblind
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Labels: &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Annotations: &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>API Version: cert-manager.io/v1
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Kind: Certificate
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Metadata:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Creation Timestamp: 2024-04-02T14:51:08Z
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Generation: &lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Resource Version: &lt;span style="color:#0000cf;font-weight:bold">1383722&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> UID: 3721465a-8ca9-4480-8ef4-529b5f11437f
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Spec:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Common Name: backend.codeblind.ai
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Dns Names:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> backend.codeblind.ai
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> *.backend.codeblind.ai
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Issuer Ref:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Kind: ClusterIssuer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Name: letsencrypt-dns01-issuer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Secret Name: codeblind-tls-secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Status:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Conditions:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Last Transition Time: 2024-04-02T14:51:08Z
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Message: Certificate is up to date and has not expired
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Observed Generation: &lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Reason: Ready
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Status: True
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Type: Ready
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Not After: 2024-07-01T02:54:35Z
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Not Before: 2024-04-02T02:54:36Z
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> Renewal Time: 2024-06-01T02:54:35Z
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Events: &amp;lt;none&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Check the certificate key material is &lt;strong>&lt;em>in the secret&lt;/em>&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl -n codeblind describe secret codeblind-tls-secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Name: codeblind-tls-secret
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Namespace: codeblind
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Labels: controller.cert-manager.io/fao&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#204a87">true&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Annotations: cert-manager.io/alt-names: *.backend.codeblind.ai,backend.codeblind.ai
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/certificate-name: codeblind-cert
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/common-name: backend.codeblind.ai
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/ip-sans:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/issuer-group:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/issuer-kind: ClusterIssuer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/issuer-name: letsencrypt-dns01-issuer
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> cert-manager.io/uri-sans:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Type: kubernetes.io/tls
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#000">Data&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ce5c00;font-weight:bold">====&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tls.crt: &lt;span style="color:#0000cf;font-weight:bold">3793&lt;/span> bytes
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>tls.key: &lt;span style="color:#0000cf;font-weight:bold">1675&lt;/span> bytes
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;/details>
&lt;p>If all went well, you now have a certificate &lt;code>READY&lt;/code> to use.&lt;/p>
&lt;h3 id="8-setting-up-ssl-modes-on-cloudflare">8. Setting up SSL modes on Cloudflare&lt;/h3>
&lt;p>Before we go further, we need to check out the &lt;a href="https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/">SSL mode setting in cloudflare&lt;/a>.According to the documenation, we should be using either &lt;code>full or strict&lt;/code>.&lt;/p>
&lt;p>What you might notice once you enable &lt;code>full or strict&lt;/code> is that when you open your github page in the browser (for example &lt;a href="https://codeblind.ai">https://codeblind.ai&lt;/a>) - it will work just fine. However if you set it to &lt;code>flexible&lt;/code> it will not render and in the debugger tab you might notice error &lt;a href="https://developers.cloudflare.com/ssl/troubleshooting/too-many-redirects/#:~:text=Redirect%20loops%20will%20occur%20if,configured%20at%20your%20origin%20server">&amp;ldquo;ERR_TOO_MANY_REDIRECTS&amp;rdquo;&lt;/a>.). So we know we must have full or strict set for our site(s) to keep working.&lt;/p>
&lt;p>However if you deploy the application, and try to send it a &lt;code>curl&lt;/code> request - you will receive a 523 error. I am saying this early because we need (for now) to configure a special rule to allow &lt;code>flexible mode&lt;/code> while taking to the backend. The backend will still be using HTTPS and the LetsEncrypt certificate, however cloudflare did not seem to work for me with strict mode. (I likely made a mistake, but let&amp;rsquo;s move on).&lt;/p>
&lt;ol>
&lt;li>In the Cloudflare Domain console, goto &lt;code>SSL&lt;/code> &amp;ndash;&amp;gt; &lt;code>Configuration Rules&lt;/code> page.
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/ssl-config-rules.png">&lt;/li>
&lt;li>Next create a new rule
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/config-rule-1.png">&lt;/li>
&lt;li>Give the rule a name
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/config-rule-2.png">&lt;/li>
&lt;li>Configure a &lt;code>custom filter&lt;/code> so that all SSL/HTTPS request destined for the backend domain name will activate this rule. Also turn on HTTPS rewrites to remove any HTTP from going to our backend.
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/config-rule-3.png">&lt;/li>
&lt;li>Finally - and really importantly - set the SSL option to &lt;code>flexible&lt;/code>. This is the setting which solves our 523 HTTP Error Code. Then click deploy.
&lt;img src="https://codeblind-ai.github.io/images/blogs/11/config-rule-4.png">&lt;/li>
&lt;/ol>
&lt;h3 id="9-deploying-a-service-with-tls-termination-at-the-ingress">9. Deploying a service with TLS termination at the Ingress&lt;/h3>
&lt;p>Finally, we can now deploy our backend service. Below is an example service I use for testing which lives in my private repository (thus the secret). Below the manifest deployment, I will discuss the critical elements of the &lt;code>Ingress&lt;/code> as that is the most important element which will terminate our HTTPS sessions.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Secret&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">type&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">kubernetes.io/dockerconfigjson&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ghcrcred&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">data&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">.dockerconfigjson&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">YOUR-REDACTED-REPO-PRIVATE-KEY&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#000">---&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">apps/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Deployment&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">labels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">selector&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">matchLabels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">replicas&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">template&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">labels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">runtimeClassName&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">kata&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">imagePullSecrets&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ghcrcred&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">containers&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">image&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ghcr.io/codeblind-ai/echo:0.0.2&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ports&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">containerPort&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">8080&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#000">---&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Service&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-backend&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">labels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-backend&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">type&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">LoadBalancer&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">selector&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ports&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">port&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">80&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">standard&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">targetPort&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">8080&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">protocol&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">TCP&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#000">---&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">networking.k8s.io/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Ingress&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-ingress&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">annotations&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">cert-manager.io/issuer&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">letsencrypt-dns01-issuer&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">tls&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">hosts&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#000">backend.codeblind.ai&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">secretName&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-tls-secret&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># cert output of our certificate (resource) we created earlier&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">rules&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">host&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">backend.codeblind.ai&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">http&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">paths&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">path&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">/&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">pathType&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Prefix&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">backend&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">service&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">codeblind-backend&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">port&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">number&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">80&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>In the &lt;code>Ingress&lt;/code> configuration I want you to notice a few things:&lt;/p>
&lt;ol>
&lt;li>the ingress TLS setting specifies the hostname which we are terminating.&lt;/li>
&lt;li>the secret &lt;code>codeblind-tls-secret&lt;/code> &lt;strong>matches&lt;/strong> the name used in during the &lt;strong>certificate creation&lt;/strong>. This is where the certificate material lives after a successful certificate creation.&lt;/li>
&lt;/ol>
&lt;p>Let&amp;rsquo;s deploy it!&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kube apply -f deployment.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Once deployed, things should be working. Let&amp;rsquo;s give it a test:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>curl -X POST https://backend.codeblind.ai/hello -d &lt;span style="color:#4e9a06">&amp;#39;Mighty-Pi&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If everything worked, you should see a success response with &lt;code>&amp;quot;Hello, Mighty-Pi&amp;quot;&lt;/code>.&lt;/p>
&lt;p>I will skip the summary, as this was kind of a long an involved post - but I hope it all worked for you. In the next post - I will be establishing Tunnels and Origin Certificates to allow us to remove the special SSL configuration rules, remove the port forwarding on our router, and prevent IP based DDoS attacks on our infrastructure. Stay tuned!&lt;/p></description></item><item><title>Blog: Simplifying DNS Management with Cloudflare</title><link>https://codeblind-ai.github.io/blog/2024/03/22/simplifying-dns-management-with-cloudflare/</link><pubDate>Fri, 22 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/22/simplifying-dns-management-with-cloudflare/</guid><description>
&lt;p>In the early days of the internet, loading a website was a straightforward process: your request traveled to a server, which then delivered the requested page. However, when too many requests flooded a server, it could crash, leaving visitors stranded. Cloudflare emerged to tackle these issues head-on, leveraging a robust edge network to deliver content and services as swiftly as possible, ensuring users receive information without delay.&lt;/p>
&lt;p>Moreover, Cloudflare provides robust security measures, safeguarding internet properties from various malicious activities, including DDoS attacks and intrusive bots. Additionally, features like SSL and content distribution are seamlessly integrated into Cloudflare&amp;rsquo;s offerings, benefiting millions of internet properties worldwide.&lt;/p>
&lt;h1 id="the-importance-of-dns-management">The Importance of DNS Management&lt;/h1>
&lt;p>DNS (Domain Name System) management is crucial for directing internet traffic to the correct destinations. Cloudflare simplifies this process, offering a comprehensive DNS service that enhances security and performance.&lt;/p>
&lt;h2 id="protecting-against-ddos-attacks">Protecting Against DDoS Attacks&lt;/h2>
&lt;p>DDoS (&lt;a href="https://www.cloudflare.com/learning/ddos/what-is-a-ddos-attack/">Distributed Denial of Service&lt;/a>) attacks pose a significant threat to online services, disrupting operations by overwhelming servers with malicious traffic. Cloudflare&amp;rsquo;s DDoS mitigation operates in four stages:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Detection:&lt;/strong> Identifying and distinguishing legitimate traffic from attack traffic.&lt;/li>
&lt;li>&lt;strong>Response:&lt;/strong> Intelligently dropping malicious bot traffic while absorbing the rest.&lt;/li>
&lt;li>&lt;strong>Routing:&lt;/strong> Efficiently directing manageable traffic chunks to prevent denial of service.&lt;/li>
&lt;li>&lt;strong>Adaptation:&lt;/strong> Analyzing traffic patterns to fortify against future attacks.&lt;/li>
&lt;/ol>
&lt;h2 id="examples-of-ddos-attacks">Examples of DDoS Attacks&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://www.cloudflare.com/learning/ddos/what-is-an-ack-flood/">ACK Flood DDoS Attack&lt;/a>: Overloads servers with TCP ACK packets, crippling their ability to serve legitimate users.&lt;/li>
&lt;li>&lt;strong>DNS Amplification Attack&lt;/strong>: Exploits open DNS resolvers to inundate target servers with amplified traffic, rendering them inaccessible.&lt;/li>
&lt;/ul>
&lt;h2 id="simplifying-dns-setup-with-cloudflare">Simplifying DNS Setup with Cloudflare&lt;/h2>
&lt;p>Transitioning your domain&amp;rsquo;s DNS management to Cloudflare is a straightforward process, offering enhanced security and performance benefits. Here&amp;rsquo;s how to do it:&lt;/p>
&lt;h3 id="1-sign-up-with-cloudflare">1. Sign Up with Cloudflare&lt;/h3>
&lt;p>First you will need to &lt;a href="https://www.cloudflare.com/plans/">create a Cloudflare account&lt;/a>. You will be presented with a set of plans to chose from. Since we are building a hobby project, I recommend starting with the &lt;code>free&lt;/code> plan as show:
&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_01.png">&lt;/p>
&lt;h3 id="2-enable-cloudflare-for-your-domain">2. Enable Cloudflare for your domain&lt;/h3>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_02.png">&lt;/p>
&lt;p>Click the &lt;code>Add a Site&lt;/code> button in Cloudflare to add your domain.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_03.png">
Enter your site name, and click &lt;code>Continue&lt;/code>&lt;/p>
&lt;h3 id="3-select-the-subscription-level">3. Select the subscription level&lt;/h3>
&lt;p>Since we are building a hobby site - we will select the &lt;code>free&lt;/code> option and &lt;code>Continue&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_04.png">&lt;/p>
&lt;h3 id="4-record-the-name-server-entires-you-will-need-to-configure-namecheap">4. Record the name server entires you will need to configure Namecheap&lt;/h3>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_05.png">&lt;/p>
&lt;h3 id="5-update-the-registrar-dns-settings">5. Update the Registrar DNS settings&lt;/h3>
&lt;p>We are using namecheap, so we can login and go to the management dashboard for our domain.
&lt;img src="https://codeblind-ai.github.io/images/blogs/10/namecheap_01.png">&lt;/p>
&lt;p>Here we will update the &lt;code>NAMESERVERS&lt;/code> configuration, selecting &lt;code>Custom DNS&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/namecheap_02.png">&lt;/p>
&lt;p>Here we will update the &lt;code>NAMESERVERS&lt;/code> configuration, selecting &lt;code>Custom DNS&lt;/code>.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/namecheap_03.png">&lt;/p>
&lt;p>Next we enter the data we collected in step 4.
&lt;img src="https://codeblind-ai.github.io/images/blogs/10/namecheap_04.png">&lt;/p>
&lt;p>Then click save - and we should see a success banner.
&lt;img src="https://codeblind-ai.github.io/images/blogs/10/namecheap_05.png">&lt;/p>
&lt;h3 id="6-update-dns-in-cloudflare">6. Update DNS in Cloudflare&lt;/h3>
&lt;p>By now, we should see a success banner in Cloudflare as well.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_06.png">&lt;/p>
&lt;p>Navigate to the DNS settings, and add two &lt;code>CNAME&lt;/code> records for your github pages site as shown:&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/10/cloudflare_07.png">&lt;/p>
&lt;p>Thats it! We are all done. The site should be working as it was before!&lt;/p>
&lt;h1 id="summary">Summary&lt;/h1>
&lt;p>We learned how to quickly add strong DDoS protection to our site using Cloudflare. Next we will setup TLS for our services using Let&amp;rsquo;s Encrypt and Cloudflare. Stay tuned!&lt;/p></description></item><item><title>Blog: Pi goes Great with Kata 🥧</title><link>https://codeblind-ai.github.io/blog/2024/03/18/pi-goes-great-with-kata/</link><pubDate>Mon, 18 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/18/pi-goes-great-with-kata/</guid><description>
&lt;style>
aside {
width: 40%;
padding-left: 0.5rem;
margin-left: 0.5rem;
float: right;
box-shadow: inset 5px 0 5px -5px #29627e;
font-style: italic;
color: #29627e;
}
aside > p {
margin: 0.5rem;
}
summary {
font-weight: bold;
font-size: 1.1em;
}
details > summary {
list-style-type: '✅ ';
color: #666666;
}
details[open] > summary {
list-style-type: '🟩 ';
color: #333333;
}
table {
margin-left: 30px;
}
&lt;/style>
&lt;p>Kata Containers offers a game-changing solution to the security and performance challenges faced in containerized environments. By seamlessly integrating lightweight VMs with Kubernetes, Kata Containers empowers developers to achieve unprecedented levels of security and efficiency.&lt;/p>
&lt;p>Key Features include:&lt;/p>
&lt;ol>
&lt;li>Enhanced isolation and security through lightweight VMs&lt;/li>
&lt;li>Sub-second boot times&lt;/li>
&lt;li>Hardware virtualization&lt;/li>
&lt;li>Support for multiple hypervisors&lt;/li>
&lt;li>GPU passthrough&lt;/li>
&lt;/ol>
&lt;p>In this post, we provide a step-by-step configuring of &lt;a href="https://katacontainers.io/docs/getting-started/kubernetes/">Kata Containers on Kubernetes&lt;/a>.&lt;/p>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;p>Previously in the series we&amp;rsquo;ve creates a Kubernetes cluster on Raspberry Pi 5. If you haven&amp;rsquo;t done so, please refer to the previous posts.&lt;/p>
&lt;h2 id="adding-kata-containers-to-kubernetes">Adding Kata Containers to Kubernetes&lt;/h2>
&lt;details open>
&lt;summary>1. Install Kata Containers&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>wget https://raw.githubusercontent.com/kata-containers/kata-containers/main/utils/kata-manager.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>chmod +x kata-manager.sh
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>./kata-manager.sh -o
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/details>
&lt;details open>
&lt;summary>2. Determine the available HyperVisor&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>./kata-manager.sh -L
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>You should expect the following output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>clh - packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>dragonball - packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87">fc&lt;/span> - packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>qemu default packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>qemu-nvidia-gpu - packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>qemu-sev - packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>qemu-snp - packaged golang
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>qemu-tdx - packaged golang
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Notice by default we have &lt;code>qemu&lt;/code> as the default hypervisor&lt;/p>
&lt;/blockquote>
&lt;/details>
&lt;details open>
&lt;summary>3. Install QEMU&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt install qemu-system
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/details>
&lt;details open>
&lt;summary>4. Update the containerd configuration&lt;/summary>
&lt;h4 id="we-are-overwriting-the-current-containerd-configuration">We are &lt;strong>overwriting&lt;/strong> the current containerd configuration&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo cat &lt;span style="color:#4e9a06">&amp;lt;&amp;lt;EOF &amp;gt; /etc/containerd/config.toml
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">version = 2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">[plugins]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.containerd]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> no_pivot = false
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.containerd.runtimes]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.containerd.runtimes.runc]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> privileged_without_host_devices = false
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> runtime_type = &amp;#34;io.containerd.runc.v2&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.containerd.runtimes.runc.options]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> BinaryName = &amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> CriuImagePath = &amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> CriuPath = &amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> CriuWorkPath = &amp;#34;&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> IoGid = 0
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.containerd.runtimes.kata]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> runtime_type = &amp;#34;io.containerd.kata.v2&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> privileged_without_host_devices = true
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> pod_annotations = [&amp;#34;io.katacontainers.*&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> container_annotations = [&amp;#34;io.katacontainers.*&amp;#34;]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.containerd.runtimes.kata.options]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> ConfigPath = &amp;#34;/opt/kata/share/defaults/kata-containers/configuration.toml&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> [plugins.&amp;#34;io.containerd.grpc.v1.cri&amp;#34;.cni]
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> conf_dir = &amp;#34;/etc/cni/net.d&amp;#34;
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h4 id="now-restart-containerd">Now restart containerd&lt;/h4>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo systemctl stop containerd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl daemon-reload
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl start containerd
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo systemctl status containerd
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/details>
&lt;details open>
&lt;summary>5. Enable Kata Containers Runtime Class&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat &lt;span style="color:#4e9a06">&amp;lt;&amp;lt;EOF &amp;gt; runtime.yaml
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">apiVersion: node.k8s.io/v1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">kind: RuntimeClass
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">metadata:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> name: kata
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">handler: kata
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kubectl apply -f runtime.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/details>
&lt;details open>
&lt;summary>6. Redeploy PingPong using kata containers and QEMU&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>cat &lt;span style="color:#4e9a06">&amp;lt;&amp;lt;EOF &amp;gt; pingpong-service.yaml
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">apiVersion: v1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">kind: Namespace
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">metadata:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> name: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">---
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">apiVersion: apps/v1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">kind: Deployment
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">metadata:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> name: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> namespace: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> labels:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> app: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">spec:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> selector:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> matchLabels:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> app: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> replicas: 2
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> template:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> metadata:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> labels:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> app: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> spec:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> runtimeClassName: kata
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> containers:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> - name: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> image: dasralph/ping:arm64_0.0.5
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> ports:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> - containerPort: 8080
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">---
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">apiVersion: v1
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">kind: Service
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">metadata:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> name: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> namespace: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> labels:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> app: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">spec:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> type: LoadBalancer
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> selector:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> app: ping
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> ports:
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> - port: 80
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> targetPort: 8080
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06"> protocol: TCP
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">---
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">EOF&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>kubectl apply -f pingpong-service.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Check that the nodes are running:&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl get pods -n ping -o wide
&lt;/code>&lt;/pre>&lt;/details>
&lt;details open>
&lt;summary>7. Check hypervisor is running&lt;/summary>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ps aux &lt;span style="color:#000;font-weight:bold">|&lt;/span> grep qemu
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Expected output looks similar to the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ps aux &lt;span style="color:#000;font-weight:bold">|&lt;/span> grep qemu
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>root &lt;span style="color:#0000cf;font-weight:bold">83180&lt;/span> 6.3 1.6 &lt;span style="color:#0000cf;font-weight:bold">2730640&lt;/span> &lt;span style="color:#0000cf;font-weight:bold">135824&lt;/span> ? Sl 02:16 0:02 /opt/kata/bin/qemu-system-aarch64 -name sandbox-26519d5f8744b3d582b81dd8986b591d055bf3debcd2e498e5947efb4abe60d7 -uuid...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/details>
&lt;h3 id="conclusion">Conclusion&lt;/h3>
&lt;p>Enabling Kata Containers is a game-changer for security and performance; not to mention not terribly hard. We&amp;rsquo;ve seen how to install Kata Containers, determine the available hypervisor, install QEMU, update the containerd configuration, enable Kata Containers Runtime Class, and redeploy PingPong using Kata Containers and QEMU.&lt;/p>
&lt;p>Stay tuned for more on how to leverage Kata Containers using Firecracker as the VM hypervisor.&lt;/p></description></item><item><title>Blog: Unlocking External Access: MetalLB Load Balancers</title><link>https://codeblind-ai.github.io/blog/2024/03/16/unlocking-external-access-metallb-load-balancers/</link><pubDate>Sat, 16 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/16/unlocking-external-access-metallb-load-balancers/</guid><description>
&lt;p>Kubernetes &lt;em>does&lt;/em> provide internal cluster IPs for services, but these IPs are only accessible within the cluster itself. When you deploy a service of type &lt;code>LoadBalancer&lt;/code> in Kubernetes, it typically relies on a cloud provider&amp;rsquo;s load balancer to expose the service externally. However, in environments like our Mighty Raspberry Pi 5 cluster where there is no built-in cloud infrastructure, you need an alternative solution to expose services externally.&lt;/p>
&lt;p>This is where MetalLB comes in. MetalLB serves as a load balancer for Kubernetes clusters, bridging the gap between internal and external accessibility. It seamlessly assigns external IP addresses to services of type LoadBalancer, enabling external traffic to reach our cluster and be directed to the appropriate pods. But how do we unleash the power of MetalLB in our non-cloud environment?&lt;/p>
&lt;h2 id="ip-addresses">IP Addresses&lt;/h2>
&lt;p>MetalLB doesn&amp;rsquo;t create IP addresses out of thin air. You must give it pools of IP addresses that it can manage. MetalLB will take care of assigning and recycling individual addresses as services come and go, but it will only ever hand out IPs that are part of its configured pools.&lt;/p>
&lt;p>How - or where - you get IP address pools for MetalLB depends on your environment. If you’re running a bare-metal cluster in a collocation facility, your hosting provider probably offers IP addresses for lease. In our case, we have a home router, so we must login to the administrative console an restrict the DHCP address range assigned by our router - to create a pool which can be managed by MetalLB.&lt;/p>
&lt;h2 id="does-this-cause-problems-routing-problems">Does this cause problems routing problems?&lt;/h2>
&lt;p>That is a great question reader! Typically your home router router acts as the DHCP server for your home LAN, assigning IP addresses to authorized devices, and advertise that assignment of IP to MAC using a Layer 2 mode (ARP/NDP) protocol.&lt;/p>
&lt;p>MetalLB supports both &lt;code>BGP&lt;/code> and &lt;code>Layer 2 ARP&lt;/code> Advertisement so our PaaS plays nice with out home network.&lt;/p>
&lt;p>If you had a larger environment, such as in a co-location, you might consider BGP. But for our purposes that is overkill.&lt;/p>
&lt;h2 id="does-layer-2-cause-bottlenecks-in-routing">Does Layer 2 cause bottlenecks in routing?&lt;/h2>
&lt;p>Astute networking question! Layer 2 mode has two main limitations you should be aware of when it comes to Kubernetes.&lt;/p>
&lt;ol>
&lt;li>In layer 2 mode, a &lt;strong>single leader-elected node&lt;/strong> handles all traffic for a service IP. This means that the ingress bandwidth of your service is restricted to the capacity of a single node, which can become a bottleneck.&lt;/li>
&lt;li>&lt;strong>Failover&lt;/strong> between nodes in layer 2 mode relies on client cooperation. When failover occurs, MetalLB sends out &amp;ldquo;gratuitous&amp;rdquo; layer 2 packets to inform clients of the change in MAC address associated with the service IP.&lt;/li>
&lt;/ol>
&lt;p>During unplanned failover, service IPs may become unreachable until problematic clients update their cache entries.&lt;/p>
&lt;pre class="mermaid">sequenceDiagram
participant MetalLB
participant Node1
participant Node2
participant Client
MetalLB-&amp;gt;&amp;gt;Node1: Single-node bottlenecking
MetalLB-&amp;gt;&amp;gt;Node2: Single-node bottlenecking
MetalLB-&amp;gt;&amp;gt;Client: Potentially slow failover
Client-&amp;gt;&amp;gt;Node1: Delayed cache update
Node1-&amp;gt;&amp;gt;Client: Forward traffic
Client-&amp;gt;&amp;gt;Node2: Updated cache
Node2-&amp;gt;&amp;gt;Client: Forward traffic&lt;/pre>
&lt;p>Hopefully this background information is enlightening, let&amp;rsquo;s setup Metal LB and see how it work!&lt;/p>
&lt;h1 id="metal-lb-quick-start">Metal LB Quick Start&lt;/h1>
&lt;h2 id="1-home-router-preparation">1. Home Router Preparation&lt;/h2>
&lt;p>Before diving into MetalLB configuration, it&amp;rsquo;s essential to ensure we have a pool of IP addresses available. In our home network scenario, this involves tweaking the DHCP settings on our router to reserve a block of addresses for MetalLB management.&lt;/p>
&lt;h2 id="11-log-into-your-router">1.1. Log into your Router&lt;/h2>
&lt;p>Login to your Router as &lt;code>admin&lt;/code>. This information is typically listed on a sticker on your router. If not, you may need to read the documentation for your router, or contact your ISP for help.
&lt;img src="https://codeblind-ai.github.io/images/blogs/9/router-1.png">&lt;/p>
&lt;h2 id="12-update-the-dhcp-settings">1.2. Update the DHCP Settings&lt;/h2>
&lt;p>Navigate to the DHCP settings, typically found under Advanced -&amp;gt; IP Addresses -&amp;gt; DHCP Settings on most routers.&lt;/p>
&lt;p>We will configure the DHCP to reserve a block of addresses within the &lt;code>192.168.1.X&lt;/code> range, which falls under Class-C private IP addresses as defined by RFC 1918 for private network use.&lt;/p>
&lt;p>In a standard IPv4 network, with one IP address reserved for the network identifier and another for broadcast, it leaves 254 IP addresses available for devices. Thus, the subnet can accommodate a maximum of 254 devices.&lt;/p>
&lt;p>To ensure efficient IP address allocation, we&amp;rsquo;ll limit the router to assigning addresses between &lt;code>192.168.1.2&lt;/code> and &lt;code>192.168.1.64&lt;/code>, allowing for up to 62 devices.&lt;/p>
&lt;p>This allocation strategy frees up addresses from &lt;code>192.168.1.65&lt;/code> to &lt;code>192.168.1.250&lt;/code>, which we&amp;rsquo;ll assign to MetalLB for managing addresses in our cluster.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/9/router-2.png">&lt;/p>
&lt;p>From a security perspective, it&amp;rsquo;s crucial to implement LAN segmentation to isolate devices within a network. However at this time we will &lt;code>Keep it Simple&lt;/code> - and visit that topic in another post.&lt;/p>
&lt;h2 id="2-metallb-installation">2. MetalLB Installation&lt;/h2>
&lt;p>With our IP pool secured, it&amp;rsquo;s time to install MetalLB. A simple command on our master node - microk8s enable metallb - sets the stage for MetalLB&amp;rsquo;s magic.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>microk8s &lt;span style="color:#204a87">enable&lt;/span> metallb
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="3-address-allocation">3. Address Allocation&lt;/h2>
&lt;p>MetalLB requires explicit instructions on IP address allocation. By creating a YAML file specifying our IP address range and applying it to our platform, we empower MetalLB to manage these addresses effectively.&lt;/p>
&lt;p>Create a file named &lt;code>metallb-address-pool.yaml&lt;/code> as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"># addresspool.yaml&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#000">---&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">metallb.io/v1beta1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">IPAddressPool&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">custom-addresspool&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">namespace&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">metallb-system&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">addresses&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#0000cf;font-weight:bold">192.168.1.65-192.168.1.254&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>IMPORTANT:&lt;/strong> don&amp;rsquo;t forget to use the IP address range you reserved on your router!&lt;/p>
&lt;/blockquote>
&lt;p>Now apply this using to your platform:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl apply -f metallb-address-pool.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="5-network-advertisement-mode">5. Network Advertisement Mode&lt;/h2>
&lt;p>In our discussion, we explored the nuances of Layer 2 mode and its implications for our network environment. We ensured smooth integration by addressing potential bottlenecks and failover challenges.&lt;/p>
&lt;p>Luckily for us we installed Microk8s which has already configured everything for us! So there is nothing to do! 🎉&lt;/p>
&lt;blockquote>
&lt;p>For everyone else, I will direct you to the &lt;a href="https://metallb.org/installation/">documentation&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="6-validation-witnessing-metallb-in-action">6. Validation: Witnessing MetalLB in Action&lt;/h2>
&lt;p>With MetalLB configured, it&amp;rsquo;s time to put it to the test. We will deploy a sample service and marveled as MetalLB seamlessly assigned an external IP address to it. Through meticulous validation steps, from checking service assignments to verifying ARP advertisements, we confirmed the robustness of our setup.&lt;/p>
&lt;h3 id="61-defined-a-service">6.1 Defined a service&lt;/h3>
&lt;p>Create a file named &lt;code>hello-deployment.yaml&lt;/code> with the following content:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">apps/v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Deployment&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">echo-deployment&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">replicas&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">selector&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">matchLabels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">echo-server&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">template&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">labels&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">echo-server&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">containers&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">echo-server&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">image&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">hashicorp/http-echo&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ports&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">http-port&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">containerPort&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">5678&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#000">---&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">apiVersion&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">v1&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">kind&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Service&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">metadata&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">echo-service&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">spec&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">type&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">LoadBalancer&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">ports&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">http-port&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">port&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">80&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">targetPort&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">http-port&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">protocol&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">TCP&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">selector&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">app&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">echo-server&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Notice the &lt;code>type: LoadBalancer&lt;/code> specified in the service? This activates MetalLB to assign a new IP address to the service externally!&lt;/p>
&lt;p>We can apply this and do some validation.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl apply -f hello-deployment.yaml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>deployment.apps/echo-deployment created
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="62-check-the-service-was-assigned-an-ip-address">6.2 Check the service was assigned an IP address&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ kubectl get services
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>NAME TYPE CLUSTER-IP EXTERNAL-IP PORT&lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>S&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span> AGE
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>echo-service LoadBalancer 10.152.183.167 192.168.1.66 80:31136/TCP 7s
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Notice we got an External IP address of &lt;code>192.168.1.66&lt;/code>!&lt;/p>
&lt;h3 id="63-verify-the-advertisement">6.3 Verify the Advertisement&lt;/h3>
&lt;p>We can verify the ARP advertisement by running the following:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ arp -a
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>? &lt;span style="color:#ce5c00;font-weight:bold">(&lt;/span>192.168.1.66&lt;span style="color:#ce5c00;font-weight:bold">)&lt;/span> at 2c:cf:67:19:72:6e on en0 ifscope &lt;span style="color:#ce5c00;font-weight:bold">[&lt;/span>ethernet&lt;span style="color:#ce5c00;font-weight:bold">]&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>...
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h3 id="63-now-lets-check-the-service-is-accessible">6.3 Now let&amp;rsquo;s check the service is accessible&lt;/h3>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>$ curl http://192.168.1.66
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>hello-world
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Great - it is all working! 🎉🎉🎉&lt;/p>
&lt;h1 id="conclusion-a-new-frontier">Conclusion: A New Frontier&lt;/h1>
&lt;p>Armed with MetalLB, we&amp;rsquo;ve unlocked a new frontier in our Kubernetes journey. External accessibility is no longer a barrier, and our cluster stands ready to face new challenges. As we bid farewell to this chapter, we look forward to the next leg of our adventure, armed with newfound knowledge and determination.&lt;/p></description></item><item><title>Blog: Mighty Pi PaaS: 🚀 Unleashing MicroK8s</title><link>https://codeblind-ai.github.io/blog/2024/03/15/mighty-pi-paas-unleashing-microk8s/</link><pubDate>Fri, 15 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/15/mighty-pi-paas-unleashing-microk8s/</guid><description>
&lt;p>Infrastructure as a Service (IaaS) is a cloud computing model that provides users with virtualized computing resources such as servers, storage, networking, and virtualization on-demand over the internet.&lt;/p>
&lt;p>Platform as a Service (PaaS) is a cloud computing model that offers a complete development and deployment environment in the cloud. It provides developers with tools and resources to build, deploy, and manage applications without having to worry about underlying infrastructure management.&lt;/p>
&lt;p>At this stage, we are setting up a working Kubernetes cluster on our Raspberry Pi 5, which serves as our IaaS foundation. Kubernetes enables us to access computing resources such as servers, networking, and compute (containers) on our Pi cluster.&lt;/p>
&lt;p>With Kubernetes installed, we can deploy and manage containers and services on our cluster. Additionally, we can access these services from our home network, laying the groundwork for our IaaS infrastructure.&lt;/p>
&lt;p>MicroK8s is a lightweight and easy-to-use Kubernetes distribution that is perfect for running on resource-constrained environments like Raspberry Pi. In this guide, we&amp;rsquo;ll walk through the process of setting up a MicroK8s cluster on Raspberry Pi devices, enabling you to harness the power of Kubernetes for your projects.&lt;/p>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;p>Before we begin, ensure you have the following:&lt;/p>
&lt;ul>
&lt;li>Raspberry Pi devices (at least two for setting up a cluster)&lt;/li>
&lt;li>Ubuntu 23.04 LTS installed and configured&lt;/li>
&lt;li>Internet connectivity on Raspberry Pi devices&lt;/li>
&lt;li>Basic familiarity with the command line interface&lt;/li>
&lt;/ul>
&lt;h2 id="1-update-the-operating-system-packages">1. Update the Operating System Packages&lt;/h2>
&lt;p>Ensure your Raspberry Pi devices are up to date and have necessary packages installed:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo apt update
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt upgrade
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt install linux-modules-extra-raspi
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="2-configure-network-settings">2. Configure Network Settings&lt;/h2>
&lt;p>Use &lt;a href="https://netplan.io/">Netplan&lt;/a> to configure network settings to ensure connectivity.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"># Set up Ethernet connection (if not already enabled)&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo ip link &lt;span style="color:#204a87">set&lt;/span> dev eth0 up
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo dhclient eth0 -v
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo vi /etc/netplan/50-cloud-init.yaml
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo netplan apply
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="2-disable-swap">2. Disable Swap&lt;/h2>
&lt;p>Disabling swap in Kubernetes environments is crucial for maintaining performance, stability, and effective resource management by preventing unnecessary swapping of memory to disk..&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo dphys-swapfile swapoff
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo dphys-swapfile uninstall
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt purge -y dphys-swapfile
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo apt autoremove -y
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="3-configuring-the-kernel-cgroup-support">3. Configuring the Kernel CGroup Support&lt;/h2>
&lt;ol>
&lt;li>
&lt;p>enable cgroups in the kernel by running the following command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo sed -i &lt;span style="color:#4e9a06">&amp;#39;/^console.*=BL/s/$/ cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1/&amp;#39;&lt;/span> /boot/firmware/cmdline.txt
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>now reboot the RPi to activate these settings:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo reboot
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h2 id="4-installing-microk8s">4. Installing MicroK8s&lt;/h2>
&lt;p>Install MicroK8s using Snap:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo snap install microk8s --classic
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="5-configure-the-microk8s-user-without-requiring-sudo">5. Configure the MicroK8s user without requiring sudo:&lt;/h2>
&lt;p>After navigating to the home directory and creating the &lt;code>.kube&lt;/code> directory, use the microk8s config command to configure the MicroK8s user settings.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87">cd&lt;/span> &lt;span style="color:#000">$HOME&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>mkdir .kube
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87">cd&lt;/span> .kube
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>sudo microk8s config &amp;gt; config
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="6-configure-the-user-for-microk8s">6. Configure the User for MicroK8s&lt;/h2>
&lt;p>Configure the a microk8s group so sudo is not required by the user:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo usermod -aG microk8s &lt;span style="color:#4e9a06">&amp;#34;&lt;/span>&lt;span style="color:#000">$USER&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>If you are provisioning more than one RPi 5 to be part of the cluster, such as in my case I have five, you will want to repeat steps 1 through 6 on each RPi.&lt;/p>
&lt;/blockquote>
&lt;h2 id="7-clustering-workers">7. Clustering Workers&lt;/h2>
&lt;p>Decide which Raspberry Pi will be the master and which ones will be workers. Add worker nodes to the cluster.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>On the master node run the following command to identify the worker join command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>microk8s add-node
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Example output:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>From the node you wish to join to this cluster, run the following:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>microk8s join 192.168.1.56:25000/0f112c22f3bbdb062abaab9a3d65c0a2f/421deadbeef
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>Use the &lt;span style="color:#4e9a06">&amp;#39;--worker&amp;#39;&lt;/span> flag to join a node as a worker not running the control plane, eg:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>microk8s join 192.168.1.56:25000/0f112c22f3bbdb062abaab9a3d65c0a2f/421deadbeef --worker
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>If the node you are adding is not reachable through the default interface you can use one of the following:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>microk8s join 192.168.1.56:25000/0f112c22f3bbdb062abaab9a3d65c0a2f/baddeadbeef
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>microk8s join 192.168.1.57:25000/0f112c22f3bbdb062abaab9a3d65c0a2f/421deadbeef
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Since we are only adding workers, and don&amp;rsquo;t plan to add more controller nodes, we only want to run the following command from above on each worker:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>microk8s join 192.168.1.56:25000/0f112c22f3bbdb062abaab9a3d65c0a2f/421deadbeef --worker
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>note you will get a different value for &lt;code>microk8s join &amp;lt;master-ip&amp;gt;:25000/&amp;lt;token&amp;gt;/&amp;lt;hash&amp;gt; --worker&lt;/code>&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>Validate the nodes have joined the cluster&lt;/p>
&lt;pre tabindex="0">&lt;code>$ microk8s kubectl get nodes
NAME STATUS ROLES AGE VERSION
pi5p0 Ready &amp;lt;none&amp;gt; 18d v1.28.7
pi5p1 Ready &amp;lt;none&amp;gt; 18d v1.28.7
pi5p2 Ready &amp;lt;none&amp;gt; 18d v1.28.7
pi5p3 Ready &amp;lt;none&amp;gt; 18d v1.28.7
pi5p4 Ready &amp;lt;none&amp;gt; 18d v1.28.7
&lt;/code>&lt;/pre>&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>Each node should be listed and ready&lt;/p>
&lt;/blockquote>
&lt;h2 id="7-configuring-aliases">7. Configuring Aliases&lt;/h2>
&lt;p>Set up aliases for easier command-line usage.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87">echo&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;alias kubectl=&amp;#39;microk8s kubectl&amp;#39;&amp;#34;&lt;/span> &amp;gt;&amp;gt; ~/.bashrc
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#204a87">echo&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;alias ctr=&amp;#39;ctr kubectl&amp;#39;&amp;#34;&amp;#34; &amp;gt;&amp;gt; ~/.bashrc
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#4e9a06">source ~/.bashrc
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>I recommend doing this on all nodes.&lt;/p>
&lt;/blockquote>
&lt;h2 id="enabling-add-ons">Enabling Add-ons&lt;/h2>
&lt;p>Enable essential add-ons for your MicroK8s cluster, such as the dashboard, DNS, and community.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sudo microk8s &lt;span style="color:#204a87">enable&lt;/span> dashboard dns community
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="test-your-deployment">Test your deployment&lt;/h2>
&lt;p>Deploy a hello world application and verify its status.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Deploy a hello world application&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl create deployment hello-node --image&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>registry.k8s.io/e2e-test-images/agnhost:2.39 -- /agnhost netexec --http-port&lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span>&lt;span style="color:#0000cf;font-weight:bold">8080&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>Check to see if the pod is ready&lt;/p>
&lt;pre tabindex="0">&lt;code>kubectl get deployments
&lt;/code>&lt;/pre>&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>note sometimes it may take a second to pull the image&lt;/p>
&lt;/blockquote>
&lt;ol start="3">
&lt;li>Inspect the pods
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl get pods
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>Check the events of the deployment
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>kubectl get events
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;h1 id="summary">Summary&lt;/h1>
&lt;p>In this guide, we&amp;rsquo;ve successfully transformed our Raspberry Pi 5 devices into a powerful Kubernetes cluster using MicroK8s. By following the step-by-step instructions, we&amp;rsquo;ve laid the foundation for our PaaS infrastructure, enabling us to deploy and manage containerized applications with ease. We&amp;rsquo;ve learned how to configure network settings, install MicroK8s, add worker nodes, and enable essential add-ons.&lt;/p>
&lt;p>Next, we&amp;rsquo;ll explore adding the MetalLB add-on and configuring our Home Router to expose our services to our LAN, taking our PaaS infrastructure to the next level. Stay tuned for more exciting developments in our journey to canning clouds with Raspberry Pi!&lt;/p></description></item><item><title>Blog: 🌩️ Idea Storm</title><link>https://codeblind-ai.github.io/blog/2024/03/06/%EF%B8%8F-idea-storm/</link><pubDate>Wed, 06 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/06/%EF%B8%8F-idea-storm/</guid><description>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/6/pi-cloud-overview.png">&lt;/p>
&lt;p>As I set up my new RPi5s, a bolt of inspiration struck me — what if I could create a real-ish cloud lab using only Raspberry Pi 5s and free resources? The possibilities are endless!&lt;/p>
&lt;p>Imagine the thrill of building your own cloud infrastructure from scratch, all while saving a ton in cloud costs. Picture the hands-on learning opportunities as we delve into security best practices and platform building techniques. This is not just a project; it&amp;rsquo;s an adventure waiting to unfold!&lt;/p>
&lt;p>The diagram above is just a glimpse of what&amp;rsquo;s to come as we embark on this journey together. But I need your help to make it happen! Join me as we push the boundaries of what&amp;rsquo;s possible with Raspberry Pi and free resources. Together, we&amp;rsquo;ll build something truly extraordinary.&lt;/p>
&lt;h2 id="could-we-make-our-own-paas-using-kubernetes">Could We Make Our Own PaaS using Kubernetes?&lt;/h2>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/6/paas-overview.png">&lt;/p>
&lt;p>As we embark on our journey to build a Raspberry Pi cloud lab, the idea of creating our own Platform as a Service (PaaS) using Kubernetes is both thrilling and ambitious.&lt;/p>
&lt;p>Imagine having the power to deploy, manage, and scale applications effortlessly, all within the confines of our Raspberry Pi cluster. Kubernetes, with its robust orchestration capabilities, provides the perfect foundation for such an endeavor.&lt;/p>
&lt;p>By harnessing the capabilities of Kubernetes, we can transform our Raspberry Pi cluster into a fully functional PaaS, offering developers the tools they need to deploy their applications seamlessly. From containerized workloads to automated scaling, our PaaS built on Kubernetes will empower developers to focus on building great software without worrying about the underlying infrastructure.&lt;/p>
&lt;p>But how exactly might this work? Stay tuned as we explore the intricacies of deploying Kubernetes on Raspberry Pi and configuring it to function as a PaaS. Together, we&amp;rsquo;ll uncover the possibilities and challenges of building our own PaaS solution from scratch.&lt;/p>
&lt;p>Get ready to dive deeper into the world of cloud-native technologies and unlock the full potential of our Raspberry Pi cloud lab. The journey ahead promises to be both exhilarating and enlightening—let&amp;rsquo;s make it happen!&lt;/p></description></item><item><title>Blog: Cloud Scaffolding: The Mighty Pi 🍇</title><link>https://codeblind-ai.github.io/blog/2024/03/05/cloud-scaffolding-the-mighty-pi/</link><pubDate>Tue, 05 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/05/cloud-scaffolding-the-mighty-pi/</guid><description>
&lt;style>
aside {
width: 40%;
padding-left: 0.5rem;
margin-left: 0.5rem;
float: right;
box-shadow: inset 5px 0 5px -5px #29627e;
font-style: italic;
color: #29627e;
}
aside > p {
margin: 0.5rem;
}
summary {
font-weight: bold;
font-size: 1.1em;
}
details > summary {
list-style-type: '✅ ';
color: #666666;
}
details[open] > summary {
list-style-type: '🟩 ';
color: #333333;
}
table {
margin-left: 30px;
}
&lt;/style>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;p>Before we begin, make sure you have the following:&lt;/p>
&lt;ul>
&lt;li>&lt;input disabled="" type="checkbox"> A laptop or workstation&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - Raspberry Pi 5 (I recommend the 8G version)&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - Micro SD card (at least 128GB)&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - Micro SW card reader/writer&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - 27W USB-C power supply&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - 40mm fan&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - RPi5 case&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> 1 - Active Head Sink&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> An internet connection (hopefully a reasonable speed)&lt;/li>
&lt;li>&lt;input disabled="" type="checkbox"> Admin login access to your router&lt;/li>
&lt;/ul>
&lt;h2 id="raspberry-pi-5-assembly">Raspberry Pi 5 Assembly&lt;/h2>
&lt;details open>
&lt;summary>1. Unbox the Raspberry Pi 5&lt;/summary>
&lt;p>This is the exciting part. Unbox the Raspberry Pi 5 and take a moment to appreciate the beauty of this tiny computer.&lt;/p>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rp5-board-1.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>2. Attach the heat sink to the board&lt;/summary>
&lt;p>This is an important step. The new RPi5 can get very hot. It&amp;rsquo;s important to keep it cool.&lt;/p>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rp5-board-2.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>3. Attach fan and place the board in the case!&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rp5-board-3.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>4. Download an install the Raspberry PI OS Installer&lt;/summary>
&lt;p>The installer is available on the &lt;a href="https://www.raspberrypi.com/software/">Raspberry Pi website&lt;/a>. Download the installer and install it onto your laptop or work station.&lt;/p>
&lt;/details>
&lt;h2 id="flashing-raspberry-pi-os">Flashing Raspberry Pi OS&lt;/h2>
&lt;details open>
&lt;summary>1. Open the Raspberry Pi OS Installer&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-1.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>2. Select the Raspberry Pi Device&lt;/summary>
&lt;p>This is an important step. The new RPi5 can get very hot. It&amp;rsquo;s important to keep it cool.&lt;/p>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-2.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>3. Select the Operating System&lt;/summary>
**For Raspberry Pi 4 or 5 I recommend the current Ubuntu 23.04 LTS.** This will allow us to deploy Canonical's MicroK8s which is much simpler to use than a Kubeadm installed Kubernetes.
&lt;/details>
&lt;details open>
&lt;summary>4. Select the Storage Media&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-4.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>4. Click Next, then `Edit Settings`&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-5-edit-1.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>5. Configure the default values for first Boot&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-5-edit-2.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;ol>
&lt;li>Make sure you set the hostname&lt;/li>
&lt;li>Make sure to configure the &lt;code>user&lt;/code> with a &lt;code>strong&lt;/code> password&lt;/li>
&lt;li>Configure the &lt;code>WiFi&lt;/code> settings to your local network. This allows you to find and access the RPi5 on your network without needing to connect a monitor and keyboard.&lt;/li>
&lt;li>Set the locale settings to your local settings&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;i class="fa fa-exclamation-triangle" aria-hidden="true" style="color: orange;"> &lt;/i> Don&amp;rsquo;t click save yet. We need to configure the &lt;code>SSH&lt;/code> settings.&lt;/p>
&lt;/blockquote>
&lt;/details>
&lt;details open>
&lt;summary>5. Customize Services (SSH)&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-5-edit-3.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;ol>
&lt;li>Select &lt;code>Enable SSH&lt;/code>&lt;/li>
&lt;li>Add your public key. If you don&amp;rsquo;t have an SSH Key, you can generate one using the &lt;code>ssh-keygen&lt;/code> command. &lt;a href="https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent">Follow the github instructions&lt;/a>. I think they are the clearest.&lt;/li>
&lt;li>Click &lt;code>Save&lt;/code>&lt;/li>
&lt;/ol>
&lt;/details>
&lt;details open>
&lt;summary>5. Apply the settings changes&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-5-edit-4.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>5. Confirm the updates&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-5-edit-5.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>5. Wait...&lt;/summary>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-os-install-5-edit-6.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;p>At the end of this process, you can install the SD card into the RPi5 and power it up. You should be able to find it on your network and SSH into it.&lt;/p>
&lt;h2 id="first-access">First Access&lt;/h2>
&lt;details open>
&lt;summary>1. Discover the IP address of your machine&lt;/summary>
After the RPi5 boots up, you should be able to find it on your network. You can use the `arp` command to find it.
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>arp -a
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div> &lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-discovery.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;details open>
&lt;summary>2. SSH to the machine&lt;/summary>
Once you have the IP address, you can SSH into the machine using the SSH certificate you provisioned, you can SSH into the machine.
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>ssh -i ~/.ssh/id_&amp;lt;your key&amp;gt; &amp;lt;user&amp;gt;@&amp;lt;ip address&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;i class="fa fa-exclamation-triangle" aria-hidden="true" style="color: orange;"> &lt;/i>Replace the &lt;code>&amp;lt;your key&amp;gt;&lt;/code> with the name of your SSH key, &lt;code>&amp;lt;user&amp;gt;&lt;/code> with the user you configured, and &lt;code>&amp;lt;ip address&amp;gt;&lt;/code> with the IP address you discovered.&lt;/p>
&lt;/blockquote>
&lt;img src="https://codeblind-ai.github.io/images/blogs/5/rpi5-login.png" alt="Raspberry Pi 5" style="width: 70%; display: block; margin-left: auto; margin-right: auto;">
&lt;/details>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>🎉🎉🎉 Congratulations! You&amp;rsquo;ve successfully set up your Raspberry Pi 5 for the first time. You can now start exploring the world of cloud native technologies on this powerful little computer. Enjoy your journey into the world of cloud computing and container orchestration!&lt;/p>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>Now that you have your Raspberry Pi 5 set up, you can start exploring various cloud native technologies such as Kubernetes, Containerd, ctr, nerdctl, and more. You can also start deploying and managing containers using Kubernetes. Enjoy your journey into the world of cloud computing and container orchestration!&lt;/p></description></item><item><title>Blog: Comparing the Berries 🍓</title><link>https://codeblind-ai.github.io/blog/2024/03/03/comparing-the-berries/</link><pubDate>Sun, 03 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/03/comparing-the-berries/</guid><description>
&lt;h1 id="bcm2711">BCM2711&lt;/h1>
&lt;p>This is the Broadcom chip used in the Raspberry Pi 4 Model B, the Raspberry Pi 400, and the Raspberry Pi Compute Module 4. The architecture of the BCM2711 is a considerable upgrade on that used by the SoCs in earlier Raspberry Pi models. It continues the quad-core CPU design of the BCM2837, but uses the more powerful ARM A72 core. It has a greatly improved GPU feature set with much faster input/output, due to the incorporation of a PCIe link that connects the USB 2 and USB 3 ports, and a natively attached Ethernet controller. It is also capable of addressing more memory than the SoCs used before.&lt;/p>
&lt;p>The ARM cores are capable of running at up to 1.5 GHz, making the Raspberry Pi 4 about 50% faster than the Raspberry Pi 3B+. The new VideoCore VI 3D unit now runs at up to 500 MHz. The ARM cores are 64-bit, and while the VideoCore is 32-bit, there is a new Memory Management Unit, which means it can access more memory than previous versions.&lt;/p>
&lt;p>The BCM2711 chip continues to use the heat spreading technology started with the BCM2837B0, which provides better thermal management.&lt;/p>
&lt;p>&lt;em>Processor:&lt;/em> Quad-core &lt;a href="https://en.wikipedia.org/wiki/ARM_Cortex-A72[Cortex-A72]">https://en.wikipedia.org/wiki/ARM_Cortex-A72[Cortex-A72]&lt;/a> (ARM v8) 64-bit SoC @ 1.5 GHz.&lt;/p>
&lt;p>&lt;em>Memory:&lt;/em> Accesses up to 8GB LPDDR4-2400 SDRAM (depending on model)&lt;/p>
&lt;p>&lt;em>Caches:&lt;/em> 32kB data + 48kB instruction L1 cache per core. 1MB L2 cache.&lt;/p>
&lt;p>&lt;em>Multimedia:&lt;/em> H.265 (4Kp60 decode); H.264 (1080p60 decode, 1080p30 encode); OpenGL ES, 3.0 graphics&lt;/p>
&lt;p>&lt;em>I/O:&lt;/em> PCIe bus, onboard Ethernet port, 2 × DSI ports (only one exposed on Raspberry Pi 4B), 2 × CSI ports (only one exposed on Raspberry Pi 4B), up to 6 × I2C, up to 6 × UART (muxed with I2C), up to 6 × SPI (only five exposed on Raspberry Pi 4B), dual HDMI video output, composite video output.&lt;/p>
&lt;p>The &lt;a href="https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf[datasheet">https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf[datasheet&lt;/a> for the BCM2711] contains further details.&lt;/p>
&lt;h1 id="bcm2712">BCM2712&lt;/h1>
&lt;p>Broadcom BCM2712 is the 16nm application processor at the heart of Raspberry Pi 5. It is the successor to the BCM2711 device used in Raspberry Pi 4, and shares many common architectural features with other devices in the BCM27xx family, used on earlier Raspberry Pi products.&lt;/p>
&lt;p>Built around a quad-core Arm Cortex-A76 CPU cluster, clocked at up to 2.4GHz, with 512KB per-core L2 caches and a 2MB shared L3 cache, it integrates an improved 12-core VideoCore VII GPU; a hardware video scaler and HDMI controller capable of driving dual 4kp60 displays; and a Raspberry Pi-developed HEVC decoder and Image Signal Processor. A 32-bit LPDDR4X memory interface provides up to 17GB/s of memory bandwidth, while x1 and x4 PCI Express interfaces support high-bandwidth external peripherals; on Raspberry Pi 5 the latter is used to connect to the Raspberry Pi RP1 south bridge, which provides the bulk of the external-facing I/O functionality on the platform.&lt;/p>
&lt;p>Headline features include:&lt;/p>
&lt;ul>
&lt;li>Quad-core Arm Cortex-A76 @ 2.4GHz
** ARMv8-A ISA
** 64KByte I and D caches
** 512KB L2 per core, 2MB shared L3&lt;/li>
&lt;li>New Raspberry Pi-developed ISP
** 1 gigapixel/sec&lt;/li>
&lt;li>Improved HVS and display pipeline
** Dual 4Kp60 support&lt;/li>
&lt;li>VideoCore V3D VII
** ~2-2.5× faster (more hardware, 1GHz versus 600MHz on Pi 4)
** OpenGL ES 3.1, Vulkan 1.3&lt;/li>
&lt;li>4Kp60 HEVC hardware decode
** Other CODECs run in software
** H264 1080p24 decode ~10–20% of CPU
** H264 1080p60 decode ~50–60% of CPU
** H264 1080p30 encode (from ISP) ~30–40% CPU&lt;/li>
&lt;/ul>
&lt;p>In aggregate, the new features present in BCM2712 deliver a performance uplift of 2-3x over Raspberry Pi 4 for common CPU or I/O-intensive use cases.&lt;/p>
&lt;hr>
&lt;h1 id="whats-in-the-cloud">Whats in the Cloud&lt;/h1>
&lt;p>Previously we looked at Cloud provider costs. We blindly selected the cheapest instance type (c6g.xlarge) and went with it. But what is really running on those instances? What is the processor? How does it compare to the Raspberry Pi?&lt;/p>
&lt;p>The c6g instance family provides the Graviton2 processor, featuring 64 ARM Neoverse N1 cores and a clock speed of 2.5 GHz, is designed for scalable cloud computing. In the case of the c6g.xlarge instance type, which typically provides access to four virtual CPUs, the allocation of cache resources plays a significant role in determining overall performance.&lt;/p>
&lt;p>Here&amp;rsquo;s the breakdown of cache allocation for each c6g.xlarge instance:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>L1 Cache: The Graviton2 processor has 32 KB of L1 cache per core. With four cores allocated to each instance, the total L1 cache available per instance is 32 KB * 4 = 128 KB. In comparison, the RPi5 gives us 128 KiB (64 KiB I-cache with parity, 64 KiB D-cache) per core of L1 cache. This is the same as the c6g.xlarge instance!&lt;/p>
&lt;/li>
&lt;li>
&lt;p>L2 Cache: Each core of the Graviton2 processor is equipped with 1 MB of L2 cache. With four cores per instance, the total L2 cache available per instance is 1 MB * 4 = 4 MB. In comparison, the RPi5 gives us 512 KiB per core of L2 cache. So the c6g.xlarge instance has 8x more L2 cache than the RPi5. This would make a big difference in compute performance for memory or IO intense workloads.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>L3 Cache: The Graviton2 processor features a shared L3 cache of 32 MB. Allocating this cache across multiple instances requires careful consideration. Assuming equal distribution, if we divide the total L3 cache equally among, for example, 10 c6g.xlarge instances, each instance would receive 32 MB / 10 = 3.2 MB of L3 cache. The RPi5 has a 2MB shared L3 cache. So the c6g.xlarge instance has more L3 cache than the RPi5 - but not a whole lot more.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>It&amp;rsquo;s essential to note that this allocation is simplified and theoretical. In practice, cloud providers dynamically manage resource allocation based on workload demands and system optimization strategies. Understanding these allocation principles enables users to make informed decisions when configuring and optimizing their cloud deployments.&lt;/p>
&lt;p>By contrast, Raspberry Pi&amp;rsquo;s BCM2711 and BCM2712 chips offer dedicated cache resources for standalone computing tasks, emphasizing performance in single-board computing and hobbyist projects. While these chips provide consistent performance within their designated environments, the shared infrastructure of cloud instances like the c6g.xlarge demands a nuanced understanding of resource allocation for optimal utilization.&lt;/p></description></item><item><title>Blog: Unlocking the Magic of SPAs, Static Sites, and Nuxt.js with OAuth</title><link>https://codeblind-ai.github.io/blog/2024/03/01/unlocking-the-magic-of-spas-static-sites-and-nuxt.js-with-oauth/</link><pubDate>Fri, 01 Mar 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/03/01/unlocking-the-magic-of-spas-static-sites-and-nuxt.js-with-oauth/</guid><description>
&lt;p>In our previous blog post, we showcased the simplicity and speed of creating static landing sites with Hugo. However, when the need for dynamic and interactive web experiences arises, Nuxt.js and Vue.js step in to offer powerful solutions.&lt;/p>
&lt;p>Nuxt.js and Vue.js provide a versatile approach for building dynamic web applications, offering benefits such as server-side rendering (SSR) or Single Page Application (SPA) behavior akin to static sites. This hybrid approach ensures better performance, SEO optimization, and enhanced user experience compared to purely static sites. Additionally, Vue.js&amp;rsquo;s component-based architecture and intuitive syntax make development straightforward and enjoyable.&lt;/p>
&lt;p>Let&amp;rsquo;s dive into building a Nuxt.js demo application, complete with login capabilities integrated using Auth0, to unlock the full potential of dynamic web experiences.&lt;/p>
&lt;h1 id="what-is-the-difference-between-a-static-site-vs-spa">What is the Difference between a Static Site vs SPA?&lt;/h1>
&lt;p>Single Page Applications (SPAs) have transformed web development, ushering in an era of seamless user experiences through dynamic content loading sans full-page refreshes. By fetching data asynchronously, SPAs deliver lightning-fast load times and fluid interactions, captivating users with their responsiveness.&lt;/p>
&lt;p>In contrast, static sites pre-render content during build time, serving up crisp, pre-generated files directly to users. This approach bypasses server-side processing, unleashing unrivaled speed and scalability upon the digital landscape.&lt;/p>
&lt;p>Now, imagine a fusion of these two paradigms—SPAs and static sites—ushering in a new era of web development innovation. Enter frameworks like Nuxt.js, seamlessly blending the dynamic prowess of SPAs with the rapid deployment capabilities of static site generation. With features like server-side rendering (SSR), static site generation (SSG), and effortless plugin integration, Nuxt.js empowers developers to craft web experiences that are as dynamic as they are efficient.&lt;/p>
&lt;h1 id="what-is-oauth-protocol-about">What is OAuth Protocol About?&lt;/h1>
&lt;p>OAuth has become the de facto standard for secure authentication and authorization on the web. It enables users to leverage login credentials from third-party applications (such as GitHub, Google, etc.) without sharing their credentials directly.&lt;/p>
&lt;p>These systems provide limited access to user contact information or resources without sharing their credentials.&lt;/p>
&lt;p>OAuth&amp;rsquo;s protocol flow involves authentication servers, authorization grants, and access tokens, ensuring secure communication between the user, client application, and resource server.&lt;/p>
&lt;p>The following diagram outlines the typical flow of implementing a web app that supports OAuth.&lt;/p>
&lt;pre class="mermaid">sequenceDiagram
participant Browser as SPA
participant Auth0 as Auth0
participant Backend as Backend Service
Browser-&amp;gt;&amp;gt;Auth0: User clicks &amp;#34;Login with Auth0&amp;#34;
Auth0-&amp;gt;&amp;gt;Browser: Redirect to Auth0 login page
Browser-&amp;gt;&amp;gt;Auth0: User enters credentials
Auth0-&amp;gt;&amp;gt;Browser: Redirect to callback URL with authorization code
Browser-&amp;gt;&amp;gt;Backend: Send authorization code
Backend-&amp;gt;&amp;gt;Auth0: Exchange code for access token
Auth0-&amp;gt;&amp;gt;Backend: Provide access token
Backend-&amp;gt;&amp;gt;Browser: Deliver requested data&lt;/pre>
&lt;p>&lt;strong>Flow Explanation:&lt;/strong>&lt;/p>
&lt;ol>
&lt;li>The user clicks on the &amp;ldquo;Login with Auth0&amp;rdquo; button in the browser (SPA).&lt;/li>
&lt;li>The browser initiates a request to Auth0.&lt;/li>
&lt;li>Auth0 redirects the browser to its login page.&lt;/li>
&lt;li>The user enters their credentials.&lt;/li>
&lt;li>Auth0 verifies the credentials and redirects the browser back to the SPA with an authorization code.&lt;/li>
&lt;li>The browser sends the authorization code to the backend service.&lt;/li>
&lt;li>The backend service exchanges the authorization code for an access token by making a request to Auth0.&lt;/li>
&lt;li>mAuth0 validates the authorization code and issues an access token to the backend service.&lt;/li>
&lt;li>The backend service uses the access token to request the required data from Auth0.&lt;/li>
&lt;li>Auth0 verifies the access token and provides the requested data to the backend service.&lt;/li>
&lt;li>Finally, the backend service delivers the requested data to the browser.&lt;/li>
&lt;/ol>
&lt;h2 id="what-is-auth0">What is Auth0?&lt;/h2>
&lt;p>Implementing OAuth authentication for every web application can indeed be cumbersome and intricate. Fortunately, authentication aggregation services like Auth0 exist to alleviate these challenges. They not only handle the complexities of authentication protocols and security measures but also simplify the integration process into your application with just a few lines of code.&lt;/p>
&lt;p>With Auth0, developers can leverage a comprehensive suite of authentication and authorization features, including user management, social login integrations, multi-factor authentication, and more. By abstracting away the intricacies of OAuth implementation and providing a user-friendly dashboard for configuration, Auth0 empowers developers to focus on building their applications&amp;rsquo; core functionality without compromising on security or user experience.&lt;/p>
&lt;hr>
&lt;h1 id="step-by-step-guide-for-oauth-authentication-with-auth0">Step-by-Step Guide for OAuth Authentication with Auth0&lt;/h1>
&lt;h2 id="1-create-or-login-to-auth0">1. Create or Login to Auth0&lt;/h2>
&lt;h2 id="2-create-a-new-application">2. Create a New Application&lt;/h2>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-01-creating-application.png">&lt;/p>
&lt;h2 id="2-select-the-application-type">2. Select the Application Type&lt;/h2>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-02-app-type-selection.png">&lt;/p>
&lt;ol>
&lt;li>Fill out the name for the new application&lt;/li>
&lt;li>Ensure you select &lt;code>Single Page App&lt;/code>&lt;/li>
&lt;li>Select &lt;code>Vue&lt;/code> (or your favorite framework)&lt;/li>
&lt;li>Click the &lt;code>Continue&lt;/code> Button&lt;/li>
&lt;/ol>
&lt;h2 id="3-download-the-generated-sample">3. Download the Generated Sample&lt;/h2>
&lt;p>Next Auth0 will allow you to download a ready to use application for that framework!&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-03-download-sample.png">&lt;/p>
&lt;h2 id="4-update-your-application-settings">4. Update your Application Settings&lt;/h2>
&lt;p>In this next screen, you will see getting started information for running the application locally.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-04-getting-started.png">&lt;/p>
&lt;p>To make this work, you must configure your settings for:&lt;/p>
&lt;ol>
&lt;li>&lt;code>Allowed Calledback URLs&lt;/code>&lt;/li>
&lt;li>&lt;code>Allowed Logout URLs&lt;/code>&lt;/li>
&lt;li>and &lt;code>Allowed Web Origins&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>Notice the link in the screen shot above, open a tab so that you can update the settings as shown below.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-05-local-config.png">&lt;/p>
&lt;p>Once done, save the settings.&lt;/p>
&lt;h2 id="5-select-your-login-support">5. Select your Login Support&lt;/h2>
&lt;p>Next navigate to the Connections Tab. Here you can enable the &amp;ldquo;Connection&amp;rdquo; types, such as:&lt;/p>
&lt;ol>
&lt;li>Google oauth2 authentication&lt;/li>
&lt;li>Github OAuth2 authentication&lt;/li>
&lt;li>and even &amp;lsquo;username and password&amp;rsquo; base authentication&lt;/li>
&lt;/ol>
&lt;p>Make you selection and save your settings.&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-06-config-access-types.png">&lt;/p>
&lt;h2 id="5-configure-and-run-the-application-locally">5. Configure and Run the Application Locally&lt;/h2>
&lt;p>Now with all the configuration out of the way, we can start working with the downloaded project from our previous step.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Unpack the downloaded application archive, and open the code in an IDE of your choice.
&lt;img src="https://codeblind-ai.github.io/images/blogs/3/unzip.png">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The project &lt;em>may&lt;/em> needs to be configured with your Auth0 domain and client ID in order for the authentication flow to work. However generally the zip is pre-configured with the application identity. Let&amp;rsquo;s look at them. Open &lt;code>auth_config.json&lt;/code>, and verify the application verification domain, and client ID are correct:&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-07-client-id-02.png">&lt;/p>
&lt;p>They should match the values from the application listing in Auth0 application settings:&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-07-client-id-01.png">&lt;/p>
&lt;h2 id="5-verifying-the-configuration">5. Verifying the Configuration&lt;/h2>
&lt;ol>
&lt;li>In a console, navigate to the root of the project and run:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>sh exec.sh
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-08-starting-the-app.png">&lt;/p>
&lt;ol start="2">
&lt;li>Open your browser to http://localhost:1313. You should expect to see something as below.&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-09-open-browser.png">&lt;/p>
&lt;ol start="3">
&lt;li>Click the login button and select a login method to test.&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-10-select-a-login-method.png">&lt;/p>
&lt;p>For example below is an example of what one might see if they clicked the github login method. Once you have reviewed and accepted the permissions - it will grant access in the users account to profile (name, email, userId).&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/auth0-11-accept-permission-grant.png">&lt;/p>
&lt;p>Once this has successfully completed, we can click the drop down next to your user avatar and select &lt;code>profile&lt;/code>. This will show you what data was captured from the user account on the provider (github, google, etc).&lt;/p>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/user-details.png">&lt;/p>
&lt;h2 id="6-deploying-to-github-pages">6. Deploying to Github Pages&lt;/h2>
&lt;p>Now that the first steps are successfully working, it is time to get this into source control, enable github pages, configure it to use DNS, update the settings on the application listing in Auth0.&lt;/p>
&lt;p>Many of these steps will be very similar to the steps we took in the previous post - when deploying our hugo blog to Github pages.&lt;/p>
&lt;ol>
&lt;li>Create a github repository
&lt;img src="https://codeblind-ai.github.io/images/blogs/3/create-new-repo.png">&lt;/li>
&lt;li>In github pages settings of the new repository, enable deployment with 1Github Actions`:
&lt;img src="https://codeblind-ai.github.io/images/blogs/3/setting-github-action.png">&lt;/li>
&lt;li>Next create a new file in the repository under the path &lt;code>.github/workflows/deploy.yaml&lt;/code> and paste in the following content:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8f5902;font-style:italic"># Simple workflow for deploying static content to GitHub Pages&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Deploy static content to Pages&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">on&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Runs on pushes targeting the default branch&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">push&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">branches&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000;font-weight:bold">[&lt;/span>&lt;span style="color:#4e9a06">&amp;#34;main&amp;#34;&lt;/span>&lt;span style="color:#000;font-weight:bold">]&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Allows you to run this workflow manually from the Actions tab&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">workflow_dispatch&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Sets the GITHUB_TOKEN permissions to allow deployment to GitHub Pages&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">permissions&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">contents&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">read&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">pages&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">write&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">id-token&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">write&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Allow one concurrent deployment&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">concurrency&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">group&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;pages&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">cancel-in-progress&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">true&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline">&lt;/span>&lt;span style="color:#204a87;font-weight:bold">jobs&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Single deploy job since we&amp;#39;re just deploying&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">deploy&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">environment&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">github-pages&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">url&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">${{ steps.deployment.outputs.page_url }}&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">runs-on&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">ubuntu-latest&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">steps&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Checkout&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">uses&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">actions/checkout@v4&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Set up Node&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">uses&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">actions/setup-node@v3&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">with&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">node-version&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#0000cf;font-weight:bold">18&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">cache&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;npm&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Install dependencies&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">run&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">npm install&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Build&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">run&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">npm run build&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Setup Pages&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">uses&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">actions/configure-pages@v3&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Upload artifact&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">uses&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">actions/upload-pages-artifact@v2&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">with&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#8f5902;font-style:italic"># Upload dist repository&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">path&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#4e9a06">&amp;#34;./dist&amp;#34;&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>- &lt;span style="color:#204a87;font-weight:bold">name&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">Deploy to GitHub Pages&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">id&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">deployment&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#204a87;font-weight:bold">uses&lt;/span>&lt;span style="color:#000;font-weight:bold">:&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline"> &lt;/span>&lt;span style="color:#000">actions/deploy-pages@v2&lt;/span>&lt;span style="color:#f8f8f8;text-decoration:underline">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Commit this change.
&lt;img src="https://codeblind-ai.github.io/images/blogs/3/deploy-automation-1.png">&lt;/p>
&lt;ol>
&lt;li>Navigate to the &lt;code>Actions&lt;/code> tab in your repository. You should see the deployment job successfully complete.&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/3/deploy-automation-2.png">&lt;/p>
&lt;ol start="5">
&lt;li>Navigate to the &lt;code>Github Pages&lt;/code> settings once more, and you will expect to see the link to your read to use site hosted on github pages.&lt;/li>
&lt;/ol>
&lt;p>From this point, I will leave the exercise of configuring a real domain name to you as a learning exercise. Here are a few hints:&lt;/p>
&lt;ol>
&lt;li>You will need to update your application listing to set the &lt;code>domain&lt;/code> of the application.&lt;/li>
&lt;li>There are 4 settings you will make there; the 3 settings we provided above and the &lt;code>Application Login URL&lt;/code>.&lt;/li>
&lt;li>If you have a custom domain, configure your DNS records - as we did in the previous post, and update the github pages settings.&lt;/li>
&lt;/ol>
&lt;h1 id="summary">Summary&lt;/h1>
&lt;p>In summary, we created a static (SPA) site - that has the ability to dynamically call backend services using Vue, NuxtJS and Auth0. From here one could easily add new backend services.&lt;/p>
&lt;p>One interesting enhancement we could might is to complete the login flow. This would entail sending the Users &lt;code>authorization code&lt;/code> provided from Auth0 to a backend API. The backend API would validate the &lt;code>authorization code&lt;/code> and obtain a &lt;code>access token&lt;/code>. Using this access token it would be possible to lookup user information and generate a JWT or grant document using &lt;a href="https://paseto.io/">PASETO grant&lt;/a>. I may provide a guide for doing this in an upcoming post. For now, check out my finished demo at &lt;a href="https://app.codeblind.ai">https://app.codeblind.ai&lt;/a>. Cheers and happy coding!&lt;/p></description></item><item><title>Blog: v0.1.0</title><link>https://codeblind-ai.github.io/blog/2024/02/29/v0.1.0/</link><pubDate>Thu, 29 Feb 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/02/29/v0.1.0/</guid><description>
&lt;style>
aside {
width: 30%;
padding-left: 0.5rem;
margin-left: 0.5rem;
float: right;
box-shadow: inset 5px 0 5px -5px #29627e;
font-style: italic;
color: #29627e;
}
aside > p {
margin: 0.5rem;
}
i {
color: green;
}
&lt;/style>
&lt;h1>
&lt;i>
crazy-horse edition
&lt;/i>
&lt;/h1>
&lt;aside>
&lt;h3>COMING SOON...&lt;/h3>
&lt;/aside>
&lt;p>
This first release will be an Exciting and Transformative moment. CodeBlind platform will change everything... So stay tuned and check back soon!
&lt;/p>
&lt;h2>Features:&lt;/h2>
&lt;dl>
&lt;dt>Beast Mode&lt;/dt>
&lt;dd>wait and see...&lt;/dd>
&lt;dt>Another feature&lt;/dt>
&lt;dd>wait and see...&lt;/dd>
&lt;/dl></description></item><item><title>Blog: Building a Landing Site</title><link>https://codeblind-ai.github.io/blog/2024/02/28/building-a-landing-site/</link><pubDate>Wed, 28 Feb 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/02/28/building-a-landing-site/</guid><description>
&lt;h2 id="discover-why-static-sites-are-valuable-to-learn-whether-you-want-to-share-your-thoughts-bootstrap-a-startup-or-build-an-open-source-project">Discover why static sites are valuable to learn, whether you want to share your thoughts, bootstrap a startup, or build an open-source project.&lt;/h2>
&lt;p>This post explores the process of building a landing site using static site hosting on Github Pages and automating deployment with Github Actions. We&amp;rsquo;ll delve into the benefits of static sites and build one together for a personal blogs, or possibly a startup landing pages.&lt;/p>
&lt;p>This site will approach build a set of sites and applications designed to bootstrap a startup on a budget, where &amp;ldquo;free&amp;rdquo; is the magic word.&lt;/p>
&lt;p>When undertaking such a task, it&amp;rsquo;s crucial to build a landing site using a real, branded domain to foster engagement and adoption. The front door to such a site should be secure, fast, and open. Publish news, an engineering or market based blog, and including product documentation increase the likelihood of search engines indexing the site, thereby improving SEO and attracting and growing a community.&lt;/p>
&lt;p>Let&amp;rsquo;s explore the characteristics of this static sites:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Simplicity:&lt;/strong> Static sites are often simpler to build and maintain compared to dynamic sites, as there is no complex business logic, or server side rending. One can add more complex CSS styling, or animations, but generally pages are written in a familiar language such as markdown, making it easier to publish new content.&lt;/li>
&lt;li>&lt;strong>Easier to Own and Maintain:&lt;/strong> because there are no server-side components, databases, or access controls to manage, the site is generally simpler to own and operate beyond building CI/CD publishing automation.&lt;/li>
&lt;li>&lt;strong>Faster:&lt;/strong> because there is no server processing, or database queries involved. The web server serves the pre-built, minified HTML, CSS, and JavaScript files directly to the browser. Additionally, content delivery networks (CDNs) caching is possible and effective - making the site perform even better.&lt;/li>
&lt;li>&lt;strong>Secure by default:&lt;/strong> because there is no backend to worry about. This means the security concerns lay in exploit vectors such as the occasional contact form - and in the supply chain; components you use to build the pages.&lt;/li>
&lt;/ul>
&lt;p>Thus, static sites are commonly used for blogs, portfolios, landing pages, documentation, and marketing websites where simplicity and speed are priorities.&lt;/p>
&lt;h3 id="what-is-seo">What is SEO?&lt;/h3>
&lt;p>Search Engine Optimization (SEO) plays a critical role in driving adoption and expanding market reach for websites. This is particularly important for startups and businesses operating on a budget. By ensuring that your site ranks well in search engine results, you can attract organic traffic, increase visibility, and ultimately, reach a wider audience.&lt;/p>
&lt;p>Because the entire site is static, search engine crawlers typically can consume can easily index and rank the content without encountering any barriers.&lt;/p>
&lt;h2 id="static-site-generators">Static Site Generators&lt;/h2>
&lt;p>Static site generators (SSGs) streamline website development by transforming structured content into static HTML, CSS, and JavaScript files. &lt;a href="https://gohugo.io/">Hugo&lt;/a> is well known for its speed and flexibility. It converts Markdown or other formats into static pages - and is written in golang - making it my top choice.&lt;/p>
&lt;p>There are other popular options - which deliver more flexible power - such as Gatsby, Next.js, and Nuxt.js. I hope to write a post soon to contract the differences of those. However today, we want to build a site. Let&amp;rsquo;s get started!&lt;/p>
&lt;hr>
&lt;h1 id="1-register-a-domain-name">1. Register a Domain Name&lt;/h1>
&lt;p>Registering a &lt;em>&amp;ldquo;good&amp;rdquo;&lt;/em> domain name is maybe the hardest part of the process. The name becomes your brand, and depending on what you are making, can become a house hold name.&lt;/p>
&lt;p>In this post, I use &lt;a href="https://www.namecheap.com/">Namecheap&lt;/a>, however there are pros and cons of each registrar.&lt;/p>
&lt;h1 id="2-create-a-hugo-site">2. Create a hugo site&lt;/h1>
&lt;p>The &lt;a href="https://gohugo.io/">Hugo&lt;/a> project has a great &lt;a href="https://gohugo.io/getting-started/quick-start/">Quick Start Guide&lt;/a> to bootstrap your site, and help you find a theme.&lt;/p>
&lt;p>For this post, I am going to take a shortcut since I know I want a landing site with multi-language support, blog and documentation support.&lt;/p>
&lt;p>&lt;a href="https://www.docsy.dev/">Docsy&lt;/a> provides those exact features and has an amazing look and feel. The fastest way to boot strap the site, is to &lt;code>fork&lt;/code> or &lt;code>clone&lt;/code> the &lt;a href="https://github.com/sprydevl/sprydevl.github.io">my example site repository&lt;/a>.&lt;/p>
&lt;p>My favorite way of doing this is:&lt;/p>
&lt;ol>
&lt;li>
&lt;p>Click the &lt;code>&amp;quot;Use This Template&amp;quot;&lt;/code> button in the repository and select &lt;code>Create a new repository&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Fill out the repository name to be &lt;code>USERNAME.github.io&lt;/code> where &lt;code>USERNAME&lt;/code> is your github username. Leave the other settings default - then click &lt;code>Create&lt;/code>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;!-- /images/blogs/2 -->
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/2/create-new-repo-1.png">&lt;/p>
&lt;h1 id="3-update-the-baseurl-for-your-new-site">3. Update the &lt;code>baseURL&lt;/code> for your new site&lt;/h1>
&lt;p>In either a local clone, or from within the github itself, change the &lt;code>baseURL&lt;/code> in the &lt;code>hugo.toml&lt;/code> to have your new domain name. For my PoC I will be using &lt;code>blindcoder.com&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>click on the &lt;code>hugo.toml&lt;/code> file link&lt;/li>
&lt;li>click the edit this file button on the upper left hand corner of the file window.&lt;/li>
&lt;li>Update the &lt;code>baseURL&lt;/code> setting:&lt;/li>
&lt;/ol>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c4a000">baseURL&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;https://blindcoder.com/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>To your domain name. For example:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-ini" data-lang="ini">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c4a000">baseURL&lt;/span> &lt;span style="color:#ce5c00;font-weight:bold">=&lt;/span> &lt;span style="color:#4e9a06">&amp;#34;https://YOUR_DOMAIN/&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>&lt;strong>Note:&lt;/strong> update &lt;code>YOUR_DOMAIN&lt;/code> in the statement above leave the trailing slash.&lt;/p>
&lt;/blockquote>
&lt;ol start="4">
&lt;li>Click the &lt;code>Commit Changes&lt;/code> button and commit the changes.&lt;/li>
&lt;/ol>
&lt;h1 id="4-setting-up-github-pages">4. Setting up Github Pages&lt;/h1>
&lt;ol>
&lt;li>
&lt;p>Click the &lt;code>Settings&lt;/code> tab at the top of the repository page
&lt;img src="https://codeblind-ai.github.io/images/blogs/2/pages-1.png">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Click the &lt;code>Pages&lt;/code> settings menu option on the left panel
&lt;img src="https://codeblind-ai.github.io/images/blogs/2/pages-2.png">&lt;/p>
&lt;/li>
&lt;li>
&lt;p>In the &lt;code>Pages&lt;/code> settings, ensure &lt;code>Source&lt;/code> is set to
In the &lt;code>Pages&lt;/code> section of the repository settings, ensure the &lt;code>Source&lt;/code> is set to Github Actions.
&lt;img src="https://codeblind-ai.github.io/images/blogs/2/pages-3.png">&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h1 id="5-github-actions-build-and-deployment-automation">5. Github Actions: Build and Deployment Automation&lt;/h1>
&lt;p>Github Actions is a powerful tool that allows you to automate your software development workflows. We will use it to build and deploy our site to Github Pages.&lt;/p>
&lt;p>If you&amp;rsquo;ve forked my repository, you will already have a actions configuration in &lt;code>.github/workflows/hugo.yaml&lt;/code>. Note there are a number of prebuilt &lt;a href="https://github.com/actions/starter-workflows/tree/main/pages">action templates&lt;/a> depending on the technology you are using. Check them out!&lt;/p>
&lt;h1 id="6-validate-the-site-is-working">6. Validate the site is working.&lt;/h1>
&lt;p>Shortly after updating the &lt;code>Pages&lt;/code> settings, the site was already published. You should verify it is all working but visiting the site &lt;a href="https://USERNAME.github.io">https://USERNAME.github.io&lt;/a> where &lt;code>USERNAME&lt;/code> is your Github username or organization name. You should expect something similar as below:&lt;/p>
&lt;!-- /images/blogs/2 -->
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/2/demo-site.png">&lt;/p>
&lt;h1 id="6-customizing-your-domain">6. Customizing your Domain&lt;/h1>
&lt;p>Now that we have validated everything is working as expected. Let&amp;rsquo;s setup our custom domain to our branded domain.&lt;/p>
&lt;p>This work will happen in two parts, one phase on &lt;a href="https://www.namecheap.com/">Namecheap&lt;/a> and the other on Github.&lt;/p>
&lt;h2 id="61-update-the-dns-settings-on-your-registrar">6.1 Update the DNS settings on your Registrar&lt;/h2>
&lt;p>As mentioned earlier, I use Namecheap, so I will provide those instructions. However the DNS settings could be applied to the DNS management of your domain on any of the registrar. Some steps may differ slightly.&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>&lt;a href="https://www.namecheap.com/myaccount/login.aspx">Sign in&lt;/a> to your Namecheap account.&lt;/strong>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Select Domain List from the left sidebar and click on the Manage button next to your domain name:&lt;/strong>&lt;/p>
&lt;/li>
&lt;/ol>
&lt;!-- /images/blogs/2 -->
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/2/nc_manage.png">&lt;/p>
&lt;ol start="3">
&lt;li>&lt;strong>Navigate to the Advanced DNS tab and click on the Add New Record button:&lt;/strong>&lt;/li>
&lt;/ol>
&lt;!-- /images/blogs/2 -->
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/2/nc_addnewrecord.png">&lt;/p>
&lt;ol start="4">
&lt;li>&lt;strong>Add the following records to your domain:&lt;/strong>&lt;/li>
&lt;/ol>
&lt;table>
&lt;tr>
&lt;th>Type&lt;/th>
&lt;th>Host&lt;/th>
&lt;th>Value&lt;/th>
&lt;th>TTL&lt;/th>
&lt;th>Notes&lt;/th>
&lt;/tr>
&lt;tr>
&lt;td>A&lt;/td>
&lt;td>@&lt;/td>
&lt;td>185.199.108.153&lt;/td>
&lt;td>Automatic&lt;/td>
&lt;td>Github IP&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A&lt;/td>
&lt;td>@&lt;/td>
&lt;td>185.199.109.153&lt;/td>
&lt;td>Automatic&lt;/td>
&lt;td>Github IP&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A&lt;/td>
&lt;td>@&lt;/td>
&lt;td>185.199.110.153&lt;/td>
&lt;td>Automatic&lt;/td>
&lt;td>Github IP&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>A&lt;/td>
&lt;td>@&lt;/td>
&lt;td>185.199.111.153&lt;/td>
&lt;td>Automatic&lt;/td>
&lt;td>Github IP&lt;/td>
&lt;/tr>
&lt;tr>
&lt;td>CNAME&lt;/td>
&lt;td>www&lt;/td>
&lt;td>&lt;code>username&lt;/code>.github.io&lt;/td>
&lt;td>Automatic&lt;/td>
&lt;td>Replace &lt;code>username&lt;/code> with your actual GitHub account username&lt;/td>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;em>&lt;strong>Note 1:&lt;/strong>&lt;/em> delete the other records that are there by default. We only need the records above for now. 🗑️&lt;/p>
&lt;p>&lt;em>&lt;strong>Note 2:&lt;/strong>&lt;/em> you may have to wait for DNS to update. It can take up to 30 minutes - so now is a great time to brew a cup of tea. ☕&lt;/p>
&lt;/blockquote>
&lt;h2 id="62-defining-the-custom-domain-on-github">6.2 Defining the Custom Domain on Github&lt;/h2>
&lt;p>Now that the DNS is setup, we need to tell Github to use the custom domain.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Navigate to the repository settings and scroll down to the &lt;code>Github Pages&lt;/code> section.&lt;/strong>&lt;/li>
&lt;li>&lt;strong>Add your custom domain to the &lt;code>Custom domain&lt;/code> input.&lt;/strong> This should be in the form of &lt;code>yourdomain.com&lt;/code> or &lt;code>www.yourdomain.com&lt;/code> depending on your preference.&lt;/li>
&lt;li>&lt;strong>Click &lt;code>Save&lt;/code> to save the changes.&lt;/strong>&lt;/li>
&lt;/ol>
&lt;p>At this point Github will validate the domain and if everything is setup correctly, your site will be available at your custom domain.&lt;/p>
&lt;p>There is a small context text area that will show you the status of the domain validation. If there are any issues, may want to look back at your Namecheap DNS configuration.&lt;/p>
&lt;h1 id="7-verify-your-new-domain">7. Verify your new Domain&lt;/h1>
&lt;!-- /images/blogs/2 -->
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/2/demo-final.png">&lt;/p>
&lt;h1 id="summary">Summary&lt;/h1>
&lt;p>&lt;strong>That&amp;rsquo;s it! It should now be live and visible at your custom domain.&lt;/strong> 🎉&lt;/p>
&lt;p>In this post, we have setup a site for our startup. We have used free services to keep costs low and automated the deployment process to ensure we can focus on the product.&lt;/p>
&lt;p>In upcoming posts, I hope to share a similar approach using Nuxt.js and Vue creating a SPA (similar to a static site) which can call backend services - and still be hosted on github pages for free! At least the SPA side anyway.&lt;/p>
&lt;p>Follow my blog for more exciting posts. Be excellent, and happy coding! 🚀&lt;/p>
&lt;!-- Links --></description></item><item><title>Blog: What is a Cloud Anyway?</title><link>https://codeblind-ai.github.io/blog/2024/02/27/what-is-a-cloud-anyway/</link><pubDate>Tue, 27 Feb 2024 00:00:00 +0000</pubDate><guid>https://codeblind-ai.github.io/blog/2024/02/27/what-is-a-cloud-anyway/</guid><description>
&lt;p>&lt;img src="https://codeblind-ai.github.io/images/blogs/1/cloud-naut.jpg">&lt;/p>
&lt;p>In modern development, the concept of the Cloud is intrinsic to the daily role of most engineers. Cloud Native development involves designing, building, owning, and operating applications running on a Cloud.&lt;/p>
&lt;p>But what exactly is the Cloud? If you&amp;rsquo;ve worked on cloud-native applications, platforms like &lt;a href="alibaba">Alibaba Cloud&lt;/a>, &lt;a href="aws">AWS&lt;/a>, &lt;a href="azure">Azure&lt;/a>, &lt;a href="do">DigitalOcean&lt;/a>, &lt;a href="fly">Fly.io&lt;/a>, &lt;a href="gcp">GCP&lt;/a>, or &lt;a href="hetzner">Hetzner&lt;/a> to mind.&lt;/p>
&lt;p>Before delving deeper, let&amp;rsquo;s establish a clear understanding of the various types of Cloud environments:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Private Cloud:&lt;/strong> A private cloud is a dedicated computing environment reserved exclusively for a single organization. It can be housed on-premises within the organization&amp;rsquo;s data center or off-premises at a third-party provider&amp;rsquo;s facility. The defining feature of a private cloud is its operation solely for the benefit of the organization, offering enhanced control, security, and customization compared to public cloud services.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Public Cloud:&lt;/strong> In contrast, a public cloud operates as a computing model where resources such as virtual machines, storage, and applications are hosted and managed by third-party providers. These resources are made available to the general public via the internet. Public cloud services typically follow a pay-as-you-go model, enabling organizations to rapidly scale their infrastructure without requiring significant upfront capital investment. Prominent examples of public cloud providers include Amazon Web Services (AWS), Microsoft Azure, and Google Cloud Platform (GCP).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Hybrid Cloud:&lt;/strong> A hybrid cloud combines aspects of both private and public clouds, offering organizations the opportunity to leverage the strengths of each model. Workloads can be dynamically distributed between on-premises infrastructure and public cloud services based on factors such as cost-effectiveness, performance requirements, and security considerations. The inherent flexibility of a hybrid cloud empowers organizations to optimize their IT resources, retain control over sensitive data, and harness the scalability and agility inherent in public cloud platforms.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h2 id="cloud-liberties-security-exploration-in-the-cloud">Cloud Liberties: Security Exploration in the Cloud&lt;/h2>
&lt;p>Exploring security in public clouds presents three fundamental challenges:&lt;/p>
&lt;ol>
&lt;li>Cloud resources become expensive once beyond the free tier many providers offer.&lt;/li>
&lt;li>Debugging lower layer behavior can be challenging or even impossible.&lt;/li>
&lt;li>Security exploration with cloud infrastructure can pose risks, potentially leading to unintended consequences, legal ramifications, or account bans.&lt;/li>
&lt;/ol>
&lt;h2 id="embracing-a-private-cloud">Embracing a Private Cloud:&lt;/h2>
&lt;p>&lt;em>So, how can we find the freedom to learn and explore in a safe environment shielded from external scrutiny?&lt;/em>&lt;/p>
&lt;p>The answer may lie in building our own private cloud! Contrary to common belief, constructing a private cloud for security and technology research isn&amp;rsquo;t as daunting as it sounds. Today, with affordable and powerful hardware like the Raspberry Pi 5, coupled with numerous &amp;ldquo;free&amp;rdquo; services, we can create an infrastructure that rivals those of major cloud providers.&lt;/p>
&lt;p>In the upcoming posts - or perhaps many posts - I&amp;rsquo;ll guide you through the process. Moreover, I&amp;rsquo;ll demonstrate how to accomplish this on a shoestring budget!&lt;/p>
&lt;p>&lt;strong>Stick with me, and let&amp;rsquo;s embark on this exciting journey together!&lt;/strong>&lt;/p>
&lt;!-- LINKS --></description></item></channel></rss>