<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[janaka.dev]]></title><description><![CDATA[Personal notes and thoughts on web technology, software development, and technical product management]]></description><link>https://janaka.dev</link><generator>GatsbyJS</generator><lastBuildDate>Fri, 04 Jul 2025 00:30:54 GMT</lastBuildDate><item><title><![CDATA[Side Project Intro - EasyRunner]]></title><description><![CDATA[Ever shipped a side project, crossed your fingers, and prayed the infra bill wouldn’t explode overnight? Yeah, me too. That moment sparked…]]></description><link>https://janaka.dev/side-project-intro-easyrunner/</link><guid isPermaLink="false">https://janaka.dev/side-project-intro-easyrunner/</guid><pubDate>Thu, 03 Jul 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Ever shipped a side project, crossed your fingers, and prayed the infra bill wouldn’t explode overnight?&lt;br&gt;
Yeah, me too. That moment sparked &lt;strong&gt;EasyRunner&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;&lt;a href=&quot;https://easyrunner.xyz&quot;&gt;EasyRunner.xyz&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;EasyRunner is a single-server, self-hosted Platform-as-a-Service aimed at indie hackers and solopreneurs building SaaS products. It guarantees no surprise bills and avoids lock-in.&lt;/p&gt;
&lt;p&gt;The first release is a CLI that configures an Ubuntu VM (or VPS) on any cloud provider for painless app deployment. Communication and configuration happen agent-lessly over SSH. The hosting stack is Caddy (reverse proxy) and Podman (container runtime). The CLI itself is written in Python.&lt;/p&gt;
&lt;p&gt;I’ve been working on EasyRunner on and off since the end of last year. It’s already usable, but a few rough edges need tidying up before launch.&lt;/p&gt;
&lt;h3&gt;Origin story — scratching my own itch&lt;/h3&gt;
&lt;p&gt;This project grew out of challenges I hit while building &lt;a href=&quot;https://docq.ai&quot;&gt;Docq.AI&lt;/a&gt;. Our monolithic app relies on an embedded SQLite DB and a handful of ML models, so Azure App Service wasn’t an option — we needed directly attached disk.&lt;/p&gt;
&lt;p&gt;Spinning up an Azure VM, automating the infra, bolting on App Gateway … it reminded me that cloud still feels like pulling teeth. Provisioning VMs and load balancers is one task; installing Podman/Docker, hardening the box, and wiring up CI/CD is another.&lt;/p&gt;
&lt;h3&gt;What I really wanted&lt;/h3&gt;
&lt;p&gt;The Developer Experience (DX) of Vercel, Render, or Railway &lt;em&gt;plus&lt;/em&gt; the portability, cost predictability, and architectural freedom of raw VMs. Direct-attached disk? ARM CPU? Custom networking? No problem.&lt;/p&gt;
&lt;p&gt;Hosted PaaS products impose plenty of hidden constraints — you rarely notice until you slam into them. More options mean more room to manoeuvre.&lt;/p&gt;
&lt;h3&gt;Side-project reality check&lt;/h3&gt;
&lt;p&gt;Most side projects never need complex, highly available clusters. The trick is staying alive long enough to find traction, &lt;em&gt;without&lt;/em&gt; a heart-stopping invoice. Cheap VMs fit the bill: simple, versatile, and you can multi-tenant several apps on one box.&lt;/p&gt;
&lt;h3&gt;Existing options didn’t click&lt;/h3&gt;
&lt;p&gt;Some competitors aren’t fully open-source, others lean on Kubernetes, or they try to solve &lt;em&gt;every&lt;/em&gt; problem and end up bloated. I’m laser-focusing EasyRunner on hosting the apps you’re building — not your media server or home automation rig.&lt;/p&gt;
&lt;h3&gt;Licensing &amp;#x26; next steps&lt;/h3&gt;
&lt;p&gt;EasyRunner is currently closed-source. I’ll ship it under a perpetual per-server business licence: buy once for major versions or subscribe for ongoing updates. If revenue clears a healthy threshold, I’ll share a cut with the open-source projects EasyRunner stands on.&lt;/p&gt;
&lt;p&gt;Stay tuned — and maybe, just maybe, you can skip that next infra-induced headache.&lt;/p&gt;
&lt;p&gt;Goto &lt;a href=&quot;https://easyrunner.xyz&quot;&gt;EasyRunner.xyz&lt;/a&gt; and join the waiting list to show your interest and support.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Arduino Desktop Clock - UK Daylightsaving Algorithm]]></title><description><![CDATA[A couple of years back I built this digitial desktop clock. It was mainly for fun but it was July 2020, we were mid pandemic and working…]]></description><link>https://janaka.dev/arduino-desktop-clock-daylight-saving-algo/</link><guid isPermaLink="false">https://janaka.dev/arduino-desktop-clock-daylight-saving-algo/</guid><pubDate>Sat, 09 Apr 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A couple of years back I built this digitial desktop clock. It was mainly for fun but it was July 2020, we were mid pandemic and working from home. I was using a little Casio wrist watch as desktop clock. It sort of did the job but the digits were small and wasn’t readable at night, I like dim lighting. So that was my “real” use case.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ed7ee897fdc675c4889af3af7112133b/4ad3a/tweet-screenshot-2022-04-09-12-22-24.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 116.89189189189189%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAABYlAAAWJQFJUiTwAAAFgUlEQVQ4y42VeVCUdRzG+a+//KNsnBqnQ8dKx8lqysZjSjwqszRCEVMGUVxuWEBhl725L5cIAYVABGQ5BAWVuEIUjcscdRo7vI/URc5dYJdlkU+/Xa/6o6nfzDPvvO8787zP9/l+v8/rMgVMWkxMWEfp6x8Q6Mdo7MXY28vde/cxmcxMTU0x+fAhD/8FjndXhyax2R/iIvior2nm3NlfuXL9Opd++4PrN27y59273L5zh+FhE/91HKIu9j0lnOLStWFuGccwmU0MDA5jHR/HPjnJuM3mhNU6zrDJhMViccJxbx4ZYWzMwqjZjGXk0Ucdlbg45DrOuCi5u7ODn8/20N7ezi8XL9DV8RM93V10dnVzpqOTjs4uJy5cvCie9dDT08O5S1fo+uNP7pknROmC0OmBUDNqtfPrPTPX+sf53WjhhvDkSr+NO8M2xixWJkU5AwND9A0MCnWjopoRRkdHGbFD7wQM2nB66fLEWKttgpPnL3D81EmqWxqoaW2lsrmZ+lOnaRDX012nMN67xVCfkYEH9xl8cn1wl6He25gHe508zpIdppqGhgiL8mWF+1LeXTGXBa5zWLR6Htt2ePD8jJfw8vGgtqqAxiMlnDheQXNtGa3HKjjTVENbfSXdJ+ux2+3PPBwQ45KZmUJuzm50yXK+CXJnveQzMr5N5I357+Pm5kbL8UqajpbTLkhONlbTUGug5WgF7Y01dLbVMzEx8XfCPvKz9Xyfo0efrCIgxIN1XouI3unH0sWLefnVOSQnaNGnxVNauIfD5fsF8RGqDYUU5Wdxqrnunwr7+x6wL3s3e79Lpq5QT1VOPMUZaqpyk0iShfLe+wtZtmoNz017BW9vb7L3ZAi1lWRlpJKpT6S6otgxN888HB4aJCFWyeIlSynLy6CroYojpYUcLS8iRadgwbsLeecDV1xcprPmC3f2F+RSIvDhkpVo1TJKD+Q9UyjGhzExnBs8NjL7rfnkZyTQVJGPITedw8U5SAN2MG36bGbMnM+LM+Ywd/5S5r39EZ6em5n52gKmvfA62yUBTDgJxQw6zs1bt1j+5TpmvTmPqIhg6kpzSVdHss3Hn+Wfb2XWAne+3BBKkDSWT9f6sny1DytXb2Stuyfr1nvgHxKKTWzVU0LH3i77fA2LP3Zl82ZPvLy2suoTN1zXBBMSXU1QVC3B8iak6nbCVW3I0q+hTTyITitHGrGLOJ1WrOLYPwm/+MqNrzduwttXgscWPzZuCcJti5avthaz3mcP3iEGtksP4xN8kG1hFcgV6cJ3BQGBIUTs0jg36CmhI10CgwIIDfFHptARHZ1EaGQWGwLacA0wszrkAZuUVwlP7cZXdRmJvBW/4CT8/cPZtUvB/vx9IjSsDsJHY9NrNJKg0wjpStFVLaqQeDx9NHj4HcAtoAVf9XmCks+jym1GknAVr6gOFDIVSYl7qK6q55fuE4+7/IRQBGpsYiyaeBW6hHhSZClEhKkJ1OSi1pQSpKxHGvsjkXFNyPWVxOgNYqNyUCpT2L07m6KCHGzOTXlMeLvXSLQg0yapCdYoiFDq0ESokWoyxZztJSg8TzSkRDToIJHaEiS6XGLi9agTvyU1MwtNktaZnU89vCM8jJbvJDlRQ5hUSkxSLHmpaTT80EiZwYBKkSZ8zUYSoUcel8X24J3EyOUkJKdTWl7Hvvy9WP7uodF4X8iPQhYTQVy8kmOGAgzpaSh0sUgjZYSGSshISyU2Jg75ThnS8DBUyhj8Jf5skQTyXcEBEQ72R3nojC8R/+UVpRwoLuBEWwOXfztLS10N2rhECouLMJTuIzk1hUOHKjlaUU5R0X7KykrIz88jOy+bI8drRVMmHyf2Y5hGLCKdxxkZszJkHnXi/x6bze78D/0FmvZ9H8hBKdwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Screenshot of clock from Tweet on 4 July 2020&quot;
        title=&quot;Screenshot of clock from Tweet on 4 July 2020&quot;
        src=&quot;/static/ed7ee897fdc675c4889af3af7112133b/fcda8/tweet-screenshot-2022-04-09-12-22-24.png&quot;
        srcset=&quot;/static/ed7ee897fdc675c4889af3af7112133b/12f09/tweet-screenshot-2022-04-09-12-22-24.png 148w,
