<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Dom Goodwin</title>
    <link>/</link>
    <description>Recent content on Dom Goodwin</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>dom@domgoodwin.dev (Dom Goodwin)</managingEditor>
    <webMaster>dom@domgoodwin.dev (Dom Goodwin)</webMaster>
    <lastBuildDate>Wed, 25 Jan 2023 19:06:09 +0000</lastBuildDate><atom:link href="/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Don’t just say ‘hello’ to me</title>
      <link>/post/dont-say-hello/</link>
      <pubDate>Wed, 25 Jan 2023 19:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/dont-say-hello/</guid>
      <description>&lt;p&gt;I was recently in a 1-1 with my new EM and was asked what annoys me at work. The one thing that immediately popped to mind was:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;‘I hate it when someone just messages me “Hello” or “Hi, how are you” when they message me for something on Slack’&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It became immediately apparent that, without proper context, this could be taken the wrong way. So I thought I’d explain my thoughts here.&lt;/p&gt;</description>
      <content>&lt;p&gt;I was recently in a 1-1 with my new EM and was asked what annoys me at work. The one thing that immediately popped to mind was:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;‘I hate it when someone just messages me “Hello” or “Hi, how are you” when they message me for something on Slack’&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It became immediately apparent that, without proper context, this could be taken the wrong way. So I thought I’d explain my thoughts here.&lt;/p&gt;
&lt;p&gt;It has annoyed me since the advent of instant messaging at work, but as more people now work remotely the problem has only got worse.&lt;/p&gt;
&lt;p&gt;At a high level, the issue is this: instant messaging is asynchronous, unlike a verbal conversation, each participant can be doing something else at the beginning of the chat and might continue doing so for the duration of the conversation.&lt;/p&gt;
&lt;p&gt;With a phone call, communication is instantaneous, so the time for pleasantries is tiny compared to the actual discussion of a problem. When it’s via chat there’s delay, even if both parties are watching the chat, waiting to respond as soon as possible, they still take time to type and find the right emojis.&lt;/p&gt;
&lt;p&gt;Let’s use a sequence diagram to show what I mean:&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/nohello-1.1.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;Bob and Alice talk in serial&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;This is a pretty typical conversation, even ignoring Bob’s rudeness of not asking after Alice. Alice needs to ask Bob a question, but starts the conversation as you would in-person or by phone. If we think of humans as single core processors, both are basically ‘blocked’ for the entire duration, unable to do anything else until this conversation is over.&lt;/p&gt;
&lt;p&gt;This gets worse if you factor delays into the responses:&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/nohello-1.2.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;Bob and Alice talk in serial with delays&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;Now obviously this is a worst case scenario, both parties could be doing other things whilst waiting for responses, but that would also introduce more interruptions to their work. Adding a context switch every time someone sends a message would slow down whatever work they were doing, as an example:&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/nohello-1.3.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;Bob and Alice talk in serial with context switch delays&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;Here, Bob is trying to complete his work whilst also responding to Alice. Each time he responds then returns to his work. However, this means he needs to context switch and remember what he was working on before the interruption.&lt;/p&gt;
&lt;p&gt;Now, how could this be improved:&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/nohello-2.1.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;Bob and Alice exchange a single question&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;Alice has a question, she messages Bob the question but then go back to their work (if possible).&lt;/p&gt;
&lt;p&gt;Bob receives the question, thinks through an answer and sends it back to Alice who is then unblocked.&lt;/p&gt;
&lt;p&gt;Alternatively, Bob is working on a tough problem so doesn’t see the message until 30 minutes later, he then responds and Alice who was looking at a different problem can then get her answer.&lt;/p&gt;
&lt;p&gt;Regardless of how long a response takes, both parties spend the same time on the communication. Compare that to earlier examples, even if Bob context switched with every message, the time consumed with the same outcome (Alice has her answer) is far greater.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ A lot of this boils down to just sending someone &lt;a href=&#34;https://www.nohello.com/&#34;&gt;https://www.nohello.com/&lt;/a&gt; which explains this a lot more succinctly than I could.&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>Reducing our NAT Gateway cost with private networking between AWS and GCP</title>
      <link>/post/monzo-gcp-egress/</link>
      <pubDate>Sun, 15 Jan 2023 10:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/monzo-gcp-egress/</guid>
      <description>&lt;p&gt;This post is hosted on the Monzo Blog:&lt;/p&gt;</description>
      <content>&lt;p&gt;This post is hosted on the Monzo Blog:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&#34;https://monzo.com/blog/2022/11/25/reducing-nat-gateway-cost-with-private-networking-between-aws-and-gcp&#34;&gt;Reducing our NAT Gateway cost with private networking between AWS and GCP&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>Kubernetes Networking #3: Ingress</title>
      <link>/post/kubernetes-networking-ingress/</link>
      <pubDate>Fri, 22 Jul 2022 18:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/kubernetes-networking-ingress/</guid>
      <description>&lt;p&gt;Kubernetes Ingress provide a way to expose HTTP(S) routes into your pods from a centralized controller and load balancer. It means you can define &lt;em&gt;how&lt;/em&gt; the network traffic can get to your pod inside a Kubernetes resource and a controller hosted in the cluster takes care of the implementation.&lt;/p&gt;</description>
      <content>&lt;p&gt;Kubernetes Ingress provide a way to expose HTTP(S) routes into your pods from a centralized controller and load balancer. It means you can define &lt;em&gt;how&lt;/em&gt; the network traffic can get to your pod inside a Kubernetes resource and a controller hosted in the cluster takes care of the implementation.&lt;/p&gt;
