<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fly-Io on blog.iankulin.com</title><link>https://blog.iankulin.com/tags/fly-io/</link><description>Recent content in Fly-Io on blog.iankulin.com</description><generator>Hugo</generator><language>en-AU</language><lastBuildDate>Mon, 16 Dec 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://blog.iankulin.com/tags/fly-io/index.xml" rel="self" type="application/rss+xml"/><item><title>Updating a deployment on fly.io</title><link>https://blog.iankulin.com/updating-a-deployment-on-fly-io/</link><pubDate>Mon, 16 Dec 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/updating-a-deployment-on-fly-io/</guid><description>&lt;img src="https://blog.iankulin.com/images/flyio_picture.png" width="620" alt=""&gt;
&lt;p&gt;I&amp;rsquo;ve had my external UptimeKuma chugging away on &lt;a href="https://fly.io/"&gt;fly.io&lt;/a&gt;, for free, for months now, and the container image it was based on was a bit out of date, so I wanted to update it. I hadn&amp;rsquo;t looked at fly.io for months, and couldn&amp;rsquo;t really recall what I&amp;rsquo;d done to create it.&lt;/p&gt;
&lt;p&gt;The way this works is that that you create a fly.toml file that sets out the details of your app. From memory I think I used the one from the docs and gave it a unique name, the name of the Docker image, the port, the datacentre location, and the directory for the persisted data. The you run &lt;code&gt;fly deploy&lt;/code&gt; from the directory with the toml file (having already installed the CLI tool and logged in) and you&amp;rsquo;re in business.&lt;/p&gt;
&lt;p&gt;Fly doesn&amp;rsquo;t actually run your container, it deconstructs it and uses the layer information to launch a firecracker instance, but of course, none of this matters to the user - it&amp;rsquo;s just as if your containerised app is magically live on the internet with hardly any effort or money (so far I&amp;rsquo;ve paid $0.00 for eight months of good service).&lt;/p&gt;
&lt;p&gt;I was sort of dreading the upgrade, I guessed I&amp;rsquo;d need to kill the old instance, start the new one and connect it back to my persistent storage, but here&amp;rsquo;s what I actually did.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Went to the folder with my fly.toml file&lt;/li&gt;
&lt;li&gt;Typed &lt;code&gt;fly deploy&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-10-28-at-6.22.46-am-1.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-10-28-at-6.22.46-am-1.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fly.io is such a great way to deploy stuff. If I wasn&amp;rsquo;t such a committed self-hoster I would use it a lot more. They used to be hosted on Heroku (which is on AWS) but I understand they have moved to their own worldwide data centers. Their secret sauce is the dev experience. So good.&lt;/p&gt;
&lt;h3 id="edit-update-from-the-future"&gt;Edit: Update from the future&lt;/h3&gt;
&lt;p&gt;So, very day or so since I did that update, which was to version 1.23, I&amp;rsquo;ve been getting these emails from Fly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#d8dee9;background-color:#2e3440;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Fly.io] ikuptime ran out of memory and crashed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Fly &amp;lt;support@fly.io&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4:12 AM (16 hours ago)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;	
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Hello! Your “ikuptime” application hosted on Fly.io crashed because it ran out of memory. Specifically, the instance 3d8d7de3b20738. Adding more RAM to your application might help!
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Hmm. In theory the free machine I&amp;rsquo;m using on Fly includes 256MB of RAM, and when I look at the average use, it&amp;rsquo;s sitting around 200MB, but it does say out of 223MB, so I guess that&amp;rsquo;s the real limit.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-11-06-at-8.37.18-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-11-06-at-8.37.18-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Looking at the graph of memory use, it does look like there&amp;rsquo;s something in the container with a memory leak, then it&amp;rsquo;s being restarted once it hits about 205MB for a while.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-11-06-at-8.31.28-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-11-06-at-8.31.28-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;An easy fix might be to swap to a lighter weight container. You can see at the end of the graph above I&amp;rsquo;ve dropped it down to about 160MB. That was by using the image tagged with &lt;code&gt;:1-alpine&lt;/code&gt;. I&amp;rsquo;ll keep and eye on it and see what happens.&lt;/p&gt;
&lt;p&gt;I am running the full size container in the home lab inside an LXC, and it doesn&amp;rsquo;t seem to have the leak.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-11-06-at-8.40.49-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-11-06-at-8.40.49-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is not quite an apples for apples comparison. Fly.io doesn&amp;rsquo;t actually run the container, it uses the container layers to build the app in a tiny VM called &lt;a href="https://firecracker-microvm.github.io/"&gt;firecracker&lt;/a&gt;. This is the technology used by AWS to run serverless functions.&lt;/p&gt;
&lt;p&gt;I guess I&amp;rsquo;ll be able to see in a day or so if I&amp;rsquo;ve solved the problem.&lt;/p&gt;
&lt;h3 id="edit-update-from-the-distant-future"&gt;Edit: Update from the distant future&lt;/h3&gt;
&lt;p&gt;Perhaps the memory growth is still there (after an update it drops down 12ish MB):&lt;/p&gt;
&lt;img src="https://blog.iankulin.com/images/screenshot-2025-03-17-at-12.56.40.png" width="900" alt=""&gt;
&lt;p&gt;but in any case, running the Alpine base image has kept the memory use well under the limits for my free instance.&lt;/p&gt;
&lt;p&gt;In other news, I was on a new laptop when I tried to run the &lt;code&gt;fly deploy&lt;/code&gt; command today, so things were a tiny bit more complex. I had to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;install the fly command line stuff with &lt;code&gt;brew install flyctl&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;then when I ran &lt;code&gt;fly deploy,&lt;/code&gt; it asked me to sign in, and opened a web page for me to do so.&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Fly.io, Uptime Kuma &amp; scraping a status page</title><link>https://blog.iankulin.com/fly-io-uptime-kuma-scraping-a-status-page/</link><pubDate>Fri, 02 Feb 2024 00:00:00 +0000</pubDate><guid>https://blog.iankulin.com/fly-io-uptime-kuma-scraping-a-status-page/</guid><description>&lt;p&gt;&lt;a href="https://dribbble.com/shots/5657880-Fly-io-Logo"&gt;&lt;img src="https://blog.iankulin.com/images/c1fef772e2dca5e1ab8c812f465c95a8.png" width="800" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve been aware since I set up &lt;a href="https://blog.iankulin.com/uptime-kuma-nfty/"&gt;Uptime Kuma&lt;/a&gt; for my monitoring, that having an instance on my local network monitoring my VPS websites wasn&amp;rsquo;t ideal. The main reason being that the flakiest part of my infrastructure is my 4G home internet, so if that goes down I have no website monitoring, and even if I did, the notifications couldn&amp;rsquo;t get out.&lt;/p&gt;
&lt;p&gt;Of course, it would also be a simple matter to run an instance on the VPS that I host the sites on, but that has a similar problem in that if the VPS goes down, so does my monitoring of the VPS. What I really need is a third, independent space to run an instance.&lt;/p&gt;
&lt;h3 id="uptime-robot"&gt;Uptime Robot&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://uptimerobot.com/"&gt;Uptime Robot&lt;/a&gt; is a monitoring service that seems somehow related to Uptime Kuma? They have some of the same terminology and colour schemes - so I&amp;rsquo;m not really sure. Perhaps it&amp;rsquo;s a fork, or perhaps Uptime Kuma was inspired by Robot. Robot does have an API which is a nice addition, since ideally if my monitoring is spread around, I&amp;rsquo;d like to pull it all back into one &amp;lsquo;pane of glass&amp;rsquo; by having my system monitor the remote for how many &amp;lsquo;down&amp;rsquo; sites it&amp;rsquo;s tracking. It also has a number of other extra features such as heartbeat monitoring.&lt;/p&gt;
&lt;p&gt;Uptime Robot is a paid service, but like nearly all VC funded things growing a user base it has a free tier with some restrictions. I like NTFY for my notifications, but on Robot I could only access email notifications. There are iOS and Android apps, but I didn&amp;rsquo;t try them.&lt;/p&gt;
&lt;h3 id="third-space"&gt;Third Space&lt;/h3&gt;
&lt;p&gt;Ideally, I like to run another Uptime Kuma in a VPS on a different provider. I&amp;rsquo;ve heard that &lt;a href="https://www.oracle.com/au/cloud/free/"&gt;Oracle have a free tier&lt;/a&gt; which seems like it would be fine for this application, but a more interesting idea that I&amp;rsquo;ve been thinking of using for other projects is Fly.io.&lt;/p&gt;
&lt;h3 id="flyio"&gt;Fly.io&lt;/h3&gt;
&lt;p&gt;Fly.io own physical servers in colo datacentres around the world on which they offer compute based on &lt;a href="https://www.amazon.science/blog/how-awss-firecracker-virtual-machines-work"&gt;Firecracker VM&amp;rsquo;s&lt;/a&gt;. The cute bit is that you give them a Docker container, and they unpack it into one of these fast baby VM&amp;rsquo;s.&lt;/p&gt;
&lt;p&gt;The exact nature of their &amp;lsquo;free tier&amp;rsquo; is hard to figure out from their &lt;a href="https://fly.io/docs/about/pricing/"&gt;pricing page&lt;/a&gt;, but based on &lt;a href="https://community.fly.io/t/fly-io-free-tier-billing/11432"&gt;some answers to questions in their forum&lt;/a&gt;, and &lt;a href="https://jfmadrid.notion.site/Uptime-Kuma-for-Free-on-Fly-io-e5eeead6dfb4425b8403c100ec986191"&gt;blog posts from others who have set up Uptime Kuma&lt;/a&gt; there, it sounds like the deal is that if you use one shared CPU &lt;em&gt;and&lt;/em&gt; keep your storage under 3GB &lt;em&gt;and&lt;/em&gt; the charges for your use add up to less than $5/month - then it&amp;rsquo;s free. I did have to provide credit card details, so if &lt;a href="https://www.youtube.com/watch?v=N6lYcXjd4pg"&gt;I get a $71,393 bill,&lt;/a&gt; I&amp;rsquo;ll come back here and edit this. (&lt;em&gt;edit from the future: eight months later I haven&amp;rsquo;t paid a cent&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;To get Uptime Kuma running on Fly.io, I followed &lt;a href="https://jfmadrid.notion.site/Uptime-Kuma-for-Free-on-Fly-io-e5eeead6dfb4425b8403c100ec986191"&gt;this guide&lt;/a&gt;, but the steps where basically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create an account on Fly.io&lt;/li&gt;
&lt;li&gt;Install the Fly.io command line tools and run a command to &amp;lsquo;create&amp;rsquo; your app&lt;/li&gt;
&lt;li&gt;Create a &amp;lsquo;&lt;a href="https://github.com/lubien/fly-uptime-kuma/blob/main/fly.toml"&gt;fly.toml&lt;/a&gt;&amp;rsquo; file which is a text config file pointing to the docker image and supplying some details such as ports and location&lt;/li&gt;
&lt;li&gt;Use the CLI to set the disk space needed, and &amp;lsquo;deploy&amp;rsquo; the app&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It was impressive how simple all this was. If the intention of the free tier is to get you to try it, and show you how painless it is to deploy any dockerised app to the edge, then mission accomplished.&lt;/p&gt;
&lt;p&gt;You can check on the status of your app at &lt;a href="https://fly.io/dashboard"&gt;https://fly.io/dashboard&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-6.31.22-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-6.31.22-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And go to &lt;appname&gt;.fly.dev to see your app. On the free tier, you&amp;rsquo;re on a shared IPV4 address but it is possible to use your own domain if desired - that&amp;rsquo;s one of the things to set up in the .toml file.&lt;/p&gt;
&lt;p&gt;It is remarkable what you can deploy for free in the golden age of venture capital.&lt;/p&gt;
&lt;h3 id="extracting-status"&gt;Extracting Status&lt;/h3&gt;
&lt;p&gt;One of Uptime Kuma&amp;rsquo;s functions is to provide public (ie viewable without being logged in) &amp;lsquo;status&amp;rsquo; pages, and if all the services you&amp;rsquo;ve added to that status group are up, it has. great big heading saying &amp;ldquo;All Systems Operational&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-7.38.45-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-7.38.45-pm.png" width="900" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So my plan to pull this status into my homelab instance of Uptime Kuma was just to add this remote status page as a monitor, and search for the keyword &amp;lsquo;All Systems Operational&amp;rsquo;. If that was found, I&amp;rsquo;d know everything was good. But of course, this is a modern web-app (I think using &lt;a href="https://vuejs.org/"&gt;Vue&lt;/a&gt;), so that text does not exist in the page, it&amp;rsquo;s added to the DOM by some JavaScript after the page is loaded based on some client side processing of (probably) some JSON data it pulls in.&lt;/p&gt;
&lt;p&gt;One option would be to use a web scraping library to write something to access this piece of information. On a page like this, that would involve a headless browser rendering the DOM then exposing it.&lt;/p&gt;
&lt;p&gt;But of course, the Javascript that is building the page we&amp;rsquo;re looking at is getting its data from somewhere, so it&amp;rsquo;s probably easier for us to grab that data directly and process it ourselves. How do we see where the data is from? We use the browser tools to look at the network requests when the page is loaded.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-7.20.50-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-7.20.50-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So if you view the status page at &lt;code&gt;&amp;lt;whatever.com&amp;gt;/status/&amp;lt;page_name&amp;gt;&lt;/code&gt;, it loads some data from &lt;code&gt;&amp;lt;whatever.com&amp;gt;/api/status-page/heartbeat/&amp;lt;page_name&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The JSON that&amp;rsquo;s returned from this request contains two objects: &lt;code&gt;heartbeatlist&lt;/code&gt;, and &lt;code&gt;uptimelist&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-8.06.05-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-8.06.05-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;heartbeatlist&lt;/code&gt; contains the last 50 retrievals for each of the URL&amp;rsquo;s being monitored. Each of these retrievals has a status (1 for up, 0 for down) and the response time. &lt;code&gt;uptimelist&lt;/code&gt; is the fraction of uptime. You can see in the data above that the first URL has a lower percentage of up-time (because I failed it to check my understanding of the status data).&lt;/p&gt;
&lt;p&gt;So I need to write an endpoint that requests this data, then checks the last array element of each of the URLs in the heartbeat list, then spit out some text saying if all the URL&amp;rsquo;s in this status group are available. That&amp;rsquo;s quite doable, I have the skills, but it&amp;rsquo;s probably a two hour job to do properly.&lt;/p&gt;
&lt;p&gt;Since this is an open source project, a better use of that time would be to add this functionality to Uptime Kuma so it would be available to anyone with the same problem. It might be a niche case, but the code to provide this output would be simpler inside the project and much more durable than reverse engineering it.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s have a look at the source and see what it&amp;rsquo;s like.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-8.34.24-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-8.34.24-pm.png" width="1000" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Well, well well. What do we have here? There&amp;rsquo;s an api route that outputs an SVG badge for a status page. The badge says &amp;lsquo;Degraded&amp;rsquo; in amber if some of the URL&amp;rsquo;s are down, and &amp;lsquo;Up&amp;rsquo; in green if they are all up. Those words are present in an aria label and the svg &lt;code&gt;&amp;lt;title&amp;gt;&lt;/code&gt; tag, so they&amp;rsquo;ll be detectable by the Uptime Kuma &amp;lsquo;keyword&amp;rsquo; search.&lt;/p&gt;
&lt;p&gt;Five minutes later, we&amp;rsquo;re in business. Thank you open source!&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-8.41.52-pm.png"&gt;&lt;img src="https://blog.iankulin.com/images/screen-shot-2024-01-16-at-8.41.52-pm.png" width="772" alt=""&gt;&lt;/a&gt;&lt;/p&gt;</description></item></channel></rss>