<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Taiwrash</title>
    <description>The latest articles on DEV Community by Taiwrash (@taiwrash).</description>
    <link>https://dev.to/taiwrash</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F186059%2F5c53649c-8308-4016-a395-807751b352d2.JPG</url>
      <title>DEV Community: Taiwrash</title>
      <link>https://dev.to/taiwrash</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/taiwrash"/>
    <language>en</language>
    <item>
      <title>I Added Langfuse to My RAG App and It Immediately Caught Two Bugs</title>
      <dc:creator>Taiwrash</dc:creator>
      <pubDate>Mon, 23 Mar 2026 23:19:39 +0000</pubDate>
      <link>https://dev.to/taiwrash/i-added-langfuse-to-my-rag-app-and-it-immediately-caught-two-bugs-4li3</link>
      <guid>https://dev.to/taiwrash/i-added-langfuse-to-my-rag-app-and-it-immediately-caught-two-bugs-4li3</guid>
      <description>&lt;h2&gt;
  
  
  &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuy3qjee6zat2eyyw32j7.png" alt=" " width="800" height="420"&gt;
&lt;/h2&gt;

&lt;p&gt;I want to tell you something that did not make it into the README.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/Taiwrash/zey-ollama-rag-lab" rel="noopener noreferrer"&gt;zey-ollama-rag-lab&lt;/a&gt; to show off ZeroEntropy's retrieval quality against a base LLM, side by side in a web UI. The demo worked. I was happy with it.&lt;/p&gt;

&lt;p&gt;Then I added Langfuse. Within five minutes of looking at real traces, I found two bugs I had no idea were there.&lt;/p&gt;

&lt;p&gt;One was embarrassing. One was silent and dangerous. Both would have stayed hidden without observability on the pipeline.&lt;/p&gt;

&lt;p&gt;Let me show you what I found and exactly how everything is set up.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the project does
&lt;/h2&gt;

&lt;p&gt;The app compares two paths for answering a question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base LLM path&lt;/strong&gt;: the question goes straight to TinyLlama via Ollama. No context, no retrieval.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RAG path&lt;/strong&gt;: ZeroEntropy retrieves relevant chunks from your indexed documents, reranks them using &lt;code&gt;zerank-2&lt;/code&gt;, then TinyLlama generates an answer using that context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both answers appear side by side in a web UI. The whole thing runs locally. Your documents never leave your machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprflqmu9ywbt0cv13xz4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fprflqmu9ywbt0cv13xz4.png" alt=" " width="800" height="631"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The claim the project makes is that the RAG path produces better answers. Langfuse is how you find out if that claim is actually true.&lt;/p&gt;




&lt;h2&gt;
  
  
  Running the project
&lt;/h2&gt;

&lt;p&gt;The cleanest way to run this is by cloning the repo and using Docker. The Dockerfile handles everything: it installs Ollama inside the container, pulls TinyLlama, installs the Python dependencies, and starts the FastAPI server. You do not need Python installed locally or Ollama set up separately.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Taiwrash/zey-ollama-rag-lab.git
&lt;span class="nb"&gt;cd &lt;/span&gt;zey-ollama-rag-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create your &lt;code&gt;.env&lt;/code&gt; file using the provided example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env-example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;.env&lt;/code&gt; and fill in your keys:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;ZEROENTROPY_API_KEY&lt;/span&gt;=&lt;span class="n"&gt;your_zeroentropy_key&lt;/span&gt;
&lt;span class="n"&gt;LANGFUSE_PUBLIC_KEY&lt;/span&gt;=&lt;span class="n"&gt;pk&lt;/span&gt;-&lt;span class="n"&gt;lf&lt;/span&gt;-...
&lt;span class="n"&gt;LANGFUSE_SECRET_KEY&lt;/span&gt;=&lt;span class="n"&gt;sk&lt;/span&gt;-&lt;span class="n"&gt;lf&lt;/span&gt;-...
&lt;span class="n"&gt;LANGFUSE_HOST&lt;/span&gt;=&lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;cloud&lt;/span&gt;.&lt;span class="n"&gt;langfuse&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then build and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; zey-rag-lab &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 zey-rag-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app is at &lt;code&gt;http://localhost:8000&lt;/code&gt;. That is it. One clone, one build, one run.&lt;/p&gt;

&lt;p&gt;The Dockerfile installs Ollama directly inside the container, exposes both port &lt;code&gt;8000&lt;/code&gt; for FastAPI and &lt;code&gt;11434&lt;/code&gt; for Ollama, and sets &lt;code&gt;OLLAMA_HOST=http://localhost:11434&lt;/code&gt; so both services find each other. The &lt;code&gt;entrypoint.sh&lt;/code&gt; script handles starting Ollama and the FastAPI app in the right order. You do not need to think about any of that, it just works.&lt;/p&gt;




&lt;h2&gt;
  
  
  Setting up Langfuse Cloud
&lt;/h2&gt;

