<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Avil Page (Posts about devops)</title><link>https://avilpage.com/</link><description></description><atom:link href="https://avilpage.com/tags/devops.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Sun, 31 May 2026 17:57:37 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Build/Deploy Full Stack Web Apps with only Config</title><link>https://avilpage.com/2026/03/config-first-tools.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;blockquote&gt;
&lt;p&gt;The best code is the code you don't have to write&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Config First Tools&lt;/h4&gt;
&lt;p&gt;Any tool that provides first class support for configuration files can be considered a Config First Tool. 
These tools allow developers to setup/build/deploy applications by writing configuration files instead of writing code.&lt;/p&gt;
&lt;p&gt;In DevOps world, tools like Terraform, Ansible, and Kubernetes are examples of Config First Tools. 
These kinds of tools are not that popular in the web development world.&lt;/p&gt;
&lt;p&gt;In this article, lets see how we can build a full stack web application using only configuration files.&lt;/p&gt;
&lt;h4&gt;Todo - Web App&lt;/h4&gt;
&lt;p&gt;A simple backend API that allows users to manage todo lists.
A simple frontend that uses the backend API.
A simple script to deploy the backend and frontend applications.&lt;/p&gt;
&lt;h4&gt;Backend API&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://pocketbase.io/"&gt;PocketBase&lt;/a&gt; is a backend API that provides a simple way to create and manage databases, authentication, and file storage.
It is a great tool for building simple backend APIs without writing any code.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;pocketbase
$&lt;span class="w"&gt; &lt;/span&gt;pocketbase&lt;span class="w"&gt; &lt;/span&gt;serve
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can create a collection called &lt;code&gt;Todo&lt;/code&gt; with required fields and pocketbase will automatically generate the API for us.&lt;/p&gt;
&lt;p&gt;&lt;img alt="config-first-tools" src="https://avilpage.com/images/config-first-tools-backend.png"&gt;&lt;/p&gt;
&lt;h4&gt;Frontend&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://lowdefy.com/"&gt;Lowdefy&lt;/a&gt; is a config first tool that allows us to build web applications using yaml config.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;npm&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-g&lt;span class="w"&gt; &lt;/span&gt;lowdefy
$&lt;span class="w"&gt; &lt;/span&gt;lowdefy&lt;span class="w"&gt; &lt;/span&gt;init
$&lt;span class="w"&gt; &lt;/span&gt;lowdefy&lt;span class="w"&gt; &lt;/span&gt;dev
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For basic crud apps, instead of us writing the boilerplate config, we can ask an AI agent to write the config for us.&lt;/p&gt;
&lt;h4&gt;Deployment&lt;/h4&gt;
&lt;p&gt;For deployment, we can use Ansible to deploy both the backend and frontend applications. Here also we can just AI agent to write the playbook for us.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;ansible
$&lt;span class="w"&gt; &lt;/span&gt;ansible-playbook&lt;span class="w"&gt; &lt;/span&gt;deploy.yml
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;OliveTin&lt;/h4&gt;
&lt;p&gt;&lt;img alt="config-first-tools" src="https://avilpage.com/images/config-first-tools-devops.png"&gt;&lt;/p&gt;
&lt;p&gt;Even though we can use ansible to deploy the applications, it is not that convenient to run ansible playbooks on mobile.
&lt;a href="https://www.olivetin.app"&gt;OliveTin&lt;/a&gt; is a config first tool that allows us to create web UIs for our scripts.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"Deploy&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ToDo&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;App"&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;popupOnStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;execution-dialog&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ansible-playbook deploy.yml&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;6000&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;"🤖"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can create a simple web UI for our deployment script with just 5 lines.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;For quick prototyping and simple applications, config first tools can be a great choice as they allow us to build applications without writing any code.
They also allow us to focus on the application logic rather than the implementation details.&lt;/p&gt;
&lt;p&gt;With the rise of AI, it is much easy to maintain 500 lines of config than 5000 lines of code.&lt;/p&gt;</description><category>AI</category><category>devops</category><category>web development</category><guid>https://avilpage.com/2026/03/config-first-tools.html</guid><pubDate>Sat, 28 Mar 2026 06:17:29 GMT</pubDate></item><item><title>In Praise of OliveTin</title><link>https://avilpage.com/2026/01/in-praise-of-olivetin.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;&lt;img alt="olivetin" src="https://avilpage.com/images/olivetin.png"&gt;&lt;/p&gt;
&lt;p&gt;In a world of complex internal tools, &lt;a href="https://www.olivetin.app"&gt;OliveTin&lt;/a&gt; bridges the gap between raw CLI and usable web UI with just yaml config.&lt;/p&gt;
&lt;h4&gt;Server Admin Panel&lt;/h4&gt;
&lt;p&gt;I used admin panels like &lt;a href="https://avilpage.com/2024/12/install-cockpit-on-remote-linux-vm.html"&gt;CockPit&lt;/a&gt;, Ajenti, etc to provide simple web UI 
for non-developers to provide access to services. Developing custom widgets is time consuming and requires programming skills as well.&lt;/p&gt;
&lt;p&gt;With OliveTin, I can provide web UI directly with just yaml config. This saves a lot of time and effort.
It also provides a clean UI as it starts from scratch.&lt;/p&gt;
&lt;h4&gt;Backend Driven UI&lt;/h4&gt;
&lt;p&gt;For existing python scripts, I often use tools like Streamlit, NiceGUI, etc to create web UIs.
Organizing the UI components for multiple scripts is time consuming.&lt;/p&gt;
&lt;p&gt;OliveTin can provide web UI directly python scripts and they can be organized in groups with just yaml config.&lt;/p&gt;
&lt;h4&gt;Mobile Friendly&lt;/h4&gt;
&lt;p&gt;To do a simple deployment on mobile, I need to open an app that supports ssh, ssh into the server, navigate to a directory, 
run a script to deploy.&lt;/p&gt;
&lt;p&gt;OliveTin provides a "Deploy" button on mobile browser which is way convenient.&lt;/p&gt;
&lt;h4&gt;Authentication&lt;/h4&gt;
&lt;p&gt;&lt;img alt="olivetin-oauth2" src="https://avilpage.com/images/olivetin-oauth2.png"&gt;&lt;/p&gt;
&lt;p&gt;OliveTin provides authentication(local users, OAuth2, JWT, etc), authorization(ACLs) &amp;amp; accounting(logs) out of the box.
With just yaml config, we can secure the web UI.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;There are hundreds of other features provided by OliveTin like scheduling, file uploads, webhooks, etc.&lt;/p&gt;
&lt;p&gt;If you ever want to provide a simple web UI for scripts with low code or no code, give OliveTin a try!&lt;/p&gt;</description><category>automation</category><category>cross-platform</category><category>devops</category><guid>https://avilpage.com/2026/01/in-praise-of-olivetin.html</guid><pubDate>Fri, 30 Jan 2026 20:13:11 GMT</pubDate></item><item><title>Remote Access to k3d/k3s Kubernetes cluster</title><link>https://avilpage.com/2025/12/remote-access-to-k3d-k3s-cluster.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Introduction&lt;/h4&gt;
&lt;p&gt;We learnt how to &lt;a href="https://avilpage.com/2023/03/setup-k8s-anywhere-k3d.html"&gt;deploy kubernetes cluster anywhere with a single k3d command&lt;/a&gt;. 
By default, k3d cluster is accessible only from the host machine.&lt;/p&gt;
&lt;h4&gt;Remote Access&lt;/h4&gt;
&lt;p&gt;&lt;img alt="k3d-remote-access" src="https://avilpage.com/images/k3s-remote-access.png"&gt;&lt;/p&gt;
&lt;p&gt;Create new cluster with&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;k3d&lt;span class="w"&gt; &lt;/span&gt;cluster&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;cloud-k8s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;--api-port&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6443&lt;/span&gt;:6443@loadbalancer&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;--k3s-arg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"--tls-san=&amp;lt;remote-ip&amp;gt;@server:*"&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--api-port 6443:6443@loadbalancer&lt;/code&gt; maps port 6443 on the host machine to the cluster's API server load balancer. 
This can be changed (e.g., 8080:6443) if 6443 is taken on the host.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--k3s-arg "--tls-san=..."&lt;/code&gt;  adds the host's public IP to the certificate, preventing SSL errors later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure remote server firewall allows incoming traffic on the chosen port (e.g., 6443 or 8080). 
To verify, run &lt;code&gt;telnet &amp;lt;remote-ip&amp;gt; 6443&lt;/code&gt; from local machine.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the remote server, get kubeconfig:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;k3d&lt;span class="w"&gt; &lt;/span&gt;kubeconfig&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;cloud-k8s
---
apiVersion:&lt;span class="w"&gt; &lt;/span&gt;v1
clusters:
-&lt;span class="w"&gt; &lt;/span&gt;cluster:
&lt;span class="w"&gt;    &lt;/span&gt;server:&lt;span class="w"&gt; &lt;/span&gt;https://0.0.0.0:6443
&lt;span class="w"&gt;  &lt;/span&gt;name:&lt;span class="w"&gt; &lt;/span&gt;k3d-rk
&lt;span class="w"&gt;   &lt;/span&gt;...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# truncated for brevity&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Copy this kubeconfig, replace &lt;code&gt;0.0.0.0&lt;/code&gt; with the remote server's public IP.&lt;/p&gt;
&lt;p&gt;Open &lt;a href="https://github.com/freelensapp/freelens"&gt;Free Lens&lt;/a&gt;, paste this config and connect to the remote k3d cluster.&lt;/p&gt;
&lt;p&gt;&lt;img alt="k3d-remote-access" src="https://avilpage.com/images/k3s-remote-access-freelens.png"&gt;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;You can use your favorite Kubernetes tools (kubectl, FreeLens, k9s, etc.) to manage the remote k8s cluster.&lt;/p&gt;</description><category>devops</category><category>kubernetes</category><category>linux</category><guid>https://avilpage.com/2025/12/remote-access-to-k3d-k3s-cluster.html</guid><pubDate>Wed, 17 Dec 2025 03:10:39 GMT</pubDate></item><item><title>Migrating from Nginx to Caddy</title><link>https://avilpage.com/2025/05/migrating-from-nginx-to-caddy.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;When deploying web apps in production, a web server is essential for serving static files, handling reverse proxying, 
and managing SSL/TLS certificates. &lt;/p&gt;
&lt;p&gt;I have been using Nginx for a long time, but I have recently switched to Caddy as it provides automatic HTTPS by default.
In addition, Caddy has a simpler configuration syntax and is easier to set up for basic use cases.&lt;/p&gt;
&lt;h4&gt;Nginx vs Caddy&lt;/h4&gt;
&lt;p&gt;To illustrate the differences, here are some examples of how to configure a simple web server in both Nginx and Caddy.&lt;/p&gt;
&lt;h5&gt;Nginx Configuration&lt;/h5&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;avilpage.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/www/html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;index.html&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;index.htm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://localhost:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With Nginx, you need to manually handle SSL/TLS certificates, which can be cumbersome. 
You typically use tools like Certbot to obtain and renew certificates.&lt;/p&gt;
&lt;h5&gt;Caddy Configuration&lt;/h5&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;avilpage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;file_server&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;reverse_proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Caddy automatically manages SSL/TLS certificates for you, so you don't need to worry about obtaining or renewing them.
It also provides default redirection from HTTP to HTTPS, making it easier to secure your site.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Caddy's automatic HTTPS and simpler configuration syntax make it a compelling choice for web servers, 
especially for those who want to get started quickly without dealing with the complexities of SSL/TLS management.&lt;/p&gt;</description><category>automation</category><category>devops</category><guid>https://avilpage.com/2025/05/migrating-from-nginx-to-caddy.html</guid><pubDate>Fri, 30 May 2025 15:51:21 GMT</pubDate></item><item><title>Free DockerHub Alternative - ECR Public Gallery</title><link>https://avilpage.com/2025/02/free-dockerhub-alternative-ecr-gallery.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;&lt;img alt="docker-rate-limits" src="https://avilpage.com/images/docker-rate-limits.png"&gt;&lt;/p&gt;
&lt;p&gt;DockerHub started rate limiting&lt;sup id="fnref:rate"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2025/02/free-dockerhub-alternative-ecr-gallery.html#fn:rate"&gt;1&lt;/a&gt;&lt;/sup&gt; anonymous docker pulls. When testing out a new CI/CD setup, I hit the rate limit and had to wait for an hour to pull the image. This was a good time to look for alternatives.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gallery.ecr.aws/"&gt;AWS ECR Public Gallery&lt;/a&gt;&lt;sup id="fnref:ecr"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2025/02/free-dockerhub-alternative-ecr-gallery.html#fn:ecr"&gt;2&lt;/a&gt;&lt;/sup&gt; is a good alternative to DockerHub as of today(2025 Feb). It is free and does not have rate limits even for anonymous users. &lt;/p&gt;
&lt;p&gt;&lt;img alt="public-ecr-gallery" src="https://avilpage.com/images/public-ecr-gallery.png"&gt;&lt;/p&gt;
&lt;p&gt;Once we find the required image from the gallery, we can simply change the image name in the &lt;code&gt;docker pull&lt;/code&gt; command to pull the image from ECR Gallery.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker&lt;span class="w"&gt; &lt;/span&gt;pull&lt;span class="w"&gt; &lt;/span&gt;public.ecr.aws/ubuntu/ubuntu
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;Dockerfile&lt;/code&gt;, we can use the image from ECR Gallery as follows:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;public.ecr.aws/ubuntu/ubuntu&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That is a quick way to avoid DockerHub rate limits.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:rate"&gt;
&lt;p&gt;&lt;a href="https://docs.docker.com/docker-hub/usage/"&gt;DockerHub Limits&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2025/02/free-dockerhub-alternative-ecr-gallery.html#fnref:rate" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:ecr"&gt;
&lt;p&gt;&lt;a href="https://gallery.ecr.aws"&gt;AWS ECR Public Gallery&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2025/02/free-dockerhub-alternative-ecr-gallery.html#fnref:ecr" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>devops</category><category>docker</category><guid>https://avilpage.com/2025/02/free-dockerhub-alternative-ecr-gallery.html</guid><pubDate>Sun, 09 Feb 2025 16:08:34 GMT</pubDate></item><item><title>How (and when) to use systemd timer instead of cronjob</title><link>https://avilpage.com/2024/08/guide-systemd-timer-cronjob.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Introduction&lt;/h4&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;demo.sh
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Just a single line of code is sufficient to schedule a cron job. However, there are some scenarios where I find systemd timer more useful than cronjob.&lt;/p&gt;
&lt;h4&gt;How to use systemd timer&lt;/h4&gt;
&lt;p&gt;We need to create a service file(contains the script to be run) and a timer(contains the schedule).&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# demo.service&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Demo&lt;span class="w"&gt; &lt;/span&gt;service

