<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>howardjohn&#39;s blog</title>
    <link>https://blog.howardjohn.info/</link>
    <description>Recent content on howardjohn&#39;s blog</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 12 May 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://blog.howardjohn.info/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>The hidden cost of mpsc channels</title>
      <link>https://blog.howardjohn.info/posts/mpsc-cost/</link>
      <pubDate>Tue, 12 May 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/mpsc-cost/</guid>
      <description>&lt;p&gt;Recently I have been spending a lot of time analyzing and optimizing memory usage in our Rust reverse-proxy, &lt;a href=&#34;https://agentgateway.dev/&#34;&gt;agentgateway&lt;/a&gt;.
One thing that repeatedly came up was a surprisingly large amount of memory allocated to innocent-looking Tokio &lt;code&gt;mpsc&lt;/code&gt; channels.&lt;/p&gt;
&lt;p&gt;In my naive understanding, I would have assumed the following allocation pattern:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;BigStruct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;data&lt;/span&gt;: &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;u8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;main&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Allocates ~1024 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tokio&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;sync&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;mpsc&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;channel&lt;/span&gt;::&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigStruct&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Allocates ~1024*1024 bytes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;tokio&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;sync&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;mpsc&lt;/span&gt;::&lt;span class=&#34;n&#34;&gt;channel&lt;/span&gt;::&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;BigStruct&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1024&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;However, in practice both of these are wrong: they each allocate 32kb!&lt;/p&gt;</description>
    </item>
    <item>
      <title>Better Kubernetes CRD Docs</title>
      <link>https://blog.howardjohn.info/posts/better-crd-docs/</link>
      <pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/better-crd-docs/</guid>
      <description>&lt;p&gt;When trying to use any Kubernetes CRD (or even core types) I am pretty much always pulling up a reference doc of some sort to see what fields are available and what they do.
However, I have pretty much always found the options for this to be pretty bad.
To remedy this, I have been working on a new tool that automatically generates documentation for Kubernetes CRDs, and I wanted to share it here.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Envoy Quirks Part 2: Filter Chain Match</title>
      <link>https://blog.howardjohn.info/posts/envoy-gotcha-2-filter-chain-match/</link>
      <pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/envoy-gotcha-2-filter-chain-match/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part two of a series.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.howardjohn.info/posts/envoy-gotcha-1-clear-route-cache/&#34;&gt;Envoy Quirks Part 1: Clear Route Cache&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Envoy Quirks Part 2: Filter Chain Match&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;One of Envoy&#39;s core features is, of course, its ability to match traffic and route it to the appropriate destination.
This is done at two levels generally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Filter Chain Matches define the top level matching of traffic, matching on attributes of the TCP and TLS handshake like port and SNI.&lt;/li&gt;
&lt;li&gt;Route Matches define the matching of HTTP traffic, matching on attributes of the HTTP request like path and headers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Filter chain matchers are notoriously tricky to get right, and have become a sort of rite of passage for Envoy users to learn how to use them correctly.
Lets dig in.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Fast GitHub Actions with Blacksmith</title>
      <link>https://blog.howardjohn.info/posts/blacksmith-gha/</link>
      <pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/blacksmith-gha/</guid>
      <description>&lt;p&gt;After years of working on a project running our own testing infrastructure, I have been working on &lt;a href=&#34;https://agentgateway.dev/&#34;&gt;Agentgateway&lt;/a&gt; utilizing the free GitHub Actions runners.&lt;/p&gt;
&lt;p&gt;While the free tier is quite generous, the performance is... not.
As someone who has spent &lt;a href=&#34;https://blog.howardjohn.info/posts/docker-builds/&#34;&gt;a&lt;/a&gt; &lt;a href=&#34;https://blog.howardjohn.info/posts/go-build-times/&#34;&gt;lot&lt;/a&gt; &lt;a href=&#34;https://blog.howardjohn.info/posts/docker-builder/&#34;&gt;of&lt;/a&gt; &lt;a href=&#34;https://blog.howardjohn.info/posts/ideal-ci/&#34;&gt;time&lt;/a&gt; optimizing build times, I found myself quite disappointed that after going through considerable lengths to optimize our workflows, our builds were still severely bottlenecked by the performance of the GitHub Actions runners.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Stop picking my Go version for me</title>
      <link>https://blog.howardjohn.info/posts/go-mod-version/</link>
      <pubDate>Fri, 27 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/go-mod-version/</guid>
      <description>&lt;p&gt;The &lt;code&gt;go.mod&lt;/code&gt; file contains a mandatory &lt;code&gt;go &amp;lt;version number&amp;gt;&lt;/code&gt; directive.
Since Go 1.21, when &lt;a href=&#34;https://go.dev/doc/go1.21#introduction&#34;&gt;a change was introduced&lt;/a&gt; to make this include a full patch number (&lt;code&gt;1.21.0&lt;/code&gt; instead of &lt;code&gt;1.21&lt;/code&gt;), a number of projects have started using this wrong, hurting everyone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The version is the minimum version your project can be compiled with&lt;/strong&gt;.
It is not the version &lt;em&gt;you&lt;/em&gt; use to compile your project, but the minimum version that &lt;em&gt;anyone&lt;/em&gt; can use to compile your project.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Exploring ListenerSets in Gateway API v1.5</title>
      <link>https://blog.howardjohn.info/posts/listenerset/</link>
      <pubDate>Wed, 25 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/listenerset/</guid>
      <description>&lt;p&gt;With the &lt;a href=&#34;https://github.com/kubernetes/ingress-NGINX&#34;&gt;retirement of ingress-nginx&lt;/a&gt; I&#39;ve seen a lot of frustrations with Gateway API migrations due to differences in some of the resource models.&lt;/p&gt;
&lt;p&gt;The common problem is that Ingress users are often running self-service models, where application teams fully own their ingress configuration, including TLS certificates.&lt;/p&gt;
&lt;p&gt;This would look something like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Ingress&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;annotations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;my-issuer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;app-a-routes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;app-a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;rules&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;app-a.example.com&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;paths&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;pathType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Prefix&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;backend&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;myservice&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tls&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;app-a.example.com&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;secretName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;myingress-cert&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Combined with &lt;a href=&#34;https://cert-manager.io/docs/usage/ingress/&#34;&gt;&lt;code&gt;cert-manager&lt;/code&gt;&lt;/a&gt; a certificate would automatically be provisioned for &lt;code&gt;app-a.example.com&lt;/code&gt; and linked up to the shared Nginx instance.
DNS would then be handled with wildcard entries or &lt;a href=&#34;https://kubernetes-sigs.github.io/external-dns/&#34;&gt;external-dns&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Envoy Quirks Part 1: Clear Route Cache</title>
      <link>https://blog.howardjohn.info/posts/envoy-gotcha-1-clear-route-cache/</link>
      <pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/envoy-gotcha-1-clear-route-cache/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part one of a series.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Envoy Quirks Part 1: Clear Route Cache&lt;/strong&gt; (this post)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.howardjohn.info/posts/envoy-gotcha-2-filter-chain-match/&#34;&gt;Envoy Quirks Part 2: Filter Chain Match&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the years working with Envoy (via Istio), I&#39;ve come across quite a few quirks and gotchas.