&lt;p&gt;For the observability side, I used Langfuse Cloud. Go to &lt;a href="https://cloud.langfuse.com" rel="noopener noreferrer"&gt;cloud.langfuse.com&lt;/a&gt;, create an account, create a project (mine is called &lt;code&gt;rag-ranker-comp&lt;/code&gt;), and grab your public and secret keys from the Settings page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx24ms7nsaxr3n60f7eg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjx24ms7nsaxr3n60f7eg.png" alt=" " width="800" height="509"&gt;&lt;/a&gt;&lt;br&gt;
Those three lines in your &lt;code&gt;.env&lt;/code&gt; are all you need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;LANGFUSE_PUBLIC_KEY&lt;/span&gt;=&lt;span class="n"&gt;pk&lt;/span&gt;-&lt;span class="n"&gt;lf&lt;/span&gt;-...
&lt;span class="n"&gt;LANGFUSE_SECRET_KEY&lt;/span&gt;=&lt;span class="n"&gt;sk&lt;/span&gt;-&lt;span class="n"&gt;lf&lt;/span&gt;-...
&lt;span class="n"&gt;LANGFUSE_HOST&lt;/span&gt;=&lt;span class="n"&gt;https&lt;/span&gt;://&lt;span class="n"&gt;cloud&lt;/span&gt;.&lt;span class="n"&gt;langfuse&lt;/span&gt;.&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK is already in &lt;code&gt;requirements.txt&lt;/code&gt;, so it gets installed when Docker builds the image. No extra steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the Langfuse integration works in the code
&lt;/h2&gt;

&lt;p&gt;The integration is already in &lt;code&gt;app.py&lt;/code&gt;. Here is how the three key pieces work.&lt;/p&gt;

&lt;h3&gt;
  
  
  The observe decorator
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langfuse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Langfuse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;observe&lt;/span&gt;

&lt;span class="n"&gt;lf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Langfuse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Langfuse()&lt;/code&gt; reads your keys from environment variables automatically. Then &lt;code&gt;@observe&lt;/code&gt; wraps any function to create a span in Langfuse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base-llm-generation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_base_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ollama_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;lf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_current_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;usage_details&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;total&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eval_count&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note &lt;code&gt;usage_details&lt;/code&gt; instead of &lt;code&gt;usage&lt;/code&gt;. That is the Langfuse v4 SDK pattern. The token count from Ollama gets attached to the generation span.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracing ZeroEntropy retrieval
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zeroentropy-retrieval&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_retrieve_context&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;snippets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zclient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;top_snippets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;collection_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;reranker&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zerank-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
              &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;snippets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;lf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_current_span&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;collection&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reranker&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;zerank-2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;num_chunks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;top_score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;score&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;chunks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every retrieval call logs the collection name, how many chunks came back, the reranker used, and the top relevance score. When retrieval fails silently, you see exactly why.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt versioning for the RAG system prompt
&lt;/h3&gt;

&lt;p&gt;This part is easy to miss but genuinely useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rag-llm-generation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;as_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;generation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_rag_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context_text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;remote_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rag-system-prompt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;remote_prompt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;lf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update_current_generation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;remote_prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;system_prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;You are a head of developer experience at ZeroEntropy. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use the following retrieved context to answer accurately. &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;If the answer is not in the context, say you don&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t know.&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Context:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context_text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The app first tries to fetch a versioned prompt called &lt;code&gt;"rag-system-prompt"&lt;/code&gt; from Langfuse. If you have created one in the Langfuse UI, it uses that. If not, it falls back to the hardcoded version. Either way, the trace records which prompt version generated which output. You can iterate on your system prompt from the Langfuse UI without touching code or rebuilding the container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Human feedback endpoint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@app.post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/api/feedback&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;feedback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FeedbackRequest&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;lf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;trace_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trace_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user-preference&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;comment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;preferred: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/api/ask&lt;/code&gt; endpoint returns a &lt;code&gt;trace_id&lt;/code&gt; with every response. When the user clicks a preference in the UI, that score gets attached to the exact trace it came from. Over many queries you start building real data on when RAG wins and when it does not.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the traces actually showed me
&lt;/h2&gt;

&lt;p&gt;I ran the container and asked "what is k8s?" a few times. Then I opened &lt;code&gt;cloud.langfuse.com&lt;/code&gt; and looked at the traces.&lt;/p&gt;