&lt;p&gt;In a &lt;a href=&#34;https://en.wikipedia.org/wiki/Utopia&#34;&gt;world without Kubernetes&lt;/a&gt;, you might have a reverse proxy deployed where you write the configuration file to detail how to expose your applications in the backend. An ingress controller takes that reverse proxy and automatically generates the config based on the &lt;code&gt;Ingress&lt;/code&gt; Kubernetes resources you create. You don’t have to create a new &lt;code&gt;LoadBalancer&lt;/code&gt; service and cloud load balancer for each service you want to expose.&lt;/p&gt;
&lt;p&gt;In this guide, we’ll use the Kubernetes maintained ingress controller, &lt;a href=&#34;https://github.com/kubernetes/ingress-nginx&#34;&gt;ingress-nginx&lt;/a&gt;, which uses nginx as it’s reverse proxy. It’s important to note, this isn’t the &lt;a href=&#34;https://docs.nginx.com/nginx-ingress-controller/&#34;&gt;nginx-ingress-controller&lt;/a&gt; from NGINX themselves which has hooks into NGINX plus and other paid offerings. The docs for ingress-nginx can be found &lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;-why-not-just-loadbalancer&#34;&gt;🤷 Why not just LoadBalancer?&lt;/h2&gt;
&lt;p&gt;Kubernetes provides a way for a cloud provisioned load balancer (an &lt;a href=&#34;https://aws.amazon.com/elasticloadbalancing/&#34;&gt;AWS elastic load balancer&lt;/a&gt; for instance) to be deployed by the control plane, see my &lt;a href=&#34;https://dgood.win/post/kubernetes-networking-2-services/&#34;&gt;services post&lt;/a&gt; for more info. We can use these to expose a single service (and collection of pods) from a load balancer. But what happens when you have 50 services deployed onto your cluster? Would you have 50 load balancers for them all? That’s ~$810 in standing charges every month not including paying for the traffic that goes through them.&lt;/p&gt;
&lt;p&gt;This is where an ingress controller comes in. An Ingress controller is a centralized place for traffic to enter your cluster via a single load balancer which then is routed to your backend services automatically. This is all based on &lt;code&gt;Ingress&lt;/code&gt; resources deployed on the cluster, through the reverse proxy.
It also introduces a place to add some control over your traffic routing. kube-proxy will default (when in &lt;code&gt;iptables&lt;/code&gt; mode) to TCP load balancing traffic randomly, the traffic coming in via a load balancer goes to any pods. With the controls you can configure affinities, round-robin routing, rate limits, CORS etc. to really shape the traffic going to your pods centrally.&lt;/p&gt;
&lt;p&gt;These diagrams compare the path a request would take with/without an ingress controller exposing your pod:&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/ingress-lb-to-pod.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;Without: Application Service LoadBalancer → NodePort → Randomly to one of your pods&lt;/figcaption&gt;
    
  &lt;/figure&gt;



  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/ingress-controller-to-pod.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;With: Ingress-controller service LoadBalancer → NodePort → Randomly to an ingress-controller pod → To one of your application pods via ClusterIP&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;There are some tradeoffs to using an ingress controller:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This introduces an extra hop for your network requests to reach your pod. If you have high throughput - and low latency is important - this could be a consideration&lt;/li&gt;
&lt;li&gt;In the same vein, the ingress controller pods also use resources. If you have the ingress controller doing a lot of TLS termination or handling high load the resource usage will increase significantly&lt;/li&gt;
&lt;li&gt;You can only really use this for (mostly) Layer 7 traffic, TCP or UDP cannot directly be exposed this way&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-so-what-does-an-ingress-controller-actually-do&#34;&gt;🛠️ So what does an ingress controller actually do?&lt;/h2&gt;
&lt;p&gt;At a high level you have the following components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Kubernetes resources:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Service: type &lt;code&gt;LoadBalancer&lt;/code&gt;, meaning your ingress-controller pods are fronted by a cloud load balancer and exposed outside the cluster&lt;/li&gt;
&lt;li&gt;Deployment: Ingress Controller itself (see components below for a breakdown)&lt;/li&gt;
&lt;li&gt;(sometimes)Deployment: default backend, this is where the ingress controller routes traffic to when there isn’t a matching host/path rule for the traffic coming in&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Components of the ingress controller:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Reverse proxy: This is what actually routes the traffic coming in to downstream services/pods. If you installed nginx on a service and ran it it’s this basically&lt;/li&gt;
&lt;li&gt;Config generator: This continuously gets the state of Ingress resources in the Kubernetes cluster (think of it as spamming &lt;code&gt;kubectl get ingress -A&lt;/code&gt; every X-seconds) and uses that to generate config that the reverse proxy (nginx in this case) understands&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;em&gt;reverse proxy&lt;/em&gt; continually has it’s config updated by the &lt;em&gt;config generator&lt;/em&gt; and then traffic coming into the cluster via the &lt;em&gt;Loadbalancer service&lt;/em&gt; hits the reverse proxy and is routed to the proper backend service/pods.&lt;/p&gt;
&lt;h2 id=&#34;-what-about-ssl&#34;&gt;🔒 What about SSL?&lt;/h2&gt;
&lt;p&gt;For HTTPS traffic, we can configure the ingress-controller to terminate the SSL and provide the certs as needed.&lt;/p&gt;
&lt;p&gt;When creating an ingress resource you can specify a Kubernetes Secret of type &lt;code&gt;tls&lt;/code&gt; and the ingress-controller will use that secret to terminate the SSL of the request at the reverse proxy.&lt;/p&gt;
&lt;p&gt;This could also be coupled with a tool like &lt;a href=&#34;https://cert-manager.io/docs/&#34;&gt;cert-manager&lt;/a&gt; to dynamically issue and renew certificates for you.&lt;/p&gt;
&lt;h2 id=&#34;-load-balancerreverse-proxy-controls&#34;&gt;🎛️ Load balancer/Reverse proxy controls&lt;/h2&gt;
&lt;p&gt;As mentioned before, by having your pods traffic route via a reverse proxy in the cluster you gain more control over the routing and connection. Some useful examples for ingress-nginx are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: Setup &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc2617&#34;&gt;basic or digest access authentication&lt;/a&gt; on routes
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx.ingress.kubernetes.io/auth-type: basic&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Session affinity:&lt;/strong&gt; Allows for things like sticky sessions, keeping a user going to the same backend pod or use cookie affinity to apply a &lt;code&gt;SameSite&lt;/code&gt; sticky cookie
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx.ingress.kubernetes.io/affinity: sticky&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSL passthrough:&lt;/strong&gt; Instead of terminating TLS at the load balancer you can let the backend handle it directly
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx.ingress.kubernetes.io/ssl-passthrough: &amp;quot;true&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Redirections:&lt;/strong&gt; Both &lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#permanent-redirect&#34;&gt;permanent&lt;/a&gt; and &lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#temporal-redirect&#34;&gt;temporary&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx.ingress.kubernetes.io/permanent-redirect: https://www.google.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Security controls&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#ssl-ciphers&#34;&gt;SSL ciphers&lt;/a&gt; can be configured controlling which SSL ciphers you support
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx.ingress.kubernetes.io/ssl-ciphers: &amp;quot;ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#enable-cors&#34;&gt;CORS rules&lt;/a&gt; to configure the cross-original resource sharing rules
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;nginx.ingress.kubernetes.io/enable-cors: &amp;quot;true&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A lot of these controls can be configured either as &lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/&#34;&gt;annotations&lt;/a&gt; directly on Ingress resources affecting only those specific routes, or can be provided in the &lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/&#34;&gt;Configmap&lt;/a&gt; to be applied at a global level.&lt;/p&gt;
&lt;h2 id=&#34;-can-i-have-multiple-ingress-controllers&#34;&gt;🤹‍♂️ Can I have multiple ingress-controllers?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Yes&lt;/strong&gt;. Let’s say you want to be able to accept traffic from the public internet as well as internally from inside your private network.&lt;/p&gt;
&lt;p&gt;We would:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploy two sets of ingress-controllers, &lt;em&gt;ingress-public&lt;/em&gt; and &lt;em&gt;ingress-private&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Configure them to be public and private. This is done usually by the annotations given to the different &lt;code&gt;Service&lt;/code&gt; resources (&lt;code&gt;service.beta.kubernetes.io/aws-load-balancer-scheme: &amp;quot;internet-facing&amp;quot;&lt;/code&gt; for instance)&lt;/li&gt;
&lt;li&gt;Setup the Ingress classes
&lt;ul&gt;
&lt;li&gt;This is a relatively new resource, it used to be managed by an annotation &lt;code&gt;kubernetes.io/ingress.class&lt;/code&gt; which is being deprecated&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;When creating &lt;code&gt;Ingress&lt;/code&gt; resources you can target the &lt;code&gt;IngressClass&lt;/code&gt; to specify which controller should setup routing for your traffic&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-what-about-hostnames&#34;&gt;📮 What about hostnames?&lt;/h2&gt;
&lt;p&gt;Ingress resources in Kubernetes allow you to specify both the Paths and the Host values to route traffic for.&lt;/p&gt;
&lt;p&gt;To have your ingress controller exposed via a friendly DNS address you’d need to point a record of one to your load balancers DNS address. In AWS, this would be creating a Route53 A record aliased to your ELBs address. This would mean anything going to &lt;code&gt;friendly-address.domain.com&lt;/code&gt; would point to your cloud-provisioned ELB and then onto your reverse proxy pods from there.&lt;/p&gt;
&lt;p&gt;Then any routes off this hostname would be directed to your specified pods, ie.:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`friendly-address.domain.com/app-a` → `svc/app-a` in the cluster
`friendly-address.domain.com/app-b` → `svc/app-b` in the cluster and so on
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;But what if you wanted to have multiple different hostnames, maybe 1 per application.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;`app-a.friendly-address.domain.com/` → `svc/app-a`
`app-b.friendly-address.domain.com/` → `svc/app-b`
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;These would mean adding a new Route53 entry manually every time you want to deploy a new application. It takes away from the benefits of defining Ingress as a Kubernetes resource if you need to go click-ops or Terraform a new host each time.&lt;/p&gt;
&lt;p&gt;That’s where a tool like &lt;a href=&#34;https://github.com/kubernetes-sigs/external-dns&#34;&gt;external-dns&lt;/a&gt; comes in.&lt;/p&gt;
&lt;h3 id=&#34;external-dns&#34;&gt;external-dns&lt;/h3&gt;
&lt;p&gt;external-dns allows you to automatically configure your DNS services based on your Kubernetes Ingress resources (and services!).&lt;/p&gt;
&lt;p&gt;As an example, if you have deployed external-dns and wanted to setup a new &lt;code&gt;app-c.friendly-address.domain.com&lt;/code&gt; to point to your service all you would need to do is create an &lt;code&gt;Ingress&lt;/code&gt; resource with the &lt;code&gt;Host&lt;/code&gt; field set to &lt;code&gt;app-c.friendly-address.domain.com&lt;/code&gt; and external-dns would provision you an A record pointing to your load balancer.&lt;/p&gt;
&lt;h2 id=&#34;-bringing-it-all-together&#34;&gt;🍵 Bringing it all together&lt;/h2&gt;
&lt;p&gt;To give an example of all of this in use, lets build resources for the following requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We have 3 applications: &lt;code&gt;alpha&lt;/code&gt; &lt;code&gt;beta&lt;/code&gt; and &lt;code&gt;gamma&lt;/code&gt; running on our cluster&lt;/li&gt;
&lt;li&gt;We want &lt;code&gt;alpha&lt;/code&gt; and &lt;code&gt;beta&lt;/code&gt; exposed via the same Hostname but with separate routes:
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;public.example.com/alpha&lt;/code&gt; and &lt;code&gt;public.example.com/beta&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We want &lt;code&gt;gamma&lt;/code&gt; to have it’s own hostname as it’s a separate, unrelated application
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gamma.public.example.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;We have the TLS key and cert for &lt;code&gt;public.example.com&lt;/code&gt; and want the ingress-controller to terminate TLS for this host&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gamma&lt;/code&gt; handles it’s own TLS so we shouldn’t terminate it at the reverse proxy,&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We already have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster running in AWS&lt;/li&gt;
&lt;li&gt;Deployed external-dns onto our cluster configured for AWS Route 53, [&lt;a href=&#34;https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/aws.md&#34;&gt;link&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;Deployed ingress-nginx onto our cluster configured for AWS, [&lt;a href=&#34;https://kubernetes.github.io/ingress-nginx/deploy/&#34;&gt;link&lt;/a&gt;]. Ingress class is set to &lt;code&gt;default&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to try these steps above for yourself the implementation and breakdown of what we’re doing come below though so spoiler alert.&lt;/p&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Create the TLS secret for our alpha/beta endpoint&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kubectl create secret tls public \
  --cert=tls.cert \
  --key=tls.key
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;YAML for the Ingress of &lt;code&gt;alpha&lt;/code&gt; and &lt;code&gt;beta&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Ingress&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;alpha-beta&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;ingressClassName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;default&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;tls&lt;/span&gt;:
  - &lt;span style=&#34;color:#f92672&#34;&gt;hosts&lt;/span&gt;:
      - &lt;span style=&#34;color:#ae81ff&#34;&gt;public.example.com&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;secretName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;public&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:
  - &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;public.example.com&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;http&lt;/span&gt;:
      &lt;span style=&#34;color:#f92672&#34;&gt;paths&lt;/span&gt;:
      - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/alpha&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;pathType&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Prefix&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;backend&lt;/span&gt;:
          &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;:
            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;alpha&lt;/span&gt;
            &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;:
              &lt;span style=&#34;color:#f92672&#34;&gt;number&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
      - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/beta&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;pathType&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Prefix&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;backend&lt;/span&gt;:
          &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;:
            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;beta&lt;/span&gt;
            &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;:
              &lt;span style=&#34;color:#f92672&#34;&gt;number&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;YAML for the Ingress of &lt;code&gt;gamma&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span style=&#34;color:#f92672&#34;&gt;apiVersion&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;kind&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Ingress&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;metadata&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gamma&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;annotations&lt;/span&gt;:
    &lt;span style=&#34;color:#f92672&#34;&gt;nginx.ingress.kubernetes.io/ssl-passthrough&lt;/span&gt;: &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#f92672&#34;&gt;spec&lt;/span&gt;:
  &lt;span style=&#34;color:#f92672&#34;&gt;ingressClassName&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;default&lt;/span&gt;
  &lt;span style=&#34;color:#f92672&#34;&gt;rules&lt;/span&gt;:
  - &lt;span style=&#34;color:#f92672&#34;&gt;host&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gamma.public.example.com&lt;/span&gt;
    &lt;span style=&#34;color:#f92672&#34;&gt;http&lt;/span&gt;:
      &lt;span style=&#34;color:#f92672&#34;&gt;paths&lt;/span&gt;:
      - &lt;span style=&#34;color:#f92672&#34;&gt;path&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;/&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;pathType&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;Prefix&lt;/span&gt;
        &lt;span style=&#34;color:#f92672&#34;&gt;backend&lt;/span&gt;:
          &lt;span style=&#34;color:#f92672&#34;&gt;service&lt;/span&gt;:
            &lt;span style=&#34;color:#f92672&#34;&gt;name&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;gamma&lt;/span&gt;
            &lt;span style=&#34;color:#f92672&#34;&gt;port&lt;/span&gt;:
              &lt;span style=&#34;color:#f92672&#34;&gt;number&lt;/span&gt;: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;☝ SSL Passthrough also needs to be enabled on the ingress-nginx deployment with the flag &lt;code&gt;--enable-ssl-passthrough&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;What happens with these resources?&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ingress-nginx:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Constantly checks for new/updated &lt;code&gt;Ingress&lt;/code&gt; resources&lt;/li&gt;
&lt;li&gt;Detects &lt;code&gt;alpha-beta&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Adds nginx config to route to the services
&lt;ul&gt;
&lt;li&gt;Can be checked with: &lt;code&gt;kubectl exec -it &amp;lt;ingress-controller-pod-name&amp;gt; -- cat /etc/nginx/nginx.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This config includes the secret mentioned to be able to terminate TLS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Updates the &lt;code&gt;Ingress&lt;/code&gt; resource &lt;code&gt;Address&lt;/code&gt; field with the DNS of the Cloud load balancer the controller knows is pointing at it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl https://public.example.com/alpha -v&lt;/code&gt; shows it routing correctly and the cert as expected&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl https://public.example.com/wrong -v&lt;/code&gt; shows the default backend&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Detects &lt;code&gt;gamma&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Adds nginx config to route to the services
&lt;ul&gt;
&lt;li&gt;Again, can be checked with: &lt;code&gt;kubectl exec -it &amp;lt;ingress-controller-pod-name&amp;gt; -- cat /etc/nginx/nginx.conf&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This config will show the ssl_passthrough is set to not handle any TLS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Updates the &lt;code&gt;Ingress&lt;/code&gt; resource &lt;code&gt;Address&lt;/code&gt; field with the DNS of the Cloud load balancer that the controller knows is pointing at it.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;curl https://gamma.public.example.com -v&lt;/code&gt; shows traffic routing correctly and with our in-application TLS handling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;external-dns:&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Constantly checking for new/updated &lt;code&gt;Ingress&lt;/code&gt; resources&lt;/li&gt;
&lt;li&gt;Sees the two new resources but with empty &lt;code&gt;Address&lt;/code&gt; fields - needs these to be set before it can point the specified host to the address the service sits behind.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Address&lt;/code&gt; field is now updated for &lt;code&gt;alpha-beta&lt;/code&gt;:
&lt;ul&gt;
&lt;li&gt;Checks if the hostname has already been created
&lt;ul&gt;
&lt;li&gt;external-dns defaults to using &lt;code&gt;txt&lt;/code&gt; records in the chosen DNS service to persist information about the domains it manages&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Creates an &lt;code&gt;A&lt;/code&gt; record pointing &lt;code&gt;public.example.com&lt;/code&gt; to the value of &lt;code&gt;Address&lt;/code&gt; in the ingress&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Address&lt;/code&gt; field is now updated for &lt;code&gt;gamma&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This does the same as &lt;code&gt;alpha-beta&lt;/code&gt; but for &lt;code&gt;gamma.public.example.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;-other-controllers-are-available&#34;&gt;🦦 Other controllers are available&lt;/h2&gt;
&lt;p&gt;Other ingress controllers are available too, notable/interesting ones include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/kubernetes-sigs/aws-load-balancer-controller#readme&#34;&gt;AWS Load balancer controller&lt;/a&gt; can manage ALBs out of cluster for ingress resources and NLBs for service resources&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://doc.traefik.io/traefik/providers/kubernetes-ingress/&#34;&gt;Traefix ingress controller&lt;/a&gt; an ingress controller using the Kubernetes native edge router&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.getambassador.io/docs/edge-stack/latest/topics/running/ingress-controller/&#34;&gt;Ambassador&lt;/a&gt; uses Envoy to act as an ingress controller and API gateway&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The benefit of having all of your configuration directly in Kubernetes as an &lt;code&gt;Ingress&lt;/code&gt; resource comes from every compliant ingress-controllers reading and interacting with Ingress in the same way. The only change between them would be the implementation specific things you control via annotations, the general routes and hosts work regardless of your choice.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Kubernetes Networking #2: Services</title>
      <link>/post/kubernetes-networking-services/</link>
      <pubDate>Thu, 21 Apr 2022 10:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/kubernetes-networking-services/</guid>
      <description>&lt;p&gt;Kubernetes services are an essential resource everyone uses, but what are all the different types and how do they work under the hood?&lt;/p&gt;</description>
      <content>&lt;p&gt;Kubernetes services are an essential resource everyone uses, but what are all the different types and how do they work under the hood?&lt;/p&gt;
&lt;p&gt;In Kubernetes pods are ephemeral (or &lt;a href=&#34;https://thenewstack.io/how-to-treat-your-kubernetes-clusters-like-cattle-not-pets/&#34;&gt;cattle&lt;/a&gt;), you should expect them to be killed, scaled and replaced whenever. So how do you talk to a set of pods which might have changed the next second? A service.&lt;/p&gt;
&lt;p&gt;Services sit in front of your application and mean you only have to call the service address and magic Kubernetes components will get that request to the right Pod(s).
How does a service know which pods it can talk to?&lt;/p&gt;
&lt;h2 id=&#34;selectors&#34;&gt;Selectors&lt;/h2&gt;
&lt;p&gt;Services map to pods via label selectors. You have a pod with label &lt;code&gt;app=etizer&lt;/code&gt; and then create a service with &lt;code&gt;.spec.selector&lt;/code&gt; for the same and that service will forward traffic to any Ready pods matching that label.&lt;/p&gt;
&lt;p&gt;Behind the scenes, a service resource also creates an &lt;code&gt;Endpoints&lt;/code&gt; resource which maintains a list of Pod IPs based on your service selector. It’s worth noting here, the readyiness checks you implement for your Pods are what controls whether the IP goes into this &lt;code&gt;Endpoints&lt;/code&gt; resource and allow traffic.&lt;/p&gt;
&lt;p&gt;The exception here is selector-less services, these don’t have a label selector so won’t also have an &lt;code&gt;Endpoint&lt;/code&gt; resource. To use these you also need to create an endpoint resource of the same name as your service, you can add any IPs and ports you want to this resource. This is a great way to map a service to something not in your cluster so your pods can talk to it as if it was a service.&lt;/p&gt;
&lt;p&gt;But what are the different types of services and how do they work?&lt;/p&gt;
&lt;h2 id=&#34;service-types&#34;&gt;Service Types&lt;/h2&gt;
&lt;h3 id=&#34;clusterip&#34;&gt;ClusterIP&lt;/h3&gt;
&lt;p&gt;When you create a &lt;code&gt;ClusterIP&lt;/code&gt; type service you’ll will get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A virtual IP for the service
&lt;ul&gt;
&lt;li&gt;This is within the &lt;code&gt;--service-cluster-ip-range&lt;/code&gt; your &lt;code&gt;api-server&lt;/code&gt; has been configured with&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kube-proxy&lt;/code&gt; is responsible for this virtual IP routing to one of your Pod IPs&lt;/li&gt;
&lt;li&gt;This virtual IP will forward requests to one of your pod IPs based on the &lt;code&gt;Endpoints&lt;/code&gt; resource associated with your service.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A local cluster DNS address, eg. &lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;.svc.cluster.local&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;This is resolved by your &lt;code&gt;kube-dns&lt;/code&gt; (CoreDNS) to your virtual service IP&lt;/li&gt;
&lt;li&gt;This is why your service name must be &lt;a href=&#34;https://datatracker.ietf.org/doc/html/rfc1035&#34;&gt;RFC 1035 compliant&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The normal way of utilising this would be giving your application the service DNS address so it can talk to another application running on the cluster. This DNS address resolves to the virtual IP and then the configuration &lt;code&gt;kube-proxy&lt;/code&gt; controls handles that IP resolving to actual pod IP addresses. From there your CNI will route your request using the pod IP.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ClusterIP&lt;/code&gt; service type is ✨&lt;em&gt;special&lt;/em&gt;✨, whilst you use it as a way to expose your service internally within the cluster, it’s also used by types &lt;code&gt;NodePort&lt;/code&gt; and &lt;code&gt;LoadBalancer&lt;/code&gt; (by extension of LoadBalancer using &lt;code&gt;NodePort&lt;/code&gt;) as part of their implementations.&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;img src=&#34;/img/k8s-services-2-types.png&#34;   /&gt;
    
      &lt;figcaption class=&#34;center&#34; &gt;Just like a Matryoshka doll&lt;/figcaption&gt;
    
  &lt;/figure&gt;


&lt;p&gt;&lt;code&gt;&amp;lt;service-ip&amp;gt;:&amp;lt;service-port&amp;gt; → &amp;lt;pod-ip&amp;gt;:&amp;lt;pod-port&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;nodeport&#34;&gt;NodePort&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;NodePort&lt;/code&gt; type service opens up a port on &lt;strong&gt;every node&lt;/strong&gt; in your cluster, this port then proxies requests to your service’s virtual IP address.&lt;/p&gt;
&lt;p&gt;The port range defaults to &lt;code&gt;30000-32767&lt;/code&gt;, interestingly enough just below the Linux kernel default &lt;a href=&#34;https://www.kernel.org/doc/html/latest//networking/ip-sysctl.html#ip-variables&#34;&gt;ephemeral port range&lt;/a&gt;. It can also be configured with the flag &lt;code&gt;--service-node-port-range&lt;/code&gt; if you need these ports for some use case.&lt;/p&gt;
&lt;p&gt;At a high level a &lt;code&gt;NodePort&lt;/code&gt; is a single rule configured by &lt;code&gt;kube-proxy&lt;/code&gt; onto every node, to forward requests to an underlying &lt;code&gt;ClusterIP&lt;/code&gt; service.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;node-ip&amp;gt;:&amp;lt;node-port&amp;gt; → &amp;lt;service-ip&amp;gt;:&amp;lt;service-port&amp;gt; → &amp;lt;pod-ip&amp;gt;:&amp;lt;pod-port&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;loadbalancer&#34;&gt;LoadBalancer&lt;/h3&gt;
&lt;p&gt;A &lt;code&gt;LoadBalancer&lt;/code&gt; type service only really works in a cloud environment. When created, asyncronously, the &lt;a href=&#34;https://kubernetes.io/docs/concepts/architecture/cloud-controller/&#34;&gt;cloud-controller-manager&lt;/a&gt; will provision you a load balancer which directs traffic to your pods.&lt;/p&gt;
&lt;p&gt;The implementation of the different cloud load balancers varys wildly. It used to be different clouds were implemented &lt;a href=&#34;https://github.com/kubernetes/kubernetes/tree/release-1.11/pkg/cloudprovider/providers/aws&#34;&gt;in-tree&lt;/a&gt;, committing directly to kubernetes but now it must be done via out-of-tree implementations, eg. &lt;a href=&#34;https://github.com/kubernetes/cloud-provider-aws&#34;&gt;cloud-provider-aws&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cloud implementations aside, once you have a &lt;em&gt;cloud&lt;/em&gt; load balancer it works by pointing to a &lt;code&gt;NodePort&lt;/code&gt; service running. This means that you have a load balancer with every Kubernetes worker node as a listener, forwarding traffic to any nodes on a particular port. From there it follows the standard &lt;code&gt;NodePort&lt;/code&gt; → &lt;code&gt;ClusterIP&lt;/code&gt; route.&lt;/p&gt;
&lt;p&gt;If you didn’t want to write a whole &lt;a href=&#34;https://kubernetes.io/docs/tasks/administer-cluster/running-cloud-controller/&#34;&gt;cloud control manager&lt;/a&gt; to expose your application on your own servers, a &lt;code&gt;NodePort&lt;/code&gt; service with that port pointed to from your existing load balancer would do the trick.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;load-balancer-ip&amp;gt;:&amp;lt;lb-port&amp;gt; -&amp;gt; &amp;lt;node-ip&amp;gt;:&amp;lt;node-port&amp;gt; → &amp;lt;service-ip&amp;gt;:service-port&amp;gt; → &amp;lt;pod-ip&amp;gt;:&amp;lt;pod-port&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&#34;externalname&#34;&gt;ExternalName&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;ExternalName&lt;/code&gt; services are the odd one out. Instead of using good ol’ &lt;code&gt;ClusterIP&lt;/code&gt; and getting a virtual IP, they create a &lt;code&gt;CNAME&lt;/code&gt; record to map your service DNS to another DNS address.&lt;/p&gt;
&lt;p&gt;As an example use case, lets say you have different environment databases, instead of service-owners changing the DNS depending on where they deploy their pods to you create a &lt;code&gt;ExternalName&lt;/code&gt; service:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;apiVersion: v1
kind: Service
metadata:
  name: database
  namespace: prod
spec:
  type: ExternalName
  externalName: prod.database.example.com
---
apiVersion: v1
kind: Service
metadata:
  name: database
  namespace: dev
spec:
  type: ExternalName
  externalName: dev.database.example.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now all the service-owners have to do is point their code to &lt;code&gt;database.svc.cluster.local&lt;/code&gt; and they will talk to the right database every time.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;database.svc.cluster.local&lt;/code&gt; = &lt;code&gt;CNAME test.database.example.com&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;It’s worth noting since the pod requesting the service will get the &lt;code&gt;CNAME&lt;/code&gt; record back, the pod also has to be configured to resolve whatever domain the &lt;code&gt;CNAME&lt;/code&gt; returns. If it’s a private record, you might want to &lt;a href=&#34;https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/&#34;&gt;configure revolvers in CoreDNS&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&#34;how-virtual-ips-work&#34;&gt;How Virtual IPs work&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Most&lt;/em&gt; services (sorry, &lt;code&gt;ExternalName&lt;/code&gt;) use a virtual IP to forward requests to the proper pods. It’s the responsibility of &lt;code&gt;kube-proxy&lt;/code&gt; to provide this virtual IP and make sure the traffic is actually forwarded. &lt;code&gt;kube-proxy&lt;/code&gt; runs on every node so the steps below happen per worker node.&lt;/p&gt;
&lt;p&gt;How this works depends on the mode of &lt;code&gt;kube-proxy&lt;/code&gt; is given with &lt;code&gt;-proxy-mode&lt;/code&gt; flag:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;strong&gt;For all of these &lt;code&gt;kube-proxy&lt;/code&gt; will monitor the control plane for new/updated/removed &lt;code&gt;Service&lt;/code&gt; and &lt;code&gt;Endpoint&lt;/code&gt; resources and run the following steps&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;userspace&lt;/strong&gt; (legacy)
&lt;ul&gt;
&lt;li&gt;For each &lt;code&gt;Service&lt;/code&gt; it opens a random proxy port on the node&lt;/li&gt;
&lt;li&gt;This proxy port is then told to iptables to capture traffic to this particular virtual IP and port to redirect to the Pod IPs in the &lt;code&gt;Endpoint&lt;/code&gt; resource&lt;/li&gt;
&lt;li&gt;The backend pod is chosen based on the &lt;code&gt;SessionAffinity&lt;/code&gt; of the service&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The traffic here is actually proxied via &lt;code&gt;kube-proxy&lt;/code&gt; itself&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iptables&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;For each &lt;code&gt;Service&lt;/code&gt; it creates iptables rules which redirect traffic to the virtual IP and service port&lt;/li&gt;
&lt;li&gt;These redirect rules point to sets of pod IPs based on what is in the endpoint resource&lt;/li&gt;
&lt;li&gt;The backend pod is chosen at random by default&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The traffic is all handled within the Linux &lt;a href=&#34;https://www.netfilter.org/&#34;&gt;netfilter&lt;/a&gt; so all within the kernelspace, &lt;code&gt;kube-proxy&lt;/code&gt; doesn’t handle the traffic it just sets up rules to process it&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IPVS&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Whilst iptables was designed to be a firewall and &lt;code&gt;kube-proxy&lt;/code&gt; just uses it to redirect network traffic, IPVS was made for load balancing&lt;/li&gt;
&lt;li&gt;At a high level this works similar to iptables, cluster IP and port → set of pod IPs&lt;/li&gt;
&lt;li&gt;IPVS is important when working at scale, if you have &amp;gt;1000 services (or 10,000 pods) in your cluster IPVS is the performant choice&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kernelspace&lt;/strong&gt; (windows)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;bringing-it-all-together&#34;&gt;Bringing it all together&lt;/h2&gt;
&lt;p&gt;Let’s create an example &lt;code&gt;LoadBalancer&lt;/code&gt; service and see what components come together to get traffic from a client to your pods. We’ll show how traffic from outside, via the load balancer, gets to your pods and how another pod in the cluster can also use this service without going via the load balancer.&lt;/p&gt;
&lt;p&gt;In this example let’s say we’re running on a Kubernetes cluster in AWS with the AWS cloud controller manager properly configured, we have pods running with label &lt;code&gt;app=alpha&lt;/code&gt; which listens on port &lt;code&gt;8080&lt;/code&gt; for traffic and &lt;code&gt;kube-proxy&lt;/code&gt; is in the default &lt;code&gt;iptables&lt;/code&gt; mode.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Service YAML&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;apiVersion: v1
kind: Service
metadata:
&lt;span style=&#34;color:#75715e&#34;&gt;# This doesn&amp;#39;t affect routing but it&amp;#39;s best practice to label components together&lt;/span&gt;
  labels:
    app: alpha
  name: example
spec:
  ports:
  - name: main
    port: &lt;span style=&#34;color:#ae81ff&#34;&gt;8081&lt;/span&gt;
    protocol: TCP
&lt;span style=&#34;color:#75715e&#34;&gt;# Target port is the port your pod has open&lt;/span&gt;
    targetPort: &lt;span style=&#34;color:#ae81ff&#34;&gt;8080&lt;/span&gt;
&lt;span style=&#34;color:#75715e&#34;&gt;# This is what tells the service which pods to route to&lt;/span&gt;
  selector:
    app: alpha
  type: LoadBalancer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lets create the service and have a look:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl apply -f service.yaml
service/example created

$ kubectl get service example
NAME      TYPE           CLUSTER-IP      EXTERNAL-IP     PORT&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;S&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;          AGE
example   LoadBalancer   10.43.205.153   192.168.0.147   8081:32255/TCP   4s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;I now have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An Endpoints resource corresponding to ready pods matching my label selector
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kubectl get endpoints example&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A cluster IP setup for my service &lt;code&gt;10.43.205.153&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A DNS address for the service configured
&lt;ul&gt;
&lt;li&gt;(from inside a Pod)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dig example.default.svc.cluster.local&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A external (to the cluster) IP which maps to my load balancer &lt;code&gt;192.168.0.147&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A NodePort setup &lt;code&gt;32255&lt;/code&gt; so all my workers now have this port open
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;netstat -tulnp | grep 32255&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;iptables rules setup
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo iptables -L | grep example&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sudo iptables -L | grep 10.43.205.153&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Lets see how this request goes through to our pod from outside the cluster and a pod within.&lt;/p&gt;
&lt;h3 id=&#34;from-outside-the-cluster&#34;&gt;From outside the cluster&lt;/h3&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/k8s-services-2-lb-external.png&#34; &gt;
    &lt;img src=&#34;/img/k8s-services-2-lb-external.png&#34;   /&gt;
    
    &lt;/a&gt;
  &lt;/figure&gt;


&lt;ol&gt;
&lt;li&gt;The client makes a request to the load balancer to try and talk to the application, for how this is configured see my post on ingress into a cluster&lt;/li&gt;
&lt;li&gt;The load balancer selects one of the configured listeners, this is usually either random or round robin but depends on your load balancer and configuration&lt;/li&gt;
&lt;li&gt;The node has port 32255 open, requests here are configured in iptables to forward the request to the virtual IP of the service. These rules were configured by &lt;code&gt;kube-proxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;iptables then resolves the virtual/service IP into a Pod IP address, one is chosen by random and the request heads there. Now the traffic is inside the cluster the CNI controls the network movements between nodes (see &lt;a href=&#34;https://dgood.win/post/kubernetes-networking-overview/&#34;&gt;here&lt;/a&gt; for more info on what the CNI sets up)&lt;/li&gt;
&lt;li&gt;Once the request has reached the node with the pod on it, the CNI and iptables will forward it to the Pod as expected&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;from-a-pod-within-the-cluster&#34;&gt;From a pod within the cluster&lt;/h3&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/k8s-services-2-lb-internal.png&#34; &gt;
    &lt;img src=&#34;/img/k8s-services-2-lb-internal.png&#34;   /&gt;
    
    &lt;/a&gt;
  &lt;/figure&gt;


&lt;ol&gt;
&lt;li&gt;The requesting pod will have been configured with the service DNS address &lt;code&gt;example.default.svc.cluster.local&lt;/code&gt;. As it makes this request from within the cluster CoreDNS running will be the DNS resolver. This request will be resolved to the Service (virtual) IP address: &lt;code&gt;10.43.205.153&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Making a request to this address will hit the rules in iptables, configured by &lt;code&gt;kube-proxy&lt;/code&gt;, this resolves the service IP into a Pod IP by randomly selecting a pod&lt;/li&gt;
&lt;li&gt;The rest of the request continues as in the external example.&lt;/li&gt;
&lt;/ol&gt;</content>
    </item>
    
    <item>
      <title>The case for time-tracking</title>
      <link>/post/case-for-timetracking/</link>
      <pubDate>Sat, 05 Feb 2022 15:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/case-for-timetracking/</guid>
      <description>&lt;p&gt;Time tracking has a bad reputation, it invokes images of managers watching over your shoulder or pay being docked as you punched in minutes before your shift ended. Due to these, and many more, if you suggest to someone to start tracking their time they’re likely to look at you like you’ve gone mad.&lt;/p&gt;</description>
      <content>&lt;p&gt;Time tracking has a bad reputation, it invokes images of managers watching over your shoulder or pay being docked as you punched in minutes before your shift ended. Due to these, and many more, if you suggest to someone to start tracking their time they’re likely to look at you like you’ve gone mad.&lt;/p&gt;
&lt;p&gt;I think time tracking, for your own benefit, can be a great way to be introspective about how you work and allow you a greater understanding of managing distractions, context switching and when you’re feeling productive.&lt;/p&gt;
&lt;h2 id=&#34;what-is-time-tracking&#34;&gt;What is time tracking&lt;/h2&gt;
&lt;p&gt;The basic gist is, you start a timer when you are working on something. Whilst you could track time per ticket or some other fine grained metric, I would strongly recommend tracking categories of activities.&lt;/p&gt;
&lt;p&gt;Ones I track are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Development&lt;/strong&gt; - directly coding, usually “when I’m in my IDE”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Live support&lt;/strong&gt; - picking up alerts that have fired or investigating issues/incidents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Messaging&lt;/strong&gt; - slack messaging people&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Meetings&lt;/strong&gt; - time spent in any meetings
&lt;ul&gt;
&lt;li&gt;I found it in the past useful to &lt;em&gt;tag&lt;/em&gt; these “ceremonies”, “1-1s”, “other”&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Break&lt;/strong&gt; - Going to grab a coffee or lunch
&lt;ul&gt;
&lt;li&gt;This one could be tracked by just not running a timer, but I find ending the Break timer when I return is a useful trigger to start working&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Collaboration&lt;/strong&gt; - Working with someone else to either plan, pair or debug&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These activities can also be expanded with tags if you want to know more detail, things like whether the activity is for client a or b can be useful if that fits your environment.&lt;/p&gt;
&lt;p&gt;I’ve also found adding activities when you want to focus on a particular area, say “Documentation” or “Reading tech books” can help you focus energy towards a goal.&lt;/p&gt;
&lt;p&gt;A key thing with the tracking is not being too detailed, it’s not useful to know ticket-12 took twice as long as ticket-14 in the scheme of things (even if Toggl do like to push jira integration). You’re not billing people for this time, it’s just about gaining understanding.&lt;/p&gt;
&lt;h2 id=&#34;how-to-time-track&#34;&gt;How to time track&lt;/h2&gt;
&lt;p&gt;This might seem like an obvious area “set timer to start when you work on something” but there’s some nuance and tips I can share.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If at any point you stop working on your current task for distractions, stop said timer (and set a new one if applicable)
&lt;ul&gt;
&lt;li&gt;A common thing might be you need to respond to someones message, ideally you try to batch these where possible and the people messaging you &lt;a href=&#34;https://www.nohello.com/&#34;&gt;don’t just say hi&lt;/a&gt;, so maybe after 30minutes, stop the timer, start the messaging timer and respond to people&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Before you begin any activity, start the timer
&lt;ul&gt;
&lt;li&gt;I find this is a useful way of getting in the mindset for that task too, it forces you to mentally think “what am I working on right now” instead of just falling into work&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;You can always update past timers if you forget too, don’t try to be too accurate, to the nearest 5 minutes should show you the gist of it.&lt;/li&gt;
&lt;li&gt;“Doesn’t this add to the context switching load?” &lt;strong&gt;Yes&lt;/strong&gt; I believe it does, but that isn’t a problem. It should be harder for you to switch what task you’re working on to avoid (where possible) context switching and having to recognize you’re doing it, stop and start a timer, adds to the overhead, it’s way too easy to down tools on work to respond to slack.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;what-time-tracking-is-not&#34;&gt;What time tracking is not&lt;/h2&gt;
&lt;p&gt;It’s important to call out what personal time tracking is not, and avoid some of the pitfalls.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Time tracking should be for your own benefit, and you should be the only one who sees the data. You’re not doing this to prove to your manager at year-end reviews you keep working even when you sneeze or to compare to your team. On the other side, this shouldn’t be something a manager imposes on you and wants to see progress reports.&lt;/li&gt;
&lt;li&gt;Related to above, it’s important to be honest when time tracking. Everyone has bad days for productivity and just leaving “development” timer on won’t help you understand anything. This timer is just meant to be data on how you work, no opinions or judgement.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;benefits-of-time-tracking&#34;&gt;Benefits of time tracking&lt;/h2&gt;
&lt;p&gt;I’ve personally found tracking my time, even for short 1 month stints, a great way to introspect on your working habits.&lt;/p&gt;
&lt;p&gt;A good example is at the end of the day, when you might be feeling like it was (or wasn’t) a productive day. Being able to look back and go “oh, those 4 meetings 30minutes apart basically translated to 4hrs of meetings for my productivity”. I’ve commonly found days when I’m feeling unproductive, I can look at my time tracked for the day and understand why.&lt;/p&gt;
&lt;p&gt;Another key aspect is seeing the effect interrupts have on you, everyone knows the bane of context switching at this point, but being able to see the switch in activity and then the lull between starting anew is clear.&lt;/p&gt;
&lt;p&gt;I’ve also found having to think about &lt;em&gt;starting&lt;/em&gt; a task, having a timer to start when I go into development mode helps mentally adjust to the task at hand.&lt;/p&gt;
&lt;h2 id=&#34;tools-and-use-and-how-to-set-them-up&#34;&gt;Tools and use and how to set them up&lt;/h2&gt;
&lt;p&gt;For actually tracking the time, I use: &lt;a href=&#34;https://toggl.com/track/&#34;&gt;toggl track&lt;/a&gt;. Honestly, I don’t particularly like it but I haven’t found an alternative that does everything I need and don&amp;rsquo;t need to install.&lt;/p&gt;
&lt;p&gt;I’ve previous used &lt;a href=&#34;https://timeryapp.com/&#34;&gt;Timery&lt;/a&gt;, which makes it easier to change timer and highly recommend it to never interact with toggl. I would highly recommend this when you can install applications on your own machine and for iOS if you have it.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I have a pinned tab open in my browser with toggl, it goes grey when there isn’t one active which I find useful
&lt;ul&gt;
&lt;li&gt;Timery will sit in the top bar of my Mac which makes using it easier&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;I then setup a widget on my phone home screen. This helps me spot any timers I’ve left running.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Within toggl, I have the activities I listed above as “Projects”. I don’t use any tags currently but I’ve found it useful in the past when working across teams or clients.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A good rule is a project should be something important to you but broad enough you don’t need to think or decide which one to use when starting a timer. It should be obvious what the work you’re doing is.&lt;/li&gt;
&lt;li&gt;As an example for tags, I wanted to see which client’s live issues were taking the most time in my day.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;to-round-up&#34;&gt;To round up&lt;/h2&gt;
&lt;p&gt;Time tracking can be a useful tool to gain insight into your working habits and productivity. I’d recommend only doing it when you’re gaining something from it; in the past I’ve used it for 1-3month stints when feeling unproductive or joining a new company. If you’re doing it and finding the data not useful.&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Kubernetes Networking #1</title>
      <link>/post/kubernetes-networking-overview/</link>
      <pubDate>Mon, 10 Jan 2022 12:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/kubernetes-networking-overview/</guid>
      <description>&lt;p&gt;Kubernetes networking can be a bit of a rabbit hole to debug and discover what your pods are actually doing. In this post we’ll explore at a high level how a request goes from 1 pod to another and which components control each.&lt;/p&gt;</description>
      <content>&lt;p&gt;Kubernetes networking can be a bit of a rabbit hole to debug and discover what your pods are actually doing. In this post we’ll explore at a high level how a request goes from 1 pod to another and which components control each.&lt;/p&gt;
&lt;h2 id=&#34;components&#34;&gt;Components&lt;/h2&gt;
&lt;p&gt;The components we’re going to look at today are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kube-dns/coredns&lt;/code&gt; resolves domain names for services (and pods) into an IP address
&lt;ul&gt;
&lt;li&gt;ℹ️ &lt;code&gt;kube-dns&lt;/code&gt; was replaced by &lt;code&gt;coredns&lt;/code&gt; but the in cluster service is still called &lt;code&gt;kube-dns&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;This is the resolver for any DNS requests inside your pods, if you wanted to resolve internal service domains or to a private DNS resolver, you could configure this to forward those requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;kube-proxy&lt;/code&gt; resolves network requests for the IP address of a service to the IP addresses of pods which match that service. This has different modes:
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Iptables&#34;&gt;iptables&lt;/a&gt; (default) - To see your iptables rules: &lt;code&gt;iptables -L&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/blog/2018/07/09/ipvs-based-in-cluster-load-balancing-deep-dive/&#34;&gt;ipvs&lt;/a&gt; - To see your ipvs rules &lt;code&gt;ipvsadm -Ln&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Your chosen &lt;a href=&#34;https://kubernetes.io/docs/concepts/cluster-administration/networking/#calico&#34;&gt;CNI&lt;/a&gt;, there’s a range of these, all which work differently. Generally a CNI will configure any networking around a Pod IP, routing to and from pods to:
&lt;ul&gt;
&lt;li&gt;Ensure pod network requests are routed properly to other pods&lt;/li&gt;
&lt;li&gt;Ensure pod network requests can reach outside the cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An easy way of thinking about it can be, resolving between a service and healthy pods is &lt;code&gt;kube-dns&lt;/code&gt; and &lt;code&gt;kube-proxy&lt;/code&gt; but then that request will need to go through routing setup by the &lt;code&gt;CNI&lt;/code&gt;. For cloud environments, your &lt;code&gt;CNI&lt;/code&gt; will usually handle (or provide ways to setup) things like cross-subnet traffic as well.&lt;/p&gt;
&lt;p&gt;To follow the resolution between components, say we wanted to go to a service called &lt;code&gt;myapp&lt;/code&gt; which sits in namespace &lt;code&gt;namespace001&lt;/code&gt; which had 2 healthy pods matching the service selector. The resolution would be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CoreDNS:&lt;/strong&gt; (service FQDN)&lt;code&gt;myapp.namespace001.svc.cluster.local&lt;/code&gt; → &lt;code&gt;172.16.10.10&lt;/code&gt; (service cluster IP)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;iptables:&lt;/strong&gt; &lt;code&gt;172.16.10.10&lt;/code&gt; → &lt;code&gt;10.10.10.10&lt;/code&gt; (a pod IP, selected at random from healthy pods)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CNI:&lt;/strong&gt; Will route traffic for &lt;code&gt;10.10.10.10&lt;/code&gt; from the requester node, to the target node&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;example-journey-of-a-request&#34;&gt;Example journey of a request&lt;/h2&gt;
&lt;p&gt;As an example, let’s explore in an example Kubernetes cluster how a pod will send a network request to another pod.
For this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The pod will try to talk to a pod on another node then itself&lt;/li&gt;
&lt;li&gt;The 2 nodes will be in seperate subnets
&lt;ul&gt;
&lt;li&gt;Routing between subnets is presumed to be setup and fine and we’ll abstract that to a &lt;code&gt;router&lt;/code&gt; in the diagram&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;CNI&lt;/code&gt; will be Calico, but we won’t be looking too much into its internals&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pod-0&lt;/strong&gt; will send a request to &lt;strong&gt;pod-3&lt;/strong&gt; through a service&lt;/li&gt;
&lt;li&gt;We’ll assume Kubernetes and Calico are setup with defaults:
&lt;ul&gt;
&lt;li&gt;iptables mode for &lt;code&gt;kube-proxy&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;vxlan encapsulation for cross subnet traffic&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/k8s_network_request_example.png&#34; &gt;
    &lt;img src=&#34;/img/k8s_network_request_example.png&#34;   /&gt;
    
    &lt;/a&gt;
  &lt;/figure&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt; &lt;strong&gt;pod-0&lt;/strong&gt; requests the service’s Cluster IP from &lt;code&gt;kube-dns&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kube-dns&lt;/code&gt; has dynamic config which updates mapping the service name to a Service IP address lets say &lt;code&gt;172.16.10.10&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;`kubectl exec command for coredns&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;*technically this whole request to &lt;code&gt;kube-dns&lt;/code&gt; goes via the same iptables→routing tables path since &lt;code&gt;kube-dns&lt;/code&gt; runs in pods on the cluster. The only key difference is the DNS resolver is an IP address so it doesn’t ask &lt;code&gt;kube-dns&lt;/code&gt; to define &lt;code&gt;kube-dns&lt;/code&gt;. But trying to show aswell would be madness.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt; With the cluster IP (&lt;code&gt;172.16.10.10&lt;/code&gt;) the request hits iptables&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iptables selects from a random one of the pod IP addresses for this particular service IP
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;iptables -L&lt;/code&gt; or &lt;code&gt;iptables-save&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;These rules are all loaded in here and dynamically updated by `kube-proxy If a pod starts failing Readiness checks for instance, it gets removed from this list.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt; The Pod IP is now resolved in the nodes routing tables &lt;code&gt;sudo route -n&lt;/code&gt; or &lt;code&gt;ip route list&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;These routing table rules will be configured based on the network environment the node sits in. Calico, running locally, will also configure rules for pod networking.&lt;/li&gt;
&lt;li&gt;Based on the Pod IP, it’ll be resolved through multiple sets of rules:
&lt;ul&gt;
&lt;li&gt;This node will have a range of Pod IPs which resolve to the local node itself&lt;/li&gt;
&lt;li&gt;This node will also have an IP range for nodes inside the same subnet - these could avoid encapsulation for performance gain&lt;/li&gt;
&lt;li&gt;This node also has range(s) for other subnets, if it’s not local to the node or subnet, it then gets routed to the subnet routing table. For these rules, Calico might instead route traffic to itself to be encapsulated before crossing the network boundary.&lt;/li&gt;
&lt;li&gt;There also might be a range for external traffic not local to the network, but if this was a private subnet this is most likely behind a NAT gateway inside the local network&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;This particular request is destined for another subnet. The routing table has directed the request to the Calico pod running locally on this node to handle routing this.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt; Calico will now encapsulate the network request to allow it to pass subnet boundaries &lt;code&gt;calicoctl node status&lt;/code&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By encapsulating the request’s original networking information is wrapped up as data and new network info is added&lt;/li&gt;
&lt;li&gt;Calico will send this as a vxlan or ipinip packet to the required node in another subnet&lt;/li&gt;
&lt;li&gt;The encapsulated packet (shown as an orange line) will:
&lt;ul&gt;
&lt;li&gt;Go back through the route table on the node itself&lt;/li&gt;
&lt;li&gt;To the local subnet router, which will resolve which subnet it needs to go into&lt;/li&gt;
&lt;li&gt;Hit the destination subnet routing table which can direct it to the node&lt;/li&gt;
&lt;li&gt;To the other node itself&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt; Once the encapsulted packet arrived at the other node, it’ll go through iptables rules to see if it’s allowed traffic.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This is why you might need to add the encapsulated packets into your firewall rules to be allowed in.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt; The routing table on this node will now:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Send the encapsulated packet to the local Calico to be unencapsulated&lt;/li&gt;
&lt;li&gt;The original (unencapsulated) network request will resolve again in iptables and routing tables rules to determine where it should go
&lt;ul&gt;
&lt;li&gt;This could also cause the packet to have to be routed again since the destination has moved&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The request is directed to the pod running locally&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;there-are-a-lot-of-things-missed-off-here&#34;&gt;There are a lot of things missed off here:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.adminsehow.com/2011/09/iptables-packet-traverse-map/&#34;&gt;Technically iptables is interacted with before, after (and sometimes during) a routing decision&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How the pod sits within it’s own &lt;a href=&#34;https://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/&#34;&gt;network namespace&lt;/a&gt; with a virtual ethernet interface for traffic coming to the pod&lt;/li&gt;
&lt;li&gt;How Calico uses &lt;a href=&#34;https://projectcalico.docs.tigera.io/reference/felix/&#34;&gt;Felix&lt;/a&gt; to program it’s routes and ACLs and &lt;a href=&#34;https://bird.network.cz/&#34;&gt;BIRD&lt;/a&gt; for distributing the routes to BGP peers on the network&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/cluster-administration/networking/&#34;&gt;Alternate CNIs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;How the whole kube-proxy aspects could be stipped out for an eBPF approach (Calico’s &lt;a href=&#34;https://projectcalico.docs.tigera.io/maintenance/ebpf/enabling-bpf&#34;&gt;eBPF dataplane&lt;/a&gt; or Cilium and it’s &lt;a href=&#34;https://docs.cilium.io/en/v1.9/gettingstarted/kubeproxy-free/&#34;&gt;kube proxy replacement&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;related-docs&#34;&gt;Related docs:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://projectcalico.docs.tigera.io/reference/architecture/overview&#34;&gt;Calico Component Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/reference/command-line-tools-reference/kube-proxy/&#34;&gt;kube-proxy reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/&#34;&gt;Kubernetes DNS docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Blog² - Blog about blogs</title>
      <link>/post/blog-squared/</link>
      <pubDate>Mon, 03 Jan 2022 12:06:09 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/blog-squared/</guid>
      <description>&lt;p&gt;Here&amp;rsquo;s a list I (hopefully) update around tech blogs I enjoy&lt;/p&gt;</description>
      <content>&lt;p&gt;Here&amp;rsquo;s a list I (hopefully) update around tech blogs I enjoy&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://jvns.ca/&#34;&gt;https://jvns.ca/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jlelse.blog/&#34;&gt;https://jlelse.blog/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://drewdevault.com/&#34;&gt;https://drewdevault.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://zwischenzugs.com/&#34;&gt;https://zwischenzugs.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kevq.uk/&#34;&gt;https://kevq.uk/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.gnoack.org/post/&#34;&gt;https://blog.gnoack.org/post/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.jessfraz.com/&#34;&gt;https://blog.jessfraz.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    </item>
    
    <item>
      <title>Kubernetes Debugging</title>
      <link>/post/kubernetes-debugging/</link>
      <pubDate>Mon, 20 Apr 2020 14:57:09 +0100</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/kubernetes-debugging/</guid>
      <description>&lt;p&gt;This is a workflow to debug common Kubernetes problems when deploying applications.&lt;/p&gt;</description>
      <content>&lt;p&gt;This is a workflow to debug common Kubernetes problems when deploying applications.&lt;/p&gt;
&lt;p&gt;Click on the image to see it in further detail&lt;/p&gt;

  &lt;figure class=&#34;left&#34; &gt;
    &lt;a href=&#34;/img/k8s_debugging_v1.svg&#34; &gt;
    &lt;img src=&#34;/img/k8s_debugging_v1.svg&#34;   /&gt;
    
    &lt;/a&gt;
  &lt;/figure&gt;</content>
    </item>
    
    <item>
      <title>Shellscript Notes</title>
      <link>/post/shellscript-day2/</link>
      <pubDate>Thu, 20 Feb 2020 15:25:00 +0100</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/shellscript-day2/</guid>
      <description>&lt;p&gt;Useful shellscript snippets&lt;/p&gt;</description>
      <content>&lt;p&gt;Useful shellscript snippets&lt;/p&gt;
&lt;h2 id=&#34;commonly-used&#34;&gt;Commonly used&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Check if variable contains mystring&lt;/span&gt;
&lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;[[&lt;/span&gt; $var &lt;span style=&#34;color:#f92672&#34;&gt;==&lt;/span&gt; *mystring*  &lt;span style=&#34;color:#f92672&#34;&gt;]]&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;then&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# The double closed brackets are essential for wildcard match&lt;/span&gt;
    echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;it does&amp;#34;&lt;/span&gt;;
&lt;span style=&#34;color:#66d9ef&#34;&gt;fi&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Split on &amp;#34;:&amp;#34; and get 1st&lt;/span&gt;
echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;docker-image:0.1&amp;#34;&lt;/span&gt; | cut -d &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;:&amp;#34;&lt;/span&gt; -f1 &lt;span style=&#34;color:#75715e&#34;&gt;# returns docker-image&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Find and replace all via pipe&lt;/span&gt;
echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello I&amp;#39;m Dom&amp;#34;&lt;/span&gt; | sed &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;s/Dom/&amp;lt;void&amp;gt;/g&amp;#39;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# &amp;#34;/&amp;#34; could be any char&lt;/span&gt;


&lt;span style=&#34;color:#75715e&#34;&gt;# Redirect stdout and stderr to the void&lt;/span&gt;
./run_script.sh &amp;gt;/dev/null 2&amp;gt;&amp;amp;&lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;basics&#34;&gt;Basics&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Read top lines of file&lt;/span&gt;
head -n &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; myfile

&lt;span style=&#34;color:#75715e&#34;&gt;# Read bottom lines of file&lt;/span&gt;
tail -n &lt;span style=&#34;color:#ae81ff&#34;&gt;3&lt;/span&gt; myfile

&lt;span style=&#34;color:#75715e&#34;&gt;# Watch all updates to file&lt;/span&gt;
tail -f myfile

&lt;span style=&#34;color:#75715e&#34;&gt;# Read file in window (not cat)&lt;/span&gt;
less myfile

&lt;span style=&#34;color:#75715e&#34;&gt;# Make all directories if not exist&lt;/span&gt;
mkdir -p exist/not/dir

&lt;span style=&#34;color:#75715e&#34;&gt;# Visualise dir structure&lt;/span&gt;
tree -L &lt;span style=&#34;color:#ae81ff&#34;&gt;2&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Remove env variable&lt;/span&gt;
unset myvar

&lt;span style=&#34;color:#75715e&#34;&gt;# Alias command to short one&lt;/span&gt;
alias lc&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;ls -laht&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# unalias to remove&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Piping output&lt;/span&gt;
echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;overwrite&amp;#34;&lt;/span&gt; &amp;gt; file &lt;span style=&#34;color:#75715e&#34;&gt;# Same as 1&amp;gt;&lt;/span&gt;
echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;append&amp;#34;&lt;/span&gt; &amp;gt;&amp;gt; file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;system&#34;&gt;System&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# See disk space usage (human readable)&lt;/span&gt;
df -h

&lt;span style=&#34;color:#75715e&#34;&gt;# See file usage for dirs&lt;/span&gt;
du &lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;--max-depth&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Show running processes, a: show other user, u: show username, x: show non terminal&lt;/span&gt;
ps -aux

&lt;span style=&#34;color:#75715e&#34;&gt;# Show usage&lt;/span&gt;
top
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;tricks&#34;&gt;Tricks&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Use command output as if it&amp;#39;s file&lt;/span&gt;
diff &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep string file1&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt; &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;(&lt;/span&gt;grep string file2&lt;span style=&#34;color:#f92672&#34;&gt;)&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Repeat last 3 command&lt;/span&gt;
!!

&lt;span style=&#34;color:#75715e&#34;&gt;# Repeat last arg of the last command&lt;/span&gt;
!$

&lt;span style=&#34;color:#75715e&#34;&gt;# Take all args from previous and use&lt;/span&gt;
!:1-$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;io&#34;&gt;IO&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Secure input&lt;/span&gt;
read -s -p &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Password: &amp;#34;&lt;/span&gt; password

&lt;span style=&#34;color:#75715e&#34;&gt;# Default value&lt;/span&gt;
read -p &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Address [http://127.0.0.1]: &amp;#34;&lt;/span&gt; ADDR
default&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;http://127.0.0.1&amp;#34;&lt;/span&gt;
ADDR&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;ADDR&lt;span style=&#34;color:#66d9ef&#34;&gt;:-&lt;/span&gt;$default&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;jq&#34;&gt;jq&lt;/h1&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Get value from object within array within object&lt;/span&gt;
jq -rec &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.parent.children | .[] | .name&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;# raw:no quotes, e:null exit0, compact&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Get object attr and value and format &amp;#34;Key=$attr,Value=$val&amp;#34;&lt;/span&gt;
jq -r &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.data | keys[] as $k | &amp;#34;Key=\($k),Value=\(.[$k])&amp;#34;&amp;#39;&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Use output in for loop&lt;/span&gt;
&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; object in &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;JSON&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; | jq -rec &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;.entries[] | .whole | @base64&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;; &lt;span style=&#34;color:#66d9ef&#34;&gt;do&lt;/span&gt;
  echo &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;This is the value: &lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;echo &lt;span style=&#34;color:#e6db74&#34;&gt;${&lt;/span&gt;val&lt;span style=&#34;color:#e6db74&#34;&gt;}&lt;/span&gt; | base64 -d | jq .attribute&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span style=&#34;color:#66d9ef&#34;&gt;done&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Args&lt;/span&gt;
curl localhost:8500/v1/catalog/nodes | &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;    jq &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;        --arg ip &lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;./get_host.sh&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;\
&lt;/span&gt;&lt;span style=&#34;color:#ae81ff&#34;&gt;&lt;/span&gt;        &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;.[] | select(.Address==$ip)&amp;#39;&lt;/span&gt;
        
&lt;span style=&#34;color:#75715e&#34;&gt;# Output mulitple entries in list&lt;/span&gt;
jq -rec &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;[.importItems[].itemId]&amp;#39;&lt;/span&gt;

&lt;span style=&#34;color:#75715e&#34;&gt;# Create object&lt;/span&gt;
jq -rec &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#39;{} +{ Items:[.importItems[].itemId]}&amp;#39;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;behaviour&#34;&gt;Behaviour&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span style=&#34;color:#75715e&#34;&gt;# Exit script if commands return nonzero&lt;/span&gt;
set -e

&lt;span style=&#34;color:#75715e&#34;&gt;# Output command as they run (debug)&lt;/span&gt;
set -x
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
    </item>
    
    <item>
      <title>Podcasts reccomendations - 07/2019</title>
      <link>/post/podcasts-2019-q2/</link>
      <pubDate>Mon, 22 Jul 2019 11:28:19 +0100</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/podcasts-2019-q2/</guid>
      <description>&lt;p&gt;These are my currently podcast reccomendations for Q2 2019&lt;/p&gt;</description>
      <content>&lt;p&gt;These are my currently podcast reccomendations for Q2 2019&lt;/p&gt;
&lt;h2 id=&#34;the-teachers-pet&#34;&gt;The Teacher&amp;rsquo;s Pet&lt;/h2&gt;
&lt;p&gt;A great true crime podcast exploring a 36 year old cold case around a woman who went missing and who&amp;rsquo;s husband brought his 17 year old, school girl, girlfriend into the house within 2 days.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Ep. 1: Bayview&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-weeds&#34;&gt;The Weeds&lt;/h2&gt;
&lt;p&gt;Podcast from Vox where they do a deep dive into a topic for ~1hr. If you pick an episode with an good topic usually very informative and interesting listen.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-1&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Americas two housing crises&lt;/li&gt;
&lt;li&gt;Into the weeds with Elizabeth Warren&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;gangster-capitalism&#34;&gt;Gangster Capitalism&lt;/h2&gt;
&lt;p&gt;Series 1 of the podcast covers the admissions scandal with some truly horrific stories of entitled parents. The podcast really going into the inner works of the scams being done and the unprecedented scale of the system in place.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-2&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;S1 [1] The Side Door&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-shrink-next-door&#34;&gt;The Shrink Next Door&lt;/h2&gt;
&lt;p&gt;A deeply interesting and weird story around a therapist who abused his position with his patients. Focuses mainly on this one individual who got taken advantage of to a ridiculous level, leading to him being ostracised from his family and friends.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-3&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Welcome To The Neighborhood | 1&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;dissect&#34;&gt;Dissect&lt;/h2&gt;
&lt;p&gt;Season 4 of Dissect covers Tyler the Creators album, Flower Boy. An amazing and indepth look into this brilliant album with some bonus episodes covering some of his over work including his new album, Igor.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-4&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;S4E1 - Tyler the Creator: Flower Boy&lt;/li&gt;
&lt;li&gt;Dissecting Igor with Anthony Fantano&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;</content>
    </item>
    
    <item>
      <title>Podcast reccomendations - 02/2019</title>
      <link>/post/podcasts-2019-q1/</link>
      <pubDate>Tue, 12 Feb 2019 14:31:03 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/podcasts-2019-q1/</guid>
      <description>&lt;p&gt;These are my currently podcast reccomendations for Q1 2019&lt;/p&gt;</description>
      <content>&lt;p&gt;These are my currently podcast reccomendations for Q1 2019&lt;/p&gt;
&lt;h2 id=&#34;the-butterfly-effect&#34;&gt;The Butterfly Effect&lt;/h2&gt;
&lt;p&gt;Jon Ronson&amp;rsquo;s Audible exclusive (now available everywhere) where he explores the affect PornHub had on the porn industy. Very insighful and interesting, each episodes covering a broad area such as the impact on kids in school. Only 7 (+1 bonus) episodes but still covers a lot.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Ep. 1: A Nondescript Building in Montreal&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;the-last-days-of-august&#34;&gt;The Last Days of August&lt;/h2&gt;
&lt;p&gt;Following on from The Butterfly Effect, released this year on Audible (public release in April), Jon explores the death of a famous porn star and the mystery surrounding her death and her husband.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-1&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Ep. 1&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;bear-brook&#34;&gt;Bear Brook&lt;/h2&gt;
&lt;p&gt;True Crime stories focussed around two barrels of bodies found in the woods. The podcast covers how crime investigations methodologies were changed forever by the techniques used.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-2&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Ep. 1: Hide and Seek&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;this-american-life&#34;&gt;This American Life&lt;/h2&gt;
&lt;p&gt;A classic podcast but some recent episodes are worth a mention, first covers&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-3&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;#661: But that&amp;rsquo;s what happened&lt;/li&gt;
&lt;li&gt;#657: The Runaways&lt;/li&gt;
&lt;li&gt;#486: Valentines Day (Act 2 in particular)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;cortex&#34;&gt;Cortex&lt;/h2&gt;
&lt;p&gt;Two youtube/podcast company owners discuss productivity, goal planning, efficiency and technology&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-4&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;78: State of the Apps 2019&lt;/li&gt;
&lt;li&gt;72: Adulting Complete&lt;/li&gt;
&lt;li&gt;79: 2019 Yearly Themes&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;</content>
    </item>
    
    <item>
      <title>About</title>
      <link>/about/</link>
      <pubDate>Sun, 27 May 2018 17:12:07 +0100</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/about/</guid>
      <description>Dom Goodwin Backend Engineer @ Monzo
Links         
       </description>
      <content>&lt;p&gt;Dom Goodwin
Backend Engineer @ Monzo&lt;/p&gt;
&lt;h2 id=&#34;links&#34;&gt;Links&lt;/h2&gt;
&lt;p&gt;&lt;a class=&#34;inline-svg social-icon fa-github&#34; href=&#34;https://github.com/domgoodwin&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 496 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z&#34;/&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-keybase&#34; href=&#34;https://keybase.io/domgoodwin&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 448 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M286.17 419a18 18 0 1 0 18 18 18 18 0 0 0-18-18zm111.92-147.6c-9.5-14.62-39.37-52.45-87.26-73.71q-9.1-4.06-18.38-7.27a78.43 78.43 0 0 0-47.88-104.13c-12.41-4.1-23.33-6-32.41-5.77-.6-2-1.89-11 9.4-35L198.66 32l-5.48 7.56c-8.69 12.06-16.92 23.55-24.34 34.89a51 51 0 0 0-8.29-1.25c-41.53-2.45-39-2.33-41.06-2.33-50.61 0-50.75 52.12-50.75 45.88l-2.36 36.68c-1.61 27 19.75 50.21 47.63 51.85l8.93.54a214 214 0 0 0-46.29 35.54C14 304.66 14 374 14 429.77v33.64l23.32-29.8a148.6 148.6 0 0 0 14.56 37.56c5.78 10.13 14.87 9.45 19.64 7.33 4.21-1.87 10-6.92 3.75-20.11a178.29 178.29 0 0 1-15.76-53.13l46.82-59.83-24.66 74.11c58.23-42.4 157.38-61.76 236.25-38.59 34.2 10.05 67.45.69 84.74-23.84.72-1 1.2-2.16 1.85-3.22a156.09 156.09 0 0 1 2.8 28.43c0 23.3-3.69 52.93-14.88 81.64-2.52 6.46 1.76 14.5 8.6 15.74 7.42 1.57 15.33-3.1 18.37-11.15C429 443 434 414 434 382.32c0-38.58-13-77.46-35.91-110.92zM142.37 128.58l-15.7-.93-1.39 21.79 13.13.78a93 93 0 0 0 .32 19.57l-22.38-1.34a12.28 12.28 0 0 1-11.76-12.79L107 119c1-12.17 13.87-11.27 13.26-11.32l29.11 1.73a144.35 144.35 0 0 0-7 19.17zm148.42 172.18a10.51 10.51 0 0 1-14.35-1.39l-9.68-11.49-34.42 27a8.09 8.09 0 0 1-11.13-1.08l-15.78-18.64a7.38 7.38 0 0 1 1.34-10.34l34.57-27.18-14.14-16.74-17.09 13.45a7.75 7.75 0 0 1-10.59-1s-3.72-4.42-3.8-4.53a7.38 7.38 0 0 1 1.37-10.34L214 225.19s-18.51-22-18.6-22.14a9.56 9.56 0 0 1 1.74-13.42 10.38 10.38 0 0 1 14.3 1.37l81.09 96.32a9.58 9.58 0 0 1-1.74 13.44zM187.44 419a18 18 0 1 0 18 18 18 18 0 0 0-18-18z&#34;/&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-twitter&#34; href=&#34;https://twitter.com/domgoodwin_&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z&#34;/&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-linkedin-in&#34; href=&#34;https://www.linkedin.com/in/dom-goodwin/&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 448 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M100.28 448H7.4V148.9h92.88zM53.79 108.1C24.09 108.1 0 83.5 0 53.8a53.79 53.79 0 0 1 107.58 0c0 29.7-24.1 54.3-53.79 54.3zM447.9 448h-92.68V302.4c0-34.7-.7-79.2-48.29-79.2-48.29 0-55.69 37.7-55.69 76.7V448h-92.78V148.9h89.08v40.8h1.3c12.4-23.5 42.69-48.3 87.88-48.3 94 0 111.28 61.9 111.28 142.3V448z&#34;/&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-mastodon&#34; href=&#34;https://social.lol/@domg&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 448 512&#34;&gt;
&lt;path fill=&#34;currentColor&#34; fill=&#34;#2b90d9&#34; d=&#34;M211.80734 139.0875c-3.18125 16.36625-28.4925 34.2775-57.5625 37.74875-15.15875 1.80875-30.08375 3.47125-45.99875 2.74125-26.0275-1.1925-46.565-6.2125-46.565-6.2125 0 2.53375.15625 4.94625.46875 7.2025 3.38375 25.68625 25.47 27.225 46.39125 27.9425 21.11625.7225 39.91875-5.20625 39.91875-5.20625l.8675 19.09s-14.77 7.93125-41.08125 9.39c-14.50875.7975-32.52375-.365-53.50625-5.91875C9.23234 213.82 1.40609 165.31125.20859 116.09125c-.365-14.61375-.14-28.39375-.14-39.91875 0-50.33 32.97625-65.0825 32.97625-65.0825C49.67234 3.45375 78.20359.2425 107.86484 0h.72875c29.66125.2425 58.21125 3.45375 74.8375 11.09 0 0 32.975 14.7525 32.975 65.0825 0 0 .41375 37.13375-4.59875 62.915&#34;/&gt;
&lt;path fill=&#34;currentColor&#34; fill=&#34;#fff&#34; fill-opacity=&#34;0&#34; d=&#34;M177.50984 80.077v60.94125h-24.14375v-59.15c0-12.46875-5.24625-18.7975-15.74-18.7975-11.6025 0-17.4175 7.5075-17.4175 22.3525v32.37625H96.20734V85.42325c0-14.845-5.81625-22.3525-17.41875-22.3525-10.49375 0-15.74 6.32875-15.74 18.7975v59.15H38.90484V80.077c0-12.455 3.17125-22.3525 9.54125-29.675 6.56875-7.3225 15.17125-11.07625 25.85-11.07625 12.355 0 21.71125 4.74875 27.8975 14.2475l6.01375 10.08125 6.015-10.08125c6.185-9.49875 15.54125-14.2475 27.8975-14.2475 10.6775 0 19.28 3.75375 25.85 11.07625 6.36875 7.3225 9.54 17.22 9.54 29.675&#34;/&gt;
&lt;/svg&gt;&lt;/p&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-bluesky&#34; href=&#34;https://bsky.app/profile/dgood.win&#34;&gt;&lt;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&gt;
&lt;svg version=&#34;1.1&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34;&gt;
 &lt;path fill=&#34;currentColor&#34; d=&#34;m135.72 44.03c66.496 49.921 138.02 151.14 164.28 205.46 26.262-54.316 97.782-155.54 164.28-205.46 47.98-36.021 125.72-63.892 125.72 24.795 0 17.712-10.155 148.79-16.111 170.07-20.703 73.984-96.144 92.854-163.25 81.433 117.3 19.964 147.14 86.092 82.697 152.22-122.39 125.59-175.91-31.511-189.63-71.766-2.514-7.3797-3.6904-10.832-3.7077-7.8964-0.0174-2.9357-1.1937 0.51669-3.7077 7.8964-13.714 40.255-67.233 197.36-189.63 71.766-64.444-66.128-34.605-132.26 82.697-152.22-67.108 11.421-142.55-7.4491-163.25-81.433-5.9562-21.282-16.111-152.36-16.111-170.07 0-88.687 77.742-60.816 125.72-24.795z&#34; fill=&#34;#1185fe&#34;/&gt;
&lt;/svg&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-rss&#34; href=&#34;index.xml&#34;&gt;&lt;svg aria-hidden=&#34;true&#34; focusable=&#34;false&#34; data-prefix=&#34;fas&#34; data-icon=&#34;rss&#34; class=&#34;svg-inline--fa fa-rss fa-w-14&#34; role=&#34;img&#34; xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 448 512&#34;&gt;&lt;path fill=&#34;currentColor&#34; fill=&#34;currentColor&#34; d=&#34;M128.081 415.959c0 35.369-28.672 64.041-64.041 64.041S0 451.328 0 415.959s28.672-64.041 64.041-64.041 64.04 28.673 64.04 64.041zm175.66 47.25c-8.354-154.6-132.185-278.587-286.95-286.95C7.656 175.765 0 183.105 0 192.253v48.069c0 8.415 6.49 15.472 14.887 16.018 111.832 7.284 201.473 96.702 208.772 208.772.547 8.397 7.604 14.887 16.018 14.887h48.069c9.149.001 16.489-7.655 15.995-16.79zm144.249.288C439.596 229.677 251.465 40.445 16.503 32.01 7.473 31.686 0 38.981 0 48.016v48.068c0 8.625 6.835 15.645 15.453 15.999 191.179 7.839 344.627 161.316 352.465 352.465.353 8.618 7.373 15.453 15.999 15.453h48.068c9.034-.001 16.329-7.474 16.005-16.504z&#34;&gt;&lt;/path&gt;&lt;/svg&gt;
&lt;/a&gt;
&lt;a class=&#34;inline-svg social-icon fa-message&#34; href=&#34;mailto:site@dgood.win&#34;&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; viewBox=&#34;0 0 512 512&#34;&gt;&lt;!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --&gt;&lt;path fill=&#34;currentColor&#34; d=&#34;M447.1 0h-384c-35.25 0-64 28.75-64 63.1v287.1c0 35.25 28.75 63.1 64 63.1h96v83.98c0 9.836 11.02 15.55 19.12 9.7l124.9-93.68h144c35.25 0 64-28.75 64-63.1V63.1C511.1 28.75 483.2 0 447.1 0zM464 352c0 8.75-7.25 16-16 16h-160l-80 60v-60H64c-8.75 0-16-7.25-16-16V64c0-8.75 7.25-16 16-16h384c8.75 0 16 7.25 16 16V352z&#34;/&gt;&lt;/svg&gt;
&lt;/a&gt;
</content>
    </item>
    
    <item>
      <title>Setting up a Hugo Blog</title>
      <link>/post/setup/</link>
      <pubDate>Fri, 06 Apr 2018 11:03:53 +0100</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/setup/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt; is a Go based, static site generator. It has some &lt;a href=&#34;https://www.youtube.com/watch?v=CdiDYZ51a2o&#34;&gt;impressive&lt;/a&gt; benchmarking figures, a &lt;a href=&#34;https://themes.gohugo.io/&#34;&gt;huge catalog&lt;/a&gt; of impressive themes and means I don&amp;rsquo;t have to write HTML.&lt;/p&gt;</description>
      <content>&lt;p&gt;&lt;a href=&#34;https://gohugo.io/&#34;&gt;Hugo&lt;/a&gt; is a Go based, static site generator. It has some &lt;a href=&#34;https://www.youtube.com/watch?v=CdiDYZ51a2o&#34;&gt;impressive&lt;/a&gt; benchmarking figures, a &lt;a href=&#34;https://themes.gohugo.io/&#34;&gt;huge catalog&lt;/a&gt; of impressive themes and means I don&amp;rsquo;t have to write HTML.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m setting this up with the follow configuratons&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;Ubuntu 16.04 LTS
Hugo 0.32
Go 1.9.4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h1 id=&#34;installing-hugo&#34;&gt;Installing Hugo&lt;/h1&gt;
&lt;p&gt;Ubuntu/Debian:&lt;br&gt;
&lt;code&gt;sudo apt-get install hugo&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Check it&amp;rsquo;s installed correctly:&lt;br&gt;
&lt;code&gt;hugo version&lt;/code&gt;&lt;/p&gt;
&lt;h1 id=&#34;creating-your-site&#34;&gt;Creating your site&lt;/h1&gt;
&lt;h2 id=&#34;basic-setup&#34;&gt;Basic setup&lt;/h2&gt;
&lt;p&gt;To generate your base site:&lt;br&gt;
&lt;code&gt;hugo new site my-blog&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;This will create a folder, my-blog, in your current directory&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The folder structure will be:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class=&#34;language-file&#34; data-lang=&#34;file&#34;&gt;+--archetypes/     Templates for content files  
+--content/        Where content for your site goes  
+--data/           Config files for generating your site  
+--layouts/        Html templates for content views  
+--static/         All static content for site goes here  
config.toml        General site properties like: theme, title  
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Setup your site as a git repo:&lt;br&gt;
&lt;code&gt;git init&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;using-a-theme&#34;&gt;Using a theme&lt;/h2&gt;
&lt;p&gt;Pick a theme you want to use from &lt;a href=&#34;https://themes.gohugo.io/&#34;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;As themes are stored as git repos, the best way to use one is a submodule&lt;br&gt;
&lt;code&gt;git submodule add {THEME-REPO} themes/{THEME-NAME}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Once the submodule has been added, add this line to your &lt;em&gt;config.toml&lt;/em&gt;:&lt;br&gt;
&lt;code&gt;theme = &amp;quot;{THEME-NAME}&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;To see what your theme looks like, run the Hugo server:&lt;br&gt;
&lt;code&gt;hugo server&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Your empty site should be availbale at:&lt;br&gt;
&lt;code&gt;localhost:1313&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;adding-content&#34;&gt;Adding content&lt;/h2&gt;
&lt;p&gt;To create a new post for your site:&lt;br&gt;
&lt;code&gt;hugo new post/hello-world.md&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;By default (because of the archetypes/default.md) your post file will look like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;title: &amp;#34;Hello World&amp;#34;  
date: 2018-04-06T11:03:53+01:00  
draft: true  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To see your page, you need to run the server with drafts enabled:&lt;br&gt;
&lt;code&gt;hugo server -D&lt;/code&gt;&lt;/p&gt;
&lt;h2 id=&#34;overriding-themes&#34;&gt;Overriding themes&lt;/h2&gt;
&lt;p&gt;You might want to change how a theme renders something. To do this, it&amp;rsquo;s easy. Just copy the files you want to change from:&lt;br&gt;
&lt;code&gt;themes/{THEME-NAME}/layouts/&lt;/code&gt; to: &lt;code&gt;layouts/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Then the files in the root layouts folder will override your theme ones&lt;/p&gt;</content>
    </item>
    
    <item>
      <title>Podcast reccomendations - 04/2018</title>
      <link>/post/podcasts/</link>
      <pubDate>Wed, 04 Apr 2018 22:03:36 +0100</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/post/podcasts/</guid>
      <description>&lt;p&gt;These are my currently podcast reccomendations as of April 2018&lt;/p&gt;</description>
      <content>&lt;p&gt;These are my currently podcast reccomendations as of April 2018&lt;/p&gt;
&lt;h2 id=&#34;reply-all&#34;&gt;Reply All&lt;/h2&gt;
&lt;p&gt;Every week, you&amp;rsquo;re presented with an intersting tale relating to the internet. From online bounty hunters to crowdsourcing medical advice, this podcast&amp;rsquo;s range of stories are always interesting and worth a listen.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Long Distance : #102 / #103&lt;/li&gt;
&lt;li&gt;The Secret Life of Alex Goldman : #96&lt;/li&gt;
&lt;li&gt;Boy in Photo : #79&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;this-american-life&#34;&gt;This American Life&lt;/h2&gt;
&lt;p&gt;This American Life is one of the most popular podcasts of all time. With over twenty years worth of archives, the amount of amazing episodes are endless.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-1&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Human Error in Voltile Situations : #634&lt;/li&gt;
&lt;li&gt;20 Acts in 60 Minutes : #241&lt;/li&gt;
&lt;li&gt;Five Women : #640&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;my-favourite-murder&#34;&gt;My Favourite Murder&lt;/h2&gt;
&lt;p&gt;Every week, the hosts tell some of their favourite, most interesting true crime, murder stories.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-2&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;My Firstest Murder : #1&lt;/li&gt;
&lt;li&gt;Decompressions : #102&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;sawbones&#34;&gt;Sawbones&lt;/h2&gt;
&lt;p&gt;A look into the history of how illnesses and medcial problems were &lt;em&gt;solved&lt;/em&gt; throughout time. Makes you wonder if we&amp;rsquo;re as wrong now as our ancestors were.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-3&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;The Women Who Gave Birth to Rabbits&lt;/li&gt;
&lt;li&gt;Opioid Addiction&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;no-such-thing-as-a-fish&#34;&gt;No Such Thing As A Fish&lt;/h2&gt;
&lt;p&gt;The researches behind the facts for QI talk about their favourites facts of the week.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-4&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Really any, they&amp;rsquo;re all great&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;page-94-the-private-eye-podcast&#34;&gt;Page 94: The Private Eye Podcast&lt;/h2&gt;
&lt;p&gt;A more detailed look into some stories within Private Eye.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-5&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Hospital and Hacks&lt;/li&gt;
&lt;li&gt;Credit and Christmas&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;disect&#34;&gt;Disect&lt;/h2&gt;
&lt;p&gt;Long form music analysis, each season focussing on an album.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-6&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;S2E1 - Kanye West: The Elephant in the Room&lt;/li&gt;
&lt;li&gt;S1E9 - Alright by Kendrick Lamar&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;hello-internet&#34;&gt;Hello Internet&lt;/h2&gt;
&lt;p&gt;Two very inteligent, insightful and interesting people discuss topics of note; always thought provoking.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-7&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Being Wrong on The Internet, #1&lt;/li&gt;
&lt;li&gt;Mr Chompers, #93&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;freakonomics&#34;&gt;Freakonomics&lt;/h2&gt;
&lt;p&gt;Two economist explore the hidden side of everything, from pizza stores to chuck e cheeses.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-8&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;What Are you Waiting For?&lt;/li&gt;
&lt;li&gt;How Big is My Penis? (And Other Things We Ask Google)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;my-dad-wrote-a-porno&#34;&gt;My Dad Wrote A Porno&lt;/h2&gt;
&lt;p&gt;I think the title of this one really says it all.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-9&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;S1E1 - &amp;lsquo;The Job Interview;&amp;rsquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;mortified&#34;&gt;Mortified&lt;/h2&gt;
&lt;p&gt;Adults tell the embarrassing stories of things they did as kids.&lt;/p&gt;
&lt;h3 id=&#34;episodes-to-get-started-10&#34;&gt;Episodes to get started&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Titanic Ruined My Love Life, #88&lt;/li&gt;
&lt;li&gt;How to Become a Catfish, #105&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;notable-mentions&#34;&gt;Notable mentions&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;S-Town, Serial, Crimetown&lt;/p&gt;
&lt;/blockquote&gt;</content>
    </item>
    
    <item>
      <title>Books</title>
      <link>/books/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/books/</guid>
      <description>article.single section, .article-list article { padding-left: 7rem !important; padding-right: 7rem !important; }  Currently reading    Share book reviews and ratings with Dom, and even join a book club on Goodreads.      Read                      Share book reviews and ratings with Dom, and even join a book club on Goodreads.</description>
      <content>&lt;style&gt;

 article.single section, .article-list article {
    padding-left: 7rem !important;
    padding-right: 7rem !important;
 }

&lt;/style&gt;

&lt;div class=&#34;books&#34;&gt;
    &lt;h2 class=&#34;headline&#34;&gt;Currently reading&lt;/h2&gt;
      &lt;div&gt;
            &lt;div id=&#34;gr_grid_widget_1555969678&#34;&gt;
              
                &lt;div class=&#34;gr_grid_container&#34;&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Silk Roads: A New History of the World&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/25812847-the-silk-roads&#34;&gt;&lt;img alt=&#34;The Silk Roads: A New History of the World&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1472636067m/25812847.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Rethinking the Economics of Land and Housing&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/34448182-rethinking-the-economics-of-land-and-housing&#34;&gt;&lt;img alt=&#34;Rethinking the Economics of Land and Housing&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1489659764m/34448182.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;noscript&gt;&lt;br/&gt;Share &lt;a rel=&#34;nofollow&#34; href=&#34;/&#34;&gt;book reviews&lt;/a&gt; and ratings with Dom, and even join a &lt;a rel=&#34;nofollow&#34; href=&#34;/group&#34;&gt;book club&lt;/a&gt; on Goodreads.&lt;/noscript&gt;
        &lt;/div&gt;
      
            &lt;/div&gt;
            &lt;script src=&#34;https://www.goodreads.com/review/grid_widget/87140010.Dom&#39;s%20currently-reading%20book%20montage?cover_size=medium&amp;hide_link=true&amp;hide_title=true&amp;num_books=20&amp;order=d&amp;shelf=currently-reading&amp;sort=date_read&amp;widget_id=1555969678&#34; type=&#34;text/javascript&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
      
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&#34;books&#34;&gt;
      &lt;h2 class=&#34;headline&#34;&gt;Read&lt;/h2&gt;
      &lt;div&gt;
            &lt;div id=&#34;gr_grid_widget_1555969331&#34;&gt;
              
                &lt;div class=&#34;gr_grid_container&#34;&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Collected Schizophrenias: Essays&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/40121993-the-collected-schizophrenias&#34;&gt;&lt;img alt=&#34;The Collected Schizophrenias: Essays&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1527408064m/40121993.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;A Walk in the Woods: Rediscovering America on the Appalachian Trail&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/9791.A_Walk_in_the_Woods&#34;&gt;&lt;img alt=&#34;A Walk in the Woods: Rediscovering America on the Appalachian Trail&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1388189974m/9791.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;How To Be Right: … in a world gone wrong&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/39078159-how-to-be-right&#34;&gt;&lt;img alt=&#34;How To Be Right: … in a world gone wrong&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1537877334m/39078159.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Undoing Project: A Friendship That Changed Our Minds&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/35631386-the-undoing-project&#34;&gt;&lt;img alt=&#34;The Undoing Project: A Friendship That Changed Our Minds&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1509135882m/35631386.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Stasiland: Stories from Behind the Berlin Wall&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/226369.Stasiland&#34;&gt;&lt;img alt=&#34;Stasiland: Stories from Behind the Berlin Wall&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1385280143m/226369.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Bad Blood: Secrets and Lies in a Silicon Valley Startup&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/37976541-bad-blood&#34;&gt;&lt;img alt=&#34;Bad Blood: Secrets and Lies in a Silicon Valley Startup&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1554560125m/37976541.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Inglorious Empire: What the British Did to India&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/34185892-inglorious-empire&#34;&gt;&lt;img alt=&#34;Inglorious Empire: What the British Did to India&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1490075230m/34185892.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Fall of Icarus&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/24874363-the-fall-of-icarus&#34;&gt;&lt;img alt=&#34;The Fall of Icarus&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1423765132m/24874363.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;SPQR: A History of Ancient Rome&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/28789711-spqr&#34;&gt;&lt;img alt=&#34;SPQR: A History of Ancient Rome&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1470421195m/28789711.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Princess: A True Story of Life Behind the Veil in Saudi Arabia&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/613283.Princess&#34;&gt;&lt;img alt=&#34;Princess: A True Story of Life Behind the Veil in Saudi Arabia&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1377538002m/613283.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Worth Dying For: The Power and Politics of Flags&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/28782793-worth-dying-for&#34;&gt;&lt;img alt=&#34;Worth Dying For: The Power and Politics of Flags&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1473682152m/28782793.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Original Gangstas: Tupac Shakur, Dr. Dre, Eazy-E, Ice Cube, and the Birth of West Coast Rap&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/33385676-original-gangstas&#34;&gt;&lt;img alt=&#34;Original Gangstas: Tupac Shakur, Dr. Dre, Eazy-E, Ice Cube, and the Birth of West Coast Rap&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1494925105m/33385676.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;I&#39;ll Be Gone in the Dark: One Woman&#39;s Obsessive Search for the Golden State Killer&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/35068432-i-ll-be-gone-in-the-dark&#34;&gt;&lt;img alt=&#34;I&#39;ll Be Gone in the Dark: One Woman&#39;s Obsessive Search for the Golden State Killer&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1499131009m/35068432.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;So You&#39;ve Been Publicly Shamed&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/22571552-so-you-ve-been-publicly-shamed&#34;&gt;&lt;img alt=&#34;So You&#39;ve Been Publicly Shamed&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1413749614m/22571552.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Modern Romance&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/23453112-modern-romance&#34;&gt;&lt;img alt=&#34;Modern Romance&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1432335014m/23453112.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Triggers: Creating Behavior That Lasts—Becoming the Person You Want to Be&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/22544758-triggers&#34;&gt;&lt;img alt=&#34;Triggers: Creating Behavior That Lasts—Becoming the Person You Want to Be&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1422811813m/22544758.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Quiet: The Power of Introverts in a World That Can&#39;t Stop Talking&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/8520610-quiet&#34;&gt;&lt;img alt=&#34;Quiet: The Power of Introverts in a World That Can&#39;t Stop Talking&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1328562861m/8520610.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Psychopath Test: A Journey Through the Madness Industry&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/12391521-the-psychopath-test&#34;&gt;&lt;img alt=&#34;The Psychopath Test: A Journey Through the Madness Industry&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1364166270m/12391521.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;How Adam Smith Can Change Your Life: An Unexpected Guide to Human Nature and Happiness&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/20821053-how-adam-smith-can-change-your-life&#34;&gt;&lt;img alt=&#34;How Adam Smith Can Change Your Life: An Unexpected Guide to Human Nature and Happiness&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1403713769m/20821053.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Harry Potter and the Sorcerer&#39;s Stone (Harry Potter, #1)&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/3.Harry_Potter_and_the_Sorcerer_s_Stone&#34;&gt;&lt;img alt=&#34;Harry Potter and the Sorcerer&#39;s Stone&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1474154022m/3.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;noscript&gt;&lt;br/&gt;Share &lt;a rel=&#34;nofollow&#34; href=&#34;/&#34;&gt;book reviews&lt;/a&gt; and ratings with Dom, and even join a &lt;a rel=&#34;nofollow&#34; href=&#34;/group&#34;&gt;book club&lt;/a&gt; on Goodreads.&lt;/noscript&gt;
        &lt;/div&gt;
      
            &lt;/div&gt;
            &lt;script src=&#34;https://www.goodreads.com/review/grid_widget/87140010.Dom&#39;s%20bookshelf:%20read?cover_size=medium&amp;hide_link=true&amp;hide_title=true&amp;num_books=32&amp;order=d&amp;shelf=read&amp;sort=date_read&amp;widget_id=1555969331&#34; type=&#34;text/javascript&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
      
      &lt;/div&gt;
  &lt;/div&gt;
  &lt;div class=&#34;books&#34;&gt;
      &lt;h2 class=&#34;headline&#34;&gt;To read&lt;/h2&gt;
      &lt;div&gt;
            &lt;div id=&#34;gr_grid_widget_1555969916&#34;&gt;
              
                &lt;div class=&#34;gr_grid_container&#34;&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Autobiography of Malcolm X&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/92057.The_Autobiography_of_Malcolm_X&#34;&gt;&lt;img alt=&#34;The Autobiography of Malcolm X&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1434682864m/92057.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Brave New World&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/5129.Brave_New_World&#34;&gt;&lt;img alt=&#34;Brave New World&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1523061131m/5129.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;El Silmarillion&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/36059465-el-silmarillion&#34;&gt;&lt;img alt=&#34;El Silmarillion&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1502998754m/36059465.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Secular Cycles&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/8778747-secular-cycles&#34;&gt;&lt;img alt=&#34;Secular Cycles&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1348613399m/8778747.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Churchill&#39;s Secret War: The British Empire and the Ravaging of India During World War II&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/8890989-churchill-s-secret-war&#34;&gt;&lt;img alt=&#34;Churchill&#39;s Secret War: The British Empire and the Ravaging of India During World War II&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1282070397m/8890989.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Thinking, Fast and Slow&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/11468377-thinking-fast-and-slow&#34;&gt;&lt;img alt=&#34;Thinking, Fast and Slow&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1317793965m/11468377.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Dictator&#39;s Handbook: Why Bad Behavior is Almost Always Good Politics&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/11612989-the-dictator-s-handbook&#34;&gt;&lt;img alt=&#34;The Dictator&#39;s Handbook: Why Bad Behavior is Almost Always Good Politics&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1328737207m/11612989.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Spider Network: The Wild Story of a Math Genius, a Gang of Backstabbing Bankers, and One of the Greatest Scams in Financial History&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/30759083-the-spider-network&#34;&gt;&lt;img alt=&#34;The Spider Network: The Wild Story of a Math Genius, a Gang of Backstabbing Bankers, and One of the Greatest Scams in Financial History&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1470598651m/30759083.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;When Britain Went Bust - The 1976 IMF Crisis&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/32828859-when-britain-went-bust---the-1976-imf-crisis&#34;&gt;&lt;img alt=&#34;When Britain Went Bust - The 1976 IMF Crisis&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1477937272m/32828859.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Dictatorland: The Men Who Stole Africa&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/36260719-dictatorland&#34;&gt;&lt;img alt=&#34;Dictatorland: The Men Who Stole Africa&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1505728611m/36260719.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Divided: Why We&#39;re Living in an Age of Walls&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/39871440-divided&#34;&gt;&lt;img alt=&#34;Divided: Why We&#39;re Living in an Age of Walls&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1533553243m/39871440.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Identity: Contemporary Identity Politics and the Struggle for Recognition&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/40543827-identity&#34;&gt;&lt;img alt=&#34;Identity: Contemporary Identity Politics and the Struggle for Recognition&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1529635965m/40543827.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Lies That Bind: Rethinking Identity&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/38321385-the-lies-that-bind&#34;&gt;&lt;img alt=&#34;The Lies That Bind: Rethinking Identity&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1537820143m/38321385.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;Capitalism in America: A History&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/38712616-capitalism-in-america&#34;&gt;&lt;img alt=&#34;Capitalism in America: A History&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1519230031m/38712616.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
          &lt;div class=&#34;gr_grid_book_container&#34;&gt;&lt;a title=&#34;The Myth of Capitalism: Monopolies and the Death of Competition&#34; rel=&#34;nofollow&#34; href=&#34;https://www.goodreads.com/book/show/40751646-the-myth-of-capitalism&#34;&gt;&lt;img alt=&#34;The Myth of Capitalism: Monopolies and the Death of Competition&#34; border=&#34;0&#34; src=&#34;https://images.gr-assets.com/books/1538427937m/40751646.jpg&#34; /&gt;&lt;/a&gt;&lt;/div&gt;
        &lt;noscript&gt;&lt;br/&gt;Share &lt;a rel=&#34;nofollow&#34; href=&#34;/&#34;&gt;book reviews&lt;/a&gt; and ratings with Dom, and even join a &lt;a rel=&#34;nofollow&#34; href=&#34;/group&#34;&gt;book club&lt;/a&gt; on Goodreads.&lt;/noscript&gt;
        &lt;/div&gt;
      
            &lt;/div&gt;
            &lt;script src=&#34;https://www.goodreads.com/review/grid_widget/87140010.Dom&#39;s%20to-read%20book%20montage?cover_size=medium&amp;hide_link=true&amp;hide_title=true&amp;num_books=18&amp;order=d&amp;shelf=to-read&amp;sort=date_read&amp;widget_id=1555969916&#34; type=&#34;text/javascript&#34; charset=&#34;utf-8&#34;&gt;&lt;/script&gt;
      
      &lt;/div&gt;
  &lt;/div&gt;

  &lt;style&gt;

.gr_grid_container {
   
}

.gr_grid_book_container {
   
  float: left;
  width: 98px;
  height: 160px;
  padding: 0px 0px;
  overflow: hidden;
}

div.books {
  display: grid;
}
  &lt;/style&gt;
</content>
    </item>
    
    <item>
      <title>Solar</title>
      <link>/solar/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <author>dom@domgoodwin.dev (Dom Goodwin)</author>
      <guid>/solar/</guid>
      <description>Solar Generation  13 405W panels 5kW inverter Days with 0 data are when the monitoring system was down        data = JSON.parse(&#39;{&#34;data&#34;:[{&#34;type&#34;:&#34;bar&#34;,&#34;x&#34;:[&#34;2023-08-01&#34;,&#34;2023-08-02&#34;,&#34;2023-08-03&#34;,&#34;2023-08-04&#34;,&#34;2023-08-05&#34;,&#34;2023-08-06&#34;,&#34;2023-08-07&#34;,&#34;2023-08-08&#34;,&#34;2023-08-09&#34;,&#34;2023-08-10&#34;,&#34;2023-08-11&#34;,&#34;2023-08-12&#34;,&#34;2023-08-13&#34;,&#34;2023-08-14&#34;,&#34;2023-08-15&#34;,&#34;2023-08-16&#34;,&#34;2023-08-17&#34;,&#34;2023-08-18&#34;,&#34;2023-08-19&#34;,&#34;2023-08-20&#34;,&#34;2023-08-21&#34;,&#34;2023-08-22&#34;,&#34;2023-08-23&#34;,&#34;2023-08-24&#34;,&#34;2023-08-25&#34;,&#34;2023-08-26&#34;,&#34;2023-08-27&#34;,&#34;2023-08-28&#34;,&#34;2023-08-29&#34;,&#34;2023-09-01&#34;,&#34;2023-09-02&#34;,&#34;2023-09-03&#34;,&#34;2023-09-04&#34;,&#34;2023-09-05&#34;,&#34;2023-09-06&#34;,&#34;2023-09-07&#34;,&#34;2023-09-08&#34;,&#34;2023-09-09&#34;,&#34;2023-09-10&#34;,&#34;2023-09-11&#34;,&#34;2023-09-12&#34;,&#34;2023-09-13&#34;,&#34;2023-09-14&#34;,&#34;2023-09-15&#34;,&#34;2023-09-16&#34;,&#34;2023-09-17&#34;,&#34;2023-09-18&#34;,&#34;2023-09-19&#34;,&#34;2023-09-20&#34;,&#34;2023-09-21&#34;,&#34;2023-09-22&#34;,&#34;2023-09-23&#34;,&#34;2023-09-24&#34;,&#34;2023-09-25&#34;,&#34;2023-09-26&#34;,&#34;2023-09-27&#34;,&#34;2023-09-28&#34;,&#34;2023-09-29&#34;,&#34;2023-09-30&#34;,&#34;2023-10-01&#34;,&#34;2023-10-02&#34;,&#34;2023-10-03&#34;,&#34;2023-10-04&#34;,&#34;2023-10-05&#34;,&#34;2023-10-06&#34;,&#34;2023-10-07&#34;,&#34;2023-10-08&#34;,&#34;2023-10-09&#34;,&#34;2023-10-10&#34;,&#34;2023-10-11&#34;,&#34;2023-10-12&#34;,&#34;2023-10-13&#34;,&#34;2023-10-14&#34;,&#34;2023-10-15&#34;,&#34;2023-10-16&#34;,&#34;2023-10-17&#34;,&#34;2023-10-18&#34;,&#34;2023-10-19&#34;,&#34;2023-10-20&#34;,&#34;2023-10-21&#34;,&#34;2023-10-22&#34;,&#34;2023-10-23&#34;,&#34;2023-10-24&#34;,&#34;2023-10-25&#34;,&#34;2023-10-26&#34;,&#34;2023-10-27&#34;,&#34;2023-10-28&#34;,&#34;2023-10-29&#34;,&#34;2023-10-30&#34;,&#34;2023-10-31&#34;,&#34;2023-11-01&#34;,&#34;2023-11-02&#34;,&#34;2023-11-03&#34;,&#34;2023-11-04&#34;,&#34;2023-11-05&#34;,&#34;2023-11-06&#34;,&#34;2023-11-07&#34;,&#34;2023-11-08&#34;,&#34;2023-11-09&#34;,&#34;2023-11-10&#34;,&#34;2023-11-11&#34;,&#34;2023-11-12&#34;,&#34;2023-11-13&#34;,&#34;2023-11-14&#34;,&#34;2023-11-15&#34;,&#34;2023-11-16&#34;,&#34;2023-11-17&#34;,&#34;2023-11-18&#34;,&#34;2023-11-19&#34;,&#34;2023-11-20&#34;,&#34;2023-11-21&#34;,&#34;2023-11-22&#34;,&#34;2023-11-23&#34;,&#34;2023-11-24&#34;,&#34;2023-11-25&#34;,&#34;2023-11-26&#34;,&#34;2023-11-27&#34;,&#34;2023-11-28&#34;,&#34;2023-11-29&#34;,&#34;2023-11-30&#34;,&#34;2023-12-01&#34;,&#34;2023-12-02&#34;,&#34;2023-12-03&#34;,&#34;2023-12-04&#34;,&#34;2023-12-05&#34;,&#34;2023-12-06&#34;,&#34;2023-12-07&#34;,&#34;2023-12-08&#34;,&#34;2023-12-09&#34;,&#34;2023-12-10&#34;,&#34;2023-12-11&#34;,&#34;2023-12-12&#34;,&#34;2023-12-13&#34;,&#34;2023-12-14&#34;,&#34;2023-12-15&#34;,&#34;2023-12-16&#34;,&#34;2023-12-17&#34;,&#34;2023-12-18&#34;,&#34;2023-12-19&#34;,&#34;2023-12-20&#34;,&#34;2023-12-21&#34;,&#34;2023-12-22&#34;,&#34;2023-12-23&#34;,&#34;2023-12-24&#34;,&#34;2023-12-25&#34;,&#34;2023-12-26&#34;,&#34;2023-12-27&#34;,&#34;2023-12-28&#34;,&#34;2023-12-29&#34;,&#34;2023-12-30&#34;,&#34;2023-12-31&#34;,&#34;2024-01-01&#34;,&#34;2024-01-02&#34;,&#34;2024-01-03&#34;,&#34;2024-01-04&#34;,&#34;2024-01-05&#34;,&#34;2024-01-06&#34;,&#34;2024-01-07&#34;,&#34;2024-01-08&#34;,&#34;2024-01-09&#34;,&#34;2024-01-10&#34;,&#34;2024-01-11&#34;,&#34;2024-01-12&#34;,&#34;2024-01-13&#34;,&#34;2024-01-14&#34;,&#34;2024-01-15&#34;,&#34;2024-01-16&#34;,&#34;2024-01-17&#34;,&#34;2024-01-18&#34;,&#34;2024-01-19&#34;,&#34;2024-01-20&#34;,&#34;2024-01-21&#34;,&#34;2024-01-22&#34;,&#34;2024-01-23&#34;,&#34;2024-01-24&#34;,&#34;2024-01-25&#34;,&#34;2024-01-26&#34;,&#34;2024-01-27&#34;,&#34;2024-01-28&#34;,&#34;2024-01-29&#34;,&#34;2024-01-30&#34;,&#34;2024-01-31&#34;,&#34;2024-02-01&#34;,&#34;2024-02-02&#34;,&#34;2024-02-03&#34;,&#34;2024-02-04&#34;,&#34;2024-02-05&#34;,&#34;2024-02-06&#34;,&#34;2024-02-07&#34;,&#34;2024-02-08&#34;,&#34;2024-02-09&#34;,&#34;2024-02-10&#34;,&#34;2024-02-11&#34;,&#34;2024-02-12&#34;,&#34;2024-02-13&#34;,&#34;2024-02-14&#34;,&#34;2024-02-15&#34;,&#34;2024-02-16&#34;,&#34;2024-02-17&#34;,&#34;2024-02-18&#34;,&#34;2024-02-19&#34;,&#34;2024-02-20&#34;,&#34;2024-02-21&#34;,&#34;2024-02-22&#34;,&#34;2024-02-23&#34;,&#34;2024-02-24&#34;,&#34;2024-02-25&#34;,&#34;2024-02-26&#34;,&#34;2024-02-27&#34;,&#34;2024-02-28&#34;,&#34;2024-02-29&#34;,&#34;2024-03-01&#34;,&#34;2024-03-02&#34;,&#34;2024-03-03&#34;,&#34;2024-03-04&#34;,&#34;2024-03-05&#34;,&#34;2024-03-06&#34;,&#34;2024-03-07&#34;,&#34;2024-03-08&#34;,&#34;2024-03-09&#34;,&#34;2024-03-10&#34;,&#34;2024-03-11&#34;,&#34;2024-03-12&#34;,&#34;2024-03-13&#34;,&#34;2024-03-14&#34;,&#34;2024-03-15&#34;,&#34;2024-03-16&#34;,&#34;2024-03-17&#34;,&#34;2024-03-18&#34;,&#34;2024-03-19&#34;,&#34;2024-03-20&#34;,&#34;2024-03-21&#34;,&#34;2024-03-22&#34;,&#34;2024-03-23&#34;,&#34;2024-03-24&#34;,&#34;2024-03-25&#34;,&#34;2024-03-26&#34;,&#34;2024-03-27&#34;,&#34;2024-03-28&#34;,&#34;2024-03-29&#34;,&#34;2024-03-30&#34;,&#34;2024-03-31&#34;,&#34;2024-04-01&#34;,&#34;2024-04-02&#34;,&#34;2024-04-03&#34;,&#34;2024-04-04&#34;,&#34;2024-04-05&#34;,&#34;2024-04-06&#34;,&#34;2024-04-07&#34;,&#34;2024-04-08&#34;,&#34;2024-04-09&#34;,&#34;2024-04-10&#34;,&#34;2024-04-11&#34;,&#34;2024-04-12&#34;,&#34;2024-04-13&#34;,&#34;2024-04-14&#34;,&#34;2024-04-15&#34;,&#34;2024-04-16&#34;,&#34;2024-04-17&#34;,&#34;2024-04-18&#34;,&#34;2024-04-19&#34;,&#34;2024-04-20&#34;,&#34;2024-04-21&#34;,&#34;2024-04-22&#34;,&#34;2024-04-23&#34;,&#34;2024-04-24&#34;,&#34;2024-04-25&#34;,&#34;2024-04-26&#34;,&#34;2024-04-27&#34;,&#34;2024-04-28&#34;,&#34;2024-04-29&#34;,&#34;2024-04-30&#34;,&#34;2024-05-01&#34;,&#34;2024-05-02&#34;,&#34;2024-05-03&#34;,&#34;2024-05-04&#34;,&#34;2024-05-05&#34;,&#34;2024-05-06&#34;,&#34;2024-05-07&#34;,&#34;2024-05-08&#34;,&#34;2024-05-09&#34;,&#34;2024-05-10&#34;,&#34;2024-05-11&#34;,&#34;2024-05-12&#34;,&#34;2024-05-13&#34;,&#34;2024-05-14&#34;,&#34;2024-05-15&#34;,&#34;2024-05-16&#34;,&#34;2024-05-17&#34;,&#34;2024-05-18&#34;,&#34;2024-05-19&#34;,&#34;2024-05-20&#34;,&#34;2024-05-21&#34;,&#34;2024-05-22&#34;,&#34;2024-05-23&#34;,&#34;2024-05-24&#34;,&#34;2024-05-25&#34;,&#34;2024-05-26&#34;,&#34;2024-05-27&#34;,&#34;2024-05-28&#34;,&#34;2024-05-29&#34;,&#34;2024-05-30&#34;,&#34;2024-05-31&#34;,&#34;2024-06-01&#34;],&#34;y&#34;:[&#34;17.299999999999955&#34;,&#34;23.900000000000006&#34;,&#34;15.299999999999983&#34;,&#34;18.400000000000006&#34;,&#34;8.100000000000023&#34;,&#34;24.800000000000125&#34;,&#34;27.700000000000045&#34;,&#34;13.099999999999966&#34;,&#34;20.699999999999932&#34;,&#34;33.700000000000045&#34;,&#34;27.200000000000045&#34;,&#34;16.29999999999984&#34;,&#34;15.100000000000023&#34;,&#34;8.699999999999989&#34;,&#34;24.099999999999966&#34;,&#34;25.800000000000068&#34;,&#34;16.100000000000023&#34;,&#34;6.100000000000023&#34;,&#34;20.59999999999991&#34;,&#34;21.200000000000045&#34;,&#34;19.500000000000114&#34;,&#34;20.700000000000045&#34;,&#34;13.699999999999932&#34;,&#34;14&#34;,&#34;14.700000000000273&#34;,&#34;15.5&#34;,&#34;15.399999999999977&#34;,&#34;13.700000000000045&#34;,&#34;9.099999999999909&#34;,&#34;31&#34;,&#34;15.79999999999984&#34;,&#34;24.500000000000227&#34;,&#34;29.5&#34;,&#34;30.300000000000068&#34;,&#34;25&#34;,&#34;20.500000000000114&#34;,&#34;14.5&#34;,&#34;22.299999999999955&#34;,&#34;8.799999999999955&#34;,&#34;11.700000000000045&#34;,&#34;0&#34;,&#34;0&#34;,&#34;29.10000000000002&#34;,&#34;16.199999999999932&#34;,&#34;4.2999999999999545&#34;,&#34;6.000000000000114&#34;,&#34;14.600000000000023&#34;,&#34;7.099999999999909&#34;,&#34;5&#34;,&#34;5.099999999999682&#34;,&#34;17.700000000000045&#34;,&#34;24.299999999999727&#34;,&#34;6.900000000000091&#34;,&#34;21.100000000000136&#34;,&#34;13.299999999999727&#34;,&#34;4.200000000000273&#34;,&#34;5.299999999999727&#34;,&#34;23.100000000000136&#34;,&#34;4.899999999999864&#34;,&#34;2.8999999999998636&#34;,&#34;5.999999999999545&#34;,&#34;15.999999999999773&#34;,&#34;6.599999999999909&#34;,&#34;4.199999999999818&#34;,&#34;5.599999999999909&#34;,&#34;9.700000000000273&#34;,&#34;19.100000000000136&#34;,&#34;13.800000000000182&#34;,&#34;13.299999999999727&#34;,&#34;2.8999999999998636&#34;,&#34;6.2000000000000455&#34;,&#34;3.199999999999818&#34;,&#34;14.799999999999955&#34;,&#34;23.399999999999636&#34;,&#34;10.2999999999995&#34;,&#34;16.500000000000227&#34;,&#34;5.5&#34;,&#34;5.7999999999999545&#34;,&#34;1.199999999999818&#34;,&#34;6.699999999999363&#34;,&#34;6.2999999999999545&#34;,&#34;7.900000000000091&#34;,&#34;6.599999999999909&#34;,&#34;4.199999999999818&#34;,&#34;7&#34;,&#34;4.499999999999773&#34;,&#34;7.2000000000000455&#34;,&#34;15&#34;,&#34;8&#34;,&#34;7.199999999999591&#34;,&#34;9.299999999999955&#34;,&#34;1.5999999999994543&#34;,&#34;14.399999999999636&#34;,&#34;1.5999999999996817&#34;,&#34;14.100000000000136&#34;,&#34;13.5&#34;,&#34;12.499999999999773&#34;,&#34;2.8999999999998636&#34;,&#34;9.899999999999864&#34;,&#34;6.7000000000000455&#34;,&#34;10.899999999999864&#34;,&#34;1.0999999999996817&#34;,&#34;9.299999999999955&#34;,&#34;3.200000000000273&#34;,&#34;10.599999999999682&#34;,&#34;2.599999999999909&#34;,&#34;12.5&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0.8999999999998636&#34;,&#34;6.800000000000182&#34;,&#34;10.900000000000091&#34;,&#34;10.399999999999636&#34;,&#34;12.600000000000136&#34;,&#34;5.699999999999818&#34;,&#34;0.599999999999909&#34;,&#34;0.3999999999996362&#34;,&#34;2.7999999999999545&#34;,&#34;5.900000000000091&#34;,&#34;0.1999999999998181&#34;,&#34;2.3999999999998636&#34;,&#34;3.6000000000001364&#34;,&#34;1.7000000000000455&#34;,&#34;2.900000000000091&#34;,&#34;1.3999999999998636&#34;,&#34;2.7000000000000455&#34;,&#34;6.7000000000000455&#34;,&#34;1.7000000000002728&#34;,&#34;11.699999999999818&#34;,&#34;1.3999999999996362&#34;,&#34;0.49999999999954525&#34;,&#34;1.5999999999996817&#34;,&#34;1.3999999999996362&#34;,&#34;5.100000000000136&#34;,&#34;3.900000000000091&#34;,&#34;3&#34;,&#34;1.2999999999997272&#34;,&#34;1.400000000000091&#34;,&#34;6&#34;,&#34;0.6999999999995907&#34;,&#34;1.7999999999997272&#34;,&#34;0&#34;,&#34;1.099999999999909&#34;,&#34;2.4999999999997726&#34;,&#34;3.3999999999998636&#34;,&#34;0.6999999999998181&#34;,&#34;1.8999999999998636&#34;,&#34;3.400000000000091&#34;,&#34;5.399999999999864&#34;,&#34;3&#34;,&#34;2.3999999999998636&#34;,&#34;1.3999999999998636&#34;,&#34;11.199999999999818&#34;,&#34;1.099999999999909&#34;,&#34;0.9999999999997726&#34;,&#34;1.099999999999909&#34;,&#34;5.499999999999773&#34;,&#34;2.099999999999909&#34;,&#34;12.799999999999727&#34;,&#34;10.700000000000045&#34;,&#34;4.099999999999682&#34;,&#34;14.499999999999545&#34;,&#34;14.799999999999727&#34;,&#34;1.2000000000000455&#34;,&#34;3.8999999999998636&#34;,&#34;5.899999999999864&#34;,&#34;1.3999999999996362&#34;,&#34;3.7999999999999545&#34;,&#34;3.399999999999636&#34;,&#34;14.599999999999909&#34;,&#34;3.7999999999999545&#34;,&#34;2.7000000000000455&#34;,&#34;1.5&#34;,&#34;3.599999999999909&#34;,&#34;1.6999999999995907&#34;,&#34;7.599999999999909&#34;,&#34;6.699999999999818&#34;,&#34;4.100000000000136&#34;,&#34;3.400000000000091&#34;,&#34;2.899999999999636&#34;,&#34;1.7999999999997272&#34;,&#34;7.100000000000136&#34;,&#34;0.9999999999997726&#34;,&#34;2.3999999999998636&#34;,&#34;6.100000000000364&#34;,&#34;9.599999999999909&#34;,&#34;18.399999999999864&#34;,&#34;2.2000000000000455&#34;,&#34;3.699999999999818&#34;,&#34;6.5&#34;,&#34;10.900000000000091&#34;,&#34;5.599999999999909&#34;,&#34;4.399999999999864&#34;,&#34;14.399999999999864&#34;,&#34;6.2999999999999545&#34;,&#34;2.3999999999998636&#34;,&#34;2.799999999999727&#34;,&#34;10.799999999999955&#34;,&#34;20.299999999999727&#34;,&#34;7.900000000000318&#34;,&#34;11.399999999999636&#34;,&#34;4.900000000000091&#34;,&#34;2.6000000000001364&#34;,&#34;5.7999999999999545&#34;,&#34;9.499999999999773&#34;,&#34;3.300000000000182&#34;,&#34;20.30&#34;,&#34;17.20&#34;,&#34;14.30&#34;,&#34;10.10&#34;,&#34;4.00&#34;,&#34;5.50&#34;,&#34;4.80&#34;,&#34;3.80&#34;,&#34;3.10&#34;,&#34;3.50&#34;,&#34;12.00&#34;,&#34;7.20&#34;,&#34;9.60&#34;,&#34;11.40&#34;,&#34;10.70&#34;,&#34;20.00&#34;,&#34;16.10&#34;,&#34;4.70&#34;,&#34;9.30&#34;,&#34;15.00&#34;,&#34;17.00&#34;,&#34;22.80&#34;,&#34;4.90&#34;,&#34;17.30&#34;,&#34;12.70&#34;,&#34;14.00&#34;,&#34;17.10&#34;,&#34;22.80&#34;,&#34;9.599999999999454&#34;,&#34;13&#34;,&#34;13&#34;,&#34;13&#34;,&#34;13&#34;,&#34;20.699999999994816&#34;,&#34;14.899999999989177&#34;,&#34;23.700000000001182&#34;,&#34;10.099999999991269&#34;,&#34;8.79999999999336&#34;,&#34;4.399999999995998&#34;,&#34;18.999999999995453&#34;,&#34;17.399999999986903&#34;,&#34;10.799999999992906&#34;,&#34;23.99999999999318&#34;,&#34;19.599999999991724&#34;,&#34;25.199999999998&#34;,&#34;23.099999999996726&#34;,&#34;25.399999999995543&#34;,&#34;19.69999999999891&#34;,&#34;31&#34;,&#34;19&#34;,&#34;5.29999999999518&#34;,&#34;20.499999999992724&#34;,&#34;22.79999999999245&#34;,&#34;17.79999999999154&#34;,&#34;26.399999999996453&#34;,&#34;10.199999999993452&#34;,&#34;14&#34;,&#34;15.09999999998763&#34;,&#34;19.499999999992724&#34;,&#34;25.999999999993634&#34;,&#34;14.399999999990996&#34;,&#34;3.7999999999974534&#34;,&#34;15.099999999991269&#34;,&#34;34.099999999999&#34;,&#34;30.399999999998272&#34;,&#34;19.39999999999054&#34;,&#34;26.699999999992542&#34;,&#34;34.50000000000409&#34;,&#34;25&#34;,&#34;33&#34;,&#34;29&#34;,&#34;12.899999999989177&#34;,&#34;10.199999999990723&#34;,&#34;22.19999999999709&#34;,&#34;10.199999999990723&#34;,&#34;22.39999999999236&#34;,&#34;18.99999999999227&#34;,&#34;37.099999999997635&#34;,&#34;12.299999999990632&#34;,&#34;23.79999999999154&#34;,&#34;6.9999999999936335&#34;,&#34;11.099999999989905&#34;,&#34;11.999999999989086&#34;,&#34;25.39999999999418&#34;,&#34;15.399999999997362&#34;,&#34;23.49999999999045&#34;,&#34;10.199999999990723&#34;,&#34;15.299999999987449&#34;,&#34;18.199999999987085&#34;,&#34;32.299999999997&#34;,&#34;24.40&#34;]}],&#34;layout&#34;:{&#34;title&#34;:{&#34;text&#34;:&#34;Solar daily generation rates&#34;},&#34;xaxis&#34;:{&#34;rangeselector&#34;:{&#34;buttons&#34;:[{&#34;count&#34;:1,&#34;label&#34;:&#34;1m&#34;,&#34;step&#34;:&#34;month&#34;,&#34;stepmode&#34;:&#34;backward&#34;},{&#34;count&#34;:6,&#34;label&#34;:&#34;6m&#34;,&#34;step&#34;:&#34;month&#34;,&#34;stepmode&#34;:&#34;backward&#34;},{&#34;count&#34;:1,&#34;label&#34;:&#34;YTD&#34;,&#34;step&#34;:&#34;year&#34;,&#34;stepmode&#34;:&#34;todate&#34;},{&#34;count&#34;:1,&#34;label&#34;:&#34;1y&#34;,&#34;step&#34;:&#34;year&#34;,&#34;stepmode&#34;:&#34;backward&#34;},{&#34;step&#34;:&#34;all&#34;}]},&#34;rangeslider&#34;:{&#34;autorange&#34;:true},&#34;title&#34;:{&#34;text&#34;:&#34;Date&#34;}},&#34;yaxis&#34;:{&#34;ticksuffix&#34;:&#34;kWh&#34;,&#34;title&#34;:{&#34;text&#34;:&#34;Generated (kWh)&#34;}}}}&#39;) Plotly.newPlot(&#39;plot&#39;, data);   </description>
      <content>&lt;h2 id=&#34;solar-generation&#34;&gt;Solar Generation&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;13 405W panels&lt;/li&gt;
&lt;li&gt;5kW inverter&lt;/li&gt;
&lt;li&gt;Days with 0 data are when the monitoring system was down&lt;/li&gt;
&lt;/ul&gt;

	&lt;head&gt;
		&lt;script src=&#34;https://cdn.plot.ly/plotly-1.58.4.min.js&#34;&gt;&lt;/script&gt;
	&lt;/head&gt;
	&lt;/body&gt;
		&lt;div id=&#34;plot&#34;&gt;&lt;/div&gt;
	&lt;script&gt;
		data = JSON.parse(&#39;{&#34;data&#34;:[{&#34;type&#34;:&#34;bar&#34;,&#34;x&#34;:[&#34;2023-08-01&#34;,&#34;2023-08-02&#34;,&#34;2023-08-03&#34;,&#34;2023-08-04&#34;,&#34;2023-08-05&#34;,&#34;2023-08-06&#34;,&#34;2023-08-07&#34;,&#34;2023-08-08&#34;,&#34;2023-08-09&#34;,&#34;2023-08-10&#34;,&#34;2023-08-11&#34;,&#34;2023-08-12&#34;,&#34;2023-08-13&#34;,&#34;2023-08-14&#34;,&#34;2023-08-15&#34;,&#34;2023-08-16&#34;,&#34;2023-08-17&#34;,&#34;2023-08-18&#34;,&#34;2023-08-19&#34;,&#34;2023-08-20&#34;,&#34;2023-08-21&#34;,&#34;2023-08-22&#34;,&#34;2023-08-23&#34;,&#34;2023-08-24&#34;,&#34;2023-08-25&#34;,&#34;2023-08-26&#34;,&#34;2023-08-27&#34;,&#34;2023-08-28&#34;,&#34;2023-08-29&#34;,&#34;2023-09-01&#34;,&#34;2023-09-02&#34;,&#34;2023-09-03&#34;,&#34;2023-09-04&#34;,&#34;2023-09-05&#34;,&#34;2023-09-06&#34;,&#34;2023-09-07&#34;,&#34;2023-09-08&#34;,&#34;2023-09-09&#34;,&#34;2023-09-10&#34;,&#34;2023-09-11&#34;,&#34;2023-09-12&#34;,&#34;2023-09-13&#34;,&#34;2023-09-14&#34;,&#34;2023-09-15&#34;,&#34;2023-09-16&#34;,&#34;2023-09-17&#34;,&#34;2023-09-18&#34;,&#34;2023-09-19&#34;,&#34;2023-09-20&#34;,&#34;2023-09-21&#34;,&#34;2023-09-22&#34;,&#34;2023-09-23&#34;,&#34;2023-09-24&#34;,&#34;2023-09-25&#34;,&#34;2023-09-26&#34;,&#34;2023-09-27&#34;,&#34;2023-09-28&#34;,&#34;2023-09-29&#34;,&#34;2023-09-30&#34;,&#34;2023-10-01&#34;,&#34;2023-10-02&#34;,&#34;2023-10-03&#34;,&#34;2023-10-04&#34;,&#34;2023-10-05&#34;,&#34;2023-10-06&#34;,&#34;2023-10-07&#34;,&#34;2023-10-08&#34;,&#34;2023-10-09&#34;,&#34;2023-10-10&#34;,&#34;2023-10-11&#34;,&#34;2023-10-12&#34;,&#34;2023-10-13&#34;,&#34;2023-10-14&#34;,&#34;2023-10-15&#34;,&#34;2023-10-16&#34;,&#34;2023-10-17&#34;,&#34;2023-10-18&#34;,&#34;2023-10-19&#34;,&#34;2023-10-20&#34;,&#34;2023-10-21&#34;,&#34;2023-10-22&#34;,&#34;2023-10-23&#34;,&#34;2023-10-24&#34;,&#34;2023-10-25&#34;,&#34;2023-10-26&#34;,&#34;2023-10-27&#34;,&#34;2023-10-28&#34;,&#34;2023-10-29&#34;,&#34;2023-10-30&#34;,&#34;2023-10-31&#34;,&#34;2023-11-01&#34;,&#34;2023-11-02&#34;,&#34;2023-11-03&#34;,&#34;2023-11-04&#34;,&#34;2023-11-05&#34;,&#34;2023-11-06&#34;,&#34;2023-11-07&#34;,&#34;2023-11-08&#34;,&#34;2023-11-09&#34;,&#34;2023-11-10&#34;,&#34;2023-11-11&#34;,&#34;2023-11-12&#34;,&#34;2023-11-13&#34;,&#34;2023-11-14&#34;,&#34;2023-11-15&#34;,&#34;2023-11-16&#34;,&#34;2023-11-17&#34;,&#34;2023-11-18&#34;,&#34;2023-11-19&#34;,&#34;2023-11-20&#34;,&#34;2023-11-21&#34;,&#34;2023-11-22&#34;,&#34;2023-11-23&#34;,&#34;2023-11-24&#34;,&#34;2023-11-25&#34;,&#34;2023-11-26&#34;,&#34;2023-11-27&#34;,&#34;2023-11-28&#34;,&#34;2023-11-29&#34;,&#34;2023-11-30&#34;,&#34;2023-12-01&#34;,&#34;2023-12-02&#34;,&#34;2023-12-03&#34;,&#34;2023-12-04&#34;,&#34;2023-12-05&#34;,&#34;2023-12-06&#34;,&#34;2023-12-07&#34;,&#34;2023-12-08&#34;,&#34;2023-12-09&#34;,&#34;2023-12-10&#34;,&#34;2023-12-11&#34;,&#34;2023-12-12&#34;,&#34;2023-12-13&#34;,&#34;2023-12-14&#34;,&#34;2023-12-15&#34;,&#34;2023-12-16&#34;,&#34;2023-12-17&#34;,&#34;2023-12-18&#34;,&#34;2023-12-19&#34;,&#34;2023-12-20&#34;,&#34;2023-12-21&#34;,&#34;2023-12-22&#34;,&#34;2023-12-23&#34;,&#34;2023-12-24&#34;,&#34;2023-12-25&#34;,&#34;2023-12-26&#34;,&#34;2023-12-27&#34;,&#34;2023-12-28&#34;,&#34;2023-12-29&#34;,&#34;2023-12-30&#34;,&#34;2023-12-31&#34;,&#34;2024-01-01&#34;,&#34;2024-01-02&#34;,&#34;2024-01-03&#34;,&#34;2024-01-04&#34;,&#34;2024-01-05&#34;,&#34;2024-01-06&#34;,&#34;2024-01-07&#34;,&#34;2024-01-08&#34;,&#34;2024-01-09&#34;,&#34;2024-01-10&#34;,&#34;2024-01-11&#34;,&#34;2024-01-12&#34;,&#34;2024-01-13&#34;,&#34;2024-01-14&#34;,&#34;2024-01-15&#34;,&#34;2024-01-16&#34;,&#34;2024-01-17&#34;,&#34;2024-01-18&#34;,&#34;2024-01-19&#34;,&#34;2024-01-20&#34;,&#34;2024-01-21&#34;,&#34;2024-01-22&#34;,&#34;2024-01-23&#34;,&#34;2024-01-24&#34;,&#34;2024-01-25&#34;,&#34;2024-01-26&#34;,&#34;2024-01-27&#34;,&#34;2024-01-28&#34;,&#34;2024-01-29&#34;,&#34;2024-01-30&#34;,&#34;2024-01-31&#34;,&#34;2024-02-01&#34;,&#34;2024-02-02&#34;,&#34;2024-02-03&#34;,&#34;2024-02-04&#34;,&#34;2024-02-05&#34;,&#34;2024-02-06&#34;,&#34;2024-02-07&#34;,&#34;2024-02-08&#34;,&#34;2024-02-09&#34;,&#34;2024-02-10&#34;,&#34;2024-02-11&#34;,&#34;2024-02-12&#34;,&#34;2024-02-13&#34;,&#34;2024-02-14&#34;,&#34;2024-02-15&#34;,&#34;2024-02-16&#34;,&#34;2024-02-17&#34;,&#34;2024-02-18&#34;,&#34;2024-02-19&#34;,&#34;2024-02-20&#34;,&#34;2024-02-21&#34;,&#34;2024-02-22&#34;,&#34;2024-02-23&#34;,&#34;2024-02-24&#34;,&#34;2024-02-25&#34;,&#34;2024-02-26&#34;,&#34;2024-02-27&#34;,&#34;2024-02-28&#34;,&#34;2024-02-29&#34;,&#34;2024-03-01&#34;,&#34;2024-03-02&#34;,&#34;2024-03-03&#34;,&#34;2024-03-04&#34;,&#34;2024-03-05&#34;,&#34;2024-03-06&#34;,&#34;2024-03-07&#34;,&#34;2024-03-08&#34;,&#34;2024-03-09&#34;,&#34;2024-03-10&#34;,&#34;2024-03-11&#34;,&#34;2024-03-12&#34;,&#34;2024-03-13&#34;,&#34;2024-03-14&#34;,&#34;2024-03-15&#34;,&#34;2024-03-16&#34;,&#34;2024-03-17&#34;,&#34;2024-03-18&#34;,&#34;2024-03-19&#34;,&#34;2024-03-20&#34;,&#34;2024-03-21&#34;,&#34;2024-03-22&#34;,&#34;2024-03-23&#34;,&#34;2024-03-24&#34;,&#34;2024-03-25&#34;,&#34;2024-03-26&#34;,&#34;2024-03-27&#34;,&#34;2024-03-28&#34;,&#34;2024-03-29&#34;,&#34;2024-03-30&#34;,&#34;2024-03-31&#34;,&#34;2024-04-01&#34;,&#34;2024-04-02&#34;,&#34;2024-04-03&#34;,&#34;2024-04-04&#34;,&#34;2024-04-05&#34;,&#34;2024-04-06&#34;,&#34;2024-04-07&#34;,&#34;2024-04-08&#34;,&#34;2024-04-09&#34;,&#34;2024-04-10&#34;,&#34;2024-04-11&#34;,&#34;2024-04-12&#34;,&#34;2024-04-13&#34;,&#34;2024-04-14&#34;,&#34;2024-04-15&#34;,&#34;2024-04-16&#34;,&#34;2024-04-17&#34;,&#34;2024-04-18&#34;,&#34;2024-04-19&#34;,&#34;2024-04-20&#34;,&#34;2024-04-21&#34;,&#34;2024-04-22&#34;,&#34;2024-04-23&#34;,&#34;2024-04-24&#34;,&#34;2024-04-25&#34;,&#34;2024-04-26&#34;,&#34;2024-04-27&#34;,&#34;2024-04-28&#34;,&#34;2024-04-29&#34;,&#34;2024-04-30&#34;,&#34;2024-05-01&#34;,&#34;2024-05-02&#34;,&#34;2024-05-03&#34;,&#34;2024-05-04&#34;,&#34;2024-05-05&#34;,&#34;2024-05-06&#34;,&#34;2024-05-07&#34;,&#34;2024-05-08&#34;,&#34;2024-05-09&#34;,&#34;2024-05-10&#34;,&#34;2024-05-11&#34;,&#34;2024-05-12&#34;,&#34;2024-05-13&#34;,&#34;2024-05-14&#34;,&#34;2024-05-15&#34;,&#34;2024-05-16&#34;,&#34;2024-05-17&#34;,&#34;2024-05-18&#34;,&#34;2024-05-19&#34;,&#34;2024-05-20&#34;,&#34;2024-05-21&#34;,&#34;2024-05-22&#34;,&#34;2024-05-23&#34;,&#34;2024-05-24&#34;,&#34;2024-05-25&#34;,&#34;2024-05-26&#34;,&#34;2024-05-27&#34;,&#34;2024-05-28&#34;,&#34;2024-05-29&#34;,&#34;2024-05-30&#34;,&#34;2024-05-31&#34;,&#34;2024-06-01&#34;],&#34;y&#34;:[&#34;17.299999999999955&#34;,&#34;23.900000000000006&#34;,&#34;15.299999999999983&#34;,&#34;18.400000000000006&#34;,&#34;8.100000000000023&#34;,&#34;24.800000000000125&#34;,&#34;27.700000000000045&#34;,&#34;13.099999999999966&#34;,&#34;20.699999999999932&#34;,&#34;33.700000000000045&#34;,&#34;27.200000000000045&#34;,&#34;16.29999999999984&#34;,&#34;15.100000000000023&#34;,&#34;8.699999999999989&#34;,&#34;24.099999999999966&#34;,&#34;25.800000000000068&#34;,&#34;16.100000000000023&#34;,&#34;6.100000000000023&#34;,&#34;20.59999999999991&#34;,&#34;21.200000000000045&#34;,&#34;19.500000000000114&#34;,&#34;20.700000000000045&#34;,&#34;13.699999999999932&#34;,&#34;14&#34;,&#34;14.700000000000273&#34;,&#34;15.5&#34;,&#34;15.399999999999977&#34;,&#34;13.700000000000045&#34;,&#34;9.099999999999909&#34;,&#34;31&#34;,&#34;15.79999999999984&#34;,&#34;24.500000000000227&#34;,&#34;29.5&#34;,&#34;30.300000000000068&#34;,&#34;25&#34;,&#34;20.500000000000114&#34;,&#34;14.5&#34;,&#34;22.299999999999955&#34;,&#34;8.799999999999955&#34;,&#34;11.700000000000045&#34;,&#34;0&#34;,&#34;0&#34;,&#34;29.10000000000002&#34;,&#34;16.199999999999932&#34;,&#34;4.2999999999999545&#34;,&#34;6.000000000000114&#34;,&#34;14.600000000000023&#34;,&#34;7.099999999999909&#34;,&#34;5&#34;,&#34;5.099999999999682&#34;,&#34;17.700000000000045&#34;,&#34;24.299999999999727&#34;,&#34;6.900000000000091&#34;,&#34;21.100000000000136&#34;,&#34;13.299999999999727&#34;,&#34;4.200000000000273&#34;,&#34;5.299999999999727&#34;,&#34;23.100000000000136&#34;,&#34;4.899999999999864&#34;,&#34;2.8999999999998636&#34;,&#34;5.999999999999545&#34;,&#34;15.999999999999773&#34;,&#34;6.599999999999909&#34;,&#34;4.199999999999818&#34;,&#34;5.599999999999909&#34;,&#34;9.700000000000273&#34;,&#34;19.100000000000136&#34;,&#34;13.800000000000182&#34;,&#34;13.299999999999727&#34;,&#34;2.8999999999998636&#34;,&#34;6.2000000000000455&#34;,&#34;3.199999999999818&#34;,&#34;14.799999999999955&#34;,&#34;23.399999999999636&#34;,&#34;10.2999999999995&#34;,&#34;16.500000000000227&#34;,&#34;5.5&#34;,&#34;5.7999999999999545&#34;,&#34;1.199999999999818&#34;,&#34;6.699999999999363&#34;,&#34;6.2999999999999545&#34;,&#34;7.900000000000091&#34;,&#34;6.599999999999909&#34;,&#34;4.199999999999818&#34;,&#34;7&#34;,&#34;4.499999999999773&#34;,&#34;7.2000000000000455&#34;,&#34;15&#34;,&#34;8&#34;,&#34;7.199999999999591&#34;,&#34;9.299999999999955&#34;,&#34;1.5999999999994543&#34;,&#34;14.399999999999636&#34;,&#34;1.5999999999996817&#34;,&#34;14.100000000000136&#34;,&#34;13.5&#34;,&#34;12.499999999999773&#34;,&#34;2.8999999999998636&#34;,&#34;9.899999999999864&#34;,&#34;6.7000000000000455&#34;,&#34;10.899999999999864&#34;,&#34;1.0999999999996817&#34;,&#34;9.299999999999955&#34;,&#34;3.200000000000273&#34;,&#34;10.599999999999682&#34;,&#34;2.599999999999909&#34;,&#34;12.5&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0&#34;,&#34;0.8999999999998636&#34;,&#34;6.800000000000182&#34;,&#34;10.900000000000091&#34;,&#34;10.399999999999636&#34;,&#34;12.600000000000136&#34;,&#34;5.699999999999818&#34;,&#34;0.599999999999909&#34;,&#34;0.3999999999996362&#34;,&#34;2.7999999999999545&#34;,&#34;5.900000000000091&#34;,&#34;0.1999999999998181&#34;,&#34;2.3999999999998636&#34;,&#34;3.6000000000001364&#34;,&#34;1.7000000000000455&#34;,&#34;2.900000000000091&#34;,&#34;1.3999999999998636&#34;,&#34;2.7000000000000455&#34;,&#34;6.7000000000000455&#34;,&#34;1.7000000000002728&#34;,&#34;11.699999999999818&#34;,&#34;1.3999999999996362&#34;,&#34;0.49999999999954525&#34;,&#34;1.5999999999996817&#34;,&#34;1.3999999999996362&#34;,&#34;5.100000000000136&#34;,&#34;3.900000000000091&#34;,&#34;3&#34;,&#34;1.2999999999997272&#34;,&#34;1.400000000000091&#34;,&#34;6&#34;,&#34;0.6999999999995907&#34;,&#34;1.7999999999997272&#34;,&#34;0&#34;,&#34;1.099999999999909&#34;,&#34;2.4999999999997726&#34;,&#34;3.3999999999998636&#34;,&#34;0.6999999999998181&#34;,&#34;1.8999999999998636&#34;,&#34;3.400000000000091&#34;,&#34;5.399999999999864&#34;,&#34;3&#34;,&#34;2.3999999999998636&#34;,&#34;1.3999999999998636&#34;,&#34;11.199999999999818&#34;,&#34;1.099999999999909&#34;,&#34;0.9999999999997726&#34;,&#34;1.099999999999909&#34;,&#34;5.499999999999773&#34;,&#34;2.099999999999909&#34;,&#34;12.799999999999727&#34;,&#34;10.700000000000045&#34;,&#34;4.099999999999682&#34;,&#34;14.499999999999545&#34;,&#34;14.799999999999727&#34;,&#34;1.2000000000000455&#34;,&#34;3.8999999999998636&#34;,&#34;5.899999999999864&#34;,&#34;1.3999999999996362&#34;,&#34;3.7999999999999545&#34;,&#34;3.399999999999636&#34;,&#34;14.599999999999909&#34;,&#34;3.7999999999999545&#34;,&#34;2.7000000000000455&#34;,&#34;1.5&#34;,&#34;3.599999999999909&#34;,&#34;1.6999999999995907&#34;,&#34;7.599999999999909&#34;,&#34;6.699999999999818&#34;,&#34;4.100000000000136&#34;,&#34;3.400000000000091&#34;,&#34;2.899999999999636&#34;,&#34;1.7999999999997272&#34;,&#34;7.100000000000136&#34;,&#34;0.9999999999997726&#34;,&#34;2.3999999999998636&#34;,&#34;6.100000000000364&#34;,&#34;9.599999999999909&#34;,&#34;18.399999999999864&#34;,&#34;2.2000000000000455&#34;,&#34;3.699999999999818&#34;,&#34;6.5&#34;,&#34;10.900000000000091&#34;,&#34;5.599999999999909&#34;,&#34;4.399999999999864&#34;,&#34;14.399999999999864&#34;,&#34;6.2999999999999545&#34;,&#34;2.3999999999998636&#34;,&#34;2.799999999999727&#34;,&#34;10.799999999999955&#34;,&#34;20.299999999999727&#34;,&#34;7.900000000000318&#34;,&#34;11.399999999999636&#34;,&#34;4.900000000000091&#34;,&#34;2.6000000000001364&#34;,&#34;5.7999999999999545&#34;,&#34;9.499999999999773&#34;,&#34;3.300000000000182&#34;,&#34;20.30&#34;,&#34;17.20&#34;,&#34;14.30&#34;,&#34;10.10&#34;,&#34;4.00&#34;,&#34;5.50&#34;,&#34;4.80&#34;,&#34;3.80&#34;,&#34;3.10&#34;,&#34;3.50&#34;,&#34;12.00&#34;,&#34;7.20&#34;,&#34;9.60&#34;,&#34;11.40&#34;,&#34;10.70&#34;,&#34;20.00&#34;,&#34;16.10&#34;,&#34;4.70&#34;,&#34;9.30&#34;,&#34;15.00&#34;,&#34;17.00&#34;,&#34;22.80&#34;,&#34;4.90&#34;,&#34;17.30&#34;,&#34;12.70&#34;,&#34;14.00&#34;,&#34;17.10&#34;,&#34;22.80&#34;,&#34;9.599999999999454&#34;,&#34;13&#34;,&#34;13&#34;,&#34;13&#34;,&#34;13&#34;,&#34;20.699999999994816&#34;,&#34;14.899999999989177&#34;,&#34;23.700000000001182&#34;,&#34;10.099999999991269&#34;,&#34;8.79999999999336&#34;,&#34;4.399999999995998&#34;,&#34;18.999999999995453&#34;,&#34;17.399999999986903&#34;,&#34;10.799999999992906&#34;,&#34;23.99999999999318&#34;,&#34;19.599999999991724&#34;,&#34;25.199999999998&#34;,&#34;23.099999999996726&#34;,&#34;25.399999999995543&#34;,&#34;19.69999999999891&#34;,&#34;31&#34;,&#34;19&#34;,&#34;5.29999999999518&#34;,&#34;20.499999999992724&#34;,&#34;22.79999999999245&#34;,&#34;17.79999999999154&#34;,&#34;26.399999999996453&#34;,&#34;10.199999999993452&#34;,&#34;14&#34;,&#34;15.09999999998763&#34;,&#34;19.499999999992724&#34;,&#34;25.999999999993634&#34;,&#34;14.399999999990996&#34;,&#34;3.7999999999974534&#34;,&#34;15.099999999991269&#34;,&#34;34.099999999999&#34;,&#34;30.399999999998272&#34;,&#34;19.39999999999054&#34;,&#34;26.699999999992542&#34;,&#34;34.50000000000409&#34;,&#34;25&#34;,&#34;33&#34;,&#34;29&#34;,&#34;12.899999999989177&#34;,&#34;10.199999999990723&#34;,&#34;22.19999999999709&#34;,&#34;10.199999999990723&#34;,&#34;22.39999999999236&#34;,&#34;18.99999999999227&#34;,&#34;37.099999999997635&#34;,&#34;12.299999999990632&#34;,&#34;23.79999999999154&#34;,&#34;6.9999999999936335&#34;,&#34;11.099999999989905&#34;,&#34;11.999999999989086&#34;,&#34;25.39999999999418&#34;,&#34;15.399999999997362&#34;,&#34;23.49999999999045&#34;,&#34;10.199999999990723&#34;,&#34;15.299999999987449&#34;,&#34;18.199999999987085&#34;,&#34;32.299999999997&#34;,&#34;24.40&#34;]}],&#34;layout&#34;:{&#34;title&#34;:{&#34;text&#34;:&#34;Solar daily generation rates&#34;},&#34;xaxis&#34;:{&#34;rangeselector&#34;:{&#34;buttons&#34;:[{&#34;count&#34;:1,&#34;label&#34;:&#34;1m&#34;,&#34;step&#34;:&#34;month&#34;,&#34;stepmode&#34;:&#34;backward&#34;},{&#34;count&#34;:6,&#34;label&#34;:&#34;6m&#34;,&#34;step&#34;:&#34;month&#34;,&#34;stepmode&#34;:&#34;backward&#34;},{&#34;count&#34;:1,&#34;label&#34;:&#34;YTD&#34;,&#34;step&#34;:&#34;year&#34;,&#34;stepmode&#34;:&#34;todate&#34;},{&#34;count&#34;:1,&#34;label&#34;:&#34;1y&#34;,&#34;step&#34;:&#34;year&#34;,&#34;stepmode&#34;:&#34;backward&#34;},{&#34;step&#34;:&#34;all&#34;}]},&#34;rangeslider&#34;:{&#34;autorange&#34;:true},&#34;title&#34;:{&#34;text&#34;:&#34;Date&#34;}},&#34;yaxis&#34;:{&#34;ticksuffix&#34;:&#34;kWh&#34;,&#34;title&#34;:{&#34;text&#34;:&#34;Generated (kWh)&#34;}}}}&#39;)
		Plotly.newPlot(&#39;plot&#39;, data);
	&lt;/script&gt;
	&lt;body&gt;
	
</content>
    </item>
    
  </channel>
</rss>