&lt;span class="o"&gt;[&lt;/span&gt;Service&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;demo.sh
&lt;/pre&gt;&lt;/div&gt;

&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="c1"&gt;# demo.timer&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;Unit&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Run&lt;span class="w"&gt; &lt;/span&gt;myscript.service&lt;span class="w"&gt; &lt;/span&gt;every&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;minutes

&lt;span class="o"&gt;[&lt;/span&gt;Timer&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;OnBootSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1min
&lt;span class="nv"&gt;OnUnitActiveSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1min

&lt;span class="o"&gt;[&lt;/span&gt;Install&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;multi-user.target
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can copy these files to &lt;code&gt;/etc/systemd/system/&lt;/code&gt; and enable the timer.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;demo.service&lt;span class="w"&gt; &lt;/span&gt;demo.timer&lt;span class="w"&gt; &lt;/span&gt;/etc/systemd/system/

$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;daemon-reload

$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--now&lt;span class="w"&gt; &lt;/span&gt;demo.timer
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can use &lt;code&gt;systemctl&lt;/code&gt; to see when the task is executed last and when it will be executed next.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;list-timers&lt;span class="w"&gt; &lt;/span&gt;--all
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src="https://avilpage.com/images/systemd-timer-cronjob.png" alt="systemd timer"&gt;&lt;/p&gt;
&lt;h4&gt;Use Cases&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Singleton - In the above example, lets say &lt;code&gt;demo.sh&lt;/code&gt; takes ~10 minutes to run. With cron job, in ten minutes we will have 10 instances of &lt;code&gt;demo.sh&lt;/code&gt; running. This is not ideal. With systemd timer, it will ensure only one instance of &lt;code&gt;demo.sh&lt;/code&gt; is running at a time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On demand runs - If we want to test out the script/job, systemd allows us to immediately run it with usual &lt;code&gt;systemctl start demo&lt;/code&gt; without needing to run the script manually.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Timer - With cron, we can run tasks upto a minute precision. Timer can run tasks till &lt;code&gt;second&lt;/code&gt; level precision. &lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Timer&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;OnCalendar&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;*-*-*&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;:30:15
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In addition to that, we can run tasks based on system events. For example, we can run a script 15 minutes from reboot.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;[&lt;/span&gt;Timer&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;OnBootSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;15min
&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Systemd timer is a powerful tool that can replace cronjob in many scenarios. It provides more control and flexibility over cronjob. However, cronjob is still a good choice for simple scheduling tasks.&lt;/p&gt;</description><category>automation</category><category>devops</category><guid>https://avilpage.com/2024/08/guide-systemd-timer-cronjob.html</guid><pubDate>Mon, 05 Aug 2024 07:37:50 GMT</pubDate></item><item><title>Mastering Kraken2 - Part 2 - Performance Optimisation</title><link>https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;h4&gt;Mastering Kraken2&lt;/h4&gt;
&lt;p&gt;&lt;a href="https://avilpage.com/2024/07/mastering-kraken2-initial-runs.html"&gt;Part 1 - Initial Runs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html"&gt;Part 2 - Classification Performance Optimisation&lt;/a&gt; (this post)&lt;/p&gt;
&lt;p&gt;&lt;a href="https://avilpage.com/2024/07/mastering-kraken2-build-custom-db.html"&gt;Part 3 - Build custom database indices&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://avilpage.com/2024/08/mastering-kraken2-fda-argos-index.html"&gt;Part 4 - Build FDA-ARGOS index&lt;/a&gt; &lt;/p&gt;
&lt;p&gt;Part 5 - Regular vs Fast Builds (upcoming)&lt;/p&gt;
&lt;p&gt;Part 6 - Benchmarking (upcoming)&lt;/p&gt;
&lt;h4&gt;Introduction&lt;/h4&gt;
&lt;p&gt;In the previous post, we learned how to set up kraken2&lt;sup id="fnref:k2"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fn:k2"&gt;1&lt;/a&gt;&lt;/sup&gt;, download pre-built indices, and run kraken2. In this post, we will learn various ways to speed up the classification process.&lt;/p&gt;
&lt;h4&gt;Increasing RAM&lt;/h4&gt;
&lt;p&gt;Kraken2 standard database is ~80GB in size. It is recommended to have at least db size RAM to run kraken2 efficiently&lt;sup id="fnref:ksr"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fn:ksr"&gt;2&lt;/a&gt;&lt;/sup&gt;. Let's use 128GB RAM machine and run kraken2 with ERR10359977&lt;sup id="fnref:err"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fn:err"&gt;3&lt;/a&gt;&lt;/sup&gt; sample.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;ERR10359977.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;.
&lt;span class="m"&gt;95064&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14&lt;/span&gt;.35&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.142s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2662&lt;/span&gt;.9&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;402&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;94816&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;99&lt;/span&gt;.74%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;248&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.26%&lt;span class="o"&gt;)&lt;/span&gt;
kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;ERR10359977.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;.68s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;152&lt;/span&gt;.19s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;35&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;:17.55&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now the time taken has come down from 40 minutes to 7 minutes. The classification speed has also increased from 0.19 Mbp/m to 402.02 Mbp/m.&lt;/p&gt;
&lt;p&gt;The previous sample had only a few reads, and the speed is not a good indicator. Let's run kraken2 with a larger sample.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;.
Processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;14980000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2972330207&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;...
&lt;span class="m"&gt;17121245&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3397&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;797&lt;/span&gt;.424s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1288&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;.61&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9826671&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.39%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7294574&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;.61%&lt;span class="o"&gt;)&lt;/span&gt;
kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;526&lt;/span&gt;.39s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;308&lt;/span&gt;.24s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;68&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;:23.86&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This took almost 20 minutes to classify ~3 Gbp of data. Out of 20 minutes, 13 minutes was spent in classification. The remaining time in loading the db into memory.&lt;/p&gt;
&lt;p&gt;Let's use k2_plusPF&lt;sup id="fnref:k2p"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fn:k2p"&gt;4&lt;/a&gt;&lt;/sup&gt; db, which is twice the size of k2_standard and run kraken2.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_plusfp&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...done.
&lt;span class="m"&gt;17121245&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3397&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;755&lt;/span&gt;.290s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1360&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;269&lt;/span&gt;.87&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9903824&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.85%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7217421&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;.15%&lt;span class="o"&gt;)&lt;/span&gt;
kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_plusfp/&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt;  &lt;/span&gt;&amp;gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;509&lt;/span&gt;.71s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;509&lt;/span&gt;.51s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;55&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;:35.49&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This took ~30 minutes to complete, but the classification took only 13 minutes similar to k2_standard. The remaining time was spent in loading the db into memory.&lt;/p&gt;
&lt;h4&gt;Preloading db into RAM&lt;/h4&gt;
&lt;p&gt;We can use vmtouch&lt;sup id="fnref:vmt"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fn:vmt"&gt;5&lt;/a&gt;&lt;/sup&gt; to preload db into RAM. kraken2 provides &lt;code&gt;--memory-mapping&lt;/code&gt; option to use preloaded db. &lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;vmtouch&lt;span class="w"&gt; &lt;/span&gt;-vt&lt;span class="w"&gt; &lt;/span&gt;k2_standard/hash.k2d&lt;span class="w"&gt; &lt;/span&gt;k2_standard/opts.k2d&lt;span class="w"&gt; &lt;/span&gt;k2_standard/taxo.k2d
&lt;span class="w"&gt;           &lt;/span&gt;Files:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;Directories:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;   &lt;/span&gt;Touched&lt;span class="w"&gt; &lt;/span&gt;Pages:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20382075&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;77G&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;Elapsed:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;434&lt;/span&gt;.77&lt;span class="w"&gt; &lt;/span&gt;seconds
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;When Linux requires RAM, it will incrementally evict the db from memory. To prevent this, we can copy the db to shared memory (/dev/shm) and then use vmtouch to preload the db.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;cp&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;/dev/shm

$&lt;span class="w"&gt; &lt;/span&gt;vmtouch&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;/dev/shm/*.k2d
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, let's run kraken2 with &lt;code&gt;--memory-mapping&lt;/code&gt; option.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--memory-mapping&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;.
&lt;span class="m"&gt;17121245&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3397&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;532&lt;/span&gt;.486s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1929&lt;/span&gt;.2&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;382&lt;/span&gt;.79&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9826671&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.39%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7294574&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;.61%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt;   &lt;/span&gt;&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;424&lt;/span&gt;.20s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;11&lt;/span&gt;.76s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;81&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;:54.98&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now the classification took only ~10 minutes.&lt;/p&gt;
&lt;h4&gt;Multi threading&lt;/h4&gt;
&lt;p&gt;kraken2 supports multiple threads. I am using a machine with 40 threads.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;--memory-mapping&lt;span class="w"&gt; &lt;/span&gt;--threads&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;.
&lt;span class="m"&gt;17121245&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3397&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;71&lt;/span&gt;.675s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;14332&lt;/span&gt;.5&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2843&lt;/span&gt;.81&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9826671&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.39%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7294574&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;.61%&lt;span class="o"&gt;)&lt;/span&gt;
kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;556&lt;/span&gt;.58s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;22&lt;/span&gt;.85s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;762&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;:16.02&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With 32 threads, the classification took only 1 minute. Beyond 32 threads, the classification time did not decrease significantly.&lt;/p&gt;
&lt;h4&gt;Optimising input files&lt;/h4&gt;
&lt;p&gt;So far we have used gzipped input files. Let's use unzipped input files and run kraken2.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;gunzip&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz
$&lt;span class="w"&gt; &lt;/span&gt;gunzip&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq.gz

$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq&lt;span class="w"&gt; &lt;/span&gt;--memory-mapping&lt;span class="w"&gt; &lt;/span&gt;--threads&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;.
&lt;span class="m"&gt;17121245&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3397&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;34&lt;/span&gt;.809s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;29512&lt;/span&gt;.0&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5855&lt;/span&gt;.68&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;9826671&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;57&lt;/span&gt;.39%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;7294574&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;42&lt;/span&gt;.61%&lt;span class="o"&gt;)&lt;/span&gt;
kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--paired&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;565&lt;/span&gt;.03s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;17&lt;/span&gt;.12s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1530&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;38&lt;/span&gt;.047&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now the classification time has come down to 40 seconds.&lt;/p&gt;
&lt;p&gt;Since the input fastq files are paired, interleaving the files also takes time. Lets interleave the files and run kraken2.&lt;/p&gt;
&lt;p&gt;To interleave the files, lets use &lt;code&gt;seqfu&lt;/code&gt; tool.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;conda&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-y&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;conda-forge&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;bioconda&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"seqfu&amp;gt;1.10"&lt;/span&gt;

$&lt;span class="w"&gt; &lt;/span&gt;seqfu&lt;span class="w"&gt; &lt;/span&gt;interleave&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_1.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;-2&lt;span class="w"&gt; &lt;/span&gt;SRR6915097_2.fastq.gz&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;SRR6915097.fastq

$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--memory-mapping&lt;span class="w"&gt; &lt;/span&gt;SRR6915097.fq&lt;span class="w"&gt; &lt;/span&gt;--threads&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;output.txt
Loading&lt;span class="w"&gt; &lt;/span&gt;database&lt;span class="w"&gt; &lt;/span&gt;information...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;.
&lt;span class="m"&gt;34242490&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3397&lt;/span&gt;.15&lt;span class="w"&gt; &lt;/span&gt;Mbp&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;processed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;.199s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;101714&lt;/span&gt;.1&lt;span class="w"&gt; &lt;/span&gt;Kseq/m,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;10090&lt;/span&gt;.91&lt;span class="w"&gt; &lt;/span&gt;Mbp/m&lt;span class="o"&gt;)&lt;/span&gt;.
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;17983321&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;classified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;52&lt;/span&gt;.52%&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;16259169&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sequences&lt;span class="w"&gt; &lt;/span&gt;unclassified&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;47&lt;/span&gt;.48%&lt;span class="o"&gt;)&lt;/span&gt;
kraken2&lt;span class="w"&gt; &lt;/span&gt;--db&lt;span class="w"&gt; &lt;/span&gt;k2_standard&lt;span class="w"&gt; &lt;/span&gt;--report&lt;span class="w"&gt; &lt;/span&gt;report.txt&lt;span class="w"&gt; &lt;/span&gt;--memory-mapping&lt;span class="w"&gt; &lt;/span&gt;SRR6915097.fq&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;618&lt;/span&gt;.96s&lt;span class="w"&gt; &lt;/span&gt;user&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;.24s&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2653&lt;/span&gt;%&lt;span class="w"&gt; &lt;/span&gt;cpu&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;24&lt;/span&gt;.013&lt;span class="w"&gt; &lt;/span&gt;total
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now the classification time has come down to 24 seconds. &lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;In terms of classification speed, we have come a long way from 0.1 Mbp/m to 1200 Mbp/m. In the next post, we will learn how to optimise the creation of custom indices.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:k2"&gt;
&lt;p&gt;&lt;a href="https://ccb.jhu.edu/software/kraken2/"&gt;Kraken2&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fnref:k2" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:ksr"&gt;
&lt;p&gt;&lt;a href="https://github.com/DerrickWood/kraken2/blob/master/docs/MANUAL.markdown#system-requirements"&gt;Kraken System Requirements&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fnref:ksr" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:err"&gt;
&lt;p&gt;&lt;a href="ftp://ftp.sra.ebi.ac.uk/vol1/fastq/ERR103/077/ERR10359977/ERR10359977.fastq.gz"&gt;ERR10359977.fastq.gz&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fnref:err" title="Jump back to footnote 3 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:k2p"&gt;
&lt;p&gt;&lt;a href="https://benlangmead.github.io/aws-indexes/k2"&gt;Genomic Index Zone - k2&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fnref:k2p" title="Jump back to footnote 4 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:vmt"&gt;
&lt;p&gt;&lt;a href="https://hoytech.com/vmtouch/"&gt;https://hoytech.com/vmtouch/&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html#fnref:vmt" title="Jump back to footnote 5 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>bioinformatics</category><category>devops</category><category>kraken2</category><category>metagenomics</category><guid>https://avilpage.com/2024/07/mastering-kraken2-performance-optimisation.html</guid><pubDate>Sun, 28 Jul 2024 05:21:30 GMT</pubDate></item><item><title>Headlamp - k8s Lens open source alternative</title><link>https://avilpage.com/2024/06/headlamp-k8s-lens-open-source-alternative.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;&lt;img alt="headlamp - Open source Kubernetes Lens alternator" src="https://avilpage.com/images/headlamp-k8s-lens-open-source-alternative.png"&gt;&lt;/p&gt;
&lt;p&gt;Since Lens is not open source, I tried out monokle, octant, k9s, and headlamp&lt;sup id="fnref:headlamp"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/headlamp-k8s-lens-open-source-alternative.html#fn:headlamp"&gt;1&lt;/a&gt;&lt;/sup&gt;. Among them, headlamp UI &amp;amp; features are closest to Lens. &lt;/p&gt;
&lt;h4&gt;Headlamp&lt;/h4&gt;
&lt;p&gt;Headlamp is CNCF sandbox project that provides cross-platform desktop application to manage Kubernetes clusters. It auto-detects clusters and provides cluster wide resource usage by default. &lt;/p&gt;
&lt;p&gt;It can also be installed inside the cluster and can be accessed using a web browser. This is useful when we want to access the cluster from a mobile device.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;helm&lt;span class="w"&gt; &lt;/span&gt;repo&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;headlamp&lt;span class="w"&gt; &lt;/span&gt;https://headlamp-k8s.github.io/headlamp/

$&lt;span class="w"&gt; &lt;/span&gt;helm&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;headlamp&lt;span class="w"&gt; &lt;/span&gt;headlamp/headlamp
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Lets port-forward the service &amp;amp; copy the token to access it.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;create&lt;span class="w"&gt; &lt;/span&gt;token&lt;span class="w"&gt; &lt;/span&gt;headlamp

&lt;span class="c1"&gt;# we can do this via headlamp UI as well&lt;/span&gt;
$&lt;span class="w"&gt; &lt;/span&gt;kubectl&lt;span class="w"&gt; &lt;/span&gt;port-forward&lt;span class="w"&gt; &lt;/span&gt;service/headlamp&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;:80
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, we can access the headlamp UI at &lt;a href="http://"&gt;http://localhost:8080&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="headlamp - Open source Kubernetes Lens alternator" src="https://avilpage.com/images/headlamp-k8s-lens-open-source-alternative2.png"&gt;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;If you are looking for an open source alternative to Lens, headlamp is a good choice. It provides a similar UI &amp;amp; features as Lens, and it is accessible via mobile devices as well. &lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:headlamp"&gt;
&lt;p&gt;&lt;a href="https://headlamp.dev/"&gt;https://headlamp.dev/&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/headlamp-k8s-lens-open-source-alternative.html#fnref:headlamp" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>devops</category><category>kubernetes</category><guid>https://avilpage.com/2024/06/headlamp-k8s-lens-open-source-alternative.html</guid><pubDate>Sun, 23 Jun 2024 20:18:02 GMT</pubDate></item><item><title>macOS - Log &amp; track historical CPU, RAM usage</title><link>https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-grafana.png"&gt;&lt;/p&gt;
&lt;p&gt;In macOS, we can use inbuilt &lt;code&gt;Activity Monitor&lt;/code&gt; or third party apps like &lt;code&gt;Stats&lt;/code&gt; to check the live CPU/RAM usage. But, we can't track the historical CPU &amp;amp; memory usage. &lt;code&gt;sar&lt;/code&gt;, &lt;code&gt;atop&lt;/code&gt; can track the historical CPU &amp;amp; memory usage. But, they are not available for macOS.&lt;/p&gt;
&lt;h4&gt;Netdata&lt;/h4&gt;
&lt;p&gt;Netdata&lt;sup id="fnref:Netdata"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:Netdata"&gt;1&lt;/a&gt;&lt;/sup&gt; is an open source observability tool that can monitor CPU, RAM, network, disk usage. It can also track the historical data. &lt;/p&gt;
&lt;p&gt;Unfortunately, it is not stable on macOS. I tried installing it on multiple macbooks, but it didn't work. I raised an issue&lt;sup id="fnref:netdata_issue"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:netdata_issue"&gt;2&lt;/a&gt;&lt;/sup&gt; on their GitHub repository and the team mentioned that macOS is a low priority for them.&lt;/p&gt;
&lt;h4&gt;Glances&lt;/h4&gt;
&lt;p&gt;Glances&lt;sup id="fnref:Glances"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:Glances"&gt;3&lt;/a&gt;&lt;/sup&gt; is a cross-platform monitoring tool that can monitor CPU, RAM, network, disk usage. It can also track the historical data.&lt;/p&gt;
&lt;p&gt;We can install it using Brew or pip.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;glances

$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;glances
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once it is installed, we can monitor the resource usage using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;glances
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-glances.png"&gt;&lt;/p&gt;
&lt;p&gt;Glances can log historical data to a file using the below command.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;glances&lt;span class="w"&gt; &lt;/span&gt;--export-csv&lt;span class="w"&gt; &lt;/span&gt;/tmp/glances.csv
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In addition to that, it can log data to services like influxdb, prometheus, etc.&lt;/p&gt;
&lt;p&gt;Let's install influxdb and export stats to it.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;influxdb
$&lt;span class="w"&gt; &lt;/span&gt;brew&lt;span class="w"&gt; &lt;/span&gt;services&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;influxdb
$&lt;span class="w"&gt; &lt;/span&gt;influx&lt;span class="w"&gt; &lt;/span&gt;setup

$&lt;span class="w"&gt; &lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;influxdb-client

$&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;glances.conf
&lt;span class="o"&gt;[&lt;/span&gt;influxdb&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nv"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;localhost
&lt;span class="nv"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;8086&lt;/span&gt;
&lt;span class="nv"&gt;protocol&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;http
&lt;span class="nv"&gt;org&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;avilpage
&lt;span class="nv"&gt;bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;glances
&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;secret_token

$&lt;span class="w"&gt; &lt;/span&gt;glances&lt;span class="w"&gt; &lt;/span&gt;--export-influxdb&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;glances.conf
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can view stats in the influxdb from Data Explorer web UI at &lt;a href="http://localhost:8086"&gt;http://localhost:8086&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-influxdb.png"&gt;&lt;/p&gt;
&lt;p&gt;Glances provides a prebuilt Grafana dashboard&lt;sup id="fnref:grafana_dashboard"&gt;&lt;a class="footnote-ref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fn:grafana_dashboard"&gt;4&lt;/a&gt;&lt;/sup&gt; that we can import to visualize the stats. &lt;/p&gt;
&lt;p&gt;From Grafana -&amp;gt; Dashboard -&amp;gt; Import, we can import the dashboard using the above URL.&lt;/p&gt;
&lt;p&gt;&lt;img alt="macOS - Log CPU &amp;amp; RAM history" src="https://avilpage.com/images/mac-log-cpu-ram-grafana.png"&gt;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;In addition to InfluxDB, Glances can export data to ~20 services. So far, it is the best tool to log, track and view historical CPU, RAM, network and disk usage in macOS. The same method works for Linux and Windows as well.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:Netdata"&gt;
&lt;p&gt;&lt;a href="https://github.com/netdata/netdata"&gt;https://github.com/netdata/netdata&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:Netdata" title="Jump back to footnote 1 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:netdata_issue"&gt;
&lt;p&gt;&lt;a href="https://github.com/netdata/netdata/issues/16696"&gt;https://github.com/netdata/netdata/issues/16696&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:netdata_issue" title="Jump back to footnote 2 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:Glances"&gt;
&lt;p&gt;&lt;a href="https://github.com/nicolargo/glances"&gt;https://github.com/niolargo/glances&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:Glances" title="Jump back to footnote 3 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:grafana_dashboard"&gt;
&lt;p&gt;&lt;a href="https://glances.readthedocs.io/en/latest/gw/influxdb.html#grafana"&gt;https://glances.readthedocs.io/en/latest/gw/influxdb.html#grafana&lt;/a&gt; &lt;a class="footnote-backref" href="https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html#fnref:grafana_dashboard" title="Jump back to footnote 4 in the text"&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</description><category>devops</category><category>macbook</category><category>python</category><guid>https://avilpage.com/2024/06/macos-log-track-cpu-ram-usage.html</guid><pubDate>Fri, 31 May 2024 20:18:02 GMT</pubDate></item><item><title>Timestamp to Relative Time - Kibana Scripted fields</title><link>https://avilpage.com/2024/04/timestamp-to-relative-time-kibana-scripted-fields.html</link><dc:creator>Anand Reddy Pandikunta</dc:creator><description>&lt;p&gt;When browsing logs in Kibana, there will be a timestamp stamp field on the left for all the docs. It is difficult to read &amp;amp; comprehend the timestamp in the logs. It would be better if we can convert the timestamp to a human-readable relative time like &lt;code&gt;5 minutes ago&lt;/code&gt;, &lt;code&gt;1 hour ago&lt;/code&gt;, etc.&lt;/p&gt;
&lt;h4&gt;Kibana Scripted Fields&lt;/h4&gt;
&lt;p&gt;Kibana provides a feature called scripted fields to create new fields in the index pattern. We can use this feature to convert the timestamp to a relative time.&lt;/p&gt;
&lt;p&gt;&lt;img alt="kibana-relative-time" src="https://avilpage.com/images/kibana-relative-time1.png"&gt;&lt;/p&gt;
&lt;p&gt;Go to &lt;code&gt;Stack Management&lt;/code&gt; -&amp;gt; &lt;code&gt;Index Patterns&lt;/code&gt; -&amp;gt; &lt;code&gt;Create index pattern&lt;/code&gt; -&amp;gt; Select the index pattern -&amp;gt; &lt;code&gt;Scripted fields&lt;/code&gt;, click on &lt;code&gt;Add scripted field&lt;/code&gt;, add the below script.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;getTime&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;timestamp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;'@timestamp'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toInstant&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;toEpochMilli&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7200000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3600000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;" hours ago"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3600000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3600000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;" hour ago"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;120000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;" minutes ago"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;" minute ago"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;" seconds ago"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the field is saved, we can go back to &lt;code&gt;Discover&lt;/code&gt; and see the new field in the logs. We can toggle the visibility of the &lt;code&gt;Relative Time&lt;/code&gt; field to see the relative time.&lt;/p&gt;
&lt;p&gt;&lt;img alt="kibana-relative-time" src="https://avilpage.com/images/kibana-relative-time2.png"&gt;&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Instead of looking at the timestamp and calculating the relative time in our head, we can use relative time in Kibana . This will make it easier to read &amp;amp; comprehend the logs.&lt;/p&gt;</description><category>devops</category><category>kibana</category><category>monitoring</category><guid>https://avilpage.com/2024/04/timestamp-to-relative-time-kibana-scripted-fields.html</guid><pubDate>Wed, 10 Apr 2024 08:45:33 GMT</pubDate></item></channel></rss>