I thought it would be fun to share some of them, and how to work around them.
Many of these surprise even Envoy experts!&lt;/p&gt;
&lt;p&gt;To start things off, lets talk about the &amp;quot;Clear route cache&amp;quot; option present on a number of Envoy filters.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Async DAGs in Bash</title>
      <link>https://blog.howardjohn.info/posts/bash-dag/</link>
      <pubDate>Wed, 04 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/bash-dag/</guid>
      <description>&lt;p&gt;Recently I had a need to run a bunch of steps in a bash script, with interweaved dependencies for a CI pipeline.&lt;/p&gt;
&lt;p&gt;While a simpler approach would do a linear flow like:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Setup Kubernetes cluster.&lt;/li&gt;
&lt;li&gt;Deploy dependencies to Kubernetes.&lt;/li&gt;
&lt;li&gt;Build image 1.&lt;/li&gt;
&lt;li&gt;Build image 2.&lt;/li&gt;
&lt;li&gt;Run tests.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;could work, its slow; we don&#39;t take advantage that we could build our images while the cluster is setting up, for instance.&lt;/p&gt;
&lt;p&gt;Essentially what we want is to be able to run a bunch of steps, declare their dependencies, and have them run as soon as their dependencies are met.
This is essentially a DAG (directed acyclic graph) execution.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Interpreting near native speeds with CEL and Rust</title>
      <link>https://blog.howardjohn.info/posts/cel-fast/</link>
      <pubDate>Wed, 04 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/cel-fast/</guid>
      <description>&lt;p&gt;When building out &lt;a href=&#34;https://agentgateway.dev/&#34;&gt;Agentgateway&lt;/a&gt;, we had a desire to introduce an embedded expression language to allow users to write custom logic to be evaluated at runtime.&lt;/p&gt;
