<?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: Esa Data</title>
    <description>The latest articles on DEV Community by Esa Data (@esadata).</description>
    <link>https://dev.to/esadata</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4135439%2F630d7e4d-0926-4c78-b8b8-a8d66f0b5c71.jpeg</url>
      <title>DEV Community: Esa Data</title>
      <link>https://dev.to/esadata</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/esadata"/>
    <language>en</language>
    <item>
      <title>Agent Relay v2</title>
      <dc:creator>Esa Data</dc:creator>
      <pubDate>Mon, 21 Sep 2026 10:44:14 +0000</pubDate>
      <link>https://dev.to/esadata/agent-relay-v2-28aa</link>
      <guid>https://dev.to/esadata/agent-relay-v2-28aa</guid>
      <description>&lt;h2&gt;
  
  
  From SQLite to Kubernetes: Building a Test-Gated CI/CD Pipeline for a Task Relay Service
&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyn7apvrukhlapq4d7emn.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyn7apvrukhlapq4d7emn.png" alt="Agent-Relay v2 Architecture" width="652" height="408"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I recently completed an engineering exercise that started as a small FastAPI + SQLite application and gradually evolved into a containerized, Kubernetes-deployed service with a full CI/CD pipeline.&lt;br&gt;
The project is Agent Relay — a task relay service for registering agents, delivering tasks, tracking claims, and recording results.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The evolution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQLite → PostgreSQL → Docker → Kubernetes (Kind) → GitHub Actions CI/CD&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What made this interesting wasn't just "getting it running" — it was watching each layer expose a new class of problem that the previous layer didn't have to deal with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I implemented and verified along the way&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;• Agent registration and authentication&lt;br&gt;
• At-least-once task delivery&lt;br&gt;
• Lease-based task claims&lt;br&gt;
• Worker heartbeats&lt;br&gt;
• Task recovery after worker failure&lt;br&gt;
• Idempotent terminal requests&lt;br&gt;
• PostgreSQL persistence&lt;br&gt;
• Docker containerization&lt;br&gt;
• Kubernetes Deployment, Service, Secret, and PVC&lt;br&gt;
• Automated pytest verification&lt;br&gt;
• Git SHA-based Docker image tagging&lt;br&gt;
• Test-gated CI/CD&lt;br&gt;
• End-to-end deployment verification&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The lesson that mattered most&lt;/strong&gt;&lt;br&gt;
A successful Kubernetes rollout does not mean an application is actually working. kubectl rollout status can go green while the app underneath is silently broken — a bad config, a missing secret, a dependency that never connected.&lt;br&gt;
So the pipeline doesn't stop at "the pods are Running." After deployment, it port-forwards the service and runs an application-level check against the dashboard — the same kind of check a human would do by opening the page and looking at it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pipeline, accurately&lt;/strong&gt;&lt;br&gt;
My first pass at diagramming this pipeline drew pytest, Docker build, and Kubernetes deployment as three parallel branches. That's not what actually happens. The real pipeline is sequential and test-gated: nothing gets built or deployed unless the tests pass first.&lt;/p&gt;

&lt;p&gt;Developer&lt;br&gt;
   ↓&lt;br&gt;
Git Repository (push)&lt;br&gt;
   ↓&lt;br&gt;
GitHub Actions&lt;br&gt;
   ↓&lt;br&gt;
job: test&lt;br&gt;
   ├── setup Python 3.11 + uv&lt;br&gt;
   ├── Postgres 16-alpine (service container)&lt;br&gt;
   └── uv run pytest -q&lt;br&gt;
   ↓  (needs: test → only proceeds if tests pass)&lt;br&gt;
job: build-and-deploy&lt;br&gt;
   ├── Docker build (image tagged with Git SHA)&lt;br&gt;
   └── deploy to Kind cluster&lt;br&gt;
          ├── kubectl apply -f k8s/&lt;br&gt;
          ├── kubectl set image&lt;br&gt;
          └── rollout status&lt;br&gt;
                ↓&lt;br&gt;
        Agent Relay (FastAPI service, incl. dashboard)&lt;br&gt;
                ↓&lt;br&gt;
        Verification: port-forward + curl → dashboard check&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters beyond one project&lt;/strong&gt;&lt;br&gt;
The instinct to treat "deployed" as "done" is exactly the instinct that breaks pipelines at scale. Whether it's a Kubernetes rollout or a data/ML pipeline, the pattern is the same: infrastructure-level success (pod is Running, DAG task is green) is not application-level success (the thing actually does what it's supposed to do). Closing that gap with a real, purpose-built check — not just a health probe — is what turns "it deployed" into "it works."&lt;/p&gt;

&lt;p&gt;I'm currently exploring how these same engineering principles — test gating, staged evolution, verifying at the application level rather than the infrastructure level — apply to larger Data Engineering and AI/LLM systems, where the failure modes are often even less visible than a crashed pod.&lt;/p&gt;

&lt;p&gt;The repository contains the implementation, Kubernetes manifests, Docker configuration, automated tests, and the CI/CD workflow.&lt;/p&gt;

&lt;p&gt;GitHub repo: &lt;a href="https://github.com/ketut-garjita/agent-relay" rel="noopener noreferrer"&gt;https://github.com/ketut-garjita/agent-relay&lt;/a&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>cicd</category>
      <category>devops</category>
      <category>kubernetes</category>
    </item>
  </channel>
</rss>
