<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Heyal Solutions blog</title><description>Practical writing on Kubernetes, EKS, GitOps, Terraform and platform engineering.</description><link>https://www.heyal.co.uk/</link><language>en-gb</language><item><title>Bootstrapping a private EKS cluster with Argo CD</title><link>https://www.heyal.co.uk/blog/bootstrapping-private-eks-argocd/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/bootstrapping-private-eks-argocd/</guid><description>Terraform for a private-endpoint EKS cluster, GitHub Actions with OIDC, and how to install Argo CD when your pipeline can&apos;t reach the Kubernetes API.</description><pubDate>Sat, 17 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A Kubernetes API server on the public internet is an attack surface most teams don’t need. In regulated environments
it’s often a non-starter. EKS lets you turn the public endpoint off entirely, so the API is only reachable from inside
your VPC.&lt;/p&gt;
&lt;p&gt;That’s great for security. It’s less great for your pipeline. GitHub Actions can create the cluster, because Terraform
only talks to the AWS API, which is public. But the moment you want to install something &lt;em&gt;into&lt;/em&gt; the cluster, the
runner has no route to the API server.&lt;/p&gt;
&lt;p&gt;This post walks through building a private EKS cluster with Terraform and GitHub Actions, then getting Argo CD
installed so it can take over from there. All of the code is in
&lt;a href=&quot;https://github.com/HeyalSolutions/eks-private-argocd-bootstrap&quot;&gt;HeyalSolutions/eks-private-argocd-bootstrap&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;the-key-insight-you-only-need-to-get-in-once&quot;&gt;The key insight: you only need to get in once&lt;/h2&gt;
&lt;p&gt;Argo CD is &lt;strong&gt;pull-based&lt;/strong&gt;. It runs inside the cluster and pulls its desired state from Git. Once it’s installed, your
pipeline never needs to talk to the Kubernetes API again. Changes go through pull requests, and Argo CD applies them.&lt;/p&gt;
&lt;p&gt;So the private endpoint problem isn’t “how does CI deploy to the cluster?”. It’s “how do we install Argo CD &lt;em&gt;once&lt;/em&gt;?”.
That’s a much smaller problem.&lt;/p&gt;
&lt;div style=&quot;overflow-x: auto&quot;&gt;
&lt;svg viewBox=&quot;0 0 760 360&quot; role=&quot;img&quot; aria-labelledby=&quot;eks-diagram-title&quot; style=&quot;min-width: 640px; width: 100%; height: auto; font-family: inherit&quot;&gt;
  &lt;title id=&quot;eks-diagram-title&quot;&gt;GitHub Actions calls the AWS API to run Terraform and start a CodeBuild build inside the VPC. The build installs Argo CD on the private EKS cluster, and Argo CD then pulls the cluster-resources repo from GitHub.&lt;/title&gt;
  &lt;defs&gt;
    &lt;marker id=&quot;eks-arrow&quot; viewBox=&quot;0 0 10 10&quot; refX=&quot;9&quot; refY=&quot;5&quot; markerWidth=&quot;7&quot; markerHeight=&quot;7&quot; orient=&quot;auto-start-reverse&quot;&gt;
      &lt;path d=&quot;M0 0 10 5 0 10z&quot; style=&quot;fill: var(--color-brand-500)&quot;/&gt;
    &lt;/marker&gt;
  &lt;/defs&gt;
  &lt;g style=&quot;font-size: 13px; fill: var(--color-ink-900)&quot;&gt;
    &lt;rect x=&quot;270&quot; y=&quot;125&quot; width=&quot;470&quot; height=&quot;215&quot; rx=&quot;14&quot; style=&quot;fill: none; stroke: var(--color-accent-400); stroke-width: 1.5; stroke-dasharray: 6 5&quot;/&gt;
    &lt;text x=&quot;286&quot; y=&quot;148&quot; style=&quot;fill: var(--color-ink-500); font-size: 12px&quot;&gt;VPC (private subnets)&lt;/text&gt;
    &lt;rect x=&quot;20&quot; y=&quot;30&quot; width=&quot;190&quot; height=&quot;60&quot; rx=&quot;10&quot; style=&quot;fill: var(--color-surface); stroke: var(--color-ink-300)&quot;/&gt;
    &lt;text x=&quot;115&quot; y=&quot;56&quot; text-anchor=&quot;middle&quot; style=&quot;font-weight: 600&quot;&gt;GitHub Actions&lt;/text&gt;
    &lt;text x=&quot;115&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; style=&quot;fill: var(--color-ink-600); font-size: 12px&quot;&gt;no route into the VPC&lt;/text&gt;
    &lt;rect x=&quot;290&quot; y=&quot;30&quot; width=&quot;180&quot; height=&quot;60&quot; rx=&quot;10&quot; style=&quot;fill: var(--color-surface); stroke: var(--color-ink-300)&quot;/&gt;
    &lt;text x=&quot;380&quot; y=&quot;56&quot; text-anchor=&quot;middle&quot; style=&quot;font-weight: 600&quot;&gt;AWS API&lt;/text&gt;
    &lt;text x=&quot;380&quot; y=&quot;74&quot; text-anchor=&quot;middle&quot; style=&quot;fill: var(--color-ink-600); font-size: 12px&quot;&gt;public&lt;/text&gt;
    &lt;rect x=&quot;290&quot; y=&quot;170&quot; width=&quot;180&quot; height=&quot;60&quot; rx=&quot;10&quot; style=&quot;fill: var(--color-surface); stroke: var(--color-ink-300)&quot;/&gt;
    &lt;text x=&quot;380&quot; y=&quot;196&quot; text-anchor=&quot;middle&quot; style=&quot;font-weight: 600&quot;&gt;CodeBuild&lt;/text&gt;
    &lt;text x=&quot;380&quot; y=&quot;214&quot; text-anchor=&quot;middle&quot; style=&quot;fill: var(--color-ink-600); font-size: 12px&quot;&gt;bootstrap build&lt;/text&gt;
    &lt;rect x=&quot;540&quot; y=&quot;170&quot; width=&quot;180&quot; height=&quot;140&quot; rx=&quot;10&quot; style=&quot;fill: var(--color-surface); stroke: var(--color-ink-300)&quot;/&gt;
    &lt;text x=&quot;630&quot; y=&quot;196&quot; text-anchor=&quot;middle&quot; style=&quot;font-weight: 600&quot;&gt;EKS cluster&lt;/text&gt;
    &lt;text x=&quot;630&quot; y=&quot;214&quot; text-anchor=&quot;middle&quot; style=&quot;fill: var(--color-ink-600); font-size: 12px&quot;&gt;private endpoint only&lt;/text&gt;
    &lt;rect x=&quot;560&quot; y=&quot;240&quot; width=&quot;140&quot; height=&quot;50&quot; rx=&quot;8&quot; style=&quot;fill: var(--color-ink-100); stroke: var(--color-ink-200)&quot;/&gt;
    &lt;text x=&quot;630&quot; y=&quot;270&quot; text-anchor=&quot;middle&quot; style=&quot;font-weight: 600&quot;&gt;Argo CD&lt;/text&gt;
    &lt;rect x=&quot;20&quot; y=&quot;250&quot; width=&quot;190&quot; height=&quot;60&quot; rx=&quot;10&quot; style=&quot;fill: var(--color-surface); stroke: var(--color-ink-300)&quot;/&gt;
    &lt;text x=&quot;115&quot; y=&quot;276&quot; text-anchor=&quot;middle&quot; style=&quot;font-weight: 600&quot;&gt;cluster-resources&lt;/text&gt;
    &lt;text x=&quot;115&quot; y=&quot;294&quot; text-anchor=&quot;middle&quot; style=&quot;fill: var(--color-ink-600); font-size: 12px&quot;&gt;Git repo (Helm chart)&lt;/text&gt;
    &lt;g style=&quot;stroke: var(--color-brand-500); stroke-width: 2; fill: none&quot;&gt;
      &lt;path d=&quot;M210 60H288&quot; marker-end=&quot;url(#eks-arrow)&quot;/&gt;
      &lt;path d=&quot;M380 90V168&quot; marker-end=&quot;url(#eks-arrow)&quot;/&gt;
      &lt;path d=&quot;M470 200H538&quot; marker-end=&quot;url(#eks-arrow)&quot;/&gt;
      &lt;path d=&quot;M560 270H212&quot; marker-end=&quot;url(#eks-arrow)&quot;/&gt;
    &lt;/g&gt;
    &lt;g style=&quot;font-size: 12px; fill: var(--color-ink-700)&quot;&gt;
      &lt;text x=&quot;249&quot; y=&quot;50&quot; text-anchor=&quot;middle&quot;&gt;1&lt;/text&gt;
      &lt;text x=&quot;392&quot; y=&quot;134&quot;&gt;2 start build&lt;/text&gt;
      &lt;text x=&quot;505&quot; y=&quot;190&quot; text-anchor=&quot;middle&quot;&gt;3&lt;/text&gt;
      &lt;text x=&quot;386&quot; y=&quot;262&quot; text-anchor=&quot;middle&quot;&gt;4 Argo CD pulls from Git&lt;/text&gt;
    &lt;/g&gt;
  &lt;/g&gt;
&lt;/svg&gt;
&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;GitHub Actions authenticates to AWS with OIDC and runs Terraform. Everything is created through the public AWS API.&lt;/li&gt;
&lt;li&gt;The pipeline starts a CodeBuild build. CodeBuild runs &lt;em&gt;inside&lt;/em&gt; the VPC.&lt;/li&gt;
&lt;li&gt;The build installs Argo CD and one root Application.&lt;/li&gt;
&lt;li&gt;Argo CD pulls everything else from Git, including its own configuration.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;step-1-let-github-actions-into-aws-without-keys&quot;&gt;Step 1: let GitHub Actions into AWS (without keys)&lt;/h2&gt;
&lt;p&gt;GitHub Actions can exchange a short-lived OIDC token for AWS credentials, so there are no access keys to store or
rotate. This needs an IAM OIDC provider and a role that trusts it. Both have to exist before the pipeline can run, so
they live in a small &lt;code&gt;bootstrap/&lt;/code&gt; stack you apply once from your own machine. It also creates the S3 bucket for
Terraform state.&lt;/p&gt;
&lt;p&gt;The important part is the trust policy. Only this repository’s &lt;code&gt;main&lt;/code&gt; branch and its pull requests can assume the role:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;aws_iam_openid_connect_provider&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;github&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  url&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;            =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;https://token.actions.githubusercontent.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  client_id_list&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;sts.amazonaws.com&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;aws_iam_policy_document&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;github_trust&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  statement&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    actions&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;sts:AssumeRoleWithWebIdentity&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    principals&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Federated&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      identifiers&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [aws_iam_openid_connect_provider&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;github&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;arn]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    condition&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      test&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;     =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;StringEquals&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      variable&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;token.actions.githubusercontent.com:aud&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      values&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;sts.amazonaws.com&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    condition&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      test&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;     =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;StringLike&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      variable&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;token.actions.githubusercontent.com:sub&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      values&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        &quot;repo:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;github_repo&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:ref:refs/heads/main&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        &quot;repo:&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;github_repo&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;:pull_request&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example attaches &lt;code&gt;AdministratorAccess&lt;/code&gt; to keep things short. In a real setup, scope it down and use a separate
read-only role for pull request plans.&lt;/p&gt;
&lt;h2 id=&quot;step-2-the-vpc&quot;&gt;Step 2: the VPC&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws&quot;&gt;VPC module&lt;/a&gt; does the heavy lifting. Three
tiers of subnets:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Private&lt;/strong&gt; subnets for nodes, internal load balancers and the CodeBuild bootstrap&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Public&lt;/strong&gt; subnets for the NAT gateway and internet-facing load balancers&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Intra&lt;/strong&gt; subnets for the EKS control plane’s network interfaces, with no route to the internet at all&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;vpc&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  source&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;terraform-aws-modules/vpc/aws&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  version&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;~&amp;gt; 6.7&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  cidr&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc_cidr&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  azs&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;azs&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  private_subnets&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; k, v &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;azs &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; cidrsubnet&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc_cidr, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, k)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  public_subnets&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; k, v &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;azs &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; cidrsubnet&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc_cidr, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, k &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 48&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  intra_subnets&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;   =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; k, v &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;azs &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; cidrsubnet&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc_cidr, &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, k &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 52&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  enable_nat_gateway&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  single_nat_gateway&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt; # one per AZ in production&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  public_subnet_tags&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;kubernetes.io/role/elb&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  private_subnet_tags&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;kubernetes.io/role/internal-elb&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; = &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The NAT gateway matters here. Nodes need it to pull images, and the bootstrap build needs it to download Helm charts.&lt;/p&gt;
&lt;h2 id=&quot;step-3-a-private-eks-cluster&quot;&gt;Step 3: a private EKS cluster&lt;/h2&gt;
&lt;p&gt;Version 21 of the &lt;a href=&quot;https://registry.terraform.io/modules/terraform-aws-modules/eks/aws&quot;&gt;EKS module&lt;/a&gt; makes the private
endpoint explicit:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;eks&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  source&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;terraform-aws-modules/eks/aws&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  version&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;~&amp;gt; 21.29&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;               =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  kubernetes_version&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;1.35&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  endpoint_private_access&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  endpoint_public_access&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  vpc_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;                   =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc_id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  subnet_ids&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;               =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;private_subnets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  control_plane_subnet_ids&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;intra_subnets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  addons&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    coredns                &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    kube-proxy             &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    eks-pod-identity-agent &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { before_compute &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    vpc-cni                &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { before_compute &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  eks_managed_node_groups&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    default &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      ami_type       &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;AL2023_x86_64_STANDARD&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      instance_types &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;m7i.large&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      min_size       &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      max_size       &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 5&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      desired_size   &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;  # ...access entries and security group rules, below&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Two more pieces wire up the bootstrap. Cluster access uses &lt;strong&gt;access entries&lt;/strong&gt; rather than the old &lt;code&gt;aws-auth&lt;/code&gt;
ConfigMap. The GitHub Actions role created the cluster, but it couldn’t reach it anyway, so it gets no Kubernetes
permissions. Only the bootstrap build’s role does:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  enable_cluster_creator_admin_permissions&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  access_entries&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    bootstrap &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      principal_arn &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; aws_iam_role.bootstrap.arn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      policy_associations &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        admin &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          policy_arn   &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;          access_scope &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; { type &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;cluster&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  security_group_additional_rules&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    bootstrap_https &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      description              &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;CodeBuild bootstrap to API server&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      protocol                 &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;tcp&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      from_port                &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      to_port                  &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 443&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      type                     &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;ingress&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      source_security_group_id &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; aws_security_group.bootstrap.id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;step-4-the-pipeline&quot;&gt;Step 4: the pipeline&lt;/h2&gt;
&lt;p&gt;The workflow plans on pull requests and applies on &lt;code&gt;main&lt;/code&gt;. &lt;code&gt;id-token: write&lt;/code&gt; is what lets the job request the OIDC
token:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;permissions&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  id-token&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;write&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  contents&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;read&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;jobs&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  terraform&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    defaults&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      run&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        working-directory&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;infra&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;actions/checkout@v7&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;aws-actions/configure-aws-credentials@v6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          role-to-assume&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${{ vars.AWS_ROLE_ARN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          aws-region&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;eu-west-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;hashicorp/setup-terraform@v4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          terraform_version&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;1.16.6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          terraform_wrapper&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;terraform init -input=false&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;run&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;terraform plan -input=false -out=tfplan&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Apply&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;github.ref == &apos;refs/heads/main&apos; &amp;amp;&amp;amp; github.event_name != &apos;pull_request&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;terraform apply -input=false tfplan&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point we have a private cluster with nodes and nothing running on it. The pipeline can’t go any further on its
own.&lt;/p&gt;
&lt;h2 id=&quot;step-5-getting-in-the-options&quot;&gt;Step 5: getting in. The options&lt;/h2&gt;
&lt;p&gt;There are plenty of ways to get from a GitHub-hosted runner to a private API endpoint. Approximate us-east-1 costs,
not counting the NAT gateway every option needs anyway:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;How it works&lt;/th&gt;
&lt;th&gt;Pros&lt;/th&gt;
&lt;th&gt;Cons&lt;/th&gt;
&lt;th&gt;Rough cost&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSH jumpbox&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Public EC2 instance with port 22 open; tunnel kubectl through it&lt;/td&gt;
&lt;td&gt;Familiar, simple&lt;/td&gt;
&lt;td&gt;Public SSH attack surface, key management, always on&lt;/td&gt;
&lt;td&gt;~$7/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS Client VPN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Runner connects to a managed VPN endpoint in the VPC&lt;/td&gt;
&lt;td&gt;Fully AWS-managed; good for human access too&lt;/td&gt;
&lt;td&gt;Expensive; certificate setup; an OpenVPN client in CI is fiddly&lt;/td&gt;
&lt;td&gt;~$73/month per subnet association, plus connection hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tailscale (or similar)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Subnet router in the VPC; the runner joins your tailnet&lt;/td&gt;
&lt;td&gt;Very easy; great for humans; no inbound ports&lt;/td&gt;
&lt;td&gt;Third party in your access path; another account and auth key&lt;/td&gt;
&lt;td&gt;Free tier, plus a ~$3/month router instance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SSM port forwarding&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Instance with no inbound ports; tunnel to the API endpoint via Session Manager&lt;/td&gt;
&lt;td&gt;No open ports; IAM-controlled; audited in CloudTrail&lt;/td&gt;
&lt;td&gt;Standing instance; Session Manager plugin in CI; kubeconfig needs a &lt;code&gt;tls-server-name&lt;/code&gt; override&lt;/td&gt;
&lt;td&gt;~$3/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda in the VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Terraform invokes a function that runs &lt;code&gt;helm install&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Effectively free; pure Terraform; nothing left running&lt;/td&gt;
&lt;td&gt;You have to package &lt;code&gt;helm&lt;/code&gt; into the function; harder to debug; 15-minute limit&lt;/td&gt;
&lt;td&gt;~$0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CodeBuild in the VPC&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The pipeline starts a build; the buildspec runs &lt;code&gt;helm&lt;/code&gt; inside the VPC&lt;/td&gt;
&lt;td&gt;Effectively free; nothing left running; plain shell script; logs in CloudWatch&lt;/td&gt;
&lt;td&gt;Another AWS service; a minute or so of start-up&lt;/td&gt;
&lt;td&gt;~$0.02 per run&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;There’s also a way to skip the problem altogether: &lt;strong&gt;EKS Capabilities&lt;/strong&gt; can run a managed Argo CD for you, operated by
AWS and able to reach a private cluster. It’s a good fit if you’re happy for AWS to own Argo CD. It wasn’t what we
wanted here, because we want Argo CD to manage &lt;em&gt;itself&lt;/em&gt; from Git like every other component. It also needs IAM
Identity Center for sign-in.&lt;/p&gt;
&lt;p&gt;We went with &lt;strong&gt;CodeBuild&lt;/strong&gt;. It ties with Lambda on cost, but there’s nothing to package: the bootstrap is a readable
shell script, and the logs land in CloudWatch.&lt;/p&gt;
&lt;h2 id=&quot;step-6-the-codebuild-bootstrap&quot;&gt;Step 6: the CodeBuild bootstrap&lt;/h2&gt;
&lt;p&gt;The CodeBuild project has no source. Its buildspec is passed in from Terraform, and it runs in the private subnets
with its own security group (the one the EKS rule above allows in):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;hcl&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;resource&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;aws_codebuild_project&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; &quot;bootstrap&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;          =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;-bootstrap&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  service_role&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; aws_iam_role&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bootstrap&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;arn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  build_timeout&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 20&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  source&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;      =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;NO_SOURCE&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    buildspec&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; file&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;${&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;path&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/buildspec.yml&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  artifacts&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;NO_ARTIFACTS&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  environment&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    type&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;         =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;LINUX_CONTAINER&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    compute_type&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;BUILD_GENERAL1_SMALL&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    image&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;        =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;aws/codebuild/amazonlinux-x86_64-standard:6.0&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    environment_variable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;CLUSTER_NAME&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      value&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;eks&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;cluster_name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    environment_variable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;ARGOCD_CHART_VERSION&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      value&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;10.10.5&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    environment_variable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;CLUSTER_RESOURCES_REPO&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      value&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;cluster_resources_repo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;    environment_variable&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      name&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;DEPLOY_KEY&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      type&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  =&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;SECRETS_MANAGER&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      value&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; data&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;aws_secretsmanager_secret&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;deploy_key&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;arn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  vpc_config&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    vpc_id&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;             =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc_id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    subnets&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;            =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; module&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;vpc&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;private_subnets&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    security_group_ids&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [aws_security_group&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;bootstrap&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;id]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Its IAM role needs &lt;code&gt;eks:DescribeCluster&lt;/code&gt; (for the kubeconfig), read access to the deploy key secret, CloudWatch Logs,
and the EC2 network interface permissions CodeBuild uses to attach to the VPC. The full policy is
&lt;a href=&quot;https://github.com/HeyalSolutions/eks-private-argocd-bootstrap/blob/main/infra/bootstrap.tf&quot;&gt;in the repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The buildspec does four things: writes a kubeconfig, creates the repo credentials so Argo CD can read the private
&lt;code&gt;cluster-resources&lt;/code&gt; repo, installs Argo CD with Helm, and applies one root Application. It only does this &lt;strong&gt;once&lt;/strong&gt;.
If the &lt;code&gt;argocd&lt;/code&gt; Helm release already exists, Argo CD is managing itself and a default install would fight with it:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;version&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;0.2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  shell&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  variables&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    HELM_VERSION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;v4.3.1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    KUBECTL_VERSION&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;v1.35.9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;phases&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  install&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    commands&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;curl -fsSL &quot;https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz&quot; | tar -xz -C /tmp&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;install /tmp/linux-amd64/helm /usr/local/bin/helm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;curl -fsSLo /usr/local/bin/kubectl &quot;https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;chmod +x /usr/local/bin/kubectl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  build&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    commands&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;aws eks update-kubeconfig --name &quot;$CLUSTER_NAME&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;kubectl get nodes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;      # (writes root-app.yaml, the Application in step 7)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        set -eo pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        if helm status argocd --namespace argocd &amp;gt;/dev/null 2&amp;gt;&amp;amp;1; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          echo &quot;Argo CD already installed; nothing to do.&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          kubectl create namespace argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          kubectl create secret generic cluster-resources-repo \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --namespace argocd \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --from-literal=type=git \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --from-literal=url=&quot;$CLUSTER_RESOURCES_REPO&quot; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --from-literal=sshPrivateKey=&quot;$DEPLOY_KEY&quot; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --dry-run=client -o yaml \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            | kubectl label --local -f - argocd.argoproj.io/secret-type=repository -o yaml \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            | kubectl apply -f -&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          helm upgrade --install argocd argo-cd \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --repo https://argoproj.github.io/argo-helm \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --version &quot;$ARGOCD_CHART_VERSION&quot; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --namespace argocd \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            --wait --timeout 10m&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          kubectl apply -f root-app.yaml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Back in the workflow, a second job starts the build through the AWS API and waits for it:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  bootstrap&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    needs&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;terraform&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;github.ref == &apos;refs/heads/main&apos; &amp;amp;&amp;amp; github.event_name != &apos;pull_request&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    runs-on&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ubuntu-latest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    steps&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;uses&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;aws-actions/configure-aws-credentials@v6&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        with&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          role-to-assume&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${{ vars.AWS_ROLE_ARN }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          aws-region&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;eu-west-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Bootstrap Argo CD&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        env&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          PROJECT&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${{ needs.terraform.outputs.bootstrap_project }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;          LOG_GROUP&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;${{ needs.terraform.outputs.bootstrap_log_group }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;        run&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          build_id=$(aws codebuild start-build --project-name &quot;$PROJECT&quot; --query &apos;build.id&apos; --output text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          while true; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            status=$(aws codebuild batch-get-builds --ids &quot;$build_id&quot; --query &apos;builds[0].buildStatus&apos; --output text)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            [ &quot;$status&quot; != &quot;IN_PROGRESS&quot; ] &amp;amp;&amp;amp; break&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            sleep 15&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          # CodeBuild names the log stream after the build ID (the part after the colon)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          aws logs tail &quot;$LOG_GROUP&quot; --log-stream-name-prefix &quot;${build_id#*:}&quot; --since 1h || true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          if [ &quot;$status&quot; != &quot;SUCCEEDED&quot; ]; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            echo &quot;::error::Bootstrap build finished with status $status&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            exit 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;          fi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It runs on every push to &lt;code&gt;main&lt;/code&gt;, but thanks to the guard it’s a no-op once Argo CD is installed. It costs a couple of
cents, and a brand new cluster gets bootstrapped automatically.&lt;/p&gt;
&lt;h2 id=&quot;step-7-argo-cd-manages-itself&quot;&gt;Step 7: Argo CD manages itself&lt;/h2&gt;
&lt;p&gt;The root Application points at the &lt;code&gt;cluster-resources&lt;/code&gt; repo, a Helm chart whose templates are themselves Argo CD
Applications (the “app of apps” pattern):&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argoproj.io/v1alpha1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;cluster-resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  namespace&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  project&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  source&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    repoURL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;git@github.com:my-org/cluster-resources.git&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    targetRevision&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    path&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  destination&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    server&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;https://kubernetes.default.svc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    namespace&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  syncPolicy&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    automated&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      prune&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      selfHeal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One of those templates is an Application for &lt;strong&gt;Argo CD itself&lt;/strong&gt;. It uses the same chart and the same release name
(&lt;code&gt;argocd&lt;/code&gt;) as the bootstrap install, so it adopts the resources Helm created rather than creating new ones:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;apiVersion&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argoproj.io/v1alpha1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;kind&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Application&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;metadata&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  namespace&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;spec&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  project&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;default&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  source&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    repoURL&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;https://argoproj.github.io/argo-helm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    chart&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argo-cd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    targetRevision&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: {{ &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;.Values.argocd.chartVersion | quote&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    helm&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      releaseName&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      valuesObject&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;        {{- &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;toYaml .Values.argocd.values | nindent 8&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  destination&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    server&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;https://kubernetes.default.svc&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    namespace&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;argocd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  syncPolicy&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    automated&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      prune&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;      selfHeal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;true&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;    syncOptions&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;      - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;ServerSideApply=true&lt;/span&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt; # Argo CD&apos;s CRDs are too big for client-side apply&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From here on, Argo CD’s configuration lives in &lt;code&gt;cluster-resources/values.yaml&lt;/code&gt;. Upgrading Argo CD is a pull request
that bumps &lt;code&gt;chartVersion&lt;/code&gt;. Every other add-on (cert-manager, ingress controllers, external-secrets, monitoring) is
another template in the same chart, following the same pattern.&lt;/p&gt;
&lt;h2 id=&quot;things-to-watch-out-for&quot;&gt;Things to watch out for&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Keep the bootstrap chart version in step.&lt;/strong&gt; The bootstrap installs &lt;code&gt;ARGOCD_CHART_VERSION&lt;/code&gt;, and Git then says what
it should be. If they drift, a new cluster briefly runs the older version until Argo CD syncs itself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The bootstrap guard is load-bearing.&lt;/strong&gt; Without it, every pipeline run would reinstall Argo CD with default values
and fight with the self-managed configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Humans still need a way in.&lt;/strong&gt; CI doesn’t need cluster access any more, but people sometimes do. SSM port
forwarding or a VPN (from the table above) works well for break-glass &lt;code&gt;kubectl&lt;/code&gt;, with its own access entry.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use a deploy key or GitHub App for Argo CD.&lt;/strong&gt; It should have read-only access to &lt;code&gt;cluster-resources&lt;/code&gt;. The example
stores a deploy key in Secrets Manager, created by the one-time &lt;code&gt;bootstrap/&lt;/code&gt; stack so it exists before the first run.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;A private EKS endpoint doesn’t have to mean self-hosted runners, VPNs in CI or a bastion you have to babysit. Because
GitOps is pull-based, you only need to get inside the VPC once, and a CodeBuild build started from the pipeline does
that for a couple of cents. After that, Git is the only way changes reach the cluster.&lt;/p&gt;
&lt;p&gt;The full example, including the IAM policies and the &lt;code&gt;cluster-resources&lt;/code&gt; chart, is at
&lt;a href=&quot;https://github.com/HeyalSolutions/eks-private-argocd-bootstrap&quot;&gt;HeyalSolutions/eks-private-argocd-bootstrap&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>kubernetes</category><category>eks</category><category>aws</category><category>argo-cd</category><category>gitops</category><category>terraform</category><category>github-actions</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>My Home Office Build, Part 4: Finishing Off, and Four Years On</title><link>https://www.heyal.co.uk/blog/office-build-finishing/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/office-build-finishing/</guid><description>Plastering, render, underfloor heating and flooring, what the build cost, and what it&apos;s like to work in four years later.</description><pubDate>Fri, 16 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A note from the future:&lt;/strong&gt; parts 1 to 3 were written in 2022, while the build was still going on. This part was
written in October 2026, after four years of working in the office, so it covers how it has held up as well
as how it was finished.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At the end of part 3 the office had walls, insulation, plasterboard and doors. It looked like a building, but it
definitely wasn’t somewhere you’d want to sit for eight hours a day. This part covers everything it took to get from
there to moving in.&lt;/p&gt;
&lt;h2 id=&quot;plastering&quot;&gt;Plastering&lt;/h2&gt;
&lt;p&gt;I fitted all of the plasterboard myself, but I got a plasterer in to skim it. Plastering is HARD!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TIP: Unless you’ve plastered before, this is one job worth paying for. Every imperfection shows once it’s painted.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;painting&quot;&gt;Painting&lt;/h2&gt;
&lt;p&gt;Once the plaster had dried out properly, everything got painted white. No feature walls, nothing fancy.&lt;/p&gt;
&lt;h2 id=&quot;outside-render-soffits-and-gutters&quot;&gt;Outside: render, soffits and gutters&lt;/h2&gt;
&lt;p&gt;The outside walls were rendered in a cream colour to match our house.&lt;/p&gt;
&lt;p&gt;The roof slopes towards the back (the 1:40 pitch from part 2), so the gutter and downpipe are at the back. It’s finished with soffit
boards, which you can see in the photo at the top of part 1.&lt;/p&gt;
&lt;p&gt;Nothing on the outside has been treated or sealed, and four years on it’s all still good with no issues.&lt;/p&gt;
&lt;h2 id=&quot;second-fix-electrics&quot;&gt;Second fix electrics&lt;/h2&gt;
&lt;p&gt;Second fix is when the sockets, switches and lights actually go on the ends of all the cables from first fix (part 3).
It went smoothly. I got an electrician to come and check and certify all of the work, because electrics are a safety
thing and not something to guess at.&lt;/p&gt;
&lt;p&gt;As for those 10 network points: I use two or three of them. I probably didn’t need them all, but I don’t regret it.
Having them everywhere means I can put the desk or the WiFi access point wherever I like.&lt;/p&gt;
&lt;h2 id=&quot;underfloor-heating-and-flooring&quot;&gt;Underfloor heating and flooring&lt;/h2&gt;
&lt;p&gt;I installed electric underfloor heating mats myself, then laid laminate on top: large, wide planks. I’ve laid
laminate in four or five rooms before, and the floor was completely flat and level because it was a brand new build, so
this was one of the easiest jobs of the whole project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TIP: Lay the flooring before the skirting boards, so the skirting covers the expansion gap around the edges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;skirting-boards&quot;&gt;Skirting boards&lt;/h2&gt;
&lt;p&gt;Standard skirting, nothing special. A mitre saw makes the corners easy.&lt;/p&gt;
&lt;h2 id=&quot;heating-and-cooling&quot;&gt;Heating and cooling&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Winter:&lt;/strong&gt; the underfloor heating plus all that insulation from part 3 keeps the office warm. It holds the heat well.
On the very coldest days I add an oil-filled radiator.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Summer:&lt;/strong&gt; this is the one thing I got wrong. The bifold doors face south, and there’s no cooling, so on a sunny day
the office gets STUPIDLY hot. Two things help:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Reflective film on the glass.&lt;/strong&gt; It made a real difference to how much heat comes in through the doors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Opening the bifolds right up&lt;/strong&gt; to let the hot air out.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;moving-in&quot;&gt;Moving in&lt;/h2&gt;
&lt;p&gt;The office is set up with a standing desk, an office chair, a sofa and a rug. Behind me there’s a sideboard with photos
and trinkets, including photos of places I’ve been on holiday.&lt;/p&gt;
&lt;h2 id=&quot;four-years-on&quot;&gt;Four years on&lt;/h2&gt;
&lt;p&gt;I’ve worked in the office for four years now, and the only real maintenance has been:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clearing leaves off the roof.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clearing the gutter and downpipe.&lt;/strong&gt; It backed up once because of leaves. Now I clear it every six months or so,
and it hasn’t happened again.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trimming back the bushes behind the office&lt;/strong&gt; so they don’t rub against the roof.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That’s it!&lt;/p&gt;
&lt;h3 id=&quot;what-would-i-do-differently&quot;&gt;What would I do differently?&lt;/h3&gt;
&lt;p&gt;Not a lot. The big one is that &lt;strong&gt;I wouldn’t make it south facing&lt;/strong&gt;. Big glass doors facing south look great, but in
summer the office is so, so hot. If I built another one, I’d face the glass away from the midday sun or plan for
cooling from the start.&lt;/p&gt;
&lt;h2 id=&quot;time-cost-and-tools&quot;&gt;Time, cost and tools&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; about two months from start to finish. That was evenings, weekends and a week off work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; about £15,000 in total. That’s not cheap! The biggest costs were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The electrician, including getting power down to the bottom of the garden&lt;/li&gt;
&lt;li&gt;The plasterer&lt;/li&gt;
&lt;li&gt;The bifold doors and the window, which were expensive&lt;/li&gt;
&lt;li&gt;The concrete pump. Looking back, the base was probably overkill!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt; if I could recommend one thing, it’s &lt;strong&gt;hiring a trench digger&lt;/strong&gt;. Digging the 20m cable trench by hand
(part 1) was the hardest part of the whole build.&lt;/p&gt;
&lt;h2 id=&quot;thanks&quot;&gt;Thanks!&lt;/h2&gt;
&lt;p&gt;A big thank you to my electrician, the plasterer, and the window and door fitters. And to the friends and family who
helped out along the way: all the “we” in this series.&lt;/p&gt;
</content:encoded><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>My Home Office Build, Part 3: Electrics, Insulation and Plasterboard</title><link>https://www.heyal.co.uk/blog/office-build-inside/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/office-build-inside/</guid><description>First fix electrics and network, rigid foam insulation, plasterboarding and fitting the bifold doors.</description><pubDate>Thu, 30 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Once the shell was watertight, the work moved inside: cables, insulation, plasterboard, and finally the windows and doors.&lt;/p&gt;
&lt;h2 id=&quot;first-fix-electrics&quot;&gt;First Fix Electrics&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Less than 1 day (cable, internet cable)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I went a bit mad with sockets. There are 10 double sockets around the 3 walls (back and 2 sides).  It’s easy to add them now and impossible to add them later.
I also added 10 internet points for the same reason. I’m currently using 2. One for the WIFI router and one for my desktop.&lt;/p&gt;
&lt;p&gt;Hint: Get your electrician to do this.&lt;/p&gt;
&lt;p&gt;I’m not going to show pictures (as I don’t have any) and didn’t do the work.&lt;/p&gt;
&lt;p&gt;We went with 5 down-lights on the front (outside), 2 up/down lights and 6 lights inside.&lt;/p&gt;
&lt;h2 id=&quot;insulation&quot;&gt;Insulation&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1-2 days (saw, insulation, tape measure)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are a lot of ways to insulate a building. It took a lot of reading to come up with the decision of using 75mm rigid foam
insulation in the walls and 100mm of the same in the floor/ceiling.&lt;/p&gt;
&lt;p&gt;This was picked because of its good “R” value (how good it is at keeping heat in/out) and the fact that the
wood used for the wall construction was about 90mm deep and we couldn’t fit 100mm.&lt;/p&gt;
&lt;p&gt;There are cheaper options! We spent about £1000 on insulation. You could use the fiber stuff on a roll and pay less than £200
for the room but you would boil in summer and freeze in winter!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;fitted insulation between the joists&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/insulation.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;As you can see from the picture you cut the big sheets into sections that snugly fit into the gaps between the frame.&lt;/p&gt;
&lt;p&gt;Once you have completed the insulation blocks you need to cut out around your lights and sockets.&lt;/p&gt;
&lt;p&gt;Then you tape over the joints, this creates a vapour barrier (keeps moisture from condensing in the wooden frame) and
helps with keeping the heat in/out.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;taped insulation&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/taped-insulation.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Hint: Don’t do what I did and push the insulation to the back of the holes, it should be flush with the
front of the frame! I created a section there behind the plasterboard for moisture to condense! I hope it doesn’t!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;plasterboard&quot;&gt;Plasterboard&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1-2 days (Plasterboard, plasterboard fixings, saw, stanley knife)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I went for 9.5mm plasterboard with a 12.5mm insulation backing, this is to reduce thermal bridging through the wall timbers.&lt;/p&gt;
&lt;p&gt;Your plasterboard needs cutting to size. For the height use the full height of the room. Width needs to end exactly
half way over a wall joist. This is so you can get a good fixing onto the board and wall!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;first plasterboard&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/first-board.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;The process is just cut, poke wires through holes and then screw on. The ceiling is hard because those boards are heavy!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;plasterboarding done&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/plasterboard.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;windows--doors&quot;&gt;Windows &amp;amp; Doors&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Less than 1 day (Window, Door, screws?)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s a good idea to get these into the building as soon as the frame is up (or even as part of building the frame).
However, the window and door I ordered had a 3 week lead time and we had to wait.&lt;/p&gt;
&lt;p&gt;Once they arrived they were professionally installed (I think most competent DIYers could do this, but a 3m bifold door was a bit daunting for me!)&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;bifold frame&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/bifold-frame.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;I don’t have any hints/tips on fitting these as I didn’t get involved. Here’s a picture of the doors fitted&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;bifold&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/bifold.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;And the window.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;window&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/window.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
</content:encoded><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>My Home Office Build, Part 2: Frame, Walls and Roof</title><link>https://www.heyal.co.uk/blog/office-build-frame/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/office-build-frame/</guid><description>Bolting down the timber frame, boarding the walls and getting a watertight roof on before the rain.</description><pubDate>Thu, 30 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;With the concrete base cured, it was time to build upwards and get the building watertight as quickly as possible.&lt;/p&gt;
&lt;h2 id=&quot;wooden-frame&quot;&gt;Wooden Frame&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1-2 days (screws, wood, screwdrivers, packers, bolts, socket sets, saw)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the concrete was dry a 4”x3” wooden frame was bolted down into the concrete. We used long concrete bolts and drilled down into the base.
The picture shows this without the second damp proof course (large plastic sheet) we added. This wooden base was leveled using the long spirit level
and placing small plastic packers under the wood to get a perfectly level and secure base.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;wooden base&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/frame.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Now we have a base, we can start to build the walls, we worked out what length to cut the uprights in the wall and then cut them all
to the same length, once we had everything we used a long beam along the top (called a wall plate) to start to build the first wall.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;walls starting to be built&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/walls.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can see the second damp proof course here (black plastic sheet) that went on top of the concrete.&lt;/p&gt;
&lt;p&gt;The corners were braced with those large diagonal lengths of wood to stop the frame falling over while we built it. Once you start
to get the wall timbers screwed onto the frame you no longer need to brace the frame (you will see these later!)&lt;/p&gt;
&lt;p&gt;You can also see 3 sheets of the rigid foam insulation we are going to use for the floor. These were put into the frame to give us somewhere to
stand so we didn’t rip the plastic sheet (you need to keep it intact to stop any water getting into the building).&lt;/p&gt;
&lt;p&gt;Once you have done all 4 walls (leaving a gap for your door and window) you can start to attach the wall panels.&lt;/p&gt;
&lt;p&gt;Because I had decided to have a 3m bifold door on the front of the building I used 2 9”x2” timbers screwed together to form the
top of the doorway. Bifold doors are HEAVY and they hang from above, so big timbers were used, bolted together with coach bolts and we also added an angle iron above the door. You will
see these details in the next few photos because we moved quickly and I didn’t get time to take photos of these specifically.&lt;/p&gt;
&lt;h2 id=&quot;walls&quot;&gt;Walls&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1-2 days (screws, wall panels 8x4’ 22mm OSB boards, screwdriver )&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;adding the wall boards&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/walls-board.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;We now have wall timbers we can start to screw in the large 8ft by 4ft boards onto the frame. These give good support to the walls and we made sure the room was
square before screwing these up. The picture shows a few being added with overhang at the top, we cut the overhang off once the roof joists were added (next section) as there
is no need to cut them before.&lt;/p&gt;
&lt;p&gt;It’s just a case of using a lot of screws here to make sure every board is securely fixed onto the timbers.&lt;/p&gt;
&lt;h2 id=&quot;roof&quot;&gt;Roof&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;1 day (wood, screws, screwdriver, step ladder, roofing material)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I decided to use a 1:40 pitched roof, this has a slight runoff and I picked heavy duty EPDM membrane (thick rubber sheet) for the roof material. It’s easy to install yourself
and you can just lay it out without fixing it down to make your roof watertight very quickly!&lt;/p&gt;
&lt;p&gt;This was important because it rained…. A LOT the day we installed the roof so we worked very quickly to get the roof joists, boards and the membrane on. Unfortunately I didn’t get
any other photos, so this one shows all those things done!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;roof starting to go on&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/roof.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
</content:encoded><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>My Home Office Build, Part 1: Groundwork</title><link>https://www.heyal.co.uk/blog/office-build/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/office-build/</guid><description>Planning a garden office, running power and network cables, and pouring the concrete base.</description><pubDate>Thu, 30 Jun 2022 00:00:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update, October 2026:&lt;/strong&gt; four years after starting this post, I’ve finally finished writing it up! The build is
now split into four parts, from digging the first trench to what it’s like to work in the finished office.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This wasn’t my first DIY project. Let’s not pretend that I suddenly knew how to build this without several years of increasingly
more complex projects.&lt;/p&gt;
&lt;p&gt;It all started when we moved house in August 2020. After 9 months waiting to move in (and therefore not doing any work on the
house we were selling) we needed to “redecorate” our new house. This involved laying some new wooden flooring, painting and
re-finishing a fireplace. These are fairly simple tasks for a “keen DIYer” and I have no doubt that anyone reading this
could have a good go at these and be happy with the results.&lt;/p&gt;
&lt;p&gt;Things got increasingly more complex from there. First it was building a window seat:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Dining room before re-decoration and window seat&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/window-seat-before.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;
&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Dining room after re-decoration and window seat&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/window-seat-after.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;This really opened my eyes to how even more complex projects were within my skill level.&lt;/p&gt;
&lt;p&gt;In the following months I re-built our fish pond (bricklaying) and totally refitted our bathroom. Took everything out, including the
flooring, walls, shower and then re-fitted everything.&lt;/p&gt;
&lt;h2 id=&quot;the-office&quot;&gt;The Office&lt;/h2&gt;
&lt;p&gt;I was already very privileged to have a dedicated room inside the house we purpose fitted to be my office.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Inside Office&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/inside-office.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;However, I like to have a project on the go!&lt;/p&gt;
&lt;p&gt;My general plan was to build a 4m x 3m office at the end of the garden. I didn’t really have more plans than this when I started
and knew I needed to lay a base as the first step.&lt;/p&gt;
&lt;p&gt;This is the spot I picked, to the left of the row of sleepers (in the gravel). Before anyone asks, the tree had unfortunately died from a fungus and
was cut down.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Bottom of the garden, space where the office will be&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/bottom-garden.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Pick a spot large enough to house your building!&lt;/p&gt;
&lt;p&gt;I’m based in the UK and the rules around garden buildings are complicated. Make sure you know what permits/permissions you need
before you start to avoid having to tear down your new building!&lt;/p&gt;
&lt;h2 id=&quot;power--internet&quot;&gt;Power &amp;amp; Internet&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;2-4 days (spade, cables, a professional electrician)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I decided to build the office at the bottom of the garden. I got my electrician to run a large armoured cable from the fuse-board
in the house down to the garden&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make sure to get a professional to install any electrical cables, they need to be rated for outdoors and you may need
to have your house electrics upgraded to be safe too!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once the electrician had connected the cable to the house (and terminated it at the end of the garden in an outdoor socket
so I could easily get power while doing the work) the cable needed burying!&lt;/p&gt;
&lt;p&gt;The UK requires that external cables that are buried are around 500mm + deep and have a yellow warning tape on top with a final layer of
gravel to make extra sure someone won’t accidentally dig into the cable! Here’s a picture.
&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Digging a trench&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/trench.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;I had to run the cable about 20m from the end of that building (in the photo) to the spot where the office was. THIS TOOK AGES!&lt;/p&gt;
&lt;p&gt;Digging is hard, it probably took 2.5 full days digging this by hand. I couldn’t get any machines into the garden because I only have access
to the back through a single doorway in the garage.&lt;/p&gt;
&lt;p&gt;Along with the power cable I ran 6 CAT6E (internet) cables from the garage, through the building into the trench. This could be done by an
electrician if you don’t know how! I saved a few £££ by doing it myself as I work in technology and know what I’m doing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TIP: If you can hire a trench digging machine DO! Unless your distance is short it will save you A LOT of time.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;ground-preparation&quot;&gt;Ground preparation&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;2-5 days (spade, wheelbarrow, pickaxe)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once I had picked a spot and run the power cable the next job was preparing the ground to pour a concrete base. I scraped back all the gravel, piled it up on the other half
of the gravel section and removed a layer of hardcore (which I kept for later!). You can see from the picture below that
I already had a good solid edge on the back, left and front of the space, so I only needed to screw a plank to the sleepers that run towards the back. (pictured)&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;removing gravel and hardcore&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/removed-gravel.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once that was removed I dug about 30cm (12”) of soil out of the hole and piled it under a tree that was close by.&lt;/p&gt;
&lt;p&gt;When the soil was removed I put out 4 corner posts and screwed 6” x 1” shuttering (thin wooden boards to hold back the concrete) using a long 6ft level to make sure it
was level! The concrete base was about 20cm larger than the planned size for the building, so 4.2m x 3.2m.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;shuttering&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/shuttering.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once the shuttering was level and square(ish) we put back the hardcore into the wood and roughly leveled it with a rake. Once
level we used a whacker plate (a machine with a big weight on a flat base plate that bashes down) to compact the hardcore to
make a really solid base.&lt;/p&gt;
&lt;p&gt;We bought some metal mesh to reinforce the concrete to reduce the chance of cracking once dry.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;ready for concrete&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/compacted.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;concrete&quot;&gt;Concrete&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;less than 1 day (concrete delivered by lorry. 2 days for self-mix )&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We bought a large plastic sheet to go under the concrete as an initial damp proof course (concrete can hold a lot of water so you need to keep as much moisture away as
possible or you risk getting damp in your building)&lt;/p&gt;
&lt;p&gt;Next job was pouring concrete. There are a few ways to do this, ranging from self-mixing using a cement mixer to getting concrete
delivered on a lorry and pumped into place. We had concrete delivered and pumped because we needed about 2.5 cubic meters (probably 1.5-2 days mixing with a cement mixer) We used
a pump (expensive! cost about 2x the price of the concrete we pumped) because we had to move the concrete 45m from the road to the site. Wheelbarrowing this would have taken several people
a few hours and I’m not strong enough for that!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;concrete poured&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/office/concrete.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once the concrete is poured and leveled you need to wait about 3-5 days for it to set.&lt;/p&gt;
&lt;p&gt;This is a good time to finalise your wood order and buy insulation.&lt;/p&gt;
</content:encoded><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>First look at loft.sh using GitOps</title><link>https://www.heyal.co.uk/blog/loft-sh/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/loft-sh/</guid><description>Using loft.sh for self-service Kubernetes namespaces and virtual clusters on a shared multi-tenant platform, installed and configured with Flux GitOps.</description><pubDate>Tue, 15 Mar 2022 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-problem&quot;&gt;The problem&lt;/h2&gt;
&lt;p&gt;I spend my days building bespoke kubernetes platforms for companies. They aim for consolidation and increased standardisation.
Often the companies are transitioning from on-prem to cloud and the first step on this journey for many organisations is to
give every team its own cloud account.&lt;/p&gt;
&lt;p&gt;This leads to every team choosing different technology to deploy, build, run, monitor and debug their systems. These usually range
from click-ops (using the console) to fully automated systems using in-house tooling and scripts, and everything between.&lt;/p&gt;
&lt;p&gt;You can already see the problem… Nobody can move teams without re-learning how to build, ship and run their systems. There is
no standard documentation. Infosec can’t easily integrate and provide good-practice patterns and alerting across the organisation.&lt;/p&gt;
&lt;p&gt;This then leads to a period of consolidation and building “Standards”. These unwieldy documents describe what and why things should be done.
They often don’t specify HOW they should be done. The reason? Every team’s setup is different. There are 50, 100, different ways
things are being done.&lt;/p&gt;
&lt;h2 id=&quot;the-idea&quot;&gt;The Idea&lt;/h2&gt;
&lt;p&gt;Wouldn’t it be better to provide one way to do something, that one way already has the security, logging and monitoring
tools built-in? In comes the need for a consolidated platform. Companies usually land on Kubernetes because it can be “Multi-cloud” (A topic for another day).&lt;/p&gt;
&lt;p&gt;The problem with this is building it. Unlike with the cloud where your provider manages the day-to-day operations of your
underlying platform (from managing disk damage with servers to managing the entire platform like with serverless), Kubernetes
requires you to build, customize and run it.&lt;/p&gt;
&lt;p&gt;The additional challenge is that Kubernetes as a platform is complex, infinitely customizable and expensive (because the people
who know how to build and run these systems are in high demand!)&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;/h2&gt;
&lt;p&gt;I have spent several years building bespoke PaaS offerings on kubernetes for large organisations, think 100s-1000s developers and 10s-100s of teams.&lt;/p&gt;
&lt;p&gt;Every time there is a base level of “stuff” that needs building/configuring to run even a basic multi-tenant cluster.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Network Isolation&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;RBAC&lt;/li&gt;
&lt;li&gt;Tenant Isolation&lt;/li&gt;
&lt;li&gt;Policy Enforcement&lt;/li&gt;
&lt;li&gt;Resource limits&lt;/li&gt;
&lt;li&gt;Financial reporting (cost allocation)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The list goes on… but you get the idea. These things take time (and therefore money) to build and configure.&lt;/p&gt;
&lt;p&gt;As Kubernetes use becomes more widespread there needs to be a better way to lay down these building blocks. I’ve been thinking for
a long time that this should be packaged up and productised. We shouldn’t be building the same things every time we want
multi-tenant kubernetes!&lt;/p&gt;
&lt;p&gt;Looks like &lt;a href=&quot;https://loft.sh&quot;&gt;loft.sh&lt;/a&gt; have done just that. I’m going to go through installing loft.sh on a new kubernetes
cluster with &lt;a href=&quot;https://github.com/fluxcd/flux2&quot;&gt;Flux&lt;/a&gt; using GitOps techniques, just like I would do for work.&lt;/p&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Get authenticated with a new Kubernetes cluster, I’m using a &lt;a href=&quot;https://civo.com&quot;&gt;Civo&lt;/a&gt; k3s cluster.&lt;/p&gt;
&lt;p&gt;Install the Flux CLI &lt;a href=&quot;https://fluxcd.io/flux/get-started/&quot;&gt;using their instructions&lt;/a&gt;, and set up your GitHub token and user.&lt;/p&gt;
&lt;p&gt;Once configured this should show a similar output&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; flux&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; check&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --pre&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;►&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; checking&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; prerequisites&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;✔&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; Kubernetes&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 1.22.2+k3s1&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;=1.20.6-0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;✔&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; prerequisites&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; checks&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; passed&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we can install Flux2, which should create a github repo, install the flux controllers and start reconciling against
that repo. This means changes we make in that repository will be reflected in the cluster.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;flux&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; bootstrap&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; github&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --owner=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$GITHUB_USER&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --repository=loft-resources&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --branch=main&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --path=./clusters/dev&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --personal&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The bootstrap command above does the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Creates a git repository &lt;code&gt;loft-resources&lt;/code&gt; on your GitHub account&lt;/li&gt;
&lt;li&gt;Adds Flux component manifests to the repository&lt;/li&gt;
&lt;li&gt;Deploys Flux Components to your Kubernetes Cluster&lt;/li&gt;
&lt;li&gt;Configures Flux components to track the path &lt;code&gt;/clusters/dev/&lt;/code&gt; in the repository&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now we can clone that repository&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; clone&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; https://github.com/&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$GITHUB_USER&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/loft-resources&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;cd&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; loft-resources&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once inside that repository we can create a Helm source to add the loft Helm repo to our cluster.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;flux&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; source&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; helm&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; loft&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --url=https://charts.loft.sh/&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --export&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; clusters/dev/loft-source.yaml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we need to set some Helm values and install the loft chart, create the following file at &lt;code&gt;loft-values.yaml&lt;/code&gt; replacing your email appropriately.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;admin&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A;--shiki-dark:#85E89D&quot;&gt;  email&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;demo@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;flux&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; hr&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; loft&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --target-namespace=loft&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --create-target-namespace=true&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --source=HelmRepository/loft&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --chart=loft&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --values=loft-values.yaml&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  --export&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; clusters/dev/loft-release.yaml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we add everything to git and commit&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -A&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -m&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;Add Loft chart&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; push&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;we should then see that loft is installed!&lt;/p&gt;
&lt;p&gt;Install the loft cli from &lt;a href=&quot;https://github.com/loft-sh/loft/releases&quot;&gt;the downloads page&lt;/a&gt; and re-set the admin password.
We need to do this because we didn’t pass in a password when generating the release, the reason is that we would have to check-in the
password.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We could have created a secret with the password and passed it into flux’s helm release as a “values-from” argument, but for simplicity we didn’t.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# run this and follow the prompt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;loft&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; reset&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; password&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can login by port-forwarding the loft service&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# port forward, then go to localhost:9898 and login with your email and password&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; port-forward&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; service/loft&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 9898:443&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --namespace&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; loft&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;navigate to &lt;code&gt;https://localhost:9898&lt;/code&gt; and login&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;loft image&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/loft-dashboard.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This was a basic installation of &lt;a href=&quot;https://loft.sh&quot;&gt;loft.sh&lt;/a&gt; using Flux, we could now use the loft provided CRDs to
build a more complex multi-tenant system. All our config is stored in Github and we could apply this same installation
to another cluster or another 10 clusters very quickly!&lt;/p&gt;
&lt;h3 id=&quot;next-steps&quot;&gt;Next steps&lt;/h3&gt;
&lt;p&gt;Start to build out templates for teams to get pre-configured environments at the click of a button!
Loft provides a set of CRDs to customize every aspect of the installation, a good start would be creating some app templates
to deliver pre-configured applications into the cluster.&lt;/p&gt;
</content:encoded><category>kubernetes</category><category>gitops</category><category>flux</category><category>multi-tenancy</category><category>vcluster</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>How to Unit Test Helm Charts with Go</title><link>https://www.heyal.co.uk/blog/unit-testing-helm-charts/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/unit-testing-helm-charts/</guid><description>Write Go unit tests that render your Helm chart templates and assert on the Kubernetes manifests, so you can change charts with confidence. Includes a full example.</description><pubDate>Sat, 23 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Learn how to write Golang unit tests for your Helm charts to keep quality high and make changes with confidence.&lt;/p&gt;
&lt;p&gt;In both my open source and commercial work I have needed to write &lt;a href=&quot;https://helm.sh/docs/topics/charts/&quot;&gt;helm charts&lt;/a&gt;.
These charts are a definition of how to install an application on kubernetes. They often include configuration options
like if we should enable auth, clustering or specific database options.&lt;/p&gt;
&lt;p&gt;These options usually boil down to some “logic” or code within the helm chart. Here is an example of
a configuration option being used to set a flag.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;yaml&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{{- &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;if .Values.auth.enabled&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  - &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;--enable-auth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{{- &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;end&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; }}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a basic example and often these logic statements can be much more complex and have larger impacts to many different
parts of the chart.&lt;/p&gt;
&lt;h2 id=&quot;how-do-we-test-this&quot;&gt;How do we test this?&lt;/h2&gt;
&lt;p&gt;The software developer in me wants to write tests for this. If I pass the &lt;code&gt;auth.enabled=true&lt;/code&gt; flag when calling helm install
I want to be sure that my above logic generates the expected outcome.&lt;/p&gt;
&lt;p&gt;I did a lot of searching before embarking on my own solution for testing this type of logic at a unit test level.
Most of the options I found were for an integration level test, such as the official &lt;a href=&quot;https://helm.sh/docs/topics/chart_tests/&quot;&gt;helm website&lt;/a&gt;.
This level of testing is great, but can be slow to test out the potentially hundreds of options and flags we may want to
set in our chart.&lt;/p&gt;
&lt;p&gt;So, I set out in search of a way to define my unit tests in code. I wanted to define what I expected the helm command to
generate and then compare what was actually generated.&lt;/p&gt;
&lt;h2 id=&quot;the-code&quot;&gt;The code&lt;/h2&gt;
&lt;p&gt;I chose &lt;code&gt;Golang&lt;/code&gt; - partly because I use golang every day, and partly because &lt;code&gt;Helm&lt;/code&gt; is written in go. This means we can
potentially import parts of the helm codebase into our test library and avoid “re inventing the wheel”.&lt;/p&gt;
&lt;p&gt;The first place to look is the code for the &lt;code&gt;helm&lt;/code&gt; CLI binary itself; we want to be able to leverage the existing implementation
so our tests match our real world use.&lt;/p&gt;
&lt;p&gt;This snippet, adapted from the &lt;code&gt;helm template&lt;/code&gt; command, is a good place to start:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Template&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;namespace&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;chartPath&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;filePath&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;valueFilePaths&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;overrideValues&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; []&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;output&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; interface&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{}) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;error&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Some setup code omitted for readability&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // This is where the magic happens, This takes the values and the template and runs the helm logic&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	release, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; client.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(chart, values)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // A function to split the output of the template, (A single array of all files in 1 variable)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // it returns a map of filename to  contents&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	manifests &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; splitChart&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(release.Manifest)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; _, exists &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; manifests[filePath]; &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;exists {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; fmt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Errorf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;no file found at path &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, filePath)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // convert the returned YAML to JSON, all internal kubernetes communication uses JSON&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	jsonBytes, err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; yaml.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;YAMLToJSON&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(manifests[filePath])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // Unmarshal the file (as json now) into a struct, We will see how we use k8s definitions in the test to reduce &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;    // code even more!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; json.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Unmarshal&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(jsonBytes, &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;output); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;		return&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	return&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This allows us to write tests where we define the struct we expect our file to match, and then compare that expected value with what
we get. Below is an example using a simple ingress record.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Test_IngressWithTLS&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209;--shiki-dark:#FFAB70&quot;&gt;t&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; *&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;testing&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;T&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	want &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; v1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Ingress&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		TypeMeta:   &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;metav1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;TypeMeta&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;			Kind:       &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Ingress&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;			APIVersion: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;networking.k8s.io/v1beta1&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		ObjectMeta: &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;metav1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ObjectMeta&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;			Name:                       &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;helmChart-nginx-example&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;			Labels:                   &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;map&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;app.kubernetes.io/instance&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;helmChart&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;app.kubernetes.io/name&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;nginx-example&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;} ,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		Spec:       &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;IngressSpec&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;			Rules: []&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;IngressRule&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;				{Host: &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;chart-example.local&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; , IngressRuleValue: &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;IngressRuleValue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{HTTP: &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;HTTPIngressRuleValue&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{Paths: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}}},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;			},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	var&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; got &lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;v1&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Ingress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	if&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; Template&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;helmChart&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;		&quot;default&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;		&quot;./chart&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;		&quot;template/ingress.yaml&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		[]&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;string&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;./chart/values.yaml&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;},&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;		nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;		&amp;amp;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;got,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	); err &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;!=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; nil&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		t.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Fatalf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;got an error templating chart: &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%v&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, err)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;	if&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; !&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;reflect.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;DeepEqual&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(want, got) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;		t.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Fatalf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;difference in chart and expected. Got:&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\n%+v\n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;Want:&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\n%+v\n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, got, want)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can now describe what we expect our chart to produce in our code, we can add logic to generate sections, like if
we enabled TLS in the values with &lt;code&gt;--set&lt;/code&gt; then we could add a section in our &lt;code&gt;want&lt;/code&gt; struct to match what the helm template logic
should generate.&lt;/p&gt;
&lt;p&gt;When we make changes to our chart we can then use our tests to validate that we don’t make any other unintended changes. For example
we could update an image version in our base &lt;code&gt;values.yaml&lt;/code&gt;, run our tests and see that our &lt;code&gt;deployment&lt;/code&gt; now fails because we
didn’t update our tests to use the new image.&lt;/p&gt;
&lt;h3 id=&quot;the-upsides&quot;&gt;The Upsides&lt;/h3&gt;
&lt;p&gt;With a good suite of unit tests written we can be confident that when we make changes to our chart that they have the
desired effect. It’s hard having to manually verify the changes each time and this is time we could better spend developing
more features!&lt;/p&gt;
&lt;p&gt;This type of testing is particularly helpful for new members of the team, they can make changes with confidence and start having
an immediate impact. Additionally, when reviewing helm chart changes we get a version of the change written in a more familiar
and strongly typed language. This should reduce the time taken to digest the changes and make informed decisions when
reviewing your team’s PRs.&lt;/p&gt;
&lt;h3 id=&quot;the-downsides&quot;&gt;The downsides?&lt;/h3&gt;
&lt;p&gt;It wouldn’t be fair to not talk about a few possible downsides when showing off this technique. Using this approach
(using go code from helm) means vendoring large chunks of the k8s.io repos and pulling in helm. This
is a lot of dependencies we have just added to our codebase. The other alternative is to write a go wrapper that executes
the &lt;code&gt;helm template&lt;/code&gt; binary with the desired values, this removes the need to vendor k8s/helm code. However, it does mean
we would need to write our own version of the &lt;code&gt;v1.Ingress&lt;/code&gt; structs. I have chosen to vendor the code because it makes
writing tests quicker as we don’t need to keep adding to our own type definitions of the kubernetes objects.&lt;/p&gt;
&lt;h2 id=&quot;full-example&quot;&gt;Full example&lt;/h2&gt;
&lt;p&gt;I have written a full example with a basic helm chart &lt;a href=&quot;https://github.com/Waterdrips/helmunit&quot;&gt;in this repo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is my second attempt at unit testing Helm charts. I took a similar approach when writing the &lt;a href=&quot;https://github.com/openfaas/openfaas-cloud/tree/master/chart/test&quot;&gt;OpenFaaS Cloud helm chart&lt;/a&gt;.
Last time I went with the “DIY” approach and wrote the type definitions and a wrapper around the helm binary. You can check out
the implementation at the link.&lt;/p&gt;
&lt;p&gt;Let me know what you think &lt;a href=&quot;https://www.linkedin.com/in/alistair-hey/&quot;&gt;on LinkedIn&lt;/a&gt;. I’d be keen to hear whether you’re
unit testing your Helm charts, and whether you see the value in this approach.&lt;/p&gt;
</content:encoded><category>helm</category><category>testing</category><category>go</category><category>kubernetes</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>OpenFaaS, what&apos;s it all about?</title><link>https://www.heyal.co.uk/blog/openfaas-whats-it-about/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/openfaas-whats-it-about/</guid><description>Exploring serverless on Kubernetes. To roll your own or not?</description><pubDate>Tue, 12 May 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Serverless should let you focus on delivering features into production fast not fiddling with infrastructure.&lt;/p&gt;
&lt;p&gt;If you spend some time on the internet you should have seen that kubernetes is everywhere. It’s a great platform for abstracting
your infrastructure away from your developers and letting them focus on code.&lt;/p&gt;
&lt;p&gt;When it comes to deploying serverless on Kubernetes I am of two minds. Part of me thinks it’s not “serverless” because you
have to (at the very least) manage worker nodes (This is not strictly true, you could use AWS Fargate backed EKS Clusters?).&lt;/p&gt;
&lt;p&gt;The other part of me thinks, well you don’t have to care about the nodes. We could call it serverless. For example using
managed Kubernetes with autoscaling worker groups using the cloud’s default VM images? You probably would never need to bother
looking at the instances, let alone connecting to them.&lt;/p&gt;
&lt;h2 id=&quot;why-bring-in-another-abstraction-with-openfaas&quot;&gt;Why bring in another abstraction with OpenFaaS&lt;/h2&gt;
&lt;p&gt;OpenFaaS abstracts away some of the complexity of running applications on kubernetes if you want to focus on delivering
value to your paying customers, who don’t care how your platform is run as long as it works.&lt;/p&gt;
&lt;p&gt;If you need to run application code, you can run it here. There are community maintained
templates for languages from Rust and Go to COBOL. If you can’t find a template that quite hits the spot you can build and
customise your own to provide exactly the base application configuration that works for you.&lt;/p&gt;
&lt;p&gt;Let’s look at this from a couple of angles. I’m going to put my Developer and Platform engineer hats on for a minute…&lt;/p&gt;
&lt;h3 id=&quot;developer&quot;&gt;Developer&lt;/h3&gt;
&lt;p&gt;You probably don’t really mind where your code gets run, as long as you can iterate on features quickly and deploy new
services without fuss.&lt;/p&gt;
&lt;p&gt;I’m going to let you into a secret, you need to write A LOT of YAML to deploy a service into kubernetes, most of it will be
the same, or very similar.&lt;/p&gt;
&lt;p&gt;In this case using plain old YAML manifests hand crafted for each service probably isn’t your bag.&lt;/p&gt;
&lt;p&gt;It takes 2 commands to deploy a service into OpenFaaS.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --lang&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; python3&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; python3-fn&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --prefix&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;dockerhub&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; usernam&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;e&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; up&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -f&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; python3-fn.yml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the same container deployed into Kubernetes using YAML manifests you would need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A Service (If you are going to scale your deployment) (20+ lines of YAML)&lt;/li&gt;
&lt;li&gt;A Deployment (50+ lines of YAML)&lt;/li&gt;
&lt;li&gt;An Ingress Definition (20+ lines of yaml)&lt;/li&gt;
&lt;li&gt;A Dockerfile (20+ Lines of Dockerfile)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Do you really want to get stuck maintaining all of these for each service you are running?&lt;/p&gt;
&lt;p&gt;In addition to this you can easily install and run OpenFaaS on your laptop using docker swarm or a local Kubernetes cluster.&lt;/p&gt;
&lt;p&gt;I like using &lt;a href=&quot;https://github.com/rancher/k3d&quot;&gt;&lt;code&gt;k3d&lt;/code&gt;&lt;/a&gt; for local testing. I can spin up a single node cluster inside docker
install OpenFaaS and route traffic to my local machine in a few commands.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Wait for that to finish, It will output a command to export KUBECONFIG&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; export&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; KUBECONFIG=&quot;$(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/usr/local/bin/k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get-kubeconfig &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;--name=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;k3s-default&apos;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# I&apos;m using arkade to install openfaas with default config https://github.com/alexellis/arkade&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# When thats deployed (all pods running, check with kubectl get pods -A)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; PASSWORD=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; secret&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; basic-auth&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; jsonpath=&quot;{.data.basic-auth-password}&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \ &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;    |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --decode&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Port forward the &quot;gateway&quot; to your localhost&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; port-forward&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; svc/gateway&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 8080:8080&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Login with the CLI&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $PASSWORD &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; login&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --username&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; admin&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --password-stdin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Deploy your stack, which by default should be in stack.yml&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; up&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It would be easy to include this in your CI pipeline. For example the Kubernetes provider for OpenFaaS
&lt;a href=&quot;https://github.com/openfaas/faas-netes/&quot;&gt;faas-netes&lt;/a&gt; uses minikube to run OpenFaaS during CI.&lt;/p&gt;
&lt;h3 id=&quot;platformops-engineer&quot;&gt;Platform/Ops engineer&lt;/h3&gt;
&lt;p&gt;You want to provide a stable, simple to use and easy to debug platform for developers to maximise productivity.&lt;/p&gt;
&lt;p&gt;If you are on a small team or don’t have bags of kubernetes experience then leveraging a platform like OpenFaaS that
abstracts away some of the complexity for you and your users seems like a good idea.&lt;/p&gt;
&lt;p&gt;If you want to focus on delivering a stable scalable platform for your services you can leverage the many
thousands of hours of community knowledge and experience that has gone into building OpenFaaS. If you wanted to build
a custom solution you would no doubt end up hitting some of the same problems that have already been overcome by the
OpenFaaS contributors. Why go to all that effort yourself?&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&quot;my-journey-with-openfaas&quot;&gt;My journey with OpenFaaS&lt;/h2&gt;
&lt;h3 id=&quot;first-look&quot;&gt;First look&lt;/h3&gt;
&lt;p&gt;My first experience with OpenFaaS was during a company “hack day” where you put aside your normal work and get into new
teams and experiment with new technologies and processes. Our team decided to look into open source serverless technology
as an alternative to your favourite cloud vendor serverless technology.&lt;/p&gt;
&lt;p&gt;We were trying to find a way of overcoming the difficult challenge of testing serverless deployments End to End in a
cost effective, fast and easy to test way.&lt;/p&gt;
&lt;p&gt;I have always found services like AWS Lambda too hard to test, run locally and debug without deploying the whole stack
into Amazon and trying things until it works. Our feedback loop for an End to End test on a AWS based serverless stack was
in excess of 30 minutes! Not to mention the costs for deploying and running on the cloud.&lt;/p&gt;
&lt;p&gt;Needless to say, within a few days we had written a serverless application on OpenFaaS. We had a range of languages in use
for our functions (we all picked our favourites!), and we could all run the stack locally for testing.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;where-am-i-now&quot;&gt;Where am I now?&lt;/h3&gt;
&lt;p&gt;I’m part of the community and a regular contributor to OpenFaaS in my spare time.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;openfaas team page&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/openfaas-team.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;
(sorry everyone else who didn’t fit onto that screenshot!)&lt;/p&gt;
&lt;p&gt;I love OpenFaaS! I think it’s the perfect platform for developing cloud native applications. It keeps its focus firmly on
providing developers with the best tools and workflows to get things done.&lt;/p&gt;
&lt;p&gt;I may be slightly biased: I contribute a lot of code to the OpenFaaS project! At the time of writing I was the 9th highest
contributor by commits.&lt;/p&gt;
&lt;h2 id=&quot;come-and-join-the-party&quot;&gt;Come and join the party!&lt;/h2&gt;
&lt;p&gt;At the time of writing there were more than 2,500 of us in the OpenFaaS community, and 20K+ stars on GitHub!&lt;/p&gt;
&lt;p&gt;What can you do to get involved? Well lots of things!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OpenFaaS has a great community - &lt;a href=&quot;https://docs.openfaas.com/community/&quot;&gt;find out how to join here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check out the &lt;a href=&quot;https://openfaas.com&quot;&gt;OpenFaaS Website and blog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Head over to Github and run through the &lt;a href=&quot;https://github.com/openfaas/workshop#openfaas-workshop&quot;&gt;getting started Workshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Follow OpenFaaS on &lt;a href=&quot;https://twitter.com/openfaas&quot;&gt;Twitter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Support the project’s maintainer &lt;a href=&quot;https://github.com/sponsors/alexellis&quot;&gt;Alex Ellis&lt;/a&gt; by sponsoring him on Github!&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
</content:encoded><category>openfaas</category><category>serverless</category><category>kubernetes</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>Introducing Arkade - The Kubernetes app installer</title><link>https://www.heyal.co.uk/blog/introducing-arkade/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/introducing-arkade/</guid><description>A CLI with strongly-typed flags to install charts and apps to your cluster in one command.</description><pubDate>Fri, 28 Feb 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;arkade-what-is-it&quot;&gt;Arkade! What is it?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://get-arkade.dev&quot;&gt;Arkade (ark for short)&lt;/a&gt; provides a clean CLI with strongly-typed flags to install charts and apps to your cluster in one command.&lt;/p&gt;
&lt;p&gt;It’s written in Golang and supported by &lt;a href=&quot;https://twitter.com/alexellisuk&quot;&gt;Alex Ellis&lt;/a&gt; and the &lt;a href=&quot;https://www.openfaas.com/&quot;&gt;OpenFaaS Community&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I added the cert-manager, openfaas-ingress, kubernetes dashboard and docker-registry-ingress apps! Big thanks to Alex
and the rest of the community for contributing all the other amazing apps.&lt;/p&gt;
&lt;h3 id=&quot;whats-it-for&quot;&gt;What’s it for?&lt;/h3&gt;
&lt;p&gt;Installing apps on Kubernetes, this is a list of the currently supported apps:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;You&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; can&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install:&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; nginx-ingress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cert-manager&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas-ingress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inlets-operator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; metrics-server&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; chart&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tiller&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; linkerd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cron-connector&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; kafka-connector&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; minio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; postgresql&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; kubernetes-dashboard&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; istio&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; crosspane&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mongodb&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; docker-registry&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; -&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; docker-registry-ingress&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Run&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; NAME&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --help&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; see&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; configuration&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; options.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow! That’s a lot of apps!&lt;/p&gt;
&lt;h3 id=&quot;lets-take-a-look&quot;&gt;Let’s take a look&lt;/h3&gt;
&lt;p&gt;The arkade cli is the &lt;a href=&quot;https://docs.openfaas.com/deployment/kubernetes/#a-deploy-with-arkade-fastest-option&quot;&gt;easiest installation method for OpenFaaS on kubernetes&lt;/a&gt;.
I am going to show you just how easy it is to get OpenFaaS installed and ready to work using this cli.&lt;/p&gt;
&lt;p&gt;I have a Kubernetes cluster on DigitalOcean ready to go, with kubectl configured on my laptop.&lt;/p&gt;
&lt;p&gt;We could install the basic default configuration like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I’m going to set an override for the Helm installation, so our functions scale down to 0 when they are idle, saving
cluster resources. In the full helm command we would use &lt;code&gt;--set faasIdler.dryRun=false&lt;/code&gt;, as you can see from the command below
we just pass the same flag in. Easy as that!&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --set&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; faasIdler.dryRun=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That should output the below message, showing it worked!&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;=======================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; OpenFaaS&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; has&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; been&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; installed.&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;                                        =&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;=======================================================================&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Get the faas-cli&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -SLsf&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; https://cli.openfaas.com&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Forward the gateway to your machine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; rollout&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; status&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; deploy/gateway&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; port-forward&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; svc/gateway&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 8080:8080&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &amp;amp;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# If basic auth is enabled, you can now log into your gateway:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;PASSWORD&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; secret&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; basic-auth&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; jsonpath=&quot;{.data.basic-auth-password}&quot;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --decode&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $PASSWORD &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; login&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --username&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; admin&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --password-stdin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; store&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; deploy&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; figlet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; list&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# For Raspberry Pi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; store&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; list&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --platform&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; armhf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; store&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; deploy&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; figlet&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --platform&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; armhf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Find out more at:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# https://github.com/openfaas/faas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Thanks&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; using&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a lot deployed in one small command. We now have OpenFaaS installed in our cluster, ready for us to deploy serverless functions, microservices or containers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: You don’t even need to remember all that information. Arkade has a command to print the info for any app again!&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; info&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/blockquote&gt;
&lt;p&gt;With two more &lt;code&gt;arkade&lt;/code&gt; commands we can set up TLS and ingress from the internet:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cert-manager&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --wait&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas-ingress&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    --email&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; example@example.com&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    --domain&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas.example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;The wait flag can be used to wait for the helm chart to install and be ready before moving on to the next command.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So now we have OpenFaaS, cert-manager and some ingress records set up. Once DNS points at this
cluster, we get a Let’s Encrypt TLS certificate, so our installation is now secured on the
&lt;code&gt;https://openfaas.example.com&lt;/code&gt; domain.&lt;/p&gt;
&lt;p&gt;Now that is actually it. We have OpenFaaS installed and secured with TLS in three commands, but let’s go through an example
function to validate the installation.&lt;/p&gt;
&lt;p&gt;Let’s grab the OpenFaaS CLI:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -sSL&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; https://cli.openfaas.com&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# We need to login, so let&apos;s grab our password and login&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; export&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; OPENFAAS_URL=&quot;https://openfaas.example.com&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; PASSWORD=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; secret&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; basic-auth&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -o&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; jsonpath=&quot;{.data.basic-auth-password}&quot;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; base64&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --decode&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;; &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;echo&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $PASSWORD &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; login&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --username&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; admin&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --password-stdin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can deploy an example function&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; store&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; deploy&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; figlet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# And test it out with&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; echo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;IT&apos;S WORKING&quot;&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; faas-cli&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; invoke&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; figlet&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ___&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; _____&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ____&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   __&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        _____&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  ____&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  _____&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  ____&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   _&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;( ) &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;___&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  \&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \ &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;     /&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \|&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  _&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \|&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; /_&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; \&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ___&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;  |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;/\___&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \ &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;  \ \ &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\ &lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; /&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; &apos; / | ||  \| | |  _ &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; | |  | |    ___) |   \ V  V /| |_| |  _ &amp;lt;| . \ | || |\  | |_| |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;|___| |_|   |____/     \_/\_/  \___/|_| \_\_|\_\___|_| \_|\____|&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;where-has-it-come-from&quot;&gt;Where has it come from?&lt;/h3&gt;
&lt;p&gt;It was spun out of the &lt;a href=&quot;https://github.com/alexellis/k3sup&quot;&gt;k3sup&lt;/a&gt; codebase to allow the &lt;code&gt;k3sup&lt;/code&gt; cli to be lean and focused
on creating &lt;a href=&quot;https://k3s.io/&quot;&gt;k3s&lt;/a&gt; clusters.&lt;/p&gt;
&lt;p&gt;While the &lt;code&gt;k3sup app install&lt;/code&gt; commands work on any Kubernetes cluster, there were some people who wouldn’t even look at
its functionality because they thought it was just for k3s clusters. It’s not! It installs helm charts and applications
onto any kubernetes cluster using strongly typed flags and sensible defaults, while still allowing users to set the more
obscure helm flags when they need to.&lt;/p&gt;
&lt;p&gt;This new direction will allow the &lt;code&gt;arkade&lt;/code&gt; cli to be more focused on providing cluster admins with the abstractions to
let them move faster with more safety.&lt;/p&gt;
&lt;h3 id=&quot;get-involved&quot;&gt;Get involved&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/alexellis/arkade&quot;&gt;Arkade&lt;/a&gt; is on github, so pop over and give it a star to show your support.&lt;/p&gt;
&lt;p&gt;You can find the developers through the &lt;a href=&quot;https://docs.openfaas.com/community/&quot;&gt;OpenFaaS community&lt;/a&gt; to talk about new
features, how you can contribute and more.&lt;/p&gt;
</content:encoded><category>arkade</category><category>kubernetes</category><category>helm</category><category>open-source</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>Exploring NAT Traversal and Tunnels with Inlets and Inlets Pro</title><link>https://www.heyal.co.uk/blog/inlets-pro/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/inlets-pro/</guid><description>How inlets tunnels give services behind NAT or a firewall a public IP, using inletsctl and the inlets-operator, and when you need inlets PRO for non-HTTP traffic.</description><pubDate>Mon, 20 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;inlets-what-is-it&quot;&gt;Inlets! What is it?&lt;/h2&gt;
&lt;p&gt;inlets is a reverse proxy and service tunnel written in Go.&lt;/p&gt;
&lt;p&gt;This is the overview from the &lt;a href=&quot;https://github.com/inlets/inlets-pro#overview&quot;&gt;inlets GitHub README&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;inlets PRO replaces SSH tunnels, VPNs, SaaS tunnels, port-forwarding and dedicated connections.&lt;/p&gt;
&lt;p&gt;It’s compatible with any HTTP (L7) or TCP (L4) software and can work through the most challenging network conditions like captive portals, HTTP proxies, firewalls and NAT to give you access to services.&lt;/p&gt;
&lt;p&gt;You can run the tunnel as a process, container or Kubernetes Pod, and it’s easy to configure or automate it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This means you can use it to create inbound network tunnels to computers that don’t have a public IP, are behind firewalls
or get assigned new IPs frequently. Things like your laptop when you move from the office to a coffee shop. While writing
this post I have probably been on 5 different networks, but still been able to connect to my laptop’s &lt;a href=&quot;https://github.com/rancher/k3d&quot;&gt;k3d&lt;/a&gt;
cluster using the same public IP address.&lt;/p&gt;
&lt;h3 id=&quot;why-inlets&quot;&gt;Why inlets&lt;/h3&gt;
&lt;p&gt;inlets has a place on the Cloud Native Computing Foundation (&lt;a href=&quot;https://cncf.io&quot;&gt;CNCF&lt;/a&gt;)’s technology landscape. It’s in the
&lt;a href=&quot;https://landscape.cncf.io/category=service-proxy&amp;amp;format=card-mode&amp;amp;grouping=category&quot;&gt;Service Proxy&lt;/a&gt;  category along
with MetalLB, Traefik, HAProxy and Nginx.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Inlets Cloud Native card&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/cncf-inlets.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;There are plenty of freemium services out there that will give you inbound network access to processes that don’t have
inbound connectivity, but most of these services are in control of your data, rate limit and are closed source. Inlets
gives you back control of your data, privacy and lets you run the service in the way you want.&lt;/p&gt;
&lt;p&gt;Services like ngrok and Cloudflare’s Argo Tunnel are closed source and have service restrictions, and you
are not fully in control of them.&lt;/p&gt;
&lt;p&gt;With cloud VMs starting at $5 with heaps of inbound data transfer there’s no need to pay 10s of dollars a month for someone else
to run a limited service for you.&lt;/p&gt;
&lt;h3 id=&quot;how-it-works&quot;&gt;How it works&lt;/h3&gt;
&lt;p&gt;Inlets creates a tunnel from your local computer to a public cloud instance (or anything that can accept inbound traffic).
I have been using DigitalOcean’s smallest VMs as my exit nodes. However, you can set up inlets using anything that can be
accessed from both the internet, and the application or process you want to expose.&lt;/p&gt;
&lt;h3 id=&quot;inletsctl&quot;&gt;inletsctl&lt;/h3&gt;
&lt;p&gt;There is a handy CLI for managing your inlets services called &lt;a href=&quot;https://github.com/inlets/inletsctl&quot;&gt;inletsctl&lt;/a&gt;.
I will be using this cli throughout the post as it simplifies the process of getting things set up and configured.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;       _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;            _&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   _&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; __&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; ___&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ___&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;  ___&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;|&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; &apos;_ \| |/ _ \ __/ __|/ __| __| |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;| | | | | |  __/ |_\__ \ (__| |_| |&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;|_|_| |_|_|\___|\__|___/\___|\__|_|&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;inletsctl automates the task of creating an exit-node on cloud infrastructure.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Once provisioned, you&apos;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ll&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; receive&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; command&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; connect&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; with.&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; You&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; can&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; use&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;tool&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; whether&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; you&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; want&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; use&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inlets&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inlets-pro&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; L4&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; TCP.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;See&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; also:&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inlets-operator&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; which&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; does&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; same&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; job,&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; but&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; Kubernetes&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; services.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Usage:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  inletsctl&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [flags]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  inletsctl&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; [command]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Available&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; Commands:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  create&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      Create&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; exit-server&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; with&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inlets&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; PRO&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; preinstalled.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  delete&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      Delete&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; an&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; exit&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; node&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  download&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;    Downloads&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inlets&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; PRO&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; binary&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  help&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        Help&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; about&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; any&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; command&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  kfwd&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;        Forward&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; Kubernetes&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; service&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; local&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; machine&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  update&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;      Print&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; update&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; instructions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  version&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;     Display&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; the&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; clients&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; version&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; information.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Flags:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;  -h,&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --help&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;   help&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inletsctl&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Use&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;inletsctl [command] --help&quot;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; for&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; more&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; information&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; about&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; a&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; command.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The create command automates the provisioning, setup and configuration of the publicly accessible exit-node using cloud
instances.&lt;/p&gt;
&lt;p&gt;Currently supported providers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Digital Ocean&lt;/li&gt;
&lt;li&gt;Equinix metal&lt;/li&gt;
&lt;li&gt;AWS EC2&lt;/li&gt;
&lt;li&gt;Scaleway&lt;/li&gt;
&lt;li&gt;Civo&lt;/li&gt;
&lt;li&gt;Google Cloud&lt;/li&gt;
&lt;li&gt;Linode&lt;/li&gt;
&lt;li&gt;Hetzner&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You will need your own account and will incur costs with whichever provider you use if you are following along.&lt;/p&gt;
&lt;p&gt;There are some great blog posts already about setting up inlets without the CLI, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://mbacchi.github.io/2019/08/21/inlets-aws-ec2.html&quot;&gt;Setting up an EC2 Instance as an Inlets Exit Node&lt;/a&gt; - Matt Bacchi&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Therefore I won’t be focusing on this, instead we will focus on the why and the what of inlets.&lt;/p&gt;
&lt;h5 id=&quot;before-you-get-started&quot;&gt;Before you get started&lt;/h5&gt;
&lt;p&gt;It’s probably best to say that if you are using a corporate network, or any network you aren’t responsible for, you should
ensure you have permission to start routing inbound internet traffic. It goes without saying that this exposes the network
to extra risk and could drastically increase the network attack surface.&lt;/p&gt;
&lt;h3 id=&quot;inlets-operator&quot;&gt;inlets-operator&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;I’m using Kubernetes and can’t forward every deployment, that would take ages…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Not to worry, the &lt;a href=&quot;https://github.com/inlets/inlets-operator&quot;&gt;inlets-operator&lt;/a&gt; has your back.&lt;/p&gt;
&lt;p&gt;The operator automates the creation of an inlets exit-node on public cloud, and runs the client as a Pod inside your
cluster. Your Kubernetes Service will be updated with the public IP of the exit-node and you can start receiving
incoming traffic immediately.&lt;/p&gt;
&lt;p&gt;The operator has a more specific use case: running Kubernetes somewhere without inbound network traffic, like
k3s, k3d, minikube, MicroK8s, Docker Desktop or KinD.&lt;/p&gt;
&lt;p&gt;It’s worth exploring if you need to expose your local kubernetes services, for example to give a demo or to collaborate.&lt;/p&gt;
&lt;h2 id=&quot;people-love-reverse-proxies&quot;&gt;People LOVE reverse proxies&lt;/h2&gt;
&lt;p&gt;My most viewed tweet so far is this&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;inlets tweet&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/inlets-tweet.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;I’m not entirely sure why people love tunnelling traffic into networks so much, especially where it’s specifically
disallowed (corporate networks!).&lt;/p&gt;
&lt;h2 id=&quot;why-inlets-pro&quot;&gt;Why Inlets Pro?&lt;/h2&gt;
&lt;p&gt;According to the GitHub README &lt;a href=&quot;https://github.com/inlets/inlets-pro-pkg/&quot;&gt;inlets-pro is an L4 TCP load-balancer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;OK, thanks.&lt;/p&gt;
&lt;p&gt;For those of us that can’t remember the entire network stack and what each layer does or is (humans?),
this roughly translates as &lt;code&gt;delivers the correct data to the correct application process over the network&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So putting that in the context of inlets-pro, it forwards TCP traffic over an encrypted websocket secured with TLS to
your application process. Cool!&lt;/p&gt;
&lt;p&gt;These are some of the &lt;a href=&quot;https://github.com/inlets/inlets-pro-pkg/#features&quot;&gt;features&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Support for any TCP protocol&lt;/li&gt;
&lt;li&gt;Automatic TLS encryption for tunnel and control-port&lt;/li&gt;
&lt;li&gt;Pass-through L4 proxy&lt;/li&gt;
&lt;li&gt;Automatic port detection, as announced by client&lt;/li&gt;
&lt;li&gt;systemd support and automatic retries&lt;/li&gt;
&lt;li&gt;Kubernetes compatible&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&quot;enough-talk---time-for-action&quot;&gt;Enough talk - time for action&lt;/h2&gt;
&lt;h4 id=&quot;setup&quot;&gt;Setup&lt;/h4&gt;
&lt;h5 id=&quot;inlets&quot;&gt;Inlets&lt;/h5&gt;
&lt;p&gt;We have already briefly looked at &lt;code&gt;inletsctl&lt;/code&gt;, but we didn’t discuss installation or setup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;All of the commands shown are for linux and will probably work on Mac too. If you are using Windows then you should probably use WSL.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Download and install inlets, inlets pro and inletsctl&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Install Inletsctl to /usr/local/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;curl&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -sLSf&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; https://inletsctl.inlets.dev&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; |&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; sudo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; sh&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Install Inlets Pro&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;sudo&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; inletsctl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; download&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Get your Inlets license by buying a subscription &lt;a href=&quot;https://openfaas.gumroad.com/l/inlets-subscription&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’m using Digital Ocean for my exit nodes, you need to grab your Digital Ocean API Key if you are following along.
I have saved mine in a file called &lt;code&gt;do-token&lt;/code&gt; in my home directory.&lt;/p&gt;
&lt;p&gt;If you want to use one of the other providers you can check the examples in the &lt;a href=&quot;https://github.com/inlets/inletsctl/#examples-for-inletsctl-create&quot;&gt;inletsctl github repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Then we can create an exit node&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;inletsctl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --access-token-file&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ~/do-token&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;example output from inletsctl create&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/inletsctl-create.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;You should have some similar output to above, this is showing that we created a node and it’s ready to be configured
to forward traffic. It’s even helpfully given us the commands we need to run to get something configured.&lt;/p&gt;
&lt;p&gt;If you have docker installed you can do a quick test to see if it’s working.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; run&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --name&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; nginx-test&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -d&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; 8080:80&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --rm&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; nginx:latest&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LICENSE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;your inlets pro license&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; UPSTREAM&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;http://127.0.0.1:8080&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;inlets-pro&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tcp&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --remote&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;ws://157.245.37.54:8080&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      --token&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;a-long-random-string&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      --upstream&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $UPSTREAM &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      --license&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $LICENSE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should have some output in your terminal that shows inlets client connecting to your exit server. You can now navigate to
the public IP of your exit node. If you see the nginx splash page then we are all set up!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;nginx splash page&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/nginx-splash.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;If that worked you can stop the docker container&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;docker&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; stop&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; nginx-test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have validated our setup we can get into some real use cases!&lt;/p&gt;
&lt;p&gt;Broadly my use cases are split into HTTP traffic, and non HTTP traffic. The example commands to forward these two
categories of traffic are the same, so I will show some example uses and then the
commands needed to get inlets or inlets-pro working.&lt;/p&gt;
&lt;br&gt;
&lt;hr&gt;
&lt;h3 id=&quot;http-based-services&quot;&gt;HTTP based services&lt;/h3&gt;
&lt;h4 id=&quot;webhooks&quot;&gt;Webhooks&lt;/h4&gt;
&lt;p&gt;While developing &lt;a href=&quot;https://github.com/openfaas/openfaas-cloud&quot;&gt;OpenFaaS Cloud&lt;/a&gt; we relied on webhooks to let us know when new
code has been pushed, and therefore when to run new builds.&lt;/p&gt;
&lt;p&gt;This is easy with inlets, we just forward the webhooks through an inlets exit-node to our local machine, this means we
can build our services locally without having to push containers up to registries and pull them back down in a remote
kubernetes cluster. This saves us loads of time and bandwidth.&lt;/p&gt;
&lt;h4 id=&quot;exposing-temporary-services&quot;&gt;Exposing temporary services&lt;/h4&gt;
&lt;p&gt;Let’s suppose you are working remotely on a set of microservices, your colleague wants to test their new front-end against
your backend service, this means committing, raising a PR and getting code into a development or staging environment to
properly test. Alternatively they could pull your code, build and deploy that service themselves.&lt;/p&gt;
&lt;p&gt;Problem is, both of these are a hassle. We like things to be easy! You get some free user testing, potentially catch a
bug before your code even makes it into PR, your colleague gets a service provided by the person building it, without
having to do anything. Sounds good.&lt;/p&gt;
&lt;p&gt;All you need to do is expose your service using inlets. The commands to do this are later in the section.&lt;/p&gt;
&lt;h4 id=&quot;demos&quot;&gt;Demos&lt;/h4&gt;
&lt;p&gt;It’s always cool to give access to the demo services and websites you are making to the “users”, this could be the product
owner, client or your business partner.&lt;/p&gt;
&lt;p&gt;Without something like inlets you would need to deploy your application up to a machine that had a public
IP, configure the service and then remember to keep that up-to-date. You would also need to go off to that machine to get
logs. Having this instance running costs you money and takes away valuable time during the early product development
stages.&lt;/p&gt;
&lt;p&gt;Using inlets we can expose a local service to the internet in less than a minute, and when we are done we can tear
everything down again, meaning we can create on-demand tunnels, only pay for what we use and spend more time where it
matters, creating value for our customers.&lt;/p&gt;
&lt;p&gt;I can deploy a local copy of my blog using docker-compose, that updates when files change and allows me to see what my
changes will look like without publishing to the rest of the world.&lt;/p&gt;
&lt;h4 id=&quot;the-commands&quot;&gt;The commands&lt;/h4&gt;
&lt;p&gt;Let’s look at the last example above, my personal blog in development mode.&lt;/p&gt;
&lt;p&gt;I can expose my service to &lt;code&gt;http://127.0.0.1:4000&lt;/code&gt; by running &lt;code&gt;docker-compose up&lt;/code&gt;. This stands up a container that
publishes to port 4000 on my local machine.&lt;/p&gt;
&lt;p&gt;Using the exit-node we created earlier we can set up an inbound network route to my blog like this&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; UPSTREAM&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;http://127.0.0.1:4000&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;inlets&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --remote&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;ws://157.245.37.54:8080&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      --token&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;a-long-random-string&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      --upstream&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $UPSTREAM &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;\&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;      --license&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $LICENSE&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My local service will be accessible at the remote ip. That’s it, all that’s needed.&lt;/p&gt;
&lt;p&gt;You can substitute the port on the &lt;code&gt;UPSTREAM&lt;/code&gt; environment variable if your service is using a different port,
5000 for example:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;export UPSTREAM=http://127.0.0.1:5000&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then we just run the &lt;code&gt;inlets&lt;/code&gt; command again.&lt;/p&gt;
&lt;br&gt;
&lt;hr&gt;
&lt;h3 id=&quot;non-http-based-services-inlets-pro&quot;&gt;Non-HTTP based services (inlets pro)&lt;/h3&gt;
&lt;h4 id=&quot;home-lab&quot;&gt;Home Lab&lt;/h4&gt;
&lt;p&gt;I didn’t know if I should have put Home Lab under HTTP services, but I decided it probably lives under the inlets-pro
section, I personally use mainly HTTP, but do have an SSH Tunnel open from time-to-time to allow configuration of the
resources from outside my home network.&lt;/p&gt;
&lt;p&gt;You might be collaborating with someone who doesn’t have their own resources, or computer with particular chipset. So
it’s useful to be able to open these up to trusted parties via the internet.&lt;/p&gt;
&lt;p&gt;Here’s an example from the inlets author&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Inlets tweet about sharing rpi using inlets&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/inlets-rpi.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;iot&quot;&gt;IoT&lt;/h4&gt;
&lt;p&gt;You could open a reverse tunnel to configure, update and change the software running on IoT Devices no-matter where they
are, provided they have outbound network connectivity.&lt;/p&gt;
&lt;p&gt;This could be a really good way to deliver updates to IoT devices.&lt;/p&gt;
&lt;h4 id=&quot;bastion-hosts&quot;&gt;Bastion hosts&lt;/h4&gt;
&lt;p&gt;Sometimes you need to get access to resources in private networks. This could be a database cluster or your kubernetes
nodes for example. A common pattern is to have “SSH Bastions”. These are machines that live within the network but have
an inbound network route. This allows you to ssh onto these machines and then jump into internal parts of your network.&lt;/p&gt;
&lt;p&gt;Access to these machines is usually controlled with IP allow-lists and SSH keys.&lt;/p&gt;
&lt;p&gt;We could add an extra layer of security into the mix here by not having any inbound network access to the machine. This
limits the discoverability of the service. If you have ever run SSH on a public IP you will be inundated by bots trying
weak username/password combinations.&lt;/p&gt;
&lt;p&gt;This would look like this:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;inbound proxy diagram&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/inbound-proxy.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;an-example-ssh&quot;&gt;An example, SSH&lt;/h4&gt;
&lt;p&gt;So to set up TCP forwarding we can use &lt;code&gt;inlets-pro&lt;/code&gt; and &lt;code&gt;inletsctl&lt;/code&gt;. I will be running through a simple SSH example,
but this could be applied to any of the non-HTTP examples in the same way.&lt;/p&gt;
&lt;p&gt;I’m going to run the client on one of my Raspberry Pi computers with ssh enabled using key pairs only (&lt;a href=&quot;https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2&quot;&gt;here is a Digital Ocean post on setting this up&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Once we are logged into our Pi on our local network we can set up the inlets-pro client to enable ssh access from the IP
of our exit node. We also need to change the default SSH port away from 22, as our exit-node will have ssh mapped to this
port and we won’t be able to use it.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://uk.godaddy.com/help/changing-the-ssh-port-for-your-linux-server-7306&quot;&gt;Here is an article about changing the default ssh port&lt;/a&gt;
I used 2222, and will refer to that from now on.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Set this to the IP of the machine you want to expose on the web&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; RPI_IP&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;192.168.0.99&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;inletsctl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --access-token-file&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; ~/do-token&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --remote-tcp&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $RPI_IP&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives you a command that looks like this to run on our client to forward the traffic&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PORTS&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;2222&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; LICENSE&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;YOUR INLETS_PRO_LICENSE&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;inlets-pro&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; tcp&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; client&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --connect&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;wss://178.62.88.252:8123/connect&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    --token&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;a-long-random-string&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    --license&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; &quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$LICENSE&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;    --ports&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; $PORTS&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We need to forward port &lt;code&gt;2222&lt;/code&gt;, so set this in the &lt;code&gt;PORTS&lt;/code&gt; variable. Don’t forget to set your inlets-pro licence key
too.&lt;/p&gt;
&lt;p&gt;The last step is starting the client on our Raspberry pi. SSH on there from your computer and run the command!&lt;/p&gt;
&lt;p&gt;If we have set up SSH correctly, and everything works as expected we should be able to ssh onto our Pi using the public IP&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;ssh&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -p&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 2222&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi@178.62.88.252&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;ssh in from the public internet&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/rpi-inlets-pro.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;This example should work for any service that uses TCP. You will just need to edit the &lt;code&gt;PORTS&lt;/code&gt; environment variable
and re-run the client command to forward different ports.&lt;/p&gt;
&lt;h2 id=&quot;have-a-go-yourself&quot;&gt;Have a go yourself&lt;/h2&gt;
&lt;p&gt;Check out each of the tools we have looked at on github&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/inlets/inlets-pro-pkg&quot;&gt;inlets-pro&lt;/a&gt; - the TCP tunnel&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/inlets/inletsctl&quot;&gt;inletsctl&lt;/a&gt; - The cli tool we use to speed up provisioning servers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m sure there are loads of other things we could do with this. I would love to hear from you if you have any more great
use cases. &lt;a href=&quot;/contact/&quot;&gt;Get in touch&lt;/a&gt; or find me on &lt;a href=&quot;https://www.linkedin.com/in/alistair-hey/&quot;&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>inlets</category><category>networking</category><category>tunnels</category><category>kubernetes</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>Docker Birmingham January 2020: Multi-Architecture Images with buildx</title><link>https://www.heyal.co.uk/blog/docker-bham-jan/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/docker-bham-jan/</guid><description>From my Docker Birmingham meetup talk: how Docker images and manifests handle CPU architectures, and building images for ARM and x86 with docker buildx.</description><pubDate>Wed, 08 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Every two months a group of us host a meetup focused on Docker. You can find &lt;a href=&quot;https://www.meetup.com/Docker-Birmingham/&quot;&gt;the meetup page here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;seeing-as-i-have-your-attention&quot;&gt;Seeing as I have your attention&lt;/h3&gt;
&lt;p&gt;We are hosting &lt;a href=&quot;https://www.meetup.com/Cloud-Native-Birmingham/events/267773567/&quot;&gt;February’s CNCF Birmingham meetup on Wednesday 5th Feb&lt;/a&gt;
and whilst we haven’t finalised the speakers yet, it looks like it will be a good event! Hopefully we will see you there
too.&lt;/p&gt;
&lt;h2 id=&quot;building-docker-images-for-multiple-architectures&quot;&gt;Building Docker images for multiple architectures&lt;/h2&gt;
&lt;p style=&quot;font-size: 0.9rem;font-style: italic;&quot;&gt;&lt;img style=&quot;display: block;&quot; src=&quot;https://farm3.staticflickr.com/2907/14050434430_c8929e270f_b.jpg&quot; alt=&quot;Raspberry Pi Compute Module&quot;&gt;&lt;a href=&quot;https://www.flickr.com/photos/45703688@N07/14050434430&quot;&gt;&quot;Raspberry Pi Compute Module&quot;&lt;/a&gt;&lt;span&gt; by &lt;a href=&quot;https://www.flickr.com/photos/45703688@N07&quot;&gt;lespounder&lt;/a&gt;&lt;/span&gt; is licensed under &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/2.0/?ref=ccsearch&amp;atype=html&quot; style=&quot;margin-right: 5px;&quot;&gt;CC BY-SA 2.0&lt;/a&gt;&lt;a href=&quot;https://creativecommons.org/licenses/by-sa/2.0/?ref=ccsearch&amp;atype=html&quot; target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; style=&quot;display: inline-block;white-space: none;margin-top: 2px;margin-left: 3px;height: 22px !important;&quot;&gt;&lt;img style=&quot;height: inherit;margin-right: 3px;display: inline-block;&quot; src=&quot;https://search.creativecommons.org/static/img/cc_icon.svg&quot; /&gt;&lt;img style=&quot;height: inherit;margin-right: 3px;display: inline-block;&quot; src=&quot;https://search.creativecommons.org/static/img/cc-by_icon.svg&quot; /&gt;&lt;img style=&quot;height: inherit;margin-right: 3px;display: inline-block;&quot; src=&quot;https://search.creativecommons.org/static/img/cc-sa_icon.svg&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This month, Docker Birmingham’s own Matt Todd was presenting about building docker images for multiple cpu architectures.&lt;/p&gt;
&lt;p&gt;Matt had received a &lt;a href=&quot;https://developer.nvidia.com/embedded/jetson-nano-developer-kit&quot;&gt;Jetson Nano by Nvidia&lt;/a&gt; over the
holidays and wanted to get &lt;a href=&quot;https://www.elastic.co/products/beats/packetbeat&quot;&gt;Elastic’s packetbeat&lt;/a&gt;
set up on his home network to understand what data was flowing about.&lt;/p&gt;
&lt;p&gt;When he went to run the docker container on his new kit it wouldn’t start, the process kept dying. If you have ever tried
running containers on a Raspberry Pi, for example, you might have found that some containers just don’t work, even though
running the same command on your laptop, desktop or cloud instance works first time. This is most likely due to the
different CPU instruction sets, and code has to be compiled differently for the different architectures.&lt;/p&gt;
&lt;h2 id=&quot;docker-images-and-cpu-architectures&quot;&gt;Docker images and CPU Architectures&lt;/h2&gt;
&lt;p&gt;Let’s take the &lt;code&gt;nginx&lt;/code&gt; container for example. If we &lt;a href=&quot;https://hub.docker.com/_/nginx?tab=tags&quot;&gt;look on Dockerhub&lt;/a&gt; at the
latest tag we can see that it is published with multiple different images all pointing at the “latest” tag.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;nginx latest tag dockerhub, multiple arch/os values&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/nginx-os-arch.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is because the maintainers of nginx have built the image for these different architectures all of these are the same
version, same source code, but they have produced different images (the digests are different).&lt;/p&gt;
&lt;h3 id=&quot;docker-cleverness&quot;&gt;Docker cleverness&lt;/h3&gt;
&lt;p&gt;So why does it “just work” when we type &lt;code&gt;docker run --rm -p 8080:80 nginx:latest&lt;/code&gt; on a Pi4(arm64) , our laptops(amd64) or
other computer.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;nginx splash screen&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/nginx-splash.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;The docker daemon basically does a “best effort” to go off to your registry, finds the image you want and matches it to
your specific CPU architecture. So in my case it went off and found this image&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;nginx latest for amd64&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/nginx-latest.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you were running the same command on a Pi, you would have got a different image. The one published for the specific
ARM cpu in your Pi. This image would (well, should) be functionally equivalent to the image pulled by an amd64 computer.&lt;/p&gt;
&lt;h2 id=&quot;how-can-we-build-these-images&quot;&gt;How can we build these images?&lt;/h2&gt;
&lt;p&gt;One common way to support multiple architectures when using docker containers is to publish images with different names
depending on which architecture they are targeting, this is a decent approach if you are using a language which you can
compile, using flags or settings, to create a binary that is specifically tied to one platform. The language I use that
does this is Go. You give it some flags and can build for a whole host of OS and CPU types.&lt;/p&gt;
&lt;p&gt;Matt introduced us to an experimental feature in docker called &lt;a href=&quot;https://docs.docker.com/buildx/working-with-buildx/&quot;&gt;buildx&lt;/a&gt;
which, through the docker cli, provides full access to the features of &lt;a href=&quot;https://github.com/moby/buildkit&quot;&gt;Moby Buildkit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Matt then showed us how, using Docker for Mac, you can enable this experimental feature and use it to create build environments
for a selection of supported architectures. This is provided through the use of an emulator called &lt;a href=&quot;https://www.qemu.org/&quot;&gt;QEMU&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This emulator provides the environments for buildkit to build these different images, all under the same tag, rather than
the first example where we create different image names or tags.&lt;/p&gt;
&lt;h3 id=&quot;using-buildx&quot;&gt;Using buildx&lt;/h3&gt;
&lt;p&gt;I’m not going to show you how to enable buildx, that’s a bit out of scope for this post. We will explore how it can be
used though.&lt;/p&gt;
&lt;p&gt;If we wanted to build this snippet of Go code, which uses the &lt;code&gt;GOOS&lt;/code&gt; and &lt;code&gt;GOARCH&lt;/code&gt; values, which are set at compile time,
to print out the cpu arch and OS we used to compile we could use the commands below.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;go&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;package&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;	&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;fmt&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;	&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;os&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;	&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;runtime&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;func&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt; main&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	hostname, _ &lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;:=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; os.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Hostname&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;	fmt.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;Printf&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;Hello World, I&apos;m &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; running on &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%s&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;/&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;%s\n&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;, hostname, runtime.GOOS, runtime.GOARCH)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To build this using the buildx feature&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# assuming contexts node-amd64 and node-arm64 exist in &quot;docker context ls&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; buildx&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --use&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --name&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mybuild&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; node-amd64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; buildx&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --append&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --name&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; mybuild&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; node-arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# We now have the buildx contexts setup, we can build multiple architectures like this!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;$&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; docker&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; buildx&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; build&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --platform&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; linux/amd64,linux/arm64&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -t&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; dockerbirmingham/hello-world:latest&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Matt did this live, and pushed the following to Dockerhub&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;dockerhub showing multiple images for the same tag&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/dockerhub-multiple-images.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you ran &lt;code&gt;docker run --rm dockerbirmingham/hello-world:latest&lt;/code&gt; on your arm64 computer, you should see it pulled
the arm64 image, and amd64 should have pulled on an amd64 computer!&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;That’s quite neat. It should allow projects building for multiple architectures to build container images more quickly and
with easier use. It’s annoying to have to keep 2 or 3 copies of docker-compose files, or helm charts just because we
pushed images with different names, or tags, for these differences.&lt;/p&gt;
&lt;p&gt;Let’s just hope it makes it into stable, and is well supported on linux (docker for Windows &amp;amp; Mac have it packaged in the
VM they use to run docker). Matt said it was a bit harder to use on Linux because docker runs natively rather than in that
VM.&lt;/p&gt;
&lt;p&gt;Matt will be &lt;a href=&quot;https://github.com/docker-birmingham/multi-architecture-builds&quot;&gt;publishing his slides and dockerfiles etc. here&lt;/a&gt; so you can run
through them for yourself.&lt;/p&gt;
&lt;p&gt;Thanks Matt!&lt;/p&gt;
</content:encoded><category>docker</category><category>multi-arch</category><category>raspberry-pi</category><category>community</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>Civo Kubernetes KUBE100: First Look at Managed k3s</title><link>https://www.heyal.co.uk/blog/civo-my-journey/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/civo-my-journey/</guid><description>What k3s is and how it differs from full Kubernetes, my experience on the beta of Civo&apos;s managed k3s service, contributing to its app marketplace, and other k3s tooling.</description><pubDate>Tue, 07 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;the-worlds-first-managed-k3s&quot;&gt;The World’s First Managed K3s&lt;/h2&gt;
&lt;p&gt;When Civo announced they were looking for Beta testers for their new managed Kubernetes offering I obviously jumped
at the chance. Free compute - never turn that down! (Thanks Civo)&lt;/p&gt;
&lt;h4 id=&quot;kube100&quot;&gt;KUBE100&lt;/h4&gt;
&lt;p&gt;Civo have been running a beta for their offering, it’s called KUBE100, you can request to join &lt;a href=&quot;https://www.civo.com/kube100&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s been great so far, there have been a few teething problems. They have all been resolved well, that’s the point of a
Beta, and Civo have been managing the process really well through a community slack group that you get access to when
you are accepted for the beta.&lt;/p&gt;
&lt;p&gt;Everyone is having a blast, or at least it appears that way, so well done &amp;amp; thanks Civo!&lt;/p&gt;
&lt;h4 id=&quot;civo-cli&quot;&gt;Civo cli&lt;/h4&gt;
&lt;p&gt;Civo provide a cli to manage clusters (as well as their other services). It’s great, works well and is even packaged in a
docker container for those of us who don’t have Ruby installed. With this it is easy to get the status of clusters, create
new ones and even install marketplace apps.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Civo CLI image&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-cli.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;what-is-k3s&quot;&gt;What is K3s?&lt;/h3&gt;
&lt;p&gt;According to Rancher, who took Kubernetes and made it smaller, it’s a “Certified Kubernetes distribution built for IoT &amp;amp;
Edge computing”. You can check out the &lt;a href=&quot;https://k3s.io&quot;&gt;k3s web page here&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;What does this actually mean though? Well, it is small, really small. The master node process runs in under 500mb ram, and
worker nodes about 50mb. It’s packaged for ARM64 and ARMv7 (think Raspberry Pi) and you can easily build installation
scripts (or tools) that can detect the CPU architecture. This allows you to spin up clusters on anything from your home
raspberry pis to large bare-metal servers.&lt;/p&gt;
&lt;p&gt;It’s fast. Civo can spin up a k3s cluster for you in under 2 minutes. We will explore more on this later.&lt;/p&gt;
&lt;p&gt;Rancher do a better job at explaining all of the features and benefits in the &lt;a href=&quot;https://docs.k3s.io/&quot;&gt;docs&lt;/a&gt;.
We won’t dwell on this much more here; there are lots of great resources on this already.&lt;/p&gt;
&lt;h3 id=&quot;how-is-k3s-different-from-k8s&quot;&gt;How is k3s different from k8s?&lt;/h3&gt;
&lt;p&gt;That’s a good question. Don’t immediately expect that you can deploy your application onto k3s without having to do some
extra work. If you’re coming from a managed kubernetes service provided by one of the large cloud providers you get a
lot of integrations out of the box.&lt;/p&gt;
&lt;p&gt;For example, the first thing I did was to install the &lt;a href=&quot;https://docs.gitlab.com/charts/&quot;&gt;gitlab helm chart&lt;/a&gt;, which sat in
pending forever. This is because there was no default storage provider for the persistent volumes required by many apps.
Not to worry though, Civo provide a 1 click &lt;a href=&quot;https://www.civo.com/learn/cloud-native-stateful-storage-for-kubernetes-with-rancher-labs-longhorn&quot;&gt;Longhorn installation&lt;/a&gt;
which can provide the persistent volumes required.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;civo marketplace screenshot&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-longhorn.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Andy Jeffries, the Civo CTO wrote a good blog post on &lt;a href=&quot;https://www.civo.com/blog/k8s-vs-k3s&quot;&gt;K8s vs k3s&lt;/a&gt; which is well
worth a read if you have the time.&lt;/p&gt;
&lt;h2 id=&quot;the-civo-community&quot;&gt;The Civo Community&lt;/h2&gt;
&lt;p&gt;I mentioned the Civo slack earlier, which is great for asking questions about their k3s offering, but it has delivered much
more than just a beta support channel to Civo. I have seen the group help each other out more times than I could count.
Civo have done a great job of engaging the developers that have offered to beta test the service.&lt;/p&gt;
&lt;p&gt;This makes sense, there’s a large section on their website about how they are community focused. This doesn’t always
mean that companies with this attitude actually follow through on this and deliver their vision.&lt;/p&gt;
&lt;p&gt;Civo have definitely focused on this, and you can tell.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;civo website community section&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-community.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;features-provided-by-civo&quot;&gt;Features provided by Civo&lt;/h2&gt;
&lt;p&gt;The managed k3s service provided by Civo is great, here are my highlights:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Marketplace apps&lt;/li&gt;
&lt;li&gt;DNS entry for master node, for when your nodes are recycled&lt;/li&gt;
&lt;li&gt;Civo CLI&lt;/li&gt;
&lt;li&gt;Speed of cluster creation&lt;/li&gt;
&lt;li&gt;Clean and friendly Web UI&lt;/li&gt;
&lt;li&gt;Their constant stream of &lt;a href=&quot;https://www.civo.com/blog&quot;&gt;blog posts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Their promotion of &lt;a href=&quot;https://www.civo.com/blog/kube100-so-far#learn-guides-and-content&quot;&gt;community content&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;openfaas-cloud&quot;&gt;OpenFaaS Cloud&lt;/h2&gt;
&lt;p&gt;My main use for Civo’s managed k3s is a platform to deploy and develop &lt;a href=&quot;https://github.com/openfaas/openfaas-cloud&quot;&gt;OpenFaaS Cloud&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;OpenFaaS cloud is a self-hosted PaaS for serverless, with built in CI&amp;amp;CD, dashboards and Git Flow.
Here are the main Features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Portable - self-host or use the hosted Community Cluster (SaaS)&lt;/li&gt;
&lt;li&gt;Multi-user - use your GitHub/GitLab identity to log into your personal dashboard&lt;/li&gt;
&lt;li&gt;Automates CI/CD triggered by git push (also known as GitOps)&lt;/li&gt;
&lt;li&gt;Onboard new git repos with a single click by adding the GitHub App or a repository tag in GitLab&lt;/li&gt;
&lt;li&gt;Immediate feedback on your personal dashboard and through GitHub Checks or GitLab Statuses&lt;/li&gt;
&lt;li&gt;Sub-domain per user or organization with HTTPS&lt;/li&gt;
&lt;li&gt;Runtime-logs for your functions&lt;/li&gt;
&lt;li&gt;Fast, non-root image builds using buildkit from Docker&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I have been contributing to OpenFaaS Cloud and needed a place to run, test and develop my new features. I used Civo’s
service to deploy my changes when I implemented runtime logs in OpenFaaS Cloud, you can see them here&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Runtime logs&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/runtime-logs.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;get-involved&quot;&gt;Get involved!&lt;/h4&gt;
&lt;p&gt;The dashboard is written in React, if anyone is interested in contributing you can reach out through &lt;a href=&quot;https://docs.openfaas.com/community/&quot;&gt;the OpenFaaS community&lt;/a&gt;. There’s also lots of Golang code involved, if you
are more comfortable with that.&lt;/p&gt;
&lt;h2 id=&quot;i-contributed-to-their-app-installers&quot;&gt;I contributed to their App installers&lt;/h2&gt;
&lt;p&gt;Their kubernetes app installers are open source. When someone on slack noticed that the postgres app wasn’t working
I pulled down the &lt;a href=&quot;https://github.com/civo/kubernetes-marketplace&quot;&gt;github repository&lt;/a&gt; that contains the apps and
committed a fix. This was swiftly merged and released to production, where several other people created clusters and
verified that the app worked.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Civo PR&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-pr.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;I didn’t write the initial implementation but it was easy enough to get involved and fix the issue. Thanks to the Civo
team for getting it merged and released so quickly!&lt;/p&gt;
&lt;h2 id=&quot;that-issue-andy-fixed-while-at-kubecon&quot;&gt;That issue Andy fixed while at Kubecon&lt;/h2&gt;
&lt;p&gt;There was an issue that seemed to be affecting my account’s ability to spin up new clusters. I mentioned that I was having
problems on the Civo slack. I needed a cluster to deploy a new OpenFaaS Cloud installation that I was testing. I was deep
in flow and wanted a cluster quickly, I turned to one of the other providers of managed kubernetes (who shall remain nameless).&lt;/p&gt;
&lt;p&gt;Before that new cluster had finished building &lt;a href=&quot;https://twitter.com/andyjeffries&quot;&gt;Andy from Civo&lt;/a&gt; had, from his chair at
Kubecon, tracked down the issue, added code, tested his fix and deployed it into production. I was even able to spin up
a new cluster and connect using kubectl before my backup cluster was ready. That’s fast… real fast. I owe Andy a drink
for that.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/alistair_hey/status/1197601237505650688&quot;&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;twitter image Andy fixing an issue FAST!&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-andy-tweet.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;the-magic-recipe&quot;&gt;The magic recipe?&lt;/h2&gt;
&lt;h4 id=&quot;people&quot;&gt;People&lt;/h4&gt;
&lt;p&gt;From where I sit, as a user, Civo have an amazing team. Everyone is helpful, knowledgeable and committed. They also have
a great sense of humour, take the title image for this blog for example.&lt;/p&gt;
&lt;p&gt;They got those cards printed for me and mailed them to me after the Kubecon fix. We were having a joke about a job title
with as many toxic recruiter buzzwords as possible. They seem to have jammed a lot onto that small business
card. Well done…&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;civo-stickers&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-card.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;If a team are working together in this way then they can do great things! Good luck guys.&lt;/p&gt;
&lt;h4 id=&quot;community&quot;&gt;Community&lt;/h4&gt;
&lt;p&gt;Civo, as I have mentioned, are smashing this community thing. Keep it up!&lt;/p&gt;
&lt;p&gt;It’s great to see their engagement with the community. This is a great way for them to improve the state of Cloud Native,
a space that is rapidly expanding and where they are providing some great content, resources and products.&lt;/p&gt;
&lt;h2 id=&quot;other-cool-k3s-projects-and-tooling&quot;&gt;Other cool k3s projects and tooling&lt;/h2&gt;
&lt;p&gt;It wouldn’t be right not to mention some of the other tools I’m finding really useful in this space.&lt;/p&gt;
&lt;h4 id=&quot;k3sup&quot;&gt;k3sup&lt;/h4&gt;
&lt;p&gt;If you want to quickly spin up k3s clusters on your own hardware you can use &lt;a href=&quot;https://github.com/alexellis/k3sup&quot;&gt;k3sup&lt;/a&gt;. It’s
maintained by &lt;a href=&quot;https://twitter.com/alexellisuk&quot;&gt;Alex Ellis&lt;/a&gt; and has contributions from loads of other people (including
myself).&lt;/p&gt;
&lt;p&gt;I can create a new k3s cluster with just 3 commands:&lt;/p&gt;
&lt;p&gt;First install a master k3s node like this:&lt;br&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3sup&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.10&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then join the two workers:&lt;br&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3sup&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; join&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.20&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --server-ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.10&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3sup&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; join&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.30&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --server-ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.10&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h4 id=&quot;arkade&quot;&gt;Arkade&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://get-arkade.dev&quot;&gt;arkade&lt;/a&gt; is a kubernetes app installer, it can be used to quickly install apps with a set of default config, maintained
by Alex Ellis&lt;/p&gt;
&lt;p&gt;Install it by following the instructions in the GitHub README, then install some applications on your new cluster:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; openfaas&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; cert-manager&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;arkade&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; postgresql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s that easy!&lt;/p&gt;
&lt;h4 id=&quot;k3d&quot;&gt;k3d&lt;/h4&gt;
&lt;p&gt;Rancher love containers, and k3s is no exception. There is a tool called &lt;a href=&quot;https://github.com/rancher/k3d&quot;&gt;k3d&lt;/a&gt; that
builds k3s clusters in docker containers. It’s great for testing out stuff, then deleting the clusters once you’re done.
Quick, easy, no fuss.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Create a cluster&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Connect to it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; KUBECONFIG&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;$(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get-kubeconfig &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;--name=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;k3s-default&apos;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; nodes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Remove your cluster &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; delete&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I used k3d a lot. If you have not used it then give it a try!&lt;/p&gt;
&lt;h2 id=&quot;thanks-for-reading&quot;&gt;Thanks for reading!&lt;/h2&gt;
&lt;p&gt;If you need help with a cloud native platform or migration, &lt;a href=&quot;/contact/&quot;&gt;get in touch&lt;/a&gt;.&lt;/p&gt;
</content:encoded><category>kubernetes</category><category>k3s</category><category>civo</category><category>open-source</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>How To Get Started Contributing to OpenFaaS</title><link>https://www.heyal.co.uk/blog/developing-openfaas/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/developing-openfaas/</guid><description>A step-by-step guide to your first OpenFaaS contribution: setting up Go, Docker and Kubernetes, finding an issue, forking the repository, and opening a pull request.</description><pubDate>Sat, 04 Jan 2020 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;new-year-new-you&quot;&gt;New Year New You?&lt;/h2&gt;
&lt;p&gt;Don’t bother with the Gym. We all know you won’t keep it up.&lt;/p&gt;
&lt;p&gt;Why not give back to the programming community by contributing to an open source project that you use?&lt;/p&gt;
&lt;p&gt;When I first started out it took me a while to get my IDE set up, all the dependencies installed and then once
I had this set up, picking a github issue and getting through the Pull Request (PR) process also seemed daunting. This
still felt like a big deal even though I raise many PRs a day at work and push code into production frequently.
For some reason this “open” and new space felt very exposed.&lt;/p&gt;
&lt;p&gt;Fortunately, I was helped through the process by &lt;a href=&quot;https://github.com/alexellis&quot;&gt;Alex&lt;/a&gt;, who was always helpful and
patient with my early contributions.&lt;/p&gt;
&lt;p&gt;This post focuses mainly on code contributions. There are other types of contributions that are just as important and
would be welcomed. Things like documentation, user guides, blog posts and helping members of the community on slack.&lt;/p&gt;
&lt;p&gt;There’s a good section in the &lt;a href=&quot;https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md&quot;&gt;OpenFaaS docs&lt;/a&gt; on contributing too.&lt;/p&gt;
&lt;h4 id=&quot;maintainers-are-amazing&quot;&gt;Maintainers are amazing!&lt;/h4&gt;
&lt;p&gt;Maintaining an open source project is hard, time consuming and often done for free. There are a load of great resources
on the internet about the things maintainers face.&lt;/p&gt;
&lt;p&gt;It might be worth you doing a small amount of reading into this, so you know what to expect from a maintainer, and what
they expect from your contribution(s).&lt;/p&gt;
&lt;p&gt;Here are some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://danielbachhuber.com/2015/06/26/my-condolences-youre-now-the-maintainer-of-a-popular-open-source-project/&quot;&gt;My condolences, you’re now the maintainer of a popular open source project&lt;/a&gt; - Daniel Bachhuber&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.alexellis.io/the-5-pressures-of-leadership/&quot;&gt;The Five Pressures of Leadership&lt;/a&gt; - Alex Ellis&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://twitter.com/balupton/status/438928812185620480&quot;&gt;This twitter thread&lt;/a&gt; - Benjamin Lupton&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setting-up-golang&quot;&gt;Setting up Golang&lt;/h2&gt;
&lt;p&gt;OpenFaaS is almost exclusively written in Golang. If you’re not a strong Golang developer don’t worry, it’s quite easy to
pick up. However, there are other contributions you could make to get started, then ease yourself into Golang at a later
date.&lt;/p&gt;
&lt;p&gt;I like using the Goland IDE by JetBrains, but you can use VSCode or any other IDE that has Golang support, or even Vim/Emacs.&lt;/p&gt;
&lt;h3 id=&quot;to-install-golang&quot;&gt;To install Golang&lt;/h3&gt;
&lt;p&gt;Install Go from &lt;a href=&quot;https://go.dev/dl/&quot;&gt;go.dev&lt;/a&gt; or with your package manager, which should sort everything out for you.&lt;/p&gt;
&lt;p&gt;You probably want to add these lines to your .bashrc or .zshrc so that &lt;code&gt;go&lt;/code&gt; is available in new terminals and after you
reboot.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; GOPATH&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$HOME/go/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; PATH&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;$PATH:/usr/local/go/bin/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code&gt;go version&lt;/code&gt; prints a version, Go is set up correctly.&lt;/p&gt;
&lt;h2 id=&quot;docker--kubernetes&quot;&gt;Docker &amp;amp; Kubernetes&lt;/h2&gt;
&lt;p&gt;You will probably need access to Docker and Kubernetes while writing contributions to OpenFaaS. You can install
Docker by following one of the many online guides.&lt;/p&gt;
&lt;p&gt;If you are using Kubernetes you will need to install &lt;code&gt;kubectl&lt;/code&gt;. Best check online for the most up to date installation
method for your Operating System.&lt;/p&gt;
&lt;p&gt;I usually use a tool called &lt;a href=&quot;https://github.com/rancher/k3d&quot;&gt;k3d&lt;/a&gt; for creating Kubernetes environments, it creates a
single node k3s cluster (Kubernetes compliant) inside a docker container.&lt;/p&gt;
&lt;p&gt;Once you have these tools installed you can create, connect to and delete kubernetes clusters like this&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Create a cluster&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; create&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Connect to it&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; KUBECONFIG&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&quot;$(&lt;/span&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get-kubeconfig &lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt;--name=&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;&apos;k3s-default&apos;)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;kubectl&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; nodes&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# Remove your cluster &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3d&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; delete&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You should now have the tools to deploy an OpenFaaS installation quickly, and reset things when you need a fresh start.&lt;/p&gt;
&lt;h2 id=&quot;finding-an-issue-to-work-on&quot;&gt;Finding an issue to work on&lt;/h2&gt;
&lt;p&gt;The best way to find something to work on is to look through the various OpenFaaS Repositories for issues that have the
&lt;code&gt;help wanted&lt;/code&gt; or &lt;code&gt;good first issue&lt;/code&gt; type labels.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/openfaas/faas/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22&quot;&gt;This search&lt;/a&gt; should show
Issues in the main &lt;code&gt;openfaas/faas&lt;/code&gt; repository that have the &lt;code&gt;help wanted&lt;/code&gt; label.&lt;/p&gt;
&lt;p&gt;There are loads of other moving parts of OpenFaaS ecosystem and projects maintained by Alex from OpenFaaS that have
various open issues, some good places to look are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openfaas/faas-cli/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22&quot;&gt;faas-cli&lt;/a&gt; The OpenFaaS CLI&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openfaas/openfaas-cloud/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22&quot;&gt;OpenFaaS Cloud&lt;/a&gt; (OFC)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openfaas-incubator/ofc-bootstrap/issues&quot;&gt;ofc-bootstrap&lt;/a&gt; a tool for provisioning OFC Clusters&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openfaas/openfaas.github.io/issues&quot;&gt;openfaas.github.io&lt;/a&gt; The OpenFaaS Website&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/alexellis/k3sup/issues&quot;&gt;k3sup&lt;/a&gt; A tool by Alex for bootstrapping k3s clusters&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openfaas/faas-netes/issues&quot;&gt;faas-netes&lt;/a&gt; The Kubernetes specific components to OpenFaaS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And many, many more…&lt;/p&gt;
&lt;p&gt;You can look in the &lt;a href=&quot;https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md#how-can-i-get-involved&quot;&gt;contributing guide&lt;/a&gt;
at what types of things you can get involved with&lt;/p&gt;
&lt;p&gt;If in doubt, reach out to &lt;a href=&quot;https://docs.openfaas.com/community/&quot;&gt;the OpenFaaS community&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;forking-the-repository&quot;&gt;Forking the repository&lt;/h2&gt;
&lt;p&gt;To get started contributing you need to create your own copy of the repository you want to contribute to.&lt;/p&gt;
&lt;p&gt;So, login to Github, and find the repository you are looking to contribute to then click the “fork” button.&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Fork a github repository&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/github-fork.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;creating-a-branch-and-committing-your-code&quot;&gt;Creating a branch and committing your code&lt;/h2&gt;
&lt;p&gt;Once you have &lt;a href=&quot;https://help.github.com/en/github/getting-started-with-github/fork-a-repo&quot;&gt;cloned your fork&lt;/a&gt; to your
computer you need to create a branch for you to work on.&lt;/p&gt;
&lt;p&gt;You can do this by typing &lt;code&gt;git checkout -b &amp;lt;branch name&amp;gt;&lt;/code&gt;. This creates your local branch to work on.&lt;/p&gt;
&lt;p&gt;Once you have written your contribution and written tests (if a code change) and tested the change manually you should
commit your code,&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; add&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt; &amp;lt;&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt;files&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; you&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; have&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; changed&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; or&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; adde&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt;d&lt;/span&gt;&lt;span style=&quot;color:#D73A49;--shiki-dark:#F97583&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D;--shiki-dark:#6A737D&quot;&gt;# then &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;git&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; commit&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; -s&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This should open a commit window in your chosen editor (Vim by default)
In this file you should write the title, leave a blank line and then a description.
&lt;a href=&quot;https://chris.beams.io/posts/git-commit/&quot;&gt;This is a good blog about commit messages&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Your IDE may also provide a mechanism to commit not using the command line, so feel free to use whatever you’re most
comfortable with&lt;/p&gt;
&lt;h2 id=&quot;opening-your-pr&quot;&gt;Opening your PR&lt;/h2&gt;
&lt;p&gt;Before you open a PR on github you should read the &lt;a href=&quot;https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md&quot;&gt;OpenFaaS Contributing guidelines&lt;/a&gt;.
This is a requirement for opening a PR against OpenFaaS, and you have to check a box to confirm you have read it.&lt;/p&gt;
&lt;p&gt;Once you have finished, you need to open a Pull Request (PR) on github.&lt;/p&gt;
&lt;p&gt;Find your fork (copy of the repository) and then go to branches page. From here there’s a “New pull request” button.&lt;/p&gt;
&lt;p&gt;You will probably find a “pull request template”, a list of questions you need to answer, like why you have made this
change, how it’s been tested and the impact of the change on existing users.&lt;/p&gt;
&lt;p&gt;If you are creating a PR that “closes” an issue then you can add &lt;code&gt;Closes #&amp;lt;Issue Number&amp;gt;&lt;/code&gt; in the box and github will
close that issue when the PR is merged!&lt;/p&gt;
&lt;p&gt;Fill in the questions inside the pull request box and submit!
&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;PR Template image&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/pr-template.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;thats-it&quot;&gt;That’s it&lt;/h2&gt;
&lt;p&gt;After you have raised your PR someone should take a look at it, provide feedback or suggestions and let you know the
next steps. You may need to make a change, update some docs or re-word commit messages.&lt;/p&gt;
&lt;p&gt;You might also want to let &lt;a href=&quot;https://docs.openfaas.com/community/&quot;&gt;the OpenFaaS community&lt;/a&gt; know about it.&lt;/p&gt;
&lt;h3 id=&quot;check-this-out&quot;&gt;Check this out&lt;/h3&gt;
&lt;p&gt;Alex Ellis, the maintainer of OpenFaaS did a call in early 2019 about contributing, you can find the recording here&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=kOgHjU38Efg&amp;amp;feature=youtu.be&quot;&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Contributing image&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/how-to-contribute.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/a&gt;&lt;/p&gt;
</content:encoded><category>openfaas</category><category>serverless</category><category>open-source</category><category>go</category><category>kubernetes</category><author>sales@heyal.co.uk (Alistair Hey)</author></item><item><title>My 2019 In Review - Hello Open Source!</title><link>https://www.heyal.co.uk/blog/my-2019/</link><guid isPermaLink="true">https://www.heyal.co.uk/blog/my-2019/</guid><description>Looking back at 2019: 75+ pull requests to OpenFaaS and OpenFaaS Cloud, k3sup, Birmingham meetups and events, and my plans for 2020.</description><pubDate>Mon, 30 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2 id=&quot;openfaas-and-openfaas-cloud-contributions&quot;&gt;OpenFaaS and OpenFaaS Cloud Contributions&lt;/h2&gt;
&lt;p&gt;In October I started contributing to the OpenFaaS project. It started out as a bugfix here, a documentation change there
and it has expanded into 75+ PRs. Not all my contributions were in the OpenFaaS org, but I still managed to get to 15th most contributions in the 12 weeks I have been involved.&lt;/p&gt;
&lt;p&gt;I was even given the chance to present some of my work on the OpenFaaS community call
&lt;a href=&quot;https://www.youtube.com/watch?v=wXnYx-wD4Zk&quot;&gt;which you can watch on Youtube&lt;/a&gt; (I’m presenting from about 50 minutes in).&lt;/p&gt;
&lt;p&gt;Probably my largest impact has been in adding features and fixing issues in the
&lt;a href=&quot;https://github.com/openfaas/openfaas-cloud&quot;&gt;OpenFaaS Cloud project&lt;/a&gt; (OFC).&lt;/p&gt;
&lt;p&gt;If I had to pick one feature that I implemented to show you it would be the addition of Runtime logs to the OpenFaaS
Cloud dashboard. This means users can view their logs directly from the UI, reducing the time taken to debug and making
it easier to focus on their code. It looks a little like this:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;runtime logs in OpenFaaS Cloud dashboard&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/runtime-logs.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Other things I have done:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Upgraded OFC cert-manager version to 0.11.0&lt;/li&gt;
&lt;li&gt;Added a splash screen to the OFC dashboard for new users to learn more about OpenFaaS and OpenFaaS Cloud&lt;/li&gt;
&lt;li&gt;Added validation for the Registry config file and a command to generate it (In the &lt;a href=&quot;https://github.com/openfaas-incubator/ofc-bootstrap&quot;&gt;ofc-bootstrap tool&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Users can now only see their own OFC dashboards &amp;amp; function information (validating a user has claims for the information they are trying to view)&lt;/li&gt;
&lt;li&gt;Migrated Kubernetes YAML manifests to 1.16&lt;/li&gt;
&lt;li&gt;Added frontend (Gateway) support for the new multi-namespace feature in OpenFaaS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There’s a great community around OpenFaaS; &lt;a href=&quot;https://docs.openfaas.com/community/&quot;&gt;find out how to join here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;k3sup&quot;&gt;k3sup&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/alexellisuk&quot;&gt;Alex Ellis&lt;/a&gt; has created &lt;a href=&quot;https://k3sup.dev&quot;&gt;this amazing tool&lt;/a&gt; to provision k3s clusters and manage the
installation of various Kubernetes apps and tools. With a few commands you can provision a new cluster, install
OpenFaaS and set up TLS ingress. There are a load of other supported apps. I made a few small contributions to k3sup,
which was fun!&lt;/p&gt;
&lt;p&gt;I had a few spare RPi boards (Or other compute) with IPs of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;192.168.0.10&lt;/li&gt;
&lt;li&gt;192.168.0.20&lt;/li&gt;
&lt;li&gt;192.168.0.30&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I created a new k3s cluster with just 3 commands:&lt;/p&gt;
&lt;p&gt;First install a master k3s node like this:&lt;br&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3sup&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; install&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.10&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi&lt;/span&gt;&lt;span style=&quot;color:#24292E;--shiki-dark:#E1E4E8&quot;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then join the two workers:&lt;br&gt;&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light github-dark&quot; style=&quot;background-color:#fff;--shiki-dark-bg:#24292e;color:#24292e;--shiki-dark:#e1e4e8; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;sh&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3sup&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; join&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.20&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --server-ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.10&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1;--shiki-dark:#B392F0&quot;&gt;k3sup&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; join&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.30&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --server-ip&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; 192.168.0.10&lt;/span&gt;&lt;span style=&quot;color:#005CC5;--shiki-dark:#79B8FF&quot;&gt; --user&lt;/span&gt;&lt;span style=&quot;color:#032F62;--shiki-dark:#9ECBFF&quot;&gt; pi&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This leaves me with a 3 node cluster&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Cluster nodes&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/k3s-nodes.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;It’s really cool and you can &lt;a href=&quot;https://github.com/alexellis/k3sup&quot;&gt;check it out here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;birmingham-uk-meetups-and-events&quot;&gt;Birmingham (UK) Meetups and Events&lt;/h2&gt;
&lt;h4 id=&quot;docker--cloud-native&quot;&gt;Docker &amp;amp; Cloud Native&lt;/h4&gt;
&lt;p&gt;This year I co-organised monthly &lt;a href=&quot;https://www.meetup.com/Docker-Birmingham&quot;&gt;Docker&lt;/a&gt; &amp;amp; &lt;a href=&quot;https://www.meetup.com/Cloud-Native-Birmingham/&quot;&gt;Cloud native&lt;/a&gt; meetups.
We had some great speakers come along, as well as talks from the organisers. You can check out the past meetups by
following the links.&lt;/p&gt;
&lt;h4 id=&quot;coffeeops&quot;&gt;CoffeeOps&lt;/h4&gt;
&lt;p&gt;In September a group of us from Birmingham went to &lt;a href=&quot;https://devopsdays.org/events/2019-london/welcome/&quot;&gt;DevOpsDays London 2019&lt;/a&gt;.
On the morning of the Friday some people attended a one-off &lt;a href=&quot;http://www.coffeeops.org/&quot;&gt;CoffeeOps&lt;/a&gt; organised and run by
&lt;a href=&quot;https://twitter.com/sigje&quot;&gt;Jennifer Davis&lt;/a&gt; and they loved the format so much that we decided to run a weekly meetup on
Tuesdays from 0730 to 0900 in &lt;a href=&quot;https://urbanemporiums.com/church-street/&quot;&gt;Urban Coffee&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Every week a group of us get together to talk about Dev, Ops and Technology in general. We have seen a good turnout (14 at max).&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;CoffeeOps meetup&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/coffe-ops.jpeg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;devopsdays-birmingham-2021&quot;&gt;DevOpsDays Birmingham 2021&lt;/h4&gt;
&lt;p&gt;We loved DevOpsDays London SO MUCH that we decided that Birmingham needed to organise its own.&lt;/p&gt;
&lt;p&gt;So five of us have got together and booked a venue for &lt;a href=&quot;https://devopsdays.org/events/2021-birmingham/contact&quot;&gt;Birmingham’s first DevOpsDays&lt;/a&gt;,
in early 2021.&lt;/p&gt;
&lt;h4 id=&quot;tech-birmingham&quot;&gt;Tech Birmingham&lt;/h4&gt;
&lt;p&gt;As we found ourselves in the business of organising a large multi-day conference, we thought it would be a good idea to
get some practice in.&lt;/p&gt;
&lt;p&gt;Between us we organise half a dozen meetups in Birmingham. We usually all individually host our own “Christmas” event,
but this year we decided that we would try and raise some sponsorship and put on a larger event with the idea of
bringing people together who might not normally mingle.&lt;/p&gt;
&lt;p&gt;We were able to provide a free alcoholic drink (or 2 non-alcoholic) and mountains of pizza. Over 90 people were scanned
in by us at the venue!&lt;/p&gt;
&lt;p&gt;We hosted on the 12th December in a Pinball bar in Birmingham:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Tilt birmingham&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/tilt.jpeg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;We got sponsorship from these amazing companies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://blackcatsolutions.co.uk/&quot;&gt;Black Cat Solutions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.civo.com/&quot;&gt;Civo Cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://siliconcanal.co.uk/&quot;&gt;Silicon Canal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.wearespinks.com/&quot;&gt;Spinks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;other-things&quot;&gt;Other Things&lt;/h2&gt;
&lt;h4 id=&quot;civo-cloud-sent-me-some-personalised-business-cards-as-a-joke&quot;&gt;Civo cloud sent me some personalised business cards as a joke&lt;/h4&gt;
&lt;p&gt;I have been using Civo Cloud’s Kubernetes service as a Beta tester, and have been finding a few little issues here and
there. They thought it would be funny to send me some business cards with a made-up job title.
&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Civo Cloud fake business card&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/civo-card.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;alex-ellis-sent-me-some-swag&quot;&gt;Alex Ellis sent me some swag&lt;/h4&gt;
&lt;p&gt;After my first few contributions to OpenFaaS Alex sent me a personalised note and an OpenFaaS Mug!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;OpenFaaS Mug&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/openfaas-mug.jpg&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/p&gt;
&lt;h4 id=&quot;i-wrote-a-tweet-people-seemed-to-like-it&quot;&gt;I wrote a tweet, people seemed to like it!&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/alistair_hey/status/1203366386963243013&quot;&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;quot;alt&amp;quot;:&amp;quot;Inlets Tweet&amp;quot;,&amp;quot;src&amp;quot;:&amp;quot;../../assets/blog/inlets-tweet.png&amp;quot;,&amp;quot;index&amp;quot;:0}&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;my-2020-plans&quot;&gt;My 2020 Plans&lt;/h2&gt;
&lt;h4 id=&quot;work&quot;&gt;Work&lt;/h4&gt;
&lt;p&gt;I left my job at the end of this year to start my own consulting company. This means my January is going to be very
interesting!&lt;/p&gt;
&lt;p&gt;I’m focusing on Cloud Native platform engineering, building DevOps cultures and empowering teams to deliver more value to
their customers!&lt;/p&gt;
&lt;p&gt;If you think we might be able to work together to build great things then get in touch.&lt;/p&gt;
&lt;h4 id=&quot;tech-community&quot;&gt;Tech Community&lt;/h4&gt;
&lt;p&gt;I’m going to be mentoring for the &lt;a href=&quot;https://www.schoolofcode.co.uk/&quot;&gt;School of Code&lt;/a&gt;, a free 16 week bootcamp run in
Birmingham. I think they are always on the lookout for mentors and guest speakers. If you are interested you can contact
them via their website.&lt;/p&gt;
&lt;p&gt;I’m going to be continuing to run the Docker, CNCF and CoffeeOps meetups in birmingham. Alongside these I’m looking to
write more talks and then give these outside Birmingham. I have given talks in Nottingham and Bristol so far.&lt;/p&gt;
&lt;h4 id=&quot;open-source&quot;&gt;Open Source&lt;/h4&gt;
&lt;p&gt;I have no plans to scale back my Open Source contributions. I have really enjoyed being part of the OpenFaaS community
and being able to see my efforts have an impact.&lt;/p&gt;
&lt;p&gt;If you were considering getting into OpenSource but are not sure where to start I would be happy to have a chat, and
guide you through your first contributions! It’s great fun and very rewarding!&lt;/p&gt;
&lt;h2 id=&quot;have-a-great-2020&quot;&gt;Have a great 2020&lt;/h2&gt;
&lt;p&gt;Thanks for taking the time to read my blog. Hope you had a good year too!&lt;/p&gt;
&lt;p&gt;It would be great to connect with more people, so feel free to &lt;a href=&quot;/contact/&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;
</content:encoded><author>sales@heyal.co.uk (Alistair Hey)</author></item></channel></rss>