/static/ed7ee897fdc675c4889af3af7112133b/e4a3f/tweet-screenshot-2022-04-09-12-22-24.png 295w,
/static/ed7ee897fdc675c4889af3af7112133b/fcda8/tweet-screenshot-2022-04-09-12-22-24.png 590w,
/static/ed7ee897fdc675c4889af3af7112133b/efc66/tweet-screenshot-2022-04-09-12-22-24.png 885w,
/static/ed7ee897fdc675c4889af3af7112133b/4ad3a/tweet-screenshot-2022-04-09-12-22-24.png 1152w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I’d been hacking around with Arduino for a few years before this. At first using the original boards but then I came across the &lt;a href=&quot;https://www.espressif.com/&quot;&gt;ESP&lt;/a&gt; boards. First the ESP8266 which was great but the network stack was limitd. For example didn’t support the newer versions of TLS so working with the likes of AWS IoT wasn’t great. IIRC memory was also too limiting for use cases making external calls. Then came the ESP32 which is the platform I’ve been using lately - I’m still using the original release there have been a few iterations with more features. This clock is the only hardware related side-project I have going for the last couple years.&lt;/p&gt;
&lt;p&gt;I’ve been hacking on this clock project here and there. To be honest the only time I needed to update it’s firmware is to adjust the daylight saving offset. After doing it three times manually I decided to automate it. The simplest solution would have been to add a physical switch to toggle. But I decided I wanted to take the relatively more complicated route just for the challenge.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;So what’s the big deal?&lt;/em&gt; I hear you ask.&lt;/p&gt;
&lt;p&gt;The ESP32 doesn’t have a built-in RTC and my design doesn’t use an RTC module. I cannot remember why exactly but I suspect that on the weekend I decided to build I wanted  an initial version up and running within a few hours so used hardware and code I already had to hack - it’s still held together by a breadboard and jump leads as seen in the photo :). Time is sync’d from Internet time servers on boot up and then once per day to handle drift. So there’s no daylight saving functionality built into the hardware or standard libs. I also have a few requirements: 1) overall optimise for minimal power usage 2) minimise third party libs, the ones I found seem to do more than just calculate if it’s BST or not. 3) minimise external network calls to save power and avoid the extra service binding code. Really it didn’t seem worth an service call for something that should be fairly simple to handle locally.&lt;/p&gt;
&lt;p&gt;Honestly, if I found code on the web I could copypaste, I would have. I didn’t find something obvious so “invented” it myself. Highly likely there’s a more efficient way of doing this but this does the job as a first iteration. One day I might optimise, again just for fun.&lt;/p&gt;
&lt;p&gt;Here’s the snippet. See the &lt;a href=&quot;https://github.com/janaka/desktop-clock/blob/master/src/sketch.ino/sketch.ino&quot;&gt;repo&lt;/a&gt; for complete code and details.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;c++&quot;&gt;&lt;pre class=&quot;language-c++&quot;&gt;&lt;code class=&quot;language-c++&quot;&gt;unsigned int tm_mon = (unsigned int)ti.tm_mon; // month 0=Jan,1=Feb,2=Mar,3=Apr,4=May,5=Jun,6=Jul,7=Aug,8=Sept,9=Oct,10=Nov,11=Dec
  unsigned int tm_mday = (unsigned int)ti.tm_mday; // date 
  unsigned int tm_wday = (unsigned int)ti.tm_wday; // day of week 0=Sun,1=Mon...6=Sat
  Serial.print(&amp;quot;mon=&amp;quot;);
  Serial.print(tm_mon);
  Serial.print(&amp;quot;, mday=&amp;quot;);
  Serial.print(tm_mday);
  Serial.print(&amp;quot;, wday=&amp;quot;);
  Serial.println(tm_wday);

  // Self contained UK daylight saving algo. 
  // Not accurate to the hour of change which is good enough for me. 
  // i.e. switch at 12am rather than BST at 1am and into GMT at 2am. 
  // Use at your own risk 
  if (tm_mon&amp;gt;2 &amp;amp;&amp;amp; tm_mon&amp;lt;9) {
     // Apr-Sept is BST for sure  
     daylightOffset_sec= 3600;
     Serial.println(&amp;quot;cond1&amp;quot;);
  } else if (tm_mon==2 &amp;amp;&amp;amp; tm_mday&amp;gt;24 &amp;amp;&amp;amp; (tm_mday+(7-tm_wday)) &amp;gt; 31) {
    // BST starts last Sun in March. Cover last Sun to 31st. Earliest Sun is 25th.  0 = Sun. 2 = Feb 
    Serial.println(&amp;quot;cond2&amp;quot;);
    daylightOffset_sec= 3600;
  } else if (tm_mon==9 &amp;amp;&amp;amp; ( tm_mday&amp;lt;24 || (tm_mday+(7-tm_wday)) &amp;lt; 32 )) { 
    // BST ends last Sun in Oct. Cover to the last Sun. Earliest Sun is 25th. 0 = Sun. 9 = Oct
    Serial.println(&amp;quot;cond3&amp;quot;);
    daylightOffset_sec= 3600;
  } else {
    Serial.println(&amp;quot;catch all&amp;quot;);
    daylightOffset_sec = 0;
  }

  Serial.print(&amp;quot;after logic, daylightOffset_sec=&amp;quot;);
  Serial.println(daylightOffset_sec);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[What's Platform Engineering?]]></title><description><![CDATA[“Platform Engineering” is the act of developing common internal systems that enable teams working on the customer-facing product (stream…]]></description><link>https://janaka.dev/whats-platform-engineering/</link><guid isPermaLink="false">https://janaka.dev/whats-platform-engineering/</guid><pubDate>Wed, 27 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;“Platform Engineering” is the act of developing common internal &lt;em&gt;systems&lt;/em&gt; that enable teams working on the customer-facing product (stream-aligned&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; or empowered&lt;sup id=&quot;fnref-2&quot;&gt;&lt;a href=&quot;#fn-2&quot; class=&quot;footnote-ref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; teams) to focus on the customer, move faster, and scale efficiently. These systems must address a common need across most, ideally all, of engineering (&lt;a href=&quot;https://en.wikipedia.org/wiki/Total_addressable_market&quot;&gt;Total Addressable Market&lt;/a&gt; for Platform Engineering). These systems need to have high standards for self-service which create autonomy. Platform team success is measured by high-levels of adoption, usage, and % engineering hours freed up for customer “feature development”. For success, develop, deliver, and support these systems as products by applying a Product Management mindset.&lt;/p&gt;
&lt;p&gt;I group platform systems into two categories:&lt;/p&gt;
&lt;p&gt;Tools - used to bake and ship a cake, the whisk used to beat the eggs and the oven. These are used at design-time/development-time throughout the development lifecycle (SDLC) aka value stream. You should think of these as the control plane of your system. Examples: testing frameworks, CI/CD systems, IDEs, launch flag systems, logging, and monitoring.&lt;/p&gt;
&lt;p&gt;Building blocks - are the ingredients that go into the cake. The customer consumes these things. How well the cake bakes and tastes depends on the quality of the ingredients. These are runtime components, you should think of these together as the data plane. Examples: programming languages, frameworks, libraries, databases, and hosting systems.&lt;/p&gt;
&lt;p&gt;Defining &lt;em&gt;platform&lt;/em&gt; is for another time but it’s not a singular thing. A SaaS stack is composed of platforms, think of them as layers with hardware all the way at the bottom. Platform engineering in SaaS exists somewhere in the middle with everything below typically bought from cloud infrastructure providers like AWS. The lines are constantly moving as the novel practices become more commonly accepted, then productised, and eventually become a utility like AWS &lt;sup id=&quot;fnref-3&quot;&gt;&lt;a href=&quot;#fn-3&quot; class=&quot;footnote-ref&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;. If you are in platform engineering get comfortable with constantly reinventing ones job spec and technology skillset.&lt;/p&gt;
&lt;p&gt;What’s the structure of a platform engineering team? this cannot and should not be answered in isolation. It must be designed in context of the wider product engineering organisation and business which includes factors such as scale. It could be a single team, a group of teams under a common platform mission, or multiple teams under independent missions.&lt;/p&gt;
&lt;p&gt;Ultimately platform engineering isn’t defined by a universal set of responsibilities anchored around specific technologies. It’s not a bucket you throw everything with labels like AWS, CI/CD, or server. Remember, the top level objective is to enable stream-aligned teams to focus on the customer, move fast, and scale. Therefore, the team structure depends on what platforms are needed which depend on what challenges the stream-aligned teams are/will be facing. There may well be some common practices and patterns that have emerged. Especially has you go lower down the stack, there should be less and less reinventing the wheel. Team Topologies&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; and Accelerate&lt;sup id=&quot;fnref-4&quot;&gt;&lt;a href=&quot;#fn-4&quot; class=&quot;footnote-ref&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; are some of the best and broadly recognised writing on this topic to-date.&lt;/p&gt;
&lt;p&gt;Finally, I remind myself that (internal) platform engineering isn’t about solving problems with &lt;em&gt;just&lt;/em&gt; technology, remember the people factor. The culture, incentives, motivations, and team interactions all play an important part.&lt;/p&gt;
&lt;p&gt;The above is my current (Oct 2021) best thinking based on experience and observations. If you have any thoughts, questions, or recommended reading hit me up on Twitter &lt;a href=&quot;https://twitter.com/janaka_a&quot;&gt;@janaka_a&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://teamtopologies.com/key-concepts&quot;&gt;Team Topologies, by Matthew Skelton&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://svpg.com/product-vs-feature-teams/&quot;&gt;Product vs. Feature Teams, by Marty Cagan, Aug 2019&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;#fnref-2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://twitter.com/swardley/status/988334146954170368&quot;&gt;Wardley Maps - Evolutionary stages, by Simon Wardley&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;#fnref-3&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;
&lt;p&gt;&lt;a href=&quot;https://itrevolution.com/accelerate-book/&quot;&gt;Accelerate: Building and Scaling High Performing Technology Organizations, by Nicole Forsgren, PhD, Jez Humble, and Gene Kim&lt;/a&gt;&lt;/p&gt;
&lt;a href=&quot;#fnref-4&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Introducing Osobisty, My Universal Personal Search Engine]]></title><description><![CDATA[Over the past 3 weeks I built a universal personal search system which I’ve named Osobisty (which means personal or private in Polish). I’ll…]]></description><link>https://janaka.dev/introducing-osobisty-universal-personal-search-engine/</link><guid isPermaLink="false">https://janaka.dev/introducing-osobisty-universal-personal-search-engine/</guid><pubDate>Fri, 01 Oct 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the past 3 weeks I built a universal personal search system which I’ve named Osobisty (which means personal or private in Polish). I’ll dive deeper into &lt;em&gt;why&lt;/em&gt; I need Osobisty in another post. The short story is I’m looking at ways to improve how I capture information, learn (turn into knowledge), and recall that information+knowledge when needed. This post is about why I decided to &lt;strong&gt;build this rather than “buy”&lt;/strong&gt; along with some technical details.&lt;/p&gt;
&lt;h2&gt;What is a Universal Personal Search Engine?&lt;/h2&gt;
&lt;p&gt;It’s a single place to &lt;em&gt;search&lt;/em&gt; and &lt;em&gt;access&lt;/em&gt; my curated content both public or private. I currently have private notes (Zettlekasten), Kindle highlights, and bookmarked tweets indexed. Bookmarked web pages are next on the list. Contact list, stared emails , and stared Google Drive content might come down the road. You get the idea.&lt;/p&gt;
&lt;h2&gt;Inspiration&lt;/h2&gt;
&lt;p&gt;The penny dropped when I heard Linus Lee (aka &lt;a href=&quot;https://twitter.com/thesephist&quot;&gt;The Sephist&lt;/a&gt;) talk about his &lt;a href=&quot;https://thesephist.com/posts/monocle/&quot;&gt;Monocle project&lt;/a&gt; on the &lt;a href=&quot;https://changelog.com/podcast/455&quot;&gt;The Changelog E455 - Building Software for Yourself&lt;/a&gt;. The problem(s) he’s trying to solve resonated. &lt;a href=&quot;https://github.com/amirgamil/apollo&quot;&gt;Apollo&lt;/a&gt; is another personal search engine, inspired by Monocle, which I also looked at.&lt;/p&gt;
&lt;p&gt;The reasons why Linus builds his own software also resonated. I used to outright dismiss the idea but I’ll give it more consideration going forward. However I don’t intend to build my own solutions to the extent Linus has. I’m definitely not going to build an entire custom stack and tool chain. I might implement a very basic programming language for fun and learning.&lt;/p&gt;
&lt;p&gt;As a side note Linus is a &lt;a href=&quot;https://thesephist.com/projects/&quot;&gt;side project&lt;/a&gt; machine, he’s obviously a very talented engineer. He shares a lot of interesting thoughts on various topics from creative work, productivity, startups, to life. It’s worth following his writing for inspiration if those topics interest you.&lt;/p&gt;
&lt;h2&gt;Why build my own solution?&lt;/h2&gt;
&lt;p&gt;Generally my preference is to buy rather than build. Other than websites and this &lt;a href=&quot;https://twitter.com/janaka_a/status/1279422672808620033?s=20&quot;&gt;Desktop Clock&lt;/a&gt; I’ve never built software for personal use. My important &lt;em&gt;needs&lt;/em&gt; and problems don’t tend to be unique so somebody else has already built a solution that is good enough. The same is of course true in this case so here are my reasons.&lt;/p&gt;
&lt;p&gt;My main requirements:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Full control over my private data. I can choose to not expose the system over the Internet. If it’s way less likely to get hacked and leaked in a public way compared to a commercial service.&lt;/li&gt;
&lt;li&gt;No data and information lock-in (including meta). I want to manage as much of the data as possible in easy to edit Markdown because want it to be super portable over a long period of time (multiple decades into the future).&lt;/li&gt;
&lt;li&gt;Support for ingesting &lt;em&gt;my&lt;/em&gt; information sources. This meant having the flexibility to extent with custom source formats.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These criteria exclude SaaS solutions. By those requirements Monocle or Apollo are still in the run, they both can meet my main requirements. However, Monocle is built in Linus’ custom programming language (Ink) and UI framework (Torus). Apollo is written in Golang. If I’m going to spend any time coding I want to use languages and technology that are the most broadly applicable in the industry today. That gives me the most return on time-investment because I gain knowledge that helps with my day job. Which gets at the &lt;strong&gt;other key reason to build rather than buy. I want a good excuse to code and build, because I enjoy it&lt;/strong&gt;. Something that adds value to learning and my day job makes it worth while.&lt;/p&gt;
&lt;p&gt;I think it’s obvious why I don’t want to learn Ink and Torus (&lt;a href=&quot;https://thesephist.com/posts/pl/&quot;&gt;Linus’ reasons are legit&lt;/a&gt;). What’s the problem with Golang then? It’s applicable in the industry. But I don’t want to build a web UI using Golang. It’s the wrong tool for the job in my opinion. If I decided to build the search engine backend myself I may have used Golang but I decided not to hand build that (more about that below). Unlike Linus I don’t have a goal to learn the insides of a search engine implementation. It’s something I’ve already dabbled in, though 10-15yrs ago, and I don’t need to understand it any deeper at this time. Of course assuming I could find a suitable search engine to build on top of…&lt;/p&gt;
&lt;h2&gt;Technologies used to build Osobisty&lt;/h2&gt;
&lt;p&gt;UI - ReactJS + TypeScript.
Crawlers and indexers - NodeJS + TypeScript
Search engine - &lt;a href=&quot;https://typesense.org/&quot;&gt;Typesense&lt;/a&gt; a fast OSS search engine that’s really easy to work with. I started out considering DuckDB which I’d come across recently (I think on &lt;a href=&quot;https://changelog.com/podcast/454&quot;&gt;Changelog E454&lt;/a&gt;) which supported text indexing. And Lucene was probably one of my backup options. But then I discovered Typesene. I also looked at &lt;a href=&quot;https://www.meilisearch.com/&quot;&gt;Meilisearch&lt;/a&gt; but Typesense seemed to be better all-round. I didn’t do a deep analysis, just on paper assessment.&lt;/p&gt;
&lt;p&gt;React is a &lt;a href=&quot;https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-web-frameworks&quot;&gt;very popular industry choice&lt;/a&gt; for web UI and I’m familiar with it. I did consider using this as an excuse to try out &lt;a href=&quot;https://nextjs.org/&quot;&gt;NextJS&lt;/a&gt; but decided against the overhead for now. I wanted to balance productivity and learning. Given the UI was going to be Typescript I decided to use the same for the indexers, again remove the learning/refreshing overheard of two languages rather double down on one.&lt;/p&gt;
&lt;p&gt;As a starting point the UI and functonality is clone of Monocle (full credit to Linus in the code) which I plan to Open Source soon.&lt;/p&gt;
&lt;p&gt;I’ve also started to work on an accompanying Chrome extension. More on that in a separate post. This is also inspired by Linus, he has a Chrome extension that does semantic search in Monocle to surface related content to a web page is browsing. It looks like I’ll have to implement the semantic search algorithm.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[DevSecOps: Taking Snyk and Github Dependabot for a Test Drive]]></title><description><![CDATA[Generally the reason I switched to hosting my own site with Gatsby and play around with various software development tools and technologies…]]></description><link>https://janaka.dev/devsecops-aking-snyk-github-dependabot-test-drive/</link><guid isPermaLink="false">https://janaka.dev/devsecops-aking-snyk-github-dependabot-test-drive/</guid><pubDate>Fri, 03 Sep 2021 10:48:10 GMT</pubDate><content:encoded>&lt;p&gt;Generally the reason I switched to hosting my own site with Gatsby and play around with various software development tools and technologies is to learn the new. Importantly it also gives me a taste of the latest developer experience. Until recently I’ve not followed the InfoSec area, my focus has been elsewhere. I expect to learn a little more on the InfoSec front as well.&lt;/p&gt;
&lt;p&gt;I’ve had Dependabot switched on for this blog (&lt;a href=&quot;https://github.com/janaka/blog-janaka-dev&quot;&gt;repo&lt;/a&gt;) for a while. I wanted to see a) if it would encourage me to keep the software up-to-date, and b) how easy does it make remediation.&lt;/p&gt;
&lt;p&gt;This mode of thinking totally applies to commercial software development. Maintenance is absolutely a necessary part of the software life cycle. But the objective is to minimise this burden so teams can focus on delivering new value to customers.&lt;/p&gt;
&lt;p&gt;This isn’t going to be a comprehensive analysis. Rather, some notes on what I learn, experience, and observe.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer: This is a naive comparison.&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;High-level&lt;/h2&gt;
&lt;p&gt;Snyk and Github provide the same code vulnerability detection and remediation functionality. They detect issues with your code and dependencies.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Github&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependabot (dependencies) + Code Scanning (your code). Code scanning can be performed by multiple tools. Github CodeQL Analysis + third-party scanning tools. Side note: Dependabot and CodeQL Analysis are acquisitions IIRC.&lt;/li&gt;
&lt;li&gt;No Infra-as-Code (IaC) scanning. But I assume this will come, It’s another lang for CodeQL.&lt;/li&gt;
&lt;li&gt;No container image scanning. I assume this will come at some point.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Snyk&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Snyk Code (your code) + Snyk Open Source (dependencies).&lt;/li&gt;
&lt;li&gt;Snyk also supports container image scanning and Infra-as-Code (like Terraform) scanning. Not sure if the latter is dependency and code also.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Github&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependabot: I can’t remember what I did exactly but IIRC it was very easy. Check a couple of boxes and click and enable button.&lt;/li&gt;
&lt;li&gt;Code Scanning (CodeQL): involves adding a GH Action Workflow to the repo. A wizard in the web UI guides you though adding the YAML file (I accepted the default), then creating and merging the PR.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Snyk&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sign up for a Snyk account. I used by Github account and was smooth. I do count this as an additional step even thought technically one needs to create a GH account if going from scratch. But typically ones would have a Github, Gitlab, or Bitbucket account forming he base of their development workflow.&lt;/li&gt;
&lt;li&gt;I got the choice of giving perms to just public or public and private reports. I opted for the former for now. In following steps I was given the option to select which repos were to be scanned.&lt;/li&gt;
&lt;li&gt;Completed the wizard and a scan was immediately kicked off.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Scanning&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Github&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependabot&lt;/li&gt;
&lt;li&gt;seems to perform regular scans and pushes to the repo also trigger scans&lt;/li&gt;
&lt;li&gt;No VS Code extension&lt;/li&gt;
&lt;li&gt;Code Scanning (CodeQL)&lt;/li&gt;
&lt;li&gt;VS Code extension is available for &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-codeql&quot;&gt;CodeQL&lt;/a&gt; but this seems optimised for CodeQL query development rather than vulnerability detection during the app dev workflow.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Snyk&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Auto scan on a daily or weekly frequency. Or manual trigger&lt;/li&gt;
&lt;li&gt;I didn’t time the initial scan. When I did a rescan on this repo today it was reasonably fast, again didn’t time, but in the order or several minutes I feel.&lt;/li&gt;
&lt;li&gt;I assume there’s CI/CD integrations that can trigger scans&lt;/li&gt;
&lt;li&gt;VS Code extension (&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=snyk-security.snyk-vulnerability-scanner&quot;&gt;Snyk Vulnerability Scanner&lt;/a&gt;) should give feedback early in the dev lifecycle. Also faster feedback during the dev inner loop. Currently (v1.1.1) only supports Snyk Code. Extension description says Snyk Open Source support is coming out in Q3.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;The results between the two are different not surprise.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Github&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dependabot: 29 issues ( 2 critical, 14 high)&lt;/li&gt;
&lt;li&gt;Snyk did pick up both these critical issues but scored them &lt;em&gt;high&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Did pick up the sanitize-html critical that Snyk reported&lt;/li&gt;
&lt;li&gt;Code Scanning ( CodeQL): 0 issues&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/75e187f511242fb4ce9c02697c22506f/cb1ac/2021-09-03-11-42-49.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAACC0lEQVQ4y4VU23LaQAz1cxtsfFvfsA0OvmAwF0NCIJ+Qhz51+tLpTP//I04lGTshTMnDGXm1u1od6chatdtje3pF2RywWD9h7ITQLV8wMj08jFUHU2F0sbO3NZq/Z9S/j6j/HJH/bDEtV4hnFbT5jxbVryOcpIIXZXCCFI6fwHQjCcRBP0N3AxgeQb1b3e6S0Cwvhppk8AhBkgv8eI5oWiJMCyh6xPbT7qELbO8WDp2xKREtoMvLzTOSbEEbcbfhJYO11GQowVcw7ACaF81QLHeYFVwDyoqzjB8p0zn4sZCsYYdy+CvoFgU0KYOs2iBfUmHzFdxwdgOmfQ/9GUvF0MZOBCUOvjztvi9wqV6KfNwkfl2/ZHGFqwz9jjLT/KY7V13tZdPbe3gYdxhxQO5MUe8wX2yQPi5u9XcH3w0F01FIJi6i0CUNs2yohuv9GdsnEjc1hxvCPqbAImf0lPr1R//YCeAFMVw/6rrMAs7r7YCq2QsWNDlsS2pWTRNUrlpZ1+sDlttnkRqfYYWwZrkprAbJMCe6pXR5eTN6/6ujzmUh2K5HlBWiwPlAuT0R7ZME9mliOGvjU/d6yoNv2OPgLgxLvVNe7Y5odi8SmG3TvgitwU+P8d6KfdujYHM4C21mFdGI8ghz5hq/OqEJYfDfIkxzmZhoWgjkm3yypossMfFnlcw1Z8Usu1IF+AcZ+oxRHHTN4gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Dependabot&quot;
        title=&quot;Dependabot&quot;
        src=&quot;/static/75e187f511242fb4ce9c02697c22506f/fcda8/2021-09-03-11-42-49.png&quot;
        srcset=&quot;/static/75e187f511242fb4ce9c02697c22506f/12f09/2021-09-03-11-42-49.png 148w,
/static/75e187f511242fb4ce9c02697c22506f/e4a3f/2021-09-03-11-42-49.png 295w,
/static/75e187f511242fb4ce9c02697c22506f/fcda8/2021-09-03-11-42-49.png 590w,
/static/75e187f511242fb4ce9c02697c22506f/efc66/2021-09-03-11-42-49.png 885w,
/static/75e187f511242fb4ce9c02697c22506f/c83ae/2021-09-03-11-42-49.png 1180w,
/static/75e187f511242fb4ce9c02697c22506f/cb1ac/2021-09-03-11-42-49.png 1936w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Snyk&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;46 issues (1 critical, 19 high)&lt;/li&gt;
&lt;li&gt;picked up the sanitize-html critical which Dependabot did not. However the fix wasn’t obvious. As the screenshot shows, there’s no fix-this-vulnerability button. Reading closer shows it’s a transient dependency of &lt;code class=&quot;language-text&quot;&gt;gatsby-transformer-remark@2.16.1&lt;/code&gt; which I assume hasn’t upgraded the sanitize-html dependency yet.&lt;/li&gt;
&lt;li&gt;There’s priority score and severity score. Interestingly the critical has lower priority score. It seems like the maturity of the exploit determines the priority together with the CVSS score. The sanitize-html doesn’t have a known exploit apparently.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/89f26288c8f4ea977a2d9dcb99f472c5/ad1ae/2021-09-03-11-44-25.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 45.27027027027027%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAABYlAAAWJQFJUiTwAAABPUlEQVQoz41S2W6DMBD0//9VfqDKW/vQSiUHIYBvMLaJMt01pApRH4o02vF6d/bAotntcNjvUb1/oPn8gjnV0FUFeTjCNS3GThJ6RClXPPMFSSnYc41AVrjjCc4YWB8whog43yHf3tDULU4BOPsbzsMN+Y7N93KEcR5DCBADiVjrkGPCRNwoD91beDsike+BnOh+DHRvimWfNQ7OeqQpYs4zbvMMoSnAaIs4JYRxIs5BAwKJ55Q3YJGwiqXSwFSa+C2aM4SSGpf6gsEPJSBSNQbzUBKmUojt0ml+6npbjLsUXduh+j6gvbYFXduXUbiA5708WU54xR+CCgxO4tGXvTiytoC5WTnfa6XXOOZms4IiyCM3lyuN3aCnJ7IkmTXRFM4xzB9njmGwX0lVxGNYfox47Izxupf/YPMSSPAHvia1EsWUhNcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Snyk&quot;
        title=&quot;Snyk&quot;
        src=&quot;/static/89f26288c8f4ea977a2d9dcb99f472c5/fcda8/2021-09-03-11-44-25.png&quot;
        srcset=&quot;/static/89f26288c8f4ea977a2d9dcb99f472c5/12f09/2021-09-03-11-44-25.png 148w,
/static/89f26288c8f4ea977a2d9dcb99f472c5/e4a3f/2021-09-03-11-44-25.png 295w,
/static/89f26288c8f4ea977a2d9dcb99f472c5/fcda8/2021-09-03-11-44-25.png 590w,
/static/89f26288c8f4ea977a2d9dcb99f472c5/efc66/2021-09-03-11-44-25.png 885w,
/static/89f26288c8f4ea977a2d9dcb99f472c5/c83ae/2021-09-03-11-44-25.png 1180w,
/static/89f26288c8f4ea977a2d9dcb99f472c5/ad1ae/2021-09-03-11-44-25.png 2270w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Applying Fixes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Both have the create PR with fix feature.&lt;/li&gt;
&lt;li&gt;For whatever reason Snyk doesn’t do this for every issue.&lt;/li&gt;
&lt;li&gt;Both create several PRs which makes sense. However it also makes it a little mentally hard to parse through and decide which order to apply. Maybe it doesn’t matter most of the time. But I do not yet trust that there aren’t going to be conflicts.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;Github Dependabot and Code Scanning are obviously integrated into the Github UI which is ideal. However, at this time the gain seems to be marginal. At least for my one off use case test. Snyk does seem to be more comprehensive feature wise. And the scanning itself seems to catch vulnerabilities more completely. But I’m no expert on this front and haven’t analysed deep enough to see if the difference is meaningful. I’m going to see how the two compare overtime while I’ll stick to only applying issues reported by Snyk.&lt;/p&gt;
&lt;h2&gt;Learnt&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;CWE (&lt;a href=&quot;https://cwe.mitre.org/index.html&quot;&gt;Common Weakness Enumeration&lt;/a&gt;) A Community-Developed List of Software &amp;#x26; Hardware Weakness Types&lt;/li&gt;
&lt;li&gt;CVSS (&lt;a href=&quot;https://www.first.org/cvss/&quot;&gt;Common Vulnerability Scoring System&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[(Note 10 June 2020) Tracing in .NET and AWS App Mesh with OpenTelemetry]]></title><description><![CDATA[As of this writing OpenTelemetry is still in beta. There isn’t a lot of writing about it yet. Official docs are minimal, especially if you…]]></description><link>https://janaka.dev/tracing-with-dotnet-app-mesh-opentelemetry/</link><guid isPermaLink="false">https://janaka.dev/tracing-with-dotnet-app-mesh-opentelemetry/</guid><pubDate>Wed, 10 Jun 2020 23:09:00 GMT</pubDate><content:encoded>&lt;p&gt;As of this writing &lt;a href=&quot;opentelemetry.io&quot;&gt;OpenTelemetry&lt;/a&gt; is still in beta. There isn’t a lot of writing about it yet. Official docs are minimal, especially if you are in .NET Core land. Now throw AWS App Mesh and Fargate into the mix and we are in for a fun ride. Here are notes on what I learnt by messing around with it in a sandbox.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ideally we would want to use Otlp (OpenTelemetry Protocol) as the export format in the app. But Envoy doesn’t support that yet.&lt;/li&gt;
&lt;li&gt;Envoy tracing config changes in newer Envoy versions. App Mesh Envoy is about 2 versions behind right now (1.12.3).&lt;/li&gt;
&lt;li&gt;Managing the Envoy tracing config like this isn’t ideal. Envoy version upgrades will involve changes to the tracing config. Appreciate the App Mesh team providing this escape hatch but I’d hope they add first class support. Not having to manually manage Envoy config is one of the main benefits of App Mesh.&lt;/li&gt;
&lt;li&gt;The Otel .NET SDK is very immature and APIs are very unstable. They are upfront about this. It’s still in Alpha. It’s also behind the Golang and maybe Java SDK. The differences in Zipkin vs Otlp are shown below in an example. It sounds like there’ll be a significant refactor soon and some bits getting pushed into .NET BCL. Aaron from Petabridge wrote more about all this &lt;a href=&quot;https://petabridge.com/blog/state-opentelemetry-dotnet/&quot;&gt;here&lt;/a&gt; and concluded that it’s about a year out still.&lt;/li&gt;
&lt;li&gt;The pipeline architecture of the collector/agent is really nice. Allows one to config multiple pipelines of receivers, processors, and exporters. This makes it easy to send traces to multiple backends and options for switching out. Makes vendor evaluation easier and cheaper. Without cost should also be low.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Agent vs Collector - the naming is poor, they are both collectors by function. The name describes the mode it runs in.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Agent: runs next to the app e.g. sidecar. This will be the core collector. See &lt;a href=&quot;https://github.com/open-telemetry/opentelemetry-collector&quot;&gt;code repo&lt;/a&gt;. It supports only vendor agnostic protocols like Zipkin or OTLP (OpenTelemetry Protocol).&lt;/li&gt;
&lt;li&gt;Collector: Runs stand-alone and aggregates traces from several agents then sends to a backend like Zipkin (self-hosted) or LightStep (cloud). This will be the collector with vendor protocol contributions. See &lt;a href=&quot;https://github.com/open-telemetry/opentelemetry-collector-contrib&quot;&gt;code repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Official docs say “Agent is capable of adding metadata” and “can offer advanced capabilities over the Agent including tail-based sampling”. This implies that there are functional differences between the two binaries.&lt;/li&gt;
&lt;li&gt;See the official explanation &lt;a href=&quot;https://opentelemetry.io/docs/collector/about/&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;High-level view&lt;/h2&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/155a6a11ccce8ad319f1ab59846a86fc/9c7c2/otel-appmesh-arch.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.62162162162163%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAgMDAwMDBAcFBAQEBAkGBwUHCgkLCwoJCgoMDREODAwQDAoKDhQPEBESExMTCw4UFhQSFhESExL/2wBDAQMDAwQEBAgFBQgSDAoMEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhL/wgARCAAOABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAECAwQI/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAAB6dbtJGcP/8QAGhABAQACAwAAAAAAAAAAAAAAAgEDERIhIv/aAAgBAQABBQIa5vCq4dQjVg9dG//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABwQAAICAgMAAAAAAAAAAAAAAAABAhESMVFhkf/aAAgBAQAGPwJ79Moza6OS72XbGrmf/8QAGxAAAwACAwAAAAAAAAAAAAAAAAERITFRYXH/2gAIAQEAAT8h1yCDF2wYpv0yqrVCLX1auCuDGnyf/9oADAMBAAIAAwAAABDTz//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8QP//EABwQAAIDAAMBAAAAAAAAAAAAAAERACExQWGRcf/aAAgBAQABPxCqcAGsL6mQa24rJcM/qZWETDKFVGYcgn6KGydRL6Aa9n//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;image&quot;
        title=&quot;image&quot;
        src=&quot;/static/155a6a11ccce8ad319f1ab59846a86fc/1c72d/otel-appmesh-arch.jpg&quot;
        srcset=&quot;/static/155a6a11ccce8ad319f1ab59846a86fc/a80bd/otel-appmesh-arch.jpg 148w,
/static/155a6a11ccce8ad319f1ab59846a86fc/1c91a/otel-appmesh-arch.jpg 295w,
/static/155a6a11ccce8ad319f1ab59846a86fc/1c72d/otel-appmesh-arch.jpg 590w,
/static/155a6a11ccce8ad319f1ab59846a86fc/a8a14/otel-appmesh-arch.jpg 885w,
/static/155a6a11ccce8ad319f1ab59846a86fc/fbd2c/otel-appmesh-arch.jpg 1180w,
/static/155a6a11ccce8ad319f1ab59846a86fc/9c7c2/otel-appmesh-arch.jpg 1211w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The agent + collector setup is &lt;a href=&quot;https://opentelemetry.io/docs/collector/about/&quot;&gt;recommended by OTel&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Important Config Snippets&lt;/h2&gt;
&lt;p&gt;I’ll link to the working example source code in the future.&lt;/p&gt;
&lt;p&gt;startup.cs for Zipkin protocol.&lt;/p&gt;
&lt;p&gt;This code propagates trace IDs on outbound calls&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;csharp&quot;&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token namespace&quot;&gt;OpenTelemetry&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Trace&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Configuration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 

&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ConfigureServices&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;IServiceCollection&lt;/span&gt; services&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddControllers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddOpenTelemetry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        builder
            &lt;span class=&quot;token comment&quot;&gt;//.SetSampler(Samplers.AlwaysSample)&lt;/span&gt;
            
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;UseZipkin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
                options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ServiceName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hello-world-api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
                options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Endpoint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;zipkinEndpoint&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddRequestAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddDependencyAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At present the API for Otlp is a little different.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;csharp&quot;&gt;&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;// ref https://github.com/open-telemetry/opentelemetry-dotnet/blob/master/src/OpenTelemetry.Exporter.OpenTelemetryProtocol/TracerBuilderExtensions.cs&lt;/span&gt;
  services&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddOpenTelemetry&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sp&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; builder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
       builder
           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SetResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Resources&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;CreateServiceResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;hello-world-api&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UseOpenTelemetryProtocolExporter &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;options &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
               options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Credentials &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ChannelCredentials&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Insecure&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
               options&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Endpoint &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; otlpEndpoint&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddRequestAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;AddDependencyAdapter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Create a custom App Mesh Envoy image with the override config because it’s the easiest way on Fargate. Not ideal for production.&lt;/p&gt;
&lt;p&gt;Envoy (v1.12.3) override config &lt;code class=&quot;language-text&quot;&gt;envoy-otel-tracer-config.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;tracing&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; envoy.zipkin
    &lt;span class=&quot;token key atrule&quot;&gt;typed_config&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;&quot;@type&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; type.googleapis.com/envoy.config.trace.v2.ZipkinConfig
      &lt;span class=&quot;token key atrule&quot;&gt;collector_cluster&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; otel&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;agent
      &lt;span class=&quot;token key atrule&quot;&gt;collector_endpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/api/v1/spans&quot;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#collector_endpoint: &quot;/api/v2/spans&quot;&lt;/span&gt;
      &lt;span class=&quot;token comment&quot;&gt;#collector_endpoint_version: HTTP_JSON&lt;/span&gt;

&lt;span class=&quot;token key atrule&quot;&gt;static_resources&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;clusters&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; otel&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;agent
    &lt;span class=&quot;token key atrule&quot;&gt;connect_timeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1s
    &lt;span class=&quot;token key atrule&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; strict_dns
    &lt;span class=&quot;token key atrule&quot;&gt;lb_policy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; round_robin
    &lt;span class=&quot;token key atrule&quot;&gt;load_assignment&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;cluster_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; otel&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;agent
      &lt;span class=&quot;token key atrule&quot;&gt;endpoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;lb_endpoints&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;endpoint&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
           &lt;span class=&quot;token key atrule&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;token key atrule&quot;&gt;socket_address&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
             &lt;span class=&quot;token key atrule&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 127.0.0.1
             &lt;span class=&quot;token key atrule&quot;&gt;port_value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9411&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;dockerfile&quot;&gt;&lt;pre class=&quot;language-dockerfile&quot;&gt;&lt;code class=&quot;language-dockerfile&quot;&gt;&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;FROM&lt;/span&gt; 840364872350.dkr.ecr.us-west-2.amazonaws.com/aws-appmesh-envoy:v1.12.3.0-prod&lt;/span&gt;
&lt;span class=&quot;token instruction&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;COPY&lt;/span&gt; envoy-otel-tracer-config.yaml /tmp/envoy-otel-tracer-config.yaml&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Env var that tells the App Mesh Envoy container to use the tracing override config file. The complete task def has 3 containers defs: 1) the app 2) App Mesh Envoy 3) OTel agent.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ENVOY_TRACING_CFG_FILE&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/tmp/envoy-otel-tracer-config.yaml&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[(Note) Using gatsby-plugin-s3 with Github Actions]]></title><description><![CDATA[I was originally using the Gatsby and S3 sync Github actions together. This worked fine bit shifting. Later I discovered that updates were…]]></description><link>https://janaka.dev/Using gatsby-plugin-s3 with Github actions/</link><guid isPermaLink="false">https://janaka.dev/Using gatsby-plugin-s3 with Github actions/</guid><pubDate>Mon, 11 May 2020 00:36:00 GMT</pubDate><content:encoded>&lt;p&gt;I was originally using the Gatsby and S3 sync Github actions together. This worked fine bit shifting. Later I discovered that updates were not showing up when browsing on my mobile. A quick Google and I realised there are some &lt;a href=&quot;https://www.gatsbyjs.org/docs/caching/&quot;&gt;HTTP cache headers that Gatsby recommend&lt;/a&gt; which I was not applying. The &lt;a href=&quot;https://gatsby-plugin-s3.jari.io/&quot;&gt;gatsby-plugin-s3&lt;/a&gt; which implements the recommended caching config. So I decided to switch. I didn’t find Github Action examples online so maybe this post will help somebody save time.&lt;/p&gt;
&lt;p&gt;I’m using Cloudflare rather than CloudFront and a pre-created S3 bucket which isn’t managed using code (i.e. Terraform, CloudFormation etc.). It seems they have some workarounds for system like TF and CF that maintain state but maybe it’s best to use the AWS CLI to codify bucket creation in this case.&lt;/p&gt;
&lt;p&gt;Here are the relevant snipets. You can view it in context in the repo &lt;a href=&quot;https://github.com/janaka/blog-janaka-dev&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a better setup than what I had before. It’s more Gatsby tuned and much faster. The previous workflow took 2-3mins to execute. This one takes less than 1.5mins. And if you are wondering, my caching issue is resolved. Well at least I’m seeing changes from my mobile. I’m yet to test if what should be cached is being cached.&lt;/p&gt;
&lt;h4&gt;gatsby-config.js fragment&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;js&quot;&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;gatsby-plugin-s3&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;bucketName&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_S3_BUCKET_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;region&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;AWS_REGION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;token literal-property property&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;janaka.dev&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;package.json fragment&lt;/h4&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;deploy&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npx -n \&quot;-r dotenv/config\&quot; gatsby-plugin-s3 deploy&quot;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Github Actions workflow&lt;/h4&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;.github/workflow/deploy_to_S3_on_push.yaml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;yaml&quot;&gt;&lt;pre class=&quot;language-yaml&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy Website to S3 Hosting

&lt;span class=&quot;token key atrule&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; master

&lt;span class=&quot;token key atrule&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build &amp;amp; Deploy
    &lt;span class=&quot;token key atrule&quot;&gt;runs-on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; ubuntu&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;latest
    &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;AWS_S3_BUCKET_NAME&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.AWS_S3_BUCKET &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;AWS_REGION&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.AWS_REGION &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token key atrule&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Checkout Repo
      &lt;span class=&quot;token key atrule&quot;&gt;uses&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; actions/checkout@master
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Install dependencies
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn install &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;prod &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;pure&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;lockfile
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Build Gatsby Site
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn build
    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Deploy to S3 (with sync)
      &lt;span class=&quot;token key atrule&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; yarn deploy
      &lt;span class=&quot;token key atrule&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.AWS_ACCESS_KEY_ID &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;token key atrule&quot;&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; $&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; secrets.AWS_SECRET_ACCESS_KEY &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;IAM policy&lt;/h4&gt;
&lt;p&gt;It seems like they haven’t figured out policies for all the combinations. See more details in this &lt;a href=&quot;https://github.com/jariz/gatsby-plugin-s3/issues/39&quot;&gt;GH issue&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;json&quot;&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token property&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Sid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;VisualEditor0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:GetBucketLocation&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;*&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Sid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;VisualEditor1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:PutBucketWebsite&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:PutObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:PutObjectAcl&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:GetObject&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:ListBucket&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;s3:DeleteObject&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token property&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::&amp;lt;S3_BUCKET_NAME_HERE&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
                &lt;span class=&quot;token string&quot;&gt;&quot;arn:aws:s3:::&amp;lt;S3_BUCKET_NAME_HERE&gt;/*&quot;&lt;/span&gt;
            &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content:encoded></item><item><title><![CDATA[(Note) Handling Secrets Correctly in Terraform Config]]></title><description><![CDATA[There two things that need to be handled. 1. Encrypt the secret in the Terraform config file Don’t have the secret as plaintext in any of…]]></description><link>https://janaka.dev/handling-secrets-terraform-config/</link><guid isPermaLink="false">https://janaka.dev/handling-secrets-terraform-config/</guid><pubDate>Fri, 08 May 2020 12:18:00 GMT</pubDate><content:encoded>&lt;p&gt;There two things that need to be handled.&lt;/p&gt;
&lt;h3&gt;1. Encrypt the secret in the Terraform config file&lt;/h3&gt;
&lt;p&gt;Don’t have the secret as plaintext in any of the config file. Encrypt using AWS KMS. Then use &lt;a href=&quot;https://www.terraform.io/docs/providers/aws/d/kms_secrets.html&quot;&gt;aws&lt;em&gt;kms&lt;/em&gt;secrets&lt;/a&gt; to decrypt at runtime.&lt;/p&gt;
&lt;p&gt;Can also use an encrypted secret store like AWS Parameter Store or Hashicorp Vault.  &lt;/p&gt;
&lt;h3&gt;2. Use an encrypted backend for state&lt;/h3&gt;
&lt;p&gt;Use Terraform Cloud (&lt;a href=&quot;https://www.terraform.io/docs/backends/types/remote.html&quot;&gt;remote&lt;/a&gt;) as the backend.&lt;/p&gt;
&lt;p&gt;State files store the plaintext version of secrets. So don’t use local statefiles and check-in to version control. Use a encryted backend like Terraform cloud or AWS S3 to persist state.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer: These are notes for myself that I’m sharing. I’m not claiming this is the way or the best way.&lt;/em&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Simple example of KMS encrypt and decrypt using AWS CLI v2]]></title><description><![CDATA[On macOS Encrypt: Decrypt: For context, I wanted to quickly encrypt an API token so I could embed it in a Terraform config. Initially, I…]]></description><link>https://janaka.dev/Simple example of KMS encrypt and decrypt using AWS CLI v2/</link><guid isPermaLink="false">https://janaka.dev/Simple example of KMS encrypt and decrypt using AWS CLI v2/</guid><pubDate>Thu, 07 May 2020 23:34:00 GMT</pubDate><content:encoded>&lt;p&gt;On macOS&lt;/p&gt;
&lt;p&gt;Encrypt:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;aws kms encrypt &lt;span class=&quot;token parameter variable&quot;&gt;--region&lt;/span&gt; eu-west-1 / 
&lt;span class=&quot;token parameter variable&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;aws_profile_name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; / 
--key-id &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;your_kms_key_here&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; /
&lt;span class=&quot;token parameter variable&quot;&gt;--plaintext&lt;/span&gt; fileb://&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;Hello Hello Hello you cheaky secret&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; / 
--encryption-context &lt;span class=&quot;token assign-left variable&quot;&gt;somekey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;sometoken / 
&lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; CiphertextBlob / 
&lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Decrypt:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;sh&quot;&gt;&lt;pre class=&quot;language-sh&quot;&gt;&lt;code class=&quot;language-sh&quot;&gt;aws kms decrypt &lt;span class=&quot;token parameter variable&quot;&gt;--region&lt;/span&gt; eu-west-1 / 
&lt;span class=&quot;token parameter variable&quot;&gt;--profile&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;aws_profile_name&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; / 
--ciphertext-blob fileb://&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;&amp;lt;the_output_from_the_encrypt_command_above&gt;&apos;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; base64 -d&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; / 
--encryption-context &lt;span class=&quot;token assign-left variable&quot;&gt;somekey&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;sometoken / 
&lt;span class=&quot;token parameter variable&quot;&gt;--output&lt;/span&gt; text / 
&lt;span class=&quot;token parameter variable&quot;&gt;--query&lt;/span&gt; Plaintext &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; base64 &lt;span class=&quot;token parameter variable&quot;&gt;-d&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For context, I wanted to quickly encrypt an API token so I could embed it in a Terraform config. Initially, I followed the Terraform doc &lt;a href=&quot;https://www.terraform.io/docs/providers/aws/d/kms_secrets.html&quot;&gt;here&lt;/a&gt;. The command in the doc ran successfully but the Terraform config couldn’t make the API call with the token successfully. As a troubleshooting step I wanted to test the decypt using CLI. This didn’t work. Trying to run the command with a sentence as the plaintext errored. It seems because it was a token the command ran successfully but didn’t encrypt the actual token. This &lt;a href=&quot;https://random.ac/cess/2017/02/04/simple-aws-cli-kms-encrypt-decrypt-example/&quot;&gt;post&lt;/a&gt; was a great simple example. But it didn’t work either. When encrypting I was getting the error &lt;code class=&quot;language-text&quot;&gt;Invalid base64: &quot;Hello Hello Hello you cheaky secret&quot;&lt;/code&gt;. This Github &lt;a href=&quot;https://github.com/aws/aws-cli/issues/4994&quot;&gt;issue&lt;/a&gt; put me on the right track. AWS made some breaking changes in CLI v2.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Hosting this blog on IPFS with DNS and TLS]]></title><description><![CDATA[I first got this site up and running a couple of weeks back. Originally my goal was to host exclusively on IPFS. This was an exercise to…]]></description><link>https://janaka.dev/Hosting this blog on IPFS with DNS and TLS/</link><guid isPermaLink="false">https://janaka.dev/Hosting this blog on IPFS with DNS and TLS/</guid><pubDate>Fri, 01 May 2020 23:38:00 GMT</pubDate><content:encoded>&lt;p&gt;I first got this site up and running a couple of weeks back. Originally my goal was to host exclusively on IPFS. This was an exercise to learn about IPFS hands-on. I wanted the site address to be &lt;code class=&quot;language-text&quot;&gt;http://janaka.dev&lt;/code&gt;. As I started setting that up, initially against the &lt;code class=&quot;language-text&quot;&gt;ipfs.io&lt;/code&gt; gateway, I learnt that the &lt;code class=&quot;language-text&quot;&gt;.dev&lt;/code&gt; TLD was TLS only. The &lt;code class=&quot;language-text&quot;&gt;ipfs.io&lt;/code&gt; gateway didn’t support TLS. So now I had the additional challenge.&lt;/p&gt;
&lt;h3&gt;CloudFlare&lt;/h3&gt;
&lt;p&gt;A little Googling and all I could find was &lt;a href=&quot;https://www.cloudflare.com/distributed-web-gateway/&quot;&gt;CloudFare’s IPFS gateway&lt;/a&gt; that supported TLS. I had used &lt;a href=&quot;textile.io&quot;&gt;textile.io&lt;/a&gt; buckets to pin the content. The site was accessible through the address they generated, no problem. But I had real problems getting the site to load reliably via the CloudFlare gateway with DNSLink and my domain. It nearly always didn’t load. So I decided to host &lt;code class=&quot;language-text&quot;&gt;https://janaka.dev&lt;/code&gt; using S3 and have a site mirror setup at &lt;a href=&quot;https://ipfs.janaka.dev&quot;&gt;https://ipfs.janaka.dev&lt;/a&gt; even though at this point is wouldn’t work. I needed setup to tinker with.&lt;/p&gt;
&lt;p&gt;I couldn’t find any formal support from CloudFlare for the IPFS gateway. I wasn’t surprised as I knew it was somewhat an experiment. I Tweeted on the off chance. The discussion put Fleek.co on my radar.&lt;/p&gt;
&lt;h3&gt;Fleek.co&lt;/h3&gt;
&lt;p&gt;Fast-Forward to today. I decided randomly to give Fleek a shot. I must say it was pretty quick to get the site moved over and working successfully. Site load performance seems great and works reliably so far.&lt;/p&gt;
&lt;p&gt;In my original setup with Textile.io + CloudFlare IPS Gateway I had to do all the work to setup CI/CD. I used Github Actions. Also Textile didn’t have a way to automate the IPNS step. With Fleek, it handles CI/CD soup to nuts (I heard this saying recently and it stuck. Apparently it’s American Google tells me :) ). It’s all wizard driven. Logging with Github. Select the repo, it detected that it was Gatsby, filled out all the build config defaults, TLS cert etc. There were a few manual steps for DNS config of course but this is expected. I presume if my domain was managed by Fleek these would also be automated. So now &lt;a href=&quot;https://ipfs.janaka.dev&quot;&gt;https://ipfs.janaka.dev&lt;/a&gt; is built, deployed, and pinned via Fleek.co&lt;/p&gt;</content:encoded></item><item><title><![CDATA[(Collection) IPFS Ecosystem]]></title><description><![CDATA[https://infura.io IPFS and Ethereum platform with API and SDK Runs an IPFS gateway . But it doesn’t support IPNS (as of 12 April 2020) https…]]></description><link>https://janaka.dev/collection-ipfs-ecosystem/</link><guid isPermaLink="false">https://janaka.dev/collection-ipfs-ecosystem/</guid><pubDate>Wed, 15 Apr 2020 03:08:00 GMT</pubDate><content:encoded>&lt;h3&gt;&lt;a href=&quot;https://infura.io&quot;&gt;https://infura.io&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IPFS and Ethereum platform with API and SDK&lt;/li&gt;
&lt;li&gt;Runs an IPFS gateway &lt;code class=&quot;language-text&quot;&gt;https://ipfs.infura.io&lt;/code&gt;. But it doesn’t support IPNS (as of 12 April 2020)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://temporal.cloud&quot;&gt;https://temporal.cloud&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IPFS platform with APIs and SDK&lt;/li&gt;
&lt;li&gt;Provides IPFS pinning. Claims to be the cheapest&lt;/li&gt;
&lt;li&gt;Public gateway at &lt;code class=&quot;language-text&quot;&gt;https://gateway.temporal.cloud&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;S3X services enables video streaming &lt;a href=&quot;https://medium.com/temporal-cloud/introducing-s3x-endless-ipfs-dynamic-possibilities-stream-videos-host-dynamic-websites-f0072127070f&quot;&gt;blog post&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://textile.io&quot;&gt;https://textile.io&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IPFS platform with some abstractions. Makes it easier to work with IPFS.&lt;/li&gt;
&lt;li&gt;buckets - an S3 esq abstraction for managing uploaded object content. Includes pinning and versioned endpoints for access over HTTP.&lt;/li&gt;
&lt;li&gt;threads - a MongoDB esq abstraction for structured data.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://pinata.cloud/&quot;&gt;https://pinata.cloud/&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IPFS platform with API and toolkit&lt;/li&gt;
&lt;li&gt;Provides an IPFS pinning service. You pay them to pin (store) your data&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://www.eternum.io/&quot;&gt;https://www.eternum.io/&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IPFS platform&lt;/li&gt;
&lt;li&gt;Provides a pinning service&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://fleek.co&quot;&gt;https://fleek.co&lt;/a&gt; previously &lt;em&gt;terminal.co&lt;/em&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;platform for building web sites &amp;#x26; apps on IPFS.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://awesome.ipfs.io/&quot;&gt;https://awesome.ipfs.io/&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Currated set of IPFS related resources&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://cloudflare-ipfs.com&quot;&gt;https://cloudflare-ipfs.com&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Public IPFS Gateway&lt;/li&gt;
&lt;li&gt;Supports TLS certs for custom domains. Useful when hosting sites on &lt;code class=&quot;language-text&quot;&gt;.dev&lt;/code&gt; TLD which is HTTPS only.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;https://d.tube/&quot;&gt;https://d.tube/&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;A Youtube clone. Video is stored on IPFS.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;a href=&quot;IPLD.io&quot;&gt;IPLD&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;IPLD is the latest protocol for linking different hash based structures e.g. link a file IPFS to a commit in Git. Bitcoin and Ethereum also examples of hasg based structured currently supported. IPLD replaces the Merkel-DAG spec in IPFS.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://explore.ipld.io&quot;&gt;IPLD Explorer in the browser&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content:encoded></item><item><title><![CDATA[Hello World]]></title><description><![CDATA[Update 15 April 2020: I’ve not managed to get IPFS hosting to work reliably yet. Until I do, https://janaka.dev is hosted traditionally (web…]]></description><link>https://janaka.dev/hello-world/</link><guid isPermaLink="false">https://janaka.dev/hello-world/</guid><pubDate>Sat, 28 Mar 2020 18:31:00 GMT</pubDate><content:encoded>&lt;p&gt;Update [15 April 2020]: I’ve not managed to get IPFS hosting to work reliably yet. Until I do, &lt;a href=&quot;https://janaka.dev&quot;&gt;https://janaka.dev&lt;/a&gt; is hosted traditionally (web2). A mirror is hosted on IPFS (web3) at &lt;a href=&quot;https://ipfs.janaka.dev&quot;&gt;https://ipfs.janaka.dev&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is my first post hosted on &lt;a href=&quot;ipfs.io&quot;&gt;IPFS&lt;/a&gt;, the distributed Internet. How exciting!&lt;/p&gt;
&lt;p&gt;I wanted an excuse to play with IPFS to learn and thought hosting a blog on IPFS would be a good little project. So over the weekend I had a little hack and here you are.&lt;/p&gt;
&lt;p&gt;It also gave me an excuse to play with static site generators. I’ve picked Gatsby. I’m starting simple, using the &lt;code class=&quot;language-text&quot;&gt;Gatsby blog starter&lt;/code&gt; and markdown files.&lt;/p&gt;
&lt;p&gt;In the future I might move the content to a headless CMS like &lt;a href=&quot;https://contentful.com&quot;&gt;Contentful&lt;/a&gt; or &lt;a href=&quot;https://prismic.io&quot;&gt;Prismic&lt;/a&gt;. Why? well not because I think I need anything fancier than MD files. I think a static site with a headless CMS is a strong architecture for a marketing website. Benefits on the technical site are very fast page load times, low hosting costs including maintenance, and static stability. If managing content at scale then content managers still get a powerful and friendly CMS. I’ve not tried Contentful or Prismic yet so that’s a bit of an assumption. Hence why I want to try the setup myself to get some idea how well it all could work.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Delivering on a cloud-first promise]]></title><description><![CDATA[This is one of those promises I made to myself, approximately 5 years ago. I had long since realised that if they can’t see it, they don’t…]]></description><link>https://janaka.dev/delivering-on-cloud-first-promise/</link><guid isPermaLink="false">https://janaka.dev/delivering-on-cloud-first-promise/</guid><pubDate>Fri, 04 Jul 2014 09:50:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;./66c3b9a3052f4d5ab04a637b4d41c644.jpg&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 590px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.1081081081081%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAgMDAwMDBAcFBAQEBAkGBwUHCgkLCwoJCgoMDREODAwQDAoKDhQPEBESExMTCw4UFhQSFhESExL/2wBDAQMDAwQEBAgFBQgSDAoMEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhL/wgARCAAbABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAYEBQcI/8QAFwEBAQEBAAAAAAAAAAAAAAAABgUCBP/aAAwDAQACEAMQAAABr2lhryS/Qy9KhvCF5NlcKHoUxE3K/8QAGhAAAwEBAQEAAAAAAAAAAAAAAwQFAgEGFf/aAAgBAQABBQK41yY0pqiWXCE8SfYYnNMK0ghHPY4dJ59ZeufSZzzHz/I9TrvbsEGNp2DkXD//xAAaEQACAwEBAAAAAAAAAAAAAAABAgADEiFB/9oACAEDAQE/AVpvZA2D2WO2zG2K175DT2f/xAAeEQACAQMFAAAAAAAAAAAAAAABAgADBDESEyEyQf/aAAgBAgEBPwF2TGdOYtvRImwncewUw3M//8QAKBAAAgAFAgUEAwAAAAAAAAAAAQIAAwQREgUhExQiQVExMmGxI5HB/9oACAEBAAY/Am6KpHBsmHow8xbSxUGflccVLD59YU63LlLU3tZR2iYtZSyGemYrd1+oWXQYyr7rLU9u+0SnDh7j3eY1Hm6inVGmYBGUko369DvEoczmUR0yUYC3n58RQcKVkOAB+LqGxI/kagL7cyx+orJ7rlMkr0E9o0xZDtLXkVNlNh7mj//EAB8QAQACAwADAAMAAAAAAAAAAAEAESExQVFxgWGh8f/aAAgBAQABPyHZQA6ubZvv6llpJVpy9e4UEOgStVpYFR9irsFlXGfGIoZi12h38s5JvnOChXTVwfdIhGRap/RL4qqYs4uwlWD5GIueYPQ9CIFUCfmjAxdcHxp+zoMOw8yf/9oADAMBAAIAAwAAABAkI8z/xAAdEQABBAIDAAAAAAAAAAAAAAABABEhMUFhUXGB/9oACAEDAQE/EBsAGM9V5BEjRU8DThNYnTd91bRwprnJX//EAB0RAAMAAgIDAAAAAAAAAAAAAAERIQAxUXGBsdH/2gAIAQIBAT8QIEAipfe7giSriiwiIFtAPyE2xNbYGd8t+8//xAAcEAEBAQEBAQADAAAAAAAAAAABESEAMUFxkcH/2gAIAQEAAT8QyamVlquCyEEaMnQQQ26WZH9uPK41BwB0CurvXvr1GAMQjBEV1XFZ1AgSlqtZZxOLeCUg1KIPjKZzTJM2B6BGkb6xOCl7aOIbYAhYPi9DNwOZQkrQ/n7yWl8Z7n6zj48XuwxbPPA8QfgYSCkA1/nf/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Front of rack before pulling kit&quot;
        title=&quot;Front of rack before pulling kit&quot;
        src=&quot;/static/8aae6074d0539ea52b8d65ea712b5da9/1c72d/66c3b9a3052f4d5ab04a637b4d41c644.jpg&quot;
        srcset=&quot;/static/8aae6074d0539ea52b8d65ea712b5da9/a80bd/66c3b9a3052f4d5ab04a637b4d41c644.jpg 148w,
/static/8aae6074d0539ea52b8d65ea712b5da9/1c91a/66c3b9a3052f4d5ab04a637b4d41c644.jpg 295w,
/static/8aae6074d0539ea52b8d65ea712b5da9/1c72d/66c3b9a3052f4d5ab04a637b4d41c644.jpg 590w,
/static/8aae6074d0539ea52b8d65ea712b5da9/212bf/66c3b9a3052f4d5ab04a637b4d41c644.jpg 768w&quot;
        sizes=&quot;(max-width: 590px) 100vw, 590px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
    &lt;/span&gt;&lt;/a&gt;
&lt;a href=&quot;./88187712676b4e6a9fff0d5caff7d3d0.jpg&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 340px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.1081081081081%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAgMDAwMDBAcFBAQEBAkGBwUHCgkLCwoJCgoMDREODAwQDAoKDhQPEBESExMTCw4UFhQSFhESExL/2wBDAQMDAwQEBAgFBQgSDAoMEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhL/wgARCAAbABQDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAMEBQYHAv/EABcBAAMBAAAAAAAAAAAAAAAAAAMEBQb/2gAMAwEAAhADEAAAAWcdDqPo7wVwLKwKU4bStVfhUdgf/8QAHxAAAgICAQUAAAAAAAAAAAAAAwQBAgUGBxITFBUj/9oACAEBAAEFAsc35fHbjVncea/r6aq3E6m4cdKuvd1jE1KksSfuQ9yXvWJOCIK0Idej/8QAGhEBAAMAAwAAAAAAAAAAAAAAAQACEQMSQf/aAAgBAwEBPwG/Ctu3hsVWLlI0Cf/EABoRAAMAAwEAAAAAAAAAAAAAAAABAgMREhP/2gAIAQIBAT8BxUuRSiLez1P/xAAoEAACAQMCAgsAAAAAAAAAAAABAgADERIhMQShBRQiI0FDUVJhkdH/2gAIAQEABj8Cps1h1WsiG3wTrzgwYH07c4fh08mgi8p0twxucalJx9j8gC0yGyB0O9ozPoTuIyva9ZgWU+FomWLrl7t4WxJvNQNHM7zXHaDSf//EAB0QAQADAAIDAQAAAAAAAAAAAAEAESExYUFRgXH/2gAIAQEAAT8hoZRZ1YIXeZZxUoQ8kwUCFeykBmjSZpp+6+RbyeZpFD08fYNNpega0PtzQPoUi1P7Sw18TTjO73hNEJdnezwEAziuIoRnz8ZGSf/aAAwDAQACAAMAAAAQYPS9/8QAHhEBAAEDBQEAAAAAAAAAAAAAAQAhQVERYXGBsdH/2gAIAQMBAT8QptkdCXv8jBhCOBC1FHXnzeKIT//EABoRAQACAwEAAAAAAAAAAAAAAAEAESFBccH/2gAIAQIBAT8QIzbUEFzCd8lmf//EAB8QAQACAgICAwAAAAAAAAAAAAEAESExUWFBcYGRof/aAAgBAQABPxBlyV5psspFnIdzL1tAaEFxk88TCkq1BKvqPJjDqbptyADRZ75j5M6LoN/BhdhVGxg6AAXmpT9v5VCXqpAzuWDVDGTjbYHXvuNsrErHZ+rByqm0AKgHBxBAujaFDg9sWE2mcs//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Back of rack before pulling kit&quot;
        title=&quot;Back of rack before pulling kit&quot;
        src=&quot;/static/a16ccfa42669c8a881c0bc3218552ddd/d30a3/88187712676b4e6a9fff0d5caff7d3d0.jpg&quot;
        srcset=&quot;/static/a16ccfa42669c8a881c0bc3218552ddd/a80bd/88187712676b4e6a9fff0d5caff7d3d0.jpg 148w,
/static/a16ccfa42669c8a881c0bc3218552ddd/1c91a/88187712676b4e6a9fff0d5caff7d3d0.jpg 295w,
/static/a16ccfa42669c8a881c0bc3218552ddd/d30a3/88187712676b4e6a9fff0d5caff7d3d0.jpg 340w&quot;
        sizes=&quot;(max-width: 340px) 100vw, 340px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is one of those promises I made to myself, approximately 5 years ago. I had long since realised that if they can’t see it, they don’t really care. They don’t care until it goes wrong that is. Therefore spending time on what mattered to my colleagues and our customers and outsourcing the rest became the strategy. I’m pretty sure this isn’t revolutionary thinking but how does one execute is always the question, right?  &lt;/p&gt;
&lt;p&gt;Outsourcing is a concept that had been around for many years but 2009 was different. It was different because cloud computing was starting to gain traction. This method of out sourcing thoroughly suited us. And there started our cloud-first strategy.  &lt;/p&gt;
&lt;p&gt;Yesterday marked a significant milestone in this journey. We pulled the plug on the final major piece of legacy infrastructure. We decommissioned the final rack in the old data centre which to be honest has largely been a very expensive storage cupboard for the last few years.  &lt;/p&gt;
&lt;p&gt;In everything we do I ask the question “Would our customers care?” “How much value would this add to our customer?”. I believe we are now firmly into the second iteration. Seeking to push higher up the stack, IaaS to PaaS to SaaS.  &lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;./0389cbdad6664a7bbd90ddc8c388415e.jpg&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 340px; &quot;
    &gt;
      &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 133.1081081081081%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAMCAgMCAgMDAgMDAwMDBAcFBAQEBAkGBwUHCgkLCwoJCgoMDREODAwQDAoKDhQPEBESExMTCw4UFhQSFhESExL/2wBDAQMDAwQEBAgFBQgSDAoMEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhISEhL/wgARCAAbABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAABwAFCAb/xAAVAQEBAAAAAAAAAAAAAAAAAAADAP/aAAwDAQACEAMQAAABPFMg6cOEr0kwELny+kCurY8p/wD/xAAdEAACAgMAAwAAAAAAAAAAAAADBAIFAQYSFRY0/9oACAEBAAEFAqsmPXaKpCwW1S4e14RH9b1wUEZW3ObDSnxKTDbC8m4/2zSfbqMcNSDDE4f/xAAXEQADAQAAAAAAAAAAAAAAAAAAAREh/9oACAEDAQE/AZhRvIQ//8QAGREAAgMBAAAAAAAAAAAAAAAAABEBAhIh/9oACAECAQE/AZv1GzLliP/EACQQAAEDAwMEAwAAAAAAAAAAAAEAAgMEEiERIjEFQVGxMmFx/9oACAEBAAY/AqS+0h074XXN18OHtXwMjbYOWM0uUo+1XQU7b5IaqKQDXjUOB9BCF+wFmLjySpuPkuoNqi4RPpbjbztcCrAcMkYBnuA1PIBOfCLezopAfy1VtRUb5oxtce2Fq/JX/8QAIBABAAICAQUBAQAAAAAAAAAAAQARITFhQVFxkbGB0f/aAAgBAQABPyG2HBScOJ7TMzYl/t0igUA/s0574lQcbPyA5SKO0XXnMSHcnOrxR31lBhKdDlN5uvcrulajNmu+6WIJ2c307eeZRq5crP/aAAwDAQACAAMAAAAQKObC/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEREP/aAAgBAwEBPxBxWWMIP//EABcRAQEBAQAAAAAAAAAAAAAAAAEAEVH/2gAIAQIBAT8QcIbcnos3/8QAHhABAQADAQACAwAAAAAAAAAAAREAITFBUWFxgZH/2gAIAQEAAT8Q0WHxOoTCVUvfMLLi2XsV1paC9/WBXIDXywvpPBWQ6Eh8vwcuGmoOF+p1PSTIa3vQfXCzURBUAowl2KFQZMXvd5LwAoFRkDTYhpiKUTrjWF8R2a+tH8zbJElUKDnBxTxw2mqQvc//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Empty rack at Colt data centre, Wapping, London&quot;
        title=&quot;Empty rack at Colt data centre, Wapping, London&quot;
        src=&quot;/static/170ee1a165e6726e0b1a5d9a20487030/d30a3/0389cbdad6664a7bbd90ddc8c388415e.jpg&quot;
        srcset=&quot;/static/170ee1a165e6726e0b1a5d9a20487030/a80bd/0389cbdad6664a7bbd90ddc8c388415e.jpg 148w,
/static/170ee1a165e6726e0b1a5d9a20487030/1c91a/0389cbdad6664a7bbd90ddc8c388415e.jpg 295w,
/static/170ee1a165e6726e0b1a5d9a20487030/d30a3/0389cbdad6664a7bbd90ddc8c388415e.jpg 340w&quot;
        sizes=&quot;(max-width: 340px) 100vw, 340px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
      /&gt;
    &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Celebrate, it’s all gone!&lt;/p&gt;
&lt;p&gt;Addition 23 Jan 2021: This rack was located in a &lt;a href=&quot;https://www.colt.net&quot;&gt;Colt&lt;/a&gt; data centre, Wapping, London, UK.&lt;/p&gt;</content:encoded></item></channel></rss>