&lt;p&gt;Here is the raw export:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Traces 1 and 2, &lt;code&gt;base-llm-generation&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"base-llm-generation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;args&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: [&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;what is k8s?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;], &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;kwargs&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: {}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output is &lt;code&gt;null&lt;/code&gt;. Twice. The trace captured the input arriving and the function running, but nothing coming back out. Without Langfuse I would have seen an empty box in the UI and assumed it was a frontend rendering bug. With the trace I knew immediately: the generation itself is returning nothing. That pointed straight at the Ollama response parsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trace 3, &lt;code&gt;base-llm-generation&lt;/code&gt;&lt;/strong&gt;, after I dug into the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kubernetes (kurz für Kubernetes Engine oder K8s) ist ein Containerorchestrator..."&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It answered. In German. For an English question. TinyLlama just decided to respond in German, confidently and fluently. In the UI this looks like text appeared so you think it worked. In the trace you can read the exact output and know it did not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trace 4, &lt;code&gt;zeroentropy-retrieval&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"zeroentropy-retrieval"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;args&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: [&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;what is k8s?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;demo_collection&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;], &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;kwargs&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: {}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Retrieval ran and returned nothing. The reason showed up in the next trace.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trace 5, &lt;code&gt;rag-llm-generation&lt;/code&gt;:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;args&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;: [&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;what is k8s?&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;[Retrieval error: Error code: 401 - {'detail': 'API Key Invalid'}]&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"output"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Kubernetes (also known as K8s) is a cloud-native platform..."&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The ZeroEntropy API key was invalid. Retrieval failed with a 401. But the app caught the exception, passed the error string as context, and TinyLlama just ignored it and answered from its own weights.&lt;/p&gt;

&lt;p&gt;So the RAG path was silently running as a base LLM with extra steps. No crash. No visible error in the UI. The user sees a correct-looking answer and has no idea retrieval never happened. That is the kind of bug that erodes trust in a system slowly, because the answers look fine until someone checks carefully.&lt;/p&gt;

&lt;p&gt;Langfuse caught both bugs in the first five minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the Langfuse dashboard shows
&lt;/h2&gt;

&lt;p&gt;The home view after that first session showed five total traces in the past day. &lt;code&gt;base-llm-generation&lt;/code&gt; appeared three times (I was debugging the base path). &lt;code&gt;rag-llm-generation&lt;/code&gt; once. &lt;code&gt;zeroentropy-retrieval&lt;/code&gt; once. Model costs at $0.00 because TinyLlama runs locally and free. Scores at zero because the feedback buttons in the UI are the next thing to wire up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd22h5q8vyy6k89xp5g1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd22h5q8vyy6k89xp5g1.png" alt=" " width="800" height="509"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The trace breakdown in the bar chart already tells you something about what is happening in the app. Three base LLM traces to one RAG trace means the base path was the thing failing. If this were a production app with real users, that ratio would tell you which path people are actually using and whether the distribution matches what you expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcen6d70xjgip71d7c1ya.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcen6d70xjgip71d7c1ya.png" alt=" " width="800" height="311"&gt;&lt;/a&gt;&lt;br&gt;
The latency dashboard is where this becomes genuinely useful at scale. How long does &lt;code&gt;zeroentropy-retrieval&lt;/code&gt; take on average compared to &lt;code&gt;ollama-generation&lt;/code&gt;? If your RAG path is slower than the base path, is the retrieval or the generation the bottleneck? You get answers to those questions without adding any logging code.&lt;/p&gt;


&lt;h2&gt;
  
  
  What I fixed
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The null outputs&lt;/strong&gt;: the issue was in how I was reading the Ollama chat response. The &lt;code&gt;message&lt;/code&gt; key was not always present on the response object in the way I expected. Seeing &lt;code&gt;output: null&lt;/code&gt; in two consecutive traces made this obvious in a way that a missing text box in the UI never would have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The German response&lt;/strong&gt;: I added &lt;code&gt;"Answer in English."&lt;/code&gt; to the base prompt. TinyLlama needs the explicit instruction. The traces now show consistent English output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The 401 error&lt;/strong&gt;: I updated &lt;code&gt;.env-example&lt;/code&gt; in the repo to make it clearer that &lt;code&gt;ZEROENTROPY_API_KEY&lt;/code&gt; has to be set before anything works. The silent failure was the real problem. The app should surface the retrieval error visibly in the UI rather than passing it as context to the LLM and pretending everything worked.&lt;/p&gt;


&lt;h2&gt;
  
  
  What is still left to do
&lt;/h2&gt;

&lt;p&gt;The dashboard shows zero scores tracked. The &lt;code&gt;/api/feedback&lt;/code&gt; endpoint is already in the backend code and working. I just have not added the thumbs up and thumbs down buttons to the UI yet.&lt;/p&gt;

&lt;p&gt;Once those are wired up, every user preference flows into Langfuse as a score attached to a trace. Over enough queries you can actually answer the question this whole project is built around: how often does RAG beat the base model, on what kinds of questions, and what happens to that number when retrieval fails?&lt;/p&gt;

&lt;p&gt;That is what turns a demo into a system you can measure and improve over time.&lt;/p&gt;


&lt;h2&gt;
  
  
  The full running setup
&lt;/h2&gt;

&lt;p&gt;Clone, configure, build, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Taiwrash/zey-ollama-rag-lab.git
&lt;span class="nb"&gt;cd &lt;/span&gt;zey-ollama-rag-lab
&lt;span class="nb"&gt;cp&lt;/span&gt; .env-example .env
&lt;span class="c"&gt;# fill in ZEROENTROPY_API_KEY, LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY&lt;/span&gt;
docker build &lt;span class="nt"&gt;-t&lt;/span&gt; zey-rag-lab &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--env-file&lt;/span&gt; .env &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 zey-rag-lab
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;App at &lt;code&gt;http://localhost:8000&lt;/code&gt;. Langfuse dashboard at &lt;code&gt;cloud.langfuse.com&lt;/code&gt;. Traces start flowing from the first query.&lt;/p&gt;

&lt;p&gt;The Langfuse integration is already in the code. You just need the keys.&lt;/p&gt;

&lt;p&gt;Find me on Twitter at &lt;a href="https://x.com/Taiwrash" rel="noopener noreferrer"&gt;@Taiwrash&lt;/a&gt; if you find something interesting in your traces.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Langfuse is open source. Cloud hosted at &lt;a href="https://cloud.langfuse.com" rel="noopener noreferrer"&gt;cloud.langfuse.com&lt;/a&gt;. Self-hostable if you need everything on-prem. Docs at &lt;a href="https://langfuse.com/docs" rel="noopener noreferrer"&gt;langfuse.com/docs&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>monitoring</category>
      <category>rag</category>
    </item>
    <item>
      <title>Jenkins on Google Kubernetes Engine</title>
      <dc:creator>Taiwrash</dc:creator>
      <pubDate>Thu, 27 Mar 2025 11:49:43 +0000</pubDate>
      <link>https://dev.to/taiwrash/jenkins-on-google-kubernetes-engine-26e0</link>
      <guid>https://dev.to/taiwrash/jenkins-on-google-kubernetes-engine-26e0</guid>
      <description>&lt;p&gt;Our goal is simple: It is just to create K8s with GKE, create a Jenkins deployment and services then connect the two.&lt;/p&gt;

&lt;h4&gt;
  
  
  Technology: Kubernetes, Google Cloud Kubernetes, Jenkins, Helms, GitHub
&lt;/h4&gt;

&lt;p&gt;Follow the below steps after verifying your user through the Google cloud console.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create the Kubernetes cluster on the Kubernetes engine using the command below on the gcloud environment.
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud container clusters create jenkins-cd \
--num-nodes 2 \
--scopes "https://www.googleapis.com/auth/projecthosting,cloud-platform"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The command specified the cluster name and the scope to access the Jenkins access to the necessary artifacts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After the command successfully completed, run the command &lt;code&gt;gcloud container clusters list&lt;/code&gt; to see the output that look like below that contain the information about the newly created cluster.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63fkvlbddx7uytjp6jmj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F63fkvlbddx7uytjp6jmj.png" alt="Image description" width="498" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;b. Let's find out the credential of the cluster by running the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud container clusters get-credentials jenkins-cd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c. Confirm the connection with the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl cluster-info
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgu817fvfk89rs84uqq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwgu817fvfk89rs84uqq4.png" alt="Image description" width="800" height="70"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Helm Installation and Configuration
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;what is helm?
Helm is a package manager that makes it easy to configure and deploy Kubernetes applications.
a. After successful installation of Helm from helm documentation guide. The next is adding the Jenkins chart repo with the command
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo add jenkins https://charts.jenkins.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For every installation, it is advisable to update to newer version. this can be done by running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;b. Let's run helm package manager against the yaml configuration files that can be found in &lt;a href="https://github.com/GoogleCloudPlatform/continuous-deployment-on-kubernetes.git" rel="noopener noreferrer"&gt;this repository&lt;/a&gt; under the Jenkins folder. Execute the below command against the config files. The values config file add the Google Cloud specific plugin necessary to use service account credentials to reach Source Repository&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm upgrade --install -f jenkins/values.yaml myjenkins jenkins/jenkins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c. Display the running pods with the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yo1zjcu2pph5qybrpxs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2yo1zjcu2pph5qybrpxs.png" alt="Image description" width="800" height="69"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;d. Let's port forward the Jenkins UI from the cloud shell with the command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo http://127.0.0.1:8080
kubectl --namespace default port-forward svc/myjenkins 8080:8080 &amp;gt;&amp;gt; /dev/null &amp;amp;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F759c0vl4pxygqstrt984.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F759c0vl4pxygqstrt984.png" alt="Image description" width="800" height="82"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 3: Connecting the Jenkins
&lt;/h2&gt;

&lt;p&gt;a. Access the Jenkins UI admin login credentials with the command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl exec --namespace default -it svc/myjenkins -c jenkins -- /bin/cat /run/secrets/additional/chart-admin-password &amp;amp;&amp;amp; echo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the deployed Jenkins running will produce a page like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1sysqs9fupjjawp3hza.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1sysqs9fupjjawp3hza.png" alt="Image description" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Congratulations, you've successfully deployed Jenkins on a Kubernetes environment using the GKE.
&lt;/h3&gt;

</description>
    </item>
    <item>
      <title>Deploy Backend API to Google Kubernetes Engine</title>
      <dc:creator>Taiwrash</dc:creator>
      <pubDate>Thu, 20 Mar 2025 16:50:12 +0000</pubDate>
      <link>https://dev.to/taiwrash/deploy-backend-api-to-google-kubernetes-engine-22oa</link>
      <guid>https://dev.to/taiwrash/deploy-backend-api-to-google-kubernetes-engine-22oa</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The goal is simply to write a NodeJS API and turn it into a replicated application running on Kubernetes, which is running on Google Kubernetes Engine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Important Note: This article uses Google Cloud Console, gcloud shell, Compute Engine, Google Container Registry, Google Kubernetes Engine.
&lt;/h4&gt;

&lt;h2&gt;
  
  
  System Architecuture
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78stg3rh8hpvdejlwzri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F78stg3rh8hpvdejlwzri.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Kubernetes
&lt;/h2&gt;

&lt;p&gt;Kubernetes, also abbreviated as K8s (with '8' representing the number of letters between 'K' and 's'), is an open-source project originally developed by Google. It is now managed by the Cloud Native Computing Foundation (CNCF). Kubernetes provides a robust way to run scalable and highly available applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  From the Beginning
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Let's build the API
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create your app file e.g app.js&lt;/li&gt;
&lt;li&gt;Put the code below
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var http = require('http');
var handleRequest = function(request, response) {
  response.writeHead(200);
  response.end("Hello World!\n");
}
var www = http.createServer(handleRequest);
www.listen(8080);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Execute it by running "node &lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;we chose the file name to be &lt;code&gt;app.js&lt;/code&gt;, therefore we will run &lt;code&gt;node app.js&lt;/code&gt; and we can find the app running on port &lt;code&gt;8080&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst1z8llb1x9e0rz4sy2o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fst1z8llb1x9e0rz4sy2o.png" alt="Image description" width="648" height="249"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Supercharge with Docker.
&lt;/h2&gt;

&lt;p&gt;Kubernetes can run Docker containers; therefore, we need to containerize our app. To run a containarize application we need a &lt;code&gt;Dockerfile&lt;/code&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simple container lifecycle: Dockerfile &amp;gt; Docker Image &amp;gt; Docker Container. A built dockerfile produces a docker image and a running docker image produces a docker container. In this article, the container will be running on cloud and managed by kubernetes.&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Create Docker file with: a file with name &lt;code&gt;Dockerfile&lt;/code&gt; and put the below code.
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:6.9.2
EXPOSE 8080
COPY server.js .
CMD node server.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Build the docker file to get a docker image&lt;/li&gt;
&lt;li&gt;Run the docker image to get a docker container to test out locally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Output on the cloudshell:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuoa1ek0t714c3f08u9dk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuoa1ek0t714c3f08u9dk.png" alt="Image description" width="800" height="33"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Output on the browser:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7q7vhv8hkun13ekr0ur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7q7vhv8hkun13ekr0ur.png" alt="Image description" width="800" height="40"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Pushing the image to the registry
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Authenticate your registry be it GCR,ECR, Dockerhub or ACR
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud auth configure-docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Push to the registry
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker push gcr.io/PROJECT_ID/hello-node:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output on the cloudshell:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwucji1guvb7nk46bjpch.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwucji1guvb7nk46bjpch.png" alt="Image description" width="800" height="118"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The image pushed to the registry can be confirmed by checking the registry via the Google cloud console.&lt;/p&gt;

&lt;p&gt;Output on th cloud console registry:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6aexy5xqinzgcp00rwp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6aexy5xqinzgcp00rwp.png" alt="Image description" width="800" height="301"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c8fl8q7jce39ljllfwo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6c8fl8q7jce39ljllfwo.png" alt="Image description" width="691" height="394"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating the Kubernetes cluster
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Confirm project ID config
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud config set project PROJECT_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;Creating the nodes
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud container clusters create hello-world \
                --num-nodes 2 \
                --machine-type e2-medium \
                --zone "us-central1-c"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;2 nodes with machine type to be e2-medium and the us-central1-c zone&lt;br&gt;
Output:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fblxxwpiz99pi2gwb9yn5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fblxxwpiz99pi2gwb9yn5.png" alt="Image description" width="800" height="244"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;this will take 2-3 minutes to complete depending on my factors, so be patient.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Creating a pod
&lt;/h2&gt;

&lt;p&gt;Running nodejs image stored in the registry serving content at port 8080. We need away to bring the docker image stored in the registry into the kubernetes cluster created and this can be done by creating a pod and run the docker image inside of it.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;kubectl command to create a deployment pod
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create deployment hello-node \
    --image=gcr.io/PROJECT_ID/hello-node:v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;the command create a deployment in the cluster referencing the docker image stored in the registry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4abkvqm9j5nnn3ca5ay.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4abkvqm9j5nnn3ca5ay.png" alt="Image description" width="800" height="43"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;show the pod created
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feez4pe71blky4j291fn4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feez4pe71blky4j291fn4.png" alt="Image description" width="800" height="108"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Let's allow external traffic from customers and internet
&lt;/h2&gt;

&lt;p&gt;In order to make the hello-node container accessible from outside the Kubernetes virtual network, we need to expose the pod as a Kubernetes service.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add a load balancer to add an external IP
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl expose deployment hello-node --type="LoadBalancer" --port=8080
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuv0lywpzdyarlopqfmjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuv0lywpzdyarlopqfmjg.png" alt="Image description" width="800" height="49"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Finding the IP address accessible everywhere
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output with a focus on the external IP on the hello-node:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3e5lgye97xfma3bcoiik.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3e5lgye97xfma3bcoiik.png" alt="Image description" width="800" height="67"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check the browser with the IP.
&amp;gt; If you put the IP address in the browser, you will get something like below which is the response from the API we are deploying&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqxn3amepn67axecyov4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqxn3amepn67axecyov4.png" alt="Image description" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Scale up the services easily
&lt;/h2&gt;

&lt;p&gt;Suppose you suddenly need more capacity. You can tell the replication controller to manage a new number of replicas for your pod with the &lt;code&gt;kubectl scale&lt;/code&gt; command.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Increase the number of pods to 4
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl scale deployment hello-node --replicas=4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzzll4s5a4t2bxgpj5pt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhzzll4s5a4t2bxgpj5pt.png" alt="Image description" width="800" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm the number of replicas
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4f22xjcxddbbvxokzn20.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4f22xjcxddbbvxokzn20.png" alt="Image description" width="800" height="65"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;See the running pods managed by the deployment
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Output:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdiswmo14m5zw2e4qb0af.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdiswmo14m5zw2e4qb0af.png" alt="Image description" width="800" height="98"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Where we are
Everything we've done so far is replicated in the diagram below for easy understand and a help to build the right mental model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bgw2m1cpyxjrh7580sd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0bgw2m1cpyxjrh7580sd.png" alt="Image description" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Roll out an upgrade to your service
&lt;/h2&gt;

&lt;p&gt;This is done without impacting users, that's the power of kubernetes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the feature: we added another endpoint return &lt;/li&gt;
&lt;li&gt;Rebuild the docker image&lt;/li&gt;
&lt;li&gt;push new version to docker registry&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;a. To interact with running cluster, you edit the k8s&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl edit deployment hello-node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Point the &lt;code&gt;spec.template.spec.containers.image&lt;/code&gt; to the new version of the image just pushed to the registry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhyuvihnt6710ua9tb3i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhyuvihnt6710ua9tb3i.png" alt="Image description" width="800" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkehty61z3fmib2wotmv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnkehty61z3fmib2wotmv.png" alt="Image description" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;While this is happening, the users using the services wouldn't see any interruption. After a little while they'll start accessing the new version of the application i.e the API responding with &lt;code&gt;Hello Kubernetes World!&lt;/code&gt;. &lt;br&gt;
These deployment, scaling, and updated features, are managed by K8s once Kubernetes Engine cluster is set up, It'll be clear that Kubernetes will help you focus on the application rather than the infrastructure.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a part of a series. take note!&lt;/p&gt;

</description>
      <category>devops</category>
      <category>googlecloud</category>
      <category>kubernetes</category>
      <category>docker</category>
    </item>
    <item>
      <title>KubeActions - N0.1 Kubernetes Deployment Tool</title>
      <dc:creator>Taiwrash</dc:creator>
      <pubDate>Sat, 20 May 2023 20:55:45 +0000</pubDate>
      <link>https://dev.to/taiwrash/kubeactions-n01-kubernetes-deployment-tool-5cfb</link>
      <guid>https://dev.to/taiwrash/kubeactions-n01-kubernetes-deployment-tool-5cfb</guid>
      <description>&lt;h2&gt;
  
  
  Continuous Deployment Action for Kubernetes Environments [dev, test, staging, prod]
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Category Submission:
&lt;/h3&gt;

&lt;p&gt;DIY Deployments: Improve the deployment process for open-source projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  App Release Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Taiwrash/kubeaction/releases/tag/kubernetes"&gt;Release Kubernete&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Description:
&lt;/h3&gt;

&lt;p&gt;The Continuous Deployment Action for Kubernetes Environments is a GitHub Action that automates the deployment process for Go applications to multiple Kubernetes environments. It simplifies the CI/CD pipeline by providing a reusable and customisable workflow to deploy your application to different environments such as test, stage, and production.&lt;/p&gt;

&lt;p&gt;The action utilises the power of Kubernetes and GitHub Actions to streamline the deployment process. It includes the necessary scripts and configuration files to deploy the application to the desired Kubernetes clusters and namespaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  Link to Source Code:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Taiwrash/kubeaction"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissive License:
&lt;/h3&gt;

&lt;p&gt;MIT License&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;The motivation behind building this action was to enhance the deployment process for Go applications in Kubernetes environments. As a developer, I found myself spending significant time configuring and managing deployment scripts for different environments. This action aims to simplify and automate the deployment workflow, enabling developers to focus more on writing code and less on manual deployment tasks.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;I leveraged GitHub Actions, Go programming language, and Kubernetes to build this action. The action is written in Go and utilises the power of the Kubernetes command-line tool (&lt;code&gt;kubectl&lt;/code&gt;) to interact with the Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;Here are the key components of the action:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GitHub Actions Workflow&lt;/strong&gt;: The main entry point of the action is the workflow defined in the &lt;code&gt;.github/workflows/&amp;lt;name_of_your_choice.yml&amp;gt;&lt;/code&gt; file. It triggers pushes to the main branch and sets up the environment for the deployment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Go Application&lt;/strong&gt;: The Go application contains the deployment logic specific to each environment. It uses environment variables to determine the target environment and executes the necessary Kubernetes commands to deploy the application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Deployment Scripts&lt;/strong&gt;: The deployment scripts, located in the &lt;code&gt;scripts&lt;/code&gt; directory, provide the necessary commands to deploy the application to different environments. Each script interacts with the Go application, passing the target environment and triggering the deployment process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Kubernetes Manifests&lt;/strong&gt;: The &lt;code&gt;Kubernetes&lt;/code&gt; directory includes the Kubernetes manifests (&lt;code&gt;test. yaml&lt;/code&gt;, &lt;code&gt;stage. yaml&lt;/code&gt;, &lt;code&gt;production. yaml&lt;/code&gt;) required for deploying the application to the respective environments. These manifests can be customised to match the specific requirements of the application.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I learned how to integrate Go with GitHub Actions and Kubernetes during the development process. I also gained a deeper understanding of CI/CD processes and best practices for deploying applications to Kubernetes environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources/Info
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions"&gt;GitHub Actions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/home/"&gt;Kubernetes Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;This article summarises the Continuous Deployment Action for Kubernetes Environments, a GitHub Action designed to simplify and automate the deployment process for Go applications in Kubernetes clusters. The action streamlines the deployment workflow, allowing developers to focus on writing code rather than managing complex deployment scripts.&lt;/p&gt;

&lt;p&gt;The source code, deployment scripts, and Kubernetes manifests are available in the GitHub repository. Feel free to explore, customise, and contribute to the project.&lt;/p&gt;

&lt;p&gt;By leveraging the power of GitHub Actions and Kubernetes, this action empowers developers to achieve efficient and reliable deployments across multiple environments. Let's embrace automation and enhance our deployment processes!&lt;/p&gt;

&lt;p&gt;Please feel free to reach out if you have any questions or suggestions. Happy deploying!&lt;/p&gt;




</description>
      <category>githubhack23</category>
      <category>githubactions</category>
      <category>go</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>The Three Fundamentals of Learning Cloud Computing and DevOps Engineering</title>
      <dc:creator>Taiwrash</dc:creator>
      <pubDate>Thu, 19 May 2022 17:43:43 +0000</pubDate>
      <link>https://dev.to/taiwrash/the-three-fundamentals-of-learning-cloud-computing-and-devops-engineering-dj7</link>
      <guid>https://dev.to/taiwrash/the-three-fundamentals-of-learning-cloud-computing-and-devops-engineering-dj7</guid>
      <description>&lt;p&gt;Getting into cloud computing or the DevOps world is made easy by various cloud providers. For instance, Amazon Web Services provides access to AWS Educate to learn both the fundamentals of the cloud and AWS cloud services specifics, and Google provides access to Qwiklabs to learn all about the cloud and Google Cloud Platform cloud services specifics. Microsoft provides access to Microsoft Learn to do the same as others provided. The Linux Foundation has courses and training on cloud native paths and so on. There are other learning platforms outside the provider platforms. KodeCloud, ACloud, and others are also a place to leverage cloud technology knowledge.&lt;br&gt;
Diving into all of the above-mentioned platforms may be very tedious and difficult without the knowledge of the basics. To find the cloud journey more interesting, one needs to have in their toolkits the basics to be discussed in this article. Don’t misunderstand this, jumping this will not hinder you from learning on those platforms. But it's worth knowing that all these platforms are like an ocean to learn on and an ocean that can easily drone beginners and starters without the full knowledge of basics and fundamentals. My exploration of those platforms made it a choice for me to support people like me to learn the right way and show them what it is necessary to have as a pre-requisite.&lt;br&gt;
The following are the basics you need to have as a person planning to start a cloud engineering journey.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_WEAKw1F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.contrastsecurity.com/hs-fs/hubfs/images/DevOps%2520Solutions/devops-old-way.gif%3Fwidth%3D1983%26name%3Ddevops-old-way.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_WEAKw1F--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://www.contrastsecurity.com/hs-fs/hubfs/images/DevOps%2520Solutions/devops-old-way.gif%3Fwidth%3D1983%26name%3Ddevops-old-way.gif" alt="DeVops" width="879" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Linux Skills&lt;/strong&gt;&lt;/em&gt;&lt;br&gt;
According to the 2020 &lt;a href="https://insights.stackoverflow.com/survey/2021#section-most-popular-technologies-operating-system"&gt;StackOverflow survey&lt;/a&gt;, Linux is the most popular platform used by developers and for servers related jobs but overtook by Windows in the 2022 survey because of the ability of WSL (Windows Subsystem for Linux) introduced by Windows developers, just provide access to Linux capabilities on Windows 10 and later. According to a survey by &lt;a href="http://w3techs.com/technologies/overview/operating_system/all"&gt;w3techs&lt;/a&gt;, over 77% of online servers run Linux, 90% of public clouds run Linux, and practically all the best cloud hosts use it, 96.3% of the world’s top 1 million servers run on Linux. There are more reasons why Linux is used for servers and other related jobs, but that is not the focus of the article. &lt;br&gt;
When getting started, learning Linux commands will come in handy as you progress in your cloud journey. This article is not a tutorial on Linux commands but a heads-up on what needs to be learned before deep diving in. Learning the basics ls – list command, just to list the content of a folder, mkdir – make directory command, which is used to create folders, touch – command to create a file, chmod – change mode command, which changes the mode of a file. curl, ping, IP, rm, mv, cp, cat, and other simple commands are very important to know beforehand.&lt;br&gt;
Another important thing to note is the environment provided by Linux Distros to run the aforementioned and other commands. This is called a "SHELL." There are four popular shells known to run various commands as listed below.&lt;br&gt;
Bourne Shell (SH Shell)&lt;br&gt;
C Shell (csh or tcsh)&lt;br&gt;
Z Shell (zsh)&lt;br&gt;
Bourne Again Shell (BASH)&lt;br&gt;
All of these provide an environment to execute Linux commands with a little difference among them. Some did not support tab for autocomplete, backspace to delete the last character and many other variations. You can run ls $SHELL to know the particular shell that is available to you in your terminal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Editors&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Familiarity with one Linux based text editor is very important as it will always come in handy going forward in the journey. There are tons of these editors on the internet, e.g.&lt;br&gt;
&lt;br&gt;
 &lt;code&gt;Vim, GNU nano, Emacs, VI, geddit&lt;/code&gt;&lt;br&gt;
&lt;br&gt;
, and others. Convenient in one is sufficient for the start but may require levelling up moving forward. These tools are used to edit file contents and also the content of a file. This requires a bit of knowledge to be more comfortable using them. VI, for instance, usually comes with almost all kinds of Linux distros. You can type vi  commands into the terminal and you will be provided with the content of the file in command mode. To edit contents, one needs to enter the insert mode. Below are some of the commands that can be used in the command mode.&lt;br&gt;
I – To enter insert mode&lt;br&gt;
Esc – to enter commands mode&lt;br&gt;
&amp;lt; ^ &amp;gt; - four arrow keys on the keyboard to move left, down, up and right, (HJLK) can also be used respectively.&lt;br&gt;
:q - to quit the VI&lt;br&gt;
:w – save the file&lt;br&gt;
:wq – save and quit the VI&lt;br&gt;
/ - to search for a letter or word&lt;br&gt;
There are other commands, but I will advise you to stick with the basics for a start to have smooth learning ahead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Labs Setup&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Some of the above-mentioned courses may introduce the students to lab setup, but having the basic knowledge of these techniques will go a long way. Virtualization, or Hypervisor in Windows terms, is a very important thing to know as it will form a large part of learning DevOps. Familiarization with TYPE-2 virtualization is very important to have. The TYPE-2 is when using a virtual box like Oracle virtual box to create virtual machines and perform connectivity and other networking setups to establish communication between more than one device. Leom has a link to the right virtualbox for you &lt;a href="https://medium.com/@leomofthings/virtualbox-installing-virtual-box-for-linux-ae2ba5f03548"&gt;here&lt;/a&gt;.&lt;br&gt;&lt;br&gt;
Finally, there is more to learn, but learning the above-mentioned concepts will be a plus for learning more advanced and difficult concepts. I am planning in-depth and simple tutorials for beginners in the three mentioned basics. You can let me know your thoughts on it.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>cloud</category>
      <category>cloudskills</category>
      <category>linux</category>
    </item>
    <item>
      <title>Simple and Easy Open Source Project for Contributors to contribute during HACKTOBERFEST - DEV-RESUME as Case study</title>
      <dc:creator>Taiwrash</dc:creator>
      <pubDate>Wed, 30 Sep 2020 06:08:33 +0000</pubDate>
      <link>https://dev.to/taiwrash/simple-and-easy-open-source-project-for-beginners-to-contribute-during-hacktoberfest-dev-resume-as-case-study-4c30</link>
      <guid>https://dev.to/taiwrash/simple-and-easy-open-source-project-for-beginners-to-contribute-during-hacktoberfest-dev-resume-as-case-study-4c30</guid>
      <description>&lt;h2&gt;
  
  
  Terms used
&lt;/h2&gt;

&lt;p&gt;a. Open-source software is a type of computer software in which source code is released under a license in which the copyright holder grants users the rights to use, study, change, and distribute the software to anyone and for any purpose. &lt;/p&gt;

&lt;p&gt;b. Pull requests let you tell others about changes you've pushed to a branch in a repository on GitHub. &lt;/p&gt;

&lt;h3&gt;
  
  
  Hacking in October (hacktoberfest) ❤️
&lt;/h3&gt;

&lt;p&gt;It is the month of October when developers and tech enthusiasts around the globe gather remotely and in person to celebrate open source. The experience has always been a big bang. The big bang is called HACKTOBERFEST. This is an annual event which runs through out the month of October. For this reason, I am inviting you to a beginner-friendly and easy-to-contribute project titled DEV_RESUME.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of contributing
&lt;/h2&gt;

&lt;p&gt;The following are the rewards and benefits for every contributors of this project.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Get recognised on GitHub with a contributor's badge issued by our GitHub contributor's bot&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A merged PR (Pull Request) get featured on our live project at &lt;a href="https://dev-resume.herokuapp.com" rel="noopener noreferrer"&gt;https://dev-resume.herokuapp.com&lt;/a&gt; which is aimed at showcasing open source contributors around the world.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Aims of the project
&lt;/h2&gt;

&lt;p&gt;To be No.1 point for recruiters to confirm developers contributions to open source.&lt;/p&gt;

&lt;h3&gt;
  
  
  Below are the simple and straight forward steps to contribute to the project.
&lt;/h3&gt;

&lt;p&gt;Step 1: Sign in to github.&lt;br&gt;
Step 2: Search Dev-resume or follow this &lt;a href="https://github.com/Taiwrash/dev-resume" rel="noopener noreferrer"&gt;https://github.com/Taiwrash/dev-resume&lt;/a&gt;.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fblhlv48cya1aooeckzr3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fblhlv48cya1aooeckzr3.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 3: Fork the repo using the fork button on GitHub&lt;br&gt;
Step 4: after successfully forked, clone the repo by using the clone button with your system terminal&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo4atulvxoild51iah0wf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fo4atulvxoild51iah0wf.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 5: Open the folder and navigate to public, then images, and move your desired image into it(note the name and extension of the image) i.e dev-resume/public/images&lt;/p&gt;

&lt;p&gt;Step 6: leave the public folder&lt;br&gt;
Step 7: Go to data.json file.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffjdhxe29l6bta0jaojhb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffjdhxe29l6bta0jaojhb.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Step 8: Copy a complete object in the array starting with { and end with } put a comma as the last character and paste.&lt;br&gt;
Step 9: Paste and edit the data to your personal data, then save. &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0re0sjmnp4cni074h1u.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fb0re0sjmnp4cni074h1u.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  You are almost there!💪
&lt;/h4&gt;

&lt;p&gt;Step 10: Commit your changes and push to the GitHub.&lt;br&gt;
Step 11: Navigate to GitHub and the forked repo should be begging for PR.&lt;/p&gt;

&lt;p&gt;Step 12: Create a PR and you are done!&lt;/p&gt;

&lt;h4&gt;
  
  
  Great work👍
&lt;/h4&gt;

&lt;p&gt;Do this and you are 3 steps away from getting your tree planted by hacktoberfest team and your tee are waiting for more 3 PRs.&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftea0p57y11gag43z83hi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ftea0p57y11gag43z83hi.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is how simple it is and you are done!&lt;/p&gt;

&lt;p&gt;Let's hack together in this October period with the HACKTOBERFEST tag!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