&lt;p&gt;This is tremendously useful for a variety of use cases, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extracting fields to log (&lt;code&gt;request.headers[&amp;quot;user-agent&amp;quot;]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Evaluating authorization conditions (&lt;code&gt;jwt.sub == &amp;quot;admin&amp;quot; || request.path == &amp;quot;/public&amp;quot;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Manipulating fields in requests/responses (&lt;code&gt;x-llm-model: &#39;json(request.body).model&#39;&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and so on.&lt;/p&gt;
&lt;p&gt;This provides a powerful way to allow users to customize behavior without needing custom compile-time extensions, external callouts, or complex YAML-based configuration.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sharing Rust Build Cache</title>
      <link>https://blog.howardjohn.info/posts/shared-rust-build/</link>
      <pubDate>Wed, 18 Feb 2026 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/shared-rust-build/</guid>
      <description>&lt;p&gt;As I ramp up coding agent usage, I found myself wanting to share the Rust build cache across multiple copies of the same project (via git worktrees) to avoid multiple-minute cold builds. This was harder than expected, but I was able to get something working.&lt;/p&gt;
&lt;p&gt;First, the failed attempts&lt;/p&gt;
&lt;h2 id=&#34;attempt-1-just-copy-the-target-directory&#34;&gt;Attempt 1: just copy the target directory&lt;/h2&gt;
&lt;p&gt;This seemed like a good idea, but took about 2 minutes which was almost as bad as doing a cold build in the first place.
That won&#39;t fly.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes v1.35 Pod Certificates won&#39;t help your service mesh</title>
      <link>https://blog.howardjohn.info/posts/pod-certs/</link>
      <pubDate>Mon, 22 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/pod-certs/</guid>
      <description>The new Pod Certificates feature in Kubernetes v1.35 promises to &amp;quot;drastically simplify service mesh architectures&amp;quot;. It will not.</description>
    </item>
    <item>
      <title>Body-Based Routing in Agentgateway</title>
      <link>https://blog.howardjohn.info/posts/bbr-agentgateway/</link>
      <pubDate>Wed, 26 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/bbr-agentgateway/</guid>
      <description>&lt;p&gt;While typical HTTP request routing happens based on the request headers/path, sometimes routing based on the body is useful.
In particular, as AI use cases become more prevalent, the need to route based on the &lt;code&gt;model&lt;/code&gt; field of the JSON request body
is pretty handy to &lt;a href=&#34;https://gateway-api-inference-extension.sigs.k8s.io/guides/serve-multiple-genai-models&#34;&gt;serve multiple models&lt;/a&gt; or route to different
external LLMs.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://github.com/kubernetes-sigs/gateway-api-inference-extension/blob/main/pkg/bbr/README.md&#34;&gt;Gateway API Inference Extension&lt;/a&gt; solution to this is to deploy an &amp;quot;external processor&amp;quot; that reads the body, and writes out a header; the header can then be matched as usual.
An &lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/ext_proc/v3/external_processor.proto&#34;&gt;external processor&lt;/a&gt; is basically a service independent of the actual gateway proxy that processes the request. It does this by streaming the request headers/body between the proxy and the external processor.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Agentgateway at Home</title>
      <link>https://blog.howardjohn.info/posts/agentgateway-at-home/</link>
      <pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/agentgateway-at-home/</guid>
      <description>How I run Agentgateway on my homelab setup.</description>
    </item>
    <item>
      <title>CEL is a great language (you are using it wrong)</title>
      <link>https://blog.howardjohn.info/posts/cel-is-good/</link>
      <pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/cel-is-good/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://cel.dev/&#34;&gt;Common Expression Language&lt;/a&gt; (CEL) is a great little language for embedding users&#39; custom logic into an application.
However, typically when I discuss it, I get a response something along the lines of &amp;quot;AHHHH!! I HATE CEL!!!&amp;quot;&lt;/p&gt;
&lt;p&gt;I, too, have been in that position. However, when building &lt;a href=&#34;https://agentgateway.dev/&#34;&gt;Agentgateway&lt;/a&gt; I decided to fully embrace CEL throughout the entire stack, and the results have been great.
The problems with CEL are not about CEL itself, but in its usage -- and a lot of usages are poor, giving CEL a bad reputation.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to build a scalable control plane</title>
      <link>https://blog.howardjohn.info/posts/scaling-control-plane/</link>
      <pubDate>Tue, 16 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/scaling-control-plane/</guid>
      <description>&lt;p&gt;I&#39;ve spent the majority of my career building Istio&#39;s control plane, Istiod, with an emphasis on making it highly performant and scalable. And while it has come a very (very) long way, it&#39;s still a long way off from what a control plane &lt;em&gt;could&lt;/em&gt; be.&lt;/p&gt;
&lt;p&gt;It&#39;s not alone. When I worked on building an &lt;a href=&#34;http://github.com/howardjohn/gateway-api-bench/&#34;&gt;open benchmark&lt;/a&gt; of Kubernetes Gateway control planes, I was surprised to find that no implementation met what I felt was a reasonable bar for a &amp;quot;highly scalable and performant control plane&amp;quot;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Rust vs Go</title>
      <link>https://blog.howardjohn.info/posts/rust-vs-go/</link>
      <pubDate>Tue, 16 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/rust-vs-go/</guid>
      <description>&lt;p&gt;An often overlooked part of the Rust license is that within a year of usage, users are required to make a comparison to their (previously) favorite language.
While I am a bit late, I am ready to pay my dues.&lt;/p&gt;
&lt;p&gt;Given the overabundance of Rust vs X content, I&#39;ll try to cover only areas that haven&#39;t been discussed to death.&lt;/p&gt;
&lt;h2 id=&#34;lifetimes-and-borrows&#34;&gt;Lifetimes and Borrows&lt;/h2&gt;
&lt;p&gt;Did I say I wouldn&#39;t cover areas everyone has already talked about?
I lied!&lt;/p&gt;</description>
    </item>
    <item>
      <title>You should buy a faster CPU</title>
      <link>https://blog.howardjohn.info/posts/buy-a-cpu/</link>
      <pubDate>Mon, 18 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/buy-a-cpu/</guid>
      <description>&lt;p&gt;In the past few years, CPUs have gotten really fast. Shockingly fast!
Yet most people are stuck on previous generation mobile chips (whether by choice, or by their companies choice), at a huge detriment to their productivity.&lt;/p&gt;
&lt;p&gt;Meanwhile, AI coding subscriptions like Cursor are all the rage these days.
I&#39;ll skip the debate on exactly how useful these tools are, and focus on the pricing.
Cursor is $480/year for the team plan (the cheapest corporate plan), and other providers are around the same, setting a clear price point: engineering productivity is worth at least $500/year.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Your AI workloads still need a service mesh</title>
      <link>https://blog.howardjohn.info/posts/ai-mesh/</link>
      <pubDate>Tue, 05 Aug 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ai-mesh/</guid>
      <description>AI workloads introduce new requirements on networking infrastructure, but the same core requirements that service meshes solve not only remain, but are exacerbated. Your AI workloads still need a service mesh - they just need a better one</description>
    </item>
    <item>
      <title>[Solo.io Blog] Gloo Mesh, The 100 Million Pod Mesh</title>
      <link>https://blog.howardjohn.info/posts/external-100m-pod-mesh/</link>
      <pubDate>Wed, 05 Feb 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/external-100m-pod-mesh/</guid>
      <description>Gloo Mesh’s ambient multi-cluster mode sets a new benchmark for scalability.</description>
    </item>
    <item>
      <title>Exploring the new &#34;go tool&#34; support in Go 1.24</title>
      <link>https://blog.howardjohn.info/posts/go-tools-command/</link>
      <pubDate>Mon, 20 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/go-tools-command/</guid>
      <description>&lt;p&gt;Go 1.24 introduces new support for &lt;a href=&#34;https://tip.golang.org/doc/go1.24#tools&#34;&gt;&amp;quot;Tools&amp;quot;&lt;/a&gt;, which allows easy consumption of tools (which are written in Go) as a dependency for a project.
This could be anything from &lt;code&gt;golangci-lint&lt;/code&gt; to &lt;code&gt;protoc-gen-go&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I will cover usage and limitations.&lt;/p&gt;
&lt;h2 id=&#34;basic-usage&#34;&gt;Basic usage&lt;/h2&gt;
&lt;p&gt;Adding a tool to a project is nearly the same as a standard runtime dependency, with the additional &lt;code&gt;-tool&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ goimports &lt;span class=&#34;c1&#34;&gt;# I don&amp;#39;t have goimports yet!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;zsh: &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; not found: goimports
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ go get -tool golang.org/x/tools/cmd/goimports
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go: added golang.org/x/mod v0.22.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go: added golang.org/x/sync v0.10.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;go: added golang.org/x/tools v0.29.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ go tool goimports --help
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;usage: goimports &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;flags&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;path ...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once we add a tool, we can access it by &lt;code&gt;go tool &amp;lt;name&amp;gt;&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ztunnel through two lenses</title>
      <link>https://blog.howardjohn.info/posts/ztunnel-compute-traffic-view/</link>
      <pubDate>Thu, 16 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ztunnel-compute-traffic-view/</guid>
      <description>Is it a per-node proxy? Is it a sidecar? The reality is somewhere in between</description>
    </item>
    <item>
      <title>[Solo.io Blog] Introducing Ambient Multi-Cluster Mode to Gloo Mesh</title>
      <link>https://blog.howardjohn.info/posts/external-solo-ambient-multicluster/</link>
      <pubDate>Wed, 15 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/external-solo-ambient-multicluster/</guid>
      <description>Reimagine service mesh with Istio’s ambient mode—lightweight, efficient, and scalable. Gloo Mesh now extends this innovation to multi-cluster environments, delivering unmatched reliability, simplicity, and scale.</description>
    </item>
    <item>
      <title>What happens when Ztunnel shuts down?</title>
      <link>https://blog.howardjohn.info/posts/ztunnel-shutdown/</link>
      <pubDate>Fri, 20 Dec 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ztunnel-shutdown/</guid>
      <description>A deep dive into the termination behavior of Istio ambient mode and how it impacts your applications.</description>
    </item>
    <item>
      <title>[AWS Blog] Transforming Istio into an enterprise-ready service mesh for Amazon ECS</title>
      <link>https://blog.howardjohn.info/posts/external-aws-ecs/</link>
      <pubDate>Wed, 27 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/external-aws-ecs/</guid>
      <description>How Istio ambient mode brings an enterprise-ready service mesh to Amazon ECS.</description>
    </item>
    <item>
      <title>Scaling Ambient In Your Sleep</title>
      <link>https://blog.howardjohn.info/posts/scaling-ambient/</link>
      <pubDate>Fri, 15 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/scaling-ambient/</guid>
      <description>How ambient achieves massive scale without toil.</description>
    </item>
    <item>
      <title>&#34;Zero to Value&#34; in two steps with Istio ambient mode</title>
      <link>https://blog.howardjohn.info/posts/zero-to-value/</link>
      <pubDate>Tue, 05 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/zero-to-value/</guid>
      <description>&lt;p&gt;When we first started designing what eventually became &lt;a href=&#34;https://istio.io/latest/blog/2022/introducing-ambient-mesh/&#34;&gt;Istio ambient mode&lt;/a&gt;,
there were many directions we explored, both in terms of implementation, and what our goals were.
What resonated most, though, was that we wanted to provide an incredibly easy onboarding story for a subset of functionality.
This subset, ultimately, was getting Mutual TLS deployed for all service-to-service communication within a cluster.
I talk a bit more about this &lt;a href=&#34;posts/flattening-curve/&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Since then, I think we have delivered on this promise... and gone even further!
In this post, I wanted to highlight some of the areas that I think ambient helps deliver some serious value to users with minimal complexity.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Looking back on &#34;Building Better Controllers&#34; 2 years later</title>
      <link>https://blog.howardjohn.info/posts/krt-recap/</link>
      <pubDate>Sun, 03 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/krt-recap/</guid>
      <description>&lt;p&gt;Over 2 years ago, I started working on some ideas to build better Kubernetes controllers.
In this post, I wanted to give a bit of a retrospective on how things have gone since then.&lt;/p&gt;
&lt;p&gt;Over the years working on Istio and other projects, I observed a number of major issues with controllers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most code was about error-prone event handling and state reconciliation, rather than business logic.&lt;/li&gt;
&lt;li&gt;Most tests, in turn, were about the same.&lt;/li&gt;
&lt;li&gt;This, in turn, made the code extremely complex, brittle, and often incorrect.&lt;/li&gt;
&lt;li&gt;This complexity lead to &lt;em&gt;user facing&lt;/em&gt; compromise: incorrectness and performance issues.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;You might argue I should just write a better controller that is faster and without bugs.
Maybe, but probably not.&lt;/p&gt;</description>
    </item>
    <item>
      <title>[Cloud Native Now Blog] How Istio Ambient is Revolutionizing Cloud Connectivity</title>
      <link>https://blog.howardjohn.info/posts/external-cloudnativenow-ambient/</link>
      <pubDate>Fri, 01 Nov 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/external-cloudnativenow-ambient/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://cloudnativenow.com/contributed-content/how-istio-ambient-is-revolutionizing-cloud-connectivity/&#34;&gt;External Blog Post&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>On-Demand Development Environments</title>
      <link>https://blog.howardjohn.info/posts/lazy-dev-env/</link>
      <pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/lazy-dev-env/</guid>
      <description>&lt;p&gt;Tools to create reproducible development environments are basically everywhere these days, from &lt;a href=&#34;https://containers.dev/&#34;&gt;Development Containers&lt;/a&gt; to &lt;a href=&#34;https://devenv.sh/&#34;&gt;Nix wrappers&lt;/a&gt; to &lt;a href=&#34;https://github.com/istio/istio/blob/master/Makefile&#34;&gt;questionable Docker hacks&lt;/a&gt;.
However, all of these (that I have found) have a common flaw that bothers me: they all require eagerly fetching the entire environment to get anything done.&lt;/p&gt;
&lt;p&gt;This kills the premise of these environments providing any easy on-ramp for users when the first step is to download GBs of binaries.
Across projects I work on, we have probably 5-10GB of dependencies, but its extremely unlikely a single developer will use more than a fraction of these at a time.
Even for repeat contributors, updates to these are not always incremental (though some are), bringing continued pain as time goes on.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Inline (YAML) Langauge Injection in JetBrains IDEs</title>
      <link>https://blog.howardjohn.info/posts/jetbrains-yaml/</link>
      <pubDate>Fri, 27 Sep 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/jetbrains-yaml/</guid>
      <description>&lt;p&gt;JetBrains IDEs (IntelliJ, GoLand, etc) have a nifty feature called &lt;a href=&#34;https://www.jetbrains.com/help/idea/language-injections-settings.html&#34;&gt;Language Injection&lt;/a&gt; that lets you get full language features when a language is embedded within another. For example, a SQL query within a string within a Go file.&lt;/p&gt;
&lt;p&gt;A few of these come out of the box, but they are pretty limited -- I only had some XML ones prior to enabling the Databases plugin which added a few SQL ones. Fortunately, there is the ability to add custom ones. Unfortunately, this is expressed in a proprietary language with, as far as I can tell, &lt;em&gt;zero&lt;/em&gt; documentation.&lt;/p&gt;</description>
    </item>
    <item>
      <title>[Solo.io Blog] Egress Gateways Made Easy</title>
      <link>https://blog.howardjohn.info/posts/external-solo-egress-gateways-made-easy/</link>
      <pubDate>Mon, 19 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/external-solo-egress-gateways-made-easy/</guid>
      <description>How Istio ambient mode greatly simplifies and improves egress gateway use cases.</description>
    </item>
    <item>
      <title>[Solo.io Blog] HTTP Observability Without Compromises</title>
      <link>https://blog.howardjohn.info/posts/external-solo-http-observability-without-compromises/</link>
      <pubDate>Tue, 13 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/external-solo-http-observability-without-compromises/</guid>
      <description>How Gloo mesh brings HTTP observability to your mesh, without compromises.</description>
    </item>
    <item>
      <title>I just want mTLS on Kubernetes</title>
      <link>https://blog.howardjohn.info/posts/mtls-kubernetes/</link>
      <pubDate>Mon, 12 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/mtls-kubernetes/</guid>
      <description>An overview of options to deploy mTLS on Kubernetes</description>
    </item>
    <item>
      <title>NetworkPolicy: the wrong solution to the right problem</title>
      <link>https://blog.howardjohn.info/posts/netpol-api/</link>
      <pubDate>Fri, 09 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/netpol-api/</guid>
      <description>Core problems with the API make it a challenging to use in a secure, scalable manner.</description>
    </item>
    <item>
      <title>Stop Trusting Your Nodes</title>
      <link>https://blog.howardjohn.info/posts/node-zerotrust/</link>
      <pubDate>Fri, 09 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/node-zerotrust/</guid>
      <description>Zero trust architectures should not treat nodes as highly privileged components.</description>
    </item>
    <item>
      <title>The Past, Present, and Future of Istio Installation</title>
      <link>https://blog.howardjohn.info/posts/past-present-future-istio-install/</link>
      <pubDate>Fri, 09 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/past-present-future-istio-install/</guid>
      <description>&lt;p&gt;Istio&#39;s installation has a long, winding, complex history, leading to an &lt;a href=&#34;https://blog.howardjohn.info/posts/istio-install/&#34;&gt;interesting current state&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In this post, I hope to explain some of the historical context of how we arrived to the current state, and where I think the project is going.
This is all my personal perspective and memory of things that happened years ago, so there is likely &lt;em&gt;some&lt;/em&gt; divergence from reality.&lt;/p&gt;
&lt;h2 id=&#34;the-past&#34;&gt;The Past&lt;/h2&gt;
&lt;p&gt;When I first started working on Istio in 2019, Istio 1.0 had just been released.
The ecosystem was a pretty difference place back then.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Shipping Anything On Go Infrastructure</title>
      <link>https://blog.howardjohn.info/posts/go-arbitrary-binary/</link>
      <pubDate>Fri, 05 Jul 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/go-arbitrary-binary/</guid>
      <description>&lt;code&gt;go run bash-script@latest&lt;/code&gt;</description>
    </item>
    <item>
      <title>Service Mesh Adoption Curve</title>
      <link>https://blog.howardjohn.info/posts/flattening-curve/</link>
      <pubDate>Mon, 24 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/flattening-curve/</guid>
      <description>How we built a best-of-both-worlds experience with Istio ambient mode.</description>
    </item>
    <item>
      <title>Everything you need to know about Istio installation</title>
      <link>https://blog.howardjohn.info/posts/istio-install/</link>
      <pubDate>Fri, 07 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/istio-install/</guid>
      <description>Installing Istio... hard could it be? A simple &lt;code&gt;istioctl install&lt;/code&gt; is all you need... right?</description>
    </item>
    <item>
      <title>Ambient and the SPOF Myth</title>
      <link>https://blog.howardjohn.info/posts/ambient-spof/</link>
      <pubDate>Tue, 04 Jun 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ambient-spof/</guid>
      <description>Does Istio ambient introduce a SPOF? No.</description>
    </item>
    <item>
      <title>Grafana Dashboard Development Workflow</title>
      <link>https://blog.howardjohn.info/posts/grafana-dashboard-dev/</link>
      <pubDate>Thu, 30 May 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/grafana-dashboard-dev/</guid>
      <description>How I iterate on Grafana dashboards</description>
    </item>
    <item>
      <title>Podless Kubernetes</title>
      <link>https://blog.howardjohn.info/posts/podless-kubernetes/</link>
      <pubDate>Tue, 07 May 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/podless-kubernetes/</guid>
      <description>Sidecarless? Why not podless?</description>
    </item>
    <item>
      <title>Testing a Kubernetes Networking Implementation Without Kubernetes</title>
      <link>https://blog.howardjohn.info/posts/ztunnel-testing/</link>
      <pubDate>Thu, 25 Apr 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ztunnel-testing/</guid>
      <description>How Istio tests its networking proxy without Kubernetes, Docker, or root.</description>
    </item>
    <item>
      <title>Securing Prometheus with Istio Ambient</title>
      <link>https://blog.howardjohn.info/posts/securing-prometheus/</link>
      <pubDate>Mon, 15 Apr 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/securing-prometheus/</guid>
      <description>tl;dr: it just works</description>
    </item>
    <item>
      <title>Building a better Kubernetes Client</title>
      <link>https://blog.howardjohn.info/posts/kube-client/</link>
      <pubDate>Sat, 23 Mar 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/kube-client/</guid>
      <description>&lt;p&gt;Like most other Kubernetes controllers in, Istio is written in Go and relies on the &lt;a href=&#34;https://github.com/kubernetes/client-go&#34;&gt;client-go&lt;/a&gt; library. While this provides an excellent low-level building block, usage in higher level code in Istio led to a variety of issues that led us to develop our own higher level, opinionated client for Istio.&lt;/p&gt;
&lt;p&gt;This post covers the issues we faced and how we incrementally solved them.&lt;/p&gt;
&lt;h2 id=&#34;background-knowledge&#34;&gt;Background knowledge&lt;/h2&gt;
&lt;p&gt;At a high level, &lt;code&gt;client-go&lt;/code&gt; provides a few layers for interactions with the API server:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advanced Helm Techniques</title>
      <link>https://blog.howardjohn.info/posts/advanced-helm/</link>
      <pubDate>Tue, 27 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/advanced-helm/</guid>
      <description>Rage bait for YAML templating haters</description>
    </item>
    <item>
      <title>Opinionated Istio Feature Recommendations</title>
      <link>https://blog.howardjohn.info/posts/opinionated-istio/</link>
      <pubDate>Tue, 06 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/opinionated-istio/</guid>
      <description>Which features I recommend using, or not using, in Istio</description>
    </item>
    <item>
      <title>Analyzing Go Binary Sizes</title>
      <link>https://blog.howardjohn.info/posts/go-binary-size/</link>
      <pubDate>Sat, 06 Jan 2024 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/go-binary-size/</guid>
      <description>&lt;p&gt;In &lt;a href=&#34;https://blog.howardjohn.info/posts/go-build-times/&#34;&gt;Analyzing Go Build Times&lt;/a&gt;, I went over how to analyze and understand Go build times, and what factors impact build times.
A close cousin to build times is build &lt;em&gt;sizes&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Large binaries can lead to a variety of issues such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generally, slower build times&lt;/li&gt;
&lt;li&gt;Increased costs of storage&lt;/li&gt;
&lt;li&gt;Increased costs and time to distribute&lt;/li&gt;
&lt;li&gt;Increased memory usage at runtime (more on this in another article, hopefully)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So its generally nice to keep them small.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Truly Extensible Proxies</title>
      <link>https://blog.howardjohn.info/posts/proxy-extensibility/</link>
      <pubDate>Fri, 13 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/proxy-extensibility/</guid>
      <description>Exploring an extreme service mesh architecture to maximize extensibility.</description>
    </item>
    <item>
      <title>Proxy Layers</title>
      <link>https://blog.howardjohn.info/posts/proxy-layers/</link>
      <pubDate>Thu, 12 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/proxy-layers/</guid>
      <description>&lt;p&gt;The &lt;a href=&#34;https://en.wikipedia.org/wiki/OSI_model&#34;&gt;OSI model&lt;/a&gt; attempts to build a model for network communications, where increasingly high level layers are built upon lower layers.
This is only slightly useful in practice, as the real world is not so simple.&lt;/p&gt;
&lt;p&gt;In service mesh, generally discussion is reduced to L4 and L7, or TCP and HTTP.
This oversimplifies the problem, leading to some confusion.&lt;/p&gt;
&lt;h2 id=&#34;thinking-in-terms-of-termination&#34;&gt;Thinking in terms of termination&lt;/h2&gt;
&lt;p&gt;Simply saying &amp;quot;HTTP&amp;quot; is not really clear about what is going on. Instead, I think its more useful to think about what layer we &lt;em&gt;terminate&lt;/em&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Service Mesh Proxy Classes</title>
      <link>https://blog.howardjohn.info/posts/proxy-types/</link>
      <pubDate>Wed, 11 Oct 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/proxy-types/</guid>
      <description>&lt;p&gt;When looking at service mesh (or even general networking) architectures, the basic idea is to send network traffic through some component, which handles various functionality. This could be authentication, authorization, encryption, observability, reliability, networking, etc. There are a few different classes of components that can do this, though:&lt;/p&gt;
&lt;figure class=&#34;image&#34;&gt;
  
  &lt;img src=&#34;https://blog.howardjohn.info/images/proxy-types.svg#center&#34; alt=&#34;Different types of proxy deployments&#34;&gt;
  
  &lt;figcaption&gt;Different types of proxy deployments&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;ol&gt;
&lt;li&gt;Native application enhancement. The application itself is compiled in with functionality. This could be something like gRPC (or, even more &amp;quot;meshy&amp;quot;, &lt;a href=&#34;https://grpc.github.io/grpc/core/md_doc_grpc_xds_features.html&#34;&gt;gRPC with xDS&lt;/a&gt;), Finagle, Hystrix, etc. Even simply instrumenting your application with metrics and traces could be classified here.&lt;/li&gt;
&lt;li&gt;&amp;quot;Sidecar&amp;quot;, or running a proxy-per-application, is probably the most common service mesh deployment pattern today, used by Istio, Linkerd, and more.&lt;/li&gt;
&lt;li&gt;Per-node proxy; like sidecar, but instead of per-application the proxy is per-node. Each node contains multiple unique workloads, so the proxy is multi-tenant.&lt;/li&gt;
&lt;li&gt;Remote proxy. A completely standalone proxy deployment we send some traffic through. This could be correlated to one or many service(s), one or many workload(s), etc -- the correlation between proxies and other infrastructure components is flexible here.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Within each of these, there is 2 actors: a client and a server.
This gives us 8 points to insert functionality. Presumably, all 8 will not be used at once -- but its possible.
If we are willing to blur the lines a bit, even a traditional sidecar based service mesh utilizes 6 of these! The most rich &amp;quot;service mesh&amp;quot; functionality may exist in the sidecar, but the application itself has &lt;em&gt;some&lt;/em&gt; functionality (even if its not terribly rich), and the node does as well (again, this may not be terribly rich -- &lt;code&gt;kube-proxy&lt;/code&gt;, for example, has very minimal functionality). And the same is mirror on the client and server side.&lt;/p&gt;</description>
    </item>
    <item>
      <title>User space isn&#39;t slow</title>
      <link>https://blog.howardjohn.info/posts/wireguard-tls/</link>
      <pubDate>Sun, 10 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/wireguard-tls/</guid>
      <description>In-kernel networking solutions, such as WireGuard, are not always faster than user space.</description>
    </item>
    <item>
      <title>An optimal CI/CD system</title>
      <link>https://blog.howardjohn.info/posts/ideal-ci/</link>
      <pubDate>Wed, 06 Sep 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ideal-ci/</guid>
      <description>Exploring an (unfortunately, hypothetical) CI/CD system for end to end tests on Kubernetes.</description>
    </item>
    <item>
      <title>Istio Ambient is not a &#34;Node Proxy&#34;</title>
      <link>https://blog.howardjohn.info/posts/ambient-not-node-proxy/</link>
      <pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/ambient-not-node-proxy/</guid>
      <description>&lt;p&gt;The common messaging around &lt;a href=&#34;https://istio.io/latest/blog/2022/introducing-ambient-mesh/&#34;&gt;Istio Ambient Mesh&lt;/a&gt; is that is a &amp;quot;node proxy.&amp;quot;&lt;/p&gt;
&lt;p&gt;For example, from &lt;a href=&#34;https://thenewstack.io/can-you-now-safely-remove-the-service-mesh-sidecar/&#34;&gt;The New Stack&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;... architecture that moves the proxy functionality from the pod-level to the node-level.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While this is technically accurate, it is misleading and really missing the point and benefits of Ambient.&lt;/p&gt;
&lt;h1 id=&#34;a-brief-history-of-service-mesh-architectures&#34;&gt;A brief history of service mesh architectures&lt;/h1&gt;
&lt;p&gt;This skips quite a bit of information, but is close enough.&lt;/p&gt;
&lt;p&gt;One of the earlier service meshes on the market was Linkerd 1 - not to be confused with Linkerd 2, which most people just call &amp;quot;Linkerd&amp;quot; today. Linkerd 1 was a per-node proxy that did all the service mesh functionality we know and love, at the node level.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Waypoint Proxies The Hard Way</title>
      <link>https://blog.howardjohn.info/posts/waypoint-the-hard-way/</link>
      <pubDate>Tue, 22 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/waypoint-the-hard-way/</guid>
      <description>How to achieve an architecture similar to &amp;quot;Waypoint Proxies&amp;quot; without ambient mesh, or even Istio.</description>
    </item>
    <item>
      <title>Building a lot of docker images</title>
      <link>https://blog.howardjohn.info/posts/docker-builder/</link>
      <pubDate>Fri, 04 Aug 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/docker-builder/</guid>
      <description>Fully utilizing buildkit&#39;s potentional</description>
    </item>
    <item>
      <title>GOMAXPROCS and GOMEMLIMIT in Kubernetes</title>
      <link>https://blog.howardjohn.info/posts/gomaxprocs/</link>
      <pubDate>Mon, 31 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/gomaxprocs/</guid>
      <description>How and why to easily these fields</description>
    </item>
    <item>
      <title>Saying No In Open Source</title>
      <link>https://blog.howardjohn.info/posts/saying-no/</link>
      <pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/saying-no/</guid>
      <description>&lt;p&gt;As an open source maintainer, I am reviewing roughly 25 ideas per day - whether they are feature requests, design proposals, or pull requests. Inevitably, this leads to saying &amp;quot;No&amp;quot; quite a bit as well.&lt;/p&gt;
&lt;p&gt;Usually, this is in a softer for like &amp;quot;No, not right now&amp;quot;, &amp;quot;No, not in its current form&amp;quot;, or &amp;quot;No, unless someone else approves&amp;quot;, but the outcome is the same: the change is not accepted, and the &lt;em&gt;emotional&lt;/em&gt; impact on the reviewer and contributor is similar.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Useful tools for Kubernetes</title>
      <link>https://blog.howardjohn.info/posts/kube-helpers/</link>
      <pubDate>Wed, 12 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/kube-helpers/</guid>
      <description>&lt;p&gt;Most people using Kubernetes extensive have already defined &lt;code&gt;alias k=kubectl&lt;/code&gt; and are using tools like &lt;a href=&#34;https://github.com/ahmetb/kubectx&#34;&gt;&lt;code&gt;kubectx&lt;/code&gt;&lt;/a&gt;.
As someone really lazy though, I have found/developed a few less common tools to help work with Kubernetes efficiently.&lt;/p&gt;
&lt;h2 id=&#34;kubectl-apply-from-clipboard&#34;&gt;&lt;code&gt;kubectl apply&lt;/code&gt; from clipboard&lt;/h2&gt;
&lt;p&gt;This relies on &lt;a href=&#34;https://www.zsh.org/&#34;&gt;&lt;code&gt;zsh&lt;/code&gt;&lt;/a&gt;, and uses the &lt;a href=&#34;https://linux.die.net/man/1/zshzle&#34;&gt;&lt;code&gt;zle&lt;/code&gt;&lt;/a&gt; to define a custom command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;function&lt;/span&gt; zle_apply &lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;LBUFFER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;xclip -se c -o&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s2&#34;&gt;EOF&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nv&#34;&gt;CURSOR&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;31&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;zle -N zle_apply&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; bindkey &lt;span class=&#34;s2&#34;&gt;&amp;#34;^k&amp;#34;&lt;/span&gt; zle_apply
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This defines a function and binds it to &lt;code&gt;Ctrl+k&lt;/code&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Tracing shell scripts with OpenTelemetry</title>
      <link>https://blog.howardjohn.info/posts/shell-tracing/</link>
      <pubDate>Tue, 11 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/shell-tracing/</guid>
      <description>A little bit of OpenTelemetry, a lot of shell hackery</description>
    </item>
    <item>
      <title>Zero allocations metrics with opentelemetry-go</title>
      <link>https://blog.howardjohn.info/posts/zero-alloc-otel/</link>
      <pubDate>Tue, 11 Jul 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/zero-alloc-otel/</guid>
      <description>&lt;p&gt;In the past, Istio has suffered from performance issues from &lt;a href=&#34;https://opencensus.io/&#34;&gt;OpenCensus&lt;/a&gt;, which was used for metrics reporting. At extremes, we saw up to 20% of CPU spent just on incrementing various metrics.
This was mitigated to some extent by &lt;a href=&#34;https://github.com/istio/istio/pull/35189&#34;&gt;batching metrics updates&lt;/a&gt;, &lt;a href=&#34;https://github.com/census-instrumentation/opencensus-go/issues/1265&#34;&gt;optimizing OpenCensus itself&lt;/a&gt;, and &lt;a href=&#34;https://github.com/istio/pkg/pull/416&#34;&gt;caching parts of our OpenCensus usage&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At best, we got down to roughly &lt;code&gt;600ns&lt;/code&gt; and 3 allocations per metric update.&lt;/p&gt;
&lt;p&gt;As OpenCensus is now deprecated, I have been looking into migration to OpenTelemetry - and hoping to avoid these issues this time around.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Analyzing Go Build Times</title>
      <link>https://blog.howardjohn.info/posts/go-build-times/</link>
      <pubDate>Sat, 24 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/go-build-times/</guid>
      <description>&lt;p&gt;Go is often praised for its fast build times.
While they are pretty quick, they are slow enough that I spend a lot of time waiting for them, enough that it prompted me to go down the rabbit hole of thoroughly analyzing them.
This post covers all aspects of what makes Go builds fast or slow.&lt;/p&gt;
&lt;p&gt;Throughout this blog, we will use &lt;a href=&#34;https://github.com/istio/istio&#34;&gt;Istio&lt;/a&gt; as an example of real-world codebase.&lt;/p&gt;
&lt;p&gt;For reference on its size:&lt;/p&gt;</description>
    </item>
    <item>
      <title>CRD Versioning</title>
      <link>https://blog.howardjohn.info/posts/crd-versioning/</link>
      <pubDate>Wed, 07 Jun 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/crd-versioning/</guid>
      <description>&lt;p&gt;How versioning works in Kubernetes, especially with &lt;code&gt;CustomResourceDefinition&lt;/code&gt;s, is a common source of confusion.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&#34;https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definition-versioning/&#34;&gt;documentation&lt;/a&gt; is pretty comprehensive but a bit complicated.
This post aims to give a simple description of how versioning works and dispel some misunderstandings.&lt;/p&gt;
&lt;h2 id=&#34;there-is-only-one-primary-version&#34;&gt;There is only one primary version&lt;/h2&gt;
&lt;p&gt;Consider a CRD with versions &lt;code&gt;alpha&lt;/code&gt; and &lt;code&gt;beta&lt;/code&gt;.
A user can create and view either resource version.&lt;/p&gt;
&lt;p&gt;Intuitively, they must be distinct things -- &lt;strong&gt;they are not&lt;/strong&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>LTS and Rolling Releases</title>
      <link>https://blog.howardjohn.info/posts/lts/</link>
      <pubDate>Fri, 26 May 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/lts/</guid>
      <description>&lt;p&gt;Across the ecosystem, a variety of software support policies can be found, where &amp;quot;support&amp;quot; can mean, bug fixes, security patches, and sometimes technical support.&lt;/p&gt;
&lt;p&gt;However, they can be roughly categorized into two types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Rolling release&lt;/strong&gt;: only latest release supported. At an extreme, this is the HEAD git commit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LTS&lt;/strong&gt; (Long Term Support): Support latest N versions. Sometimes specific versions have extended support. &amp;quot;Long&amp;quot; is relative: Kubernetes supports a version for around a year, while RHEL does for 10 years.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;enterprises-love-lts&#34;&gt;Enterprises love LTS&lt;/h2&gt;
&lt;p&gt;Historically, enterprise users have favored -- if not &lt;em&gt;demanded&lt;/em&gt; -- LTS software.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Outbound sidecars are not secure enforcement points</title>
      <link>https://blog.howardjohn.info/posts/bypass-egress/</link>
      <pubDate>Mon, 22 May 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/bypass-egress/</guid>
      <description>&lt;p&gt;It is a very common misconception that egress policies in Istio can be used for security purposes.
This is not true.
Despite repeatedly explaining this (and &lt;a href=&#34;https://istio.io/latest/docs/ops/best-practices/security/#understand-traffic-capture-limitations&#34;&gt;documenting it&lt;/a&gt;), I still often see people that do not believe it, and that they can just add one more check to lock things down.&lt;/p&gt;
&lt;p&gt;In this post, I will show a variety of ways to bypass any possible check, and prove that these policies cannot be used as secure policies.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ergonomic Map in Go</title>
      <link>https://blog.howardjohn.info/posts/go-map/</link>
      <pubDate>Tue, 31 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/go-map/</guid>
      <description>&lt;p&gt;In many languages, on of the things I find myself doing is &lt;code&gt;map&lt;/code&gt;ing over a list to extract some field. For example, coverting a &lt;code&gt;[]Person&lt;/code&gt; to &lt;code&gt;[]Name&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Most languages these days have ways to do this pretty easily:&lt;/p&gt;
&lt;p&gt;Kotlin:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-kotlin&#34; data-lang=&#34;kotlin&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;people&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;it&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;JavaScript:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-js&#34; data-lang=&#34;js&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;people&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Rust:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;people&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Scala:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scala&#34; data-lang=&#34;scala&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;people&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;With generics, Go finally can do this in a type safe manner:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;Map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;people&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Person&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Name&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;... but we immediately stand out amongst other languages as having ugly, verbose syntax.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Building Docker Images Fast (by not using Docker)</title>
      <link>https://blog.howardjohn.info/posts/docker-builds/</link>
      <pubDate>Mon, 23 Jan 2023 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/docker-builds/</guid>
      <description>&lt;p&gt;This post follows the journey &lt;a href=&#34;https://github.com/istio/istio&#34;&gt;Istio&lt;/a&gt; has taken over the years to optimize our docker image builds. While there is some useful tips to take out of this, this is not intended to be a guide on how a project &lt;em&gt;should&lt;/em&gt; build images - the steps taken here go far past the needs of a typical project, optimizing exclusively for speed (and fun) regardless of the complexity to maintain.&lt;/p&gt;
&lt;p&gt;For background, over the years Istio has consisted of ~10-20 docker images (many are for tests only) made up of ~10-15 Go binaries and various static files. We also have a few variants (&lt;code&gt;debug&lt;/code&gt; and &lt;code&gt;distroless&lt;/code&gt;) and architectures (&lt;code&gt;amd64&lt;/code&gt; and &lt;code&gt;arm64&lt;/code&gt;). Aside from CI which is building thousands of these images daily, building images quickly is important for the inner development loop. While I try to &lt;a href=&#34;https://github.com/howardjohn/local-istio-development&#34;&gt;run things locally where possible&lt;/a&gt;, in many cases each minor code change is built and loaded into a &lt;a href=&#34;https://kind.sigs.k8s.io/&#34;&gt;local Kubernetes cluster&lt;/a&gt; to more closely resemble a real world deployment. This makes image build time critical for efficient development&lt;/p&gt;</description>
    </item>
    <item>
      <title>Kubernetes Operators</title>
      <link>https://blog.howardjohn.info/posts/operators/</link>
      <pubDate>Mon, 19 Dec 2022 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/operators/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://kubernetes.io/docs/concepts/extend-kubernetes/operator/&#34;&gt;Kubernetes Operators&lt;/a&gt; are powerful tools when used right, pushing complex operations from human operators to code. This sounds great - and is in some cases - but often the tradeoffs operators expose are not taken into account, both by operator developers and users. This article goes over my take on when operators are useful and not, and what makes a good operator.&lt;/p&gt;
&lt;h2 id=&#34;a-basic-installation-operator&#34;&gt;A basic installation operator&lt;/h2&gt;
&lt;p&gt;A common feature amongst almost all operators is the ability to deploy Kubernetes resources. For example, lets consider a hypothetical &lt;code&gt;nginx&lt;/code&gt; operator.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Local Gateway</title>
      <link>https://blog.howardjohn.info/posts/local-gateway/</link>
      <pubDate>Fri, 12 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/local-gateway/</guid>
      <description>&lt;p&gt;When deploying a proxy outside of Kubernetes, users typically reach for solutions like nginx or Traefik; it&#39;s pretty rare to see Kubernetes-native load balancers, like Istio, used outside of the Kubernetes context. While it is not documented anywhere on &lt;a href=&#34;https://istio.io&#34;&gt;istio.io&lt;/a&gt;, it is completely possible to set up an Istio Gateway outside of Kubernetes - not just running out of the cluster, but not connected to any Kubernetes api-server whatsoever.&lt;/p&gt;
&lt;p&gt;In this post, we will set up Istiod, and Istio ingress gateway, and a test application using &lt;code&gt;docker-compose&lt;/code&gt;. The full configuration can be found in &lt;a href=&#34;https://github.com/howardjohn/local-istio-gateway&#34;&gt;howardjohn/local-istio-gateway&lt;/a&gt;. Setting up a full mesh outside of Kubernetes is possible, but outside of the scope of this post.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Istio PR Approvers</title>
      <link>https://blog.howardjohn.info/posts/pr-approvers/</link>
      <pubDate>Sat, 06 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/posts/pr-approvers/</guid>
      <description>&lt;p&gt;The following graph shows PR approvals for &lt;a href=&#34;https://github.com/istio/istio&#34;&gt;istio/istio&lt;/a&gt; since 2020.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DevA 100 &amp;lt;-&amp;gt; DevB 50&lt;/code&gt; indicates DevB approved 100 PRs from DevA, and DevA approved 50 PRs from DevB.&lt;/p&gt;


&lt;div class=&#34;flourish-embed flourish-chord&#34; data-src=&#34;visualisation/5483100&#34; data-width=&#34;1000px&#34; data-height=&#34;1000px&#34;&gt;&lt;script src=&#34;https://public.flourish.studio/resources/embed.js&#34;&gt;&lt;/script&gt;&lt;/div&gt;


&lt;p&gt;The data was collected from our policy bot data and graphed using &lt;a href=&#34;https://flourish.studio/&#34;&gt;flourish&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-shell&#34; data-lang=&#34;shell&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;gcloud spanner databases execute-sql main --instance istio-policy-bot --project istio-testing --format&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;json --sql&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;select prr.Author as Approver, pr.Author as Author, count(*)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;from PullRequestReviews as prr
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;join PullRequests as pr on pr.PullRequestNumber = prr.PullRequestNumber
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;where SubmittedAt &amp;gt; &amp;#34;2020-01-01T00:00:00.00Z&amp;#34; and prr.state = &amp;#34;APPROVED&amp;#34; and prr.RepoName = &amp;#34;istio&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s1&#34;&gt;group by Approver, Author&amp;#39;&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; jq &lt;span class=&#34;s1&#34;&gt;&amp;#39;.rows[] | select((.[2]|tonumber) &amp;gt; 5) |  .[1] + &amp;#34;,&amp;#34; + .[0] + &amp;#34;,&amp;#34; + .[2]&amp;#39;&lt;/span&gt; -r
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the dynamic graph doesn&#39;t work a static version can be found &lt;a href=&#34;https://blog.howardjohn.info/images/PR_Approvers.svg&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Talks</title>
      <link>https://blog.howardjohn.info/talks/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://blog.howardjohn.info/talks/</guid>
      <description>talks</description>
    </item>
  </channel>
</rss>
