<?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: Mario Ezquerro</title>
    <description>The latest articles on DEV Community by Mario Ezquerro (@marioezquerro).</description>
    <link>https://dev.to/marioezquerro</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%2F878530%2F7288c9b0-63e5-4a85-b7a1-be9f1234dfbd.jpeg</url>
      <title>DEV Community: Mario Ezquerro</title>
      <link>https://dev.to/marioezquerro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marioezquerro"/>
    <language>en</language>
    <item>
      <title>Building Sarrera: Self-Hosted Enterprise AI Inference Gateway with RBAC, Token Quotas &amp; Telemetry</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Fri, 02 Oct 2026 12:19:36 +0000</pubDate>
      <link>https://dev.to/gde/building-sarrera-self-hosted-enterprise-ai-inference-gateway-with-rbac-token-quotas-telemetry-316o</link>
      <guid>https://dev.to/gde/building-sarrera-self-hosted-enterprise-ai-inference-gateway-with-rbac-token-quotas-telemetry-316o</guid>
      <description>&lt;p&gt;Engineering teams worldwide face a common dilemma when adopting generative AI:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cloud AI privacy &amp;amp; security risks&lt;/strong&gt;: Sending proprietary source code to third-party APIs (OpenAI, Anthropic) triggers compliance alarms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uncontrolled cloud billing&lt;/strong&gt;: A handful of developers running autonomous agents (Cline, Roo Code, Cursor) can easily run up thousands of dollars in surprise monthly token bills.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware fragmentation&lt;/strong&gt;: On-premise clusters often consist of heterogeneous hardware—a few servers with NVIDIA A100/RTX 4090s, some mid-range workstation GPUs (RTX 3060/4060), and fallback CPU clusters. Without smart routing, high-end GPUs saturate while other machines sit idle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To solve this, we built and open-sourced &lt;strong&gt;&lt;a href="https://github.com/Sarrera/sarrera" rel="noopener noreferrer"&gt;Sarrera&lt;/a&gt;&lt;/strong&gt; (&lt;em&gt;"Entryway / Portal"&lt;/em&gt; in Basque) — an enterprise local AI inference gateway, access control (RBAC), and observability platform packaged into a single Docker Compose deployment.&lt;/p&gt;

&lt;p&gt;In this article, I will walk you through the architecture, multi-tier subscription quotas, dynamic node management, and how you can deploy your own private AI hub in under 5 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏛️ High-Level Architecture
&lt;/h2&gt;

&lt;p&gt;Sarrera decouples client IDEs from physical compute hardware, shielding your internal network behind a single perimeter reverse proxy.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                                [ Internet / Corporate LAN ]
                                              │
                                              ▼ (Ports 80 / 443 Only)
                             ┌───────────────────────────────────┐
                             │       ai-caddy (Caddy v2)         │
                             │  - Central TLS Termination        │
                             │  - Sarrera Service Hub &amp;amp; Portal   │
                             │  - Security Headers (HSTS)        │
                             └─────────────────┬─────────────────┘
                                               │
         ┌────────────────────────┬────────────┴────────────┬────────────────────────┐
         ▼                        ▼                         ▼                        ▼
┌──────────────────┐    ┌──────────────────┐      ┌──────────────────┐     ┌──────────────────┐
│  Open WebUI      │    │  LiteLLM Proxy   │      │  Langfuse v2     │     │  MinIO Console   │
│  (Chat Portal)   │    │  (Gateway/Admin) │      │  (Observability) │     │  (Trace Storage) │
│  Internal :8080  │    │  Internal :4000  │      │  Internal :3000  │     │  Internal :9001  │
└──────────────────┘    └─────────┬────────┘      └──────────────────┘     └──────────────────┘
                                  │
                 ┌────────────────┼────────────────┐
                 ▼ (least-busy)   ▼                ▼
          [GPU Premium]    [GPU Standard]    [CPU Cluster]
         (A100 / RTX 4090) (RTX 3060/4060)  (AVX-512 CPU)
           :11434           :11434            :11434
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The 7 Core Building Blocks
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Edge Reverse Proxy (&lt;code&gt;Caddy v2&lt;/code&gt;)&lt;/strong&gt;: Serves as the single exposed internet entrypoint on ports 80/443. Manages automated TLS certificate lifecycles (Let's Encrypt / ZeroSSL / Internal CA), and serves the integrated Sarrera Service Hub.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Gateway &amp;amp; Router (&lt;code&gt;LiteLLM Proxy&lt;/code&gt;)&lt;/strong&gt;: Standard &lt;code&gt;/v1/chat/completions&lt;/code&gt; OpenAI-compatible API gateway. Enforces subscription Tiers, virtual API keys, and weighted &lt;code&gt;least-busy&lt;/code&gt; load balancing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Observability &amp;amp; Auditing (&lt;code&gt;Langfuse v2&lt;/code&gt;)&lt;/strong&gt;: Asynchronous, non-blocking telemetry engine recording every prompt, completion, Time-To-First-Token (TTFT), token sum, and department cost attribution.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chat &amp;amp; Prompt Portal (&lt;code&gt;Open WebUI&lt;/code&gt;)&lt;/strong&gt;: Interactive chat interface for non-developer staff, document RAG, and Active Directory / LDAP authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Relational State (&lt;code&gt;PostgreSQL 16&lt;/code&gt;)&lt;/strong&gt;: Dedicated persistent databases for LiteLLM keys/budgets and Langfuse trace metadata.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object Storage (&lt;code&gt;MinIO S3&lt;/code&gt;)&lt;/strong&gt;: High-performance S3 storage bucket retaining large trace payloads and prompt attachments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local Stand-in Engine (&lt;code&gt;Ollama&lt;/code&gt;)&lt;/strong&gt;: Local container with network aliases (&lt;code&gt;gpu-entry-node&lt;/code&gt;, &lt;code&gt;cpu-cluster-node&lt;/code&gt;, &lt;code&gt;gpu-premium-node&lt;/code&gt;) for instant testing without external GPU dependencies.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🛡️ 3-Tier Subscription &amp;amp; Token Quota Governance
&lt;/h2&gt;

&lt;p&gt;To avoid budget blowouts, Sarrera maps developer virtual API keys to &lt;strong&gt;LiteLLM Teams&lt;/strong&gt; representing corporate subscription tiers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────────────────────────────────────────────────────────────────────┐
│                           SARRERA SUBSCRIPTION TIERS                          │
├───────────────────────┬───────────────────────────────┬───────────────────────┤
│      tier-basic       │         tier-standard         │     tier-premium      │
│   (Junior / Entry)    │        (Pro / Standard)       │     (Lead / Expert)   │
├───────────────────────┼───────────────────────────────┼───────────────────────┤
│ • basic-coder (7B)    │ • basic-coder (7B)            │ • basic-coder (7B)    │
│                       │ • premium-coder (32B)         │ • premium-coder (32B) │
│                       │                               │ • premium-reasoning   │
│                       │                               │   (DeepSeek-R1)       │
├───────────────────────┼───────────────────────────────┼───────────────────────┤
│ Budget: 15 EUR/month  │ Budget: 50 EUR/month          │ Budget: 100 EUR/month │
│ 60 RPM · 30k TPM      │ 120 RPM · 60k TPM             │ 180 RPM · 120k TPM    │
└───────────────────────┴───────────────────────────────┴───────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sub-Millisecond Enforcement
&lt;/h3&gt;

&lt;p&gt;When a developer in VS Code triggers autocomplete:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;LiteLLM checks if the requested model is whitelisted for their tier.&lt;/li&gt;
&lt;li&gt;If a junior developer with &lt;code&gt;tier-basic&lt;/code&gt; requests &lt;code&gt;premium-reasoning&lt;/code&gt; (DeepSeek-R1), the gateway immediately returns &lt;strong&gt;&lt;code&gt;HTTP 403 Forbidden&lt;/code&gt;&lt;/strong&gt; in &lt;strong&gt;10 milliseconds&lt;/strong&gt; without touching the GPU cluster.&lt;/li&gt;
&lt;li&gt;If accumulated monthly spend exceeds the team's cap, it returns &lt;code&gt;HTTP 400 Budget Exceeded&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If rate limits are exceeded, it returns &lt;code&gt;HTTP 429 Too Many Requests&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ⚡ Heterogeneous Load Balancing: Do You Need HAProxy?
&lt;/h2&gt;

&lt;p&gt;A frequent question from infrastructure engineers is: &lt;em&gt;"Do we need HAProxy or Nginx to balance traffic across our inference servers?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short answer is NO.&lt;/strong&gt; Traditional Layer 4 / Layer 7 proxies like HAProxy only see HTTP byte streams and status codes. They do not understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VRAM memory footprints per request.&lt;/li&gt;
&lt;li&gt;The difference between a 20-token autocomplete versus a 4,000-token multi-file refactoring.&lt;/li&gt;
&lt;li&gt;Token streaming (&lt;code&gt;text/event-stream&lt;/code&gt;), TTFT latencies, or Out-Of-Memory (OOM) GPU states.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;LiteLLM is an &lt;strong&gt;LLM-aware Application Router&lt;/strong&gt;. In &lt;a href="https://github.com/Sarrera/sarrera/blob/main/config/litellm-config.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;config/litellm-config.yaml&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;model_list&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Route 1: Mid-range dedicated GPU (RTX 4060)&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;basic-coder&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ollama/qwen2.5-coder:7b&lt;/span&gt;
      &lt;span class="na"&gt;api_base&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://192.168.1.50:11434&lt;/span&gt;
      &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8&lt;/span&gt;
      &lt;span class="na"&gt;rpm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60&lt;/span&gt;

  &lt;span class="c1"&gt;# Route 2: Fallback CPU cluster&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;model_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;basic-coder&lt;/span&gt;
    &lt;span class="na"&gt;litellm_params&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ollama/qwen2.5-coder:7b&lt;/span&gt;
      &lt;span class="na"&gt;api_base&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://192.168.1.51:11434&lt;/span&gt;
      &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="na"&gt;rpm&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;

&lt;span class="na"&gt;router_settings&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;routing_strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;least-busy"&lt;/span&gt;
  &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;45&lt;/span&gt;
  &lt;span class="na"&gt;num_retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;least-busy&lt;/code&gt; routing&lt;/strong&gt;: Dynamically tracks active requests in flight and routes the next query to the least saturated host.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Failover &amp;amp; Retries (&lt;code&gt;num_retries: 2&lt;/code&gt;)&lt;/strong&gt;: If a GPU server crashes or encounters a kernel stall, LiteLLM transparently retries the query against the alternate node before returning an error to the developer.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🖥️ Live Dynamic Node Administration (Zero-Downtime)
&lt;/h2&gt;

&lt;p&gt;Editing configuration files and restarting containers during office hours is impractical. &lt;/p&gt;

&lt;p&gt;We built an &lt;strong&gt;Authenticated Admin Control Center&lt;/strong&gt; directly into the Caddy web interface (&lt;code&gt;https://localhost/&lt;/code&gt;):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;&lt;code&gt;🔐 Admin Control Panel&lt;/code&gt;&lt;/strong&gt; in the top navigation.&lt;/li&gt;
&lt;li&gt;Sign in with the credentials defined in &lt;code&gt;.env&lt;/code&gt; (&lt;code&gt;ADMIN_USERNAME&lt;/code&gt; and &lt;code&gt;ADMIN_PASSWORD&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;You can:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Register new GPU/CPU nodes on the fly&lt;/strong&gt;: Provide the node IP (&lt;code&gt;api_base&lt;/code&gt;), backend model, engine (Ollama, vLLM, TGI), weight, and RPM limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ping &amp;amp; test latency&lt;/strong&gt;: Verify network connectivity before saving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persist in PostgreSQL&lt;/strong&gt;: Saves the node directly into LiteLLM without touching YAML files or restarting Docker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Issue scoped developer keys&lt;/strong&gt;: Create keys for &lt;code&gt;tier-basic&lt;/code&gt;, &lt;code&gt;tier-standard&lt;/code&gt;, or &lt;code&gt;tier-premium&lt;/code&gt; with one click.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  💻 Developer Client Integration (VS Code Continue)
&lt;/h2&gt;

&lt;p&gt;Developers consume the platform just like OpenAI:&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;~/.continue/config.json&lt;/code&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;"models"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sarrera (tier-standard)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"premium-coder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"apiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sk-your-virtual-key-here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"apiBase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ai.company.local/v1"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tabAutocompleteModel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sarrera Autocomplete"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provider"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openai"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"basic-coder"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apiKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sk-your-virtual-key-here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"apiBase"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ai.company.local/v1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="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;Every autocomplete and chat interaction appears in &lt;strong&gt;Langfuse&lt;/strong&gt; in real time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact prompt and generated code snippet.&lt;/li&gt;
&lt;li&gt;Exact tokens consumed (&lt;code&gt;prompt_tokens&lt;/code&gt;, &lt;code&gt;completion_tokens&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Time-To-First-Token (TTFT) and total latency.&lt;/li&gt;
&lt;li&gt;Tagged with the developer's username and department for monthly chargeback.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🚀 Quickstart: Deploy in 5 Minutes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Clone &amp;amp; Configure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/Sarrera/sarrera.git
&lt;span class="nb"&gt;cd &lt;/span&gt;sarrera
&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Launch the Stack
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Bootstrap the 3 Subscription Tiers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/bootstrap-tiers.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Issue a Virtual API Key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/issue-key.sh alex tier-standard 90d &lt;span class="s2"&gt;"Core-Engineering"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Run the End-to-End Validation Suite
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/smoke-test.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;strong&gt;&lt;a href="https://localhost/" rel="noopener noreferrer"&gt;https://localhost/&lt;/a&gt;&lt;/strong&gt; in your browser to access the Sarrera Central Portal!&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 What's Next &amp;amp; Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/Sarrera/sarrera" rel="noopener noreferrer"&gt;https://github.com/Sarrera/sarrera&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation Portal&lt;/strong&gt;: Hosted on GitHub Pages inside the repository (&lt;code&gt;/docs&lt;/code&gt;), featuring complete runbooks for Jekyll, Docsify, and MkDocs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your organization is exploring private, compliant local AI inference, check out the repository, give it a star ⭐, and let me know your thoughts in the comments!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>docker</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Stop Running 15 Commands Over SSH: Meet Dockeretior, the Proactive Docker TUI &amp; AutoDoctor #builtwithantigravity</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Thu, 01 Oct 2026 12:54:32 +0000</pubDate>
      <link>https://dev.to/gde/stop-running-15-commands-over-ssh-meet-dockeretior-the-proactive-docker-tui-autodoctor-419f</link>
      <guid>https://dev.to/gde/stop-running-15-commands-over-ssh-meet-dockeretior-the-proactive-docker-tui-autodoctor-419f</guid>
      <description>&lt;h2&gt;
  
  
  😫 The 2:00 AM SSH Nightmare
&lt;/h2&gt;

&lt;p&gt;Every sysadmin, DevOps engineer, and backend developer knows this drill by heart:&lt;/p&gt;

&lt;p&gt;Your monitoring ping rings. A production or staging server is sluggish. You SSH into the remote machine, open your shell, and start typing the ritual sequence of 15 commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker stats &lt;span class="nt"&gt;--no-stream&lt;/span&gt;
docker inspect &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{{.State.ExitCode}}'&lt;/span&gt; &amp;lt;container&amp;gt;
docker logs &lt;span class="nt"&gt;--tail&lt;/span&gt; 50 &amp;lt;container&amp;gt;
docker system &lt;span class="nb"&gt;df
df&lt;/span&gt; &lt;span class="nt"&gt;-h&lt;/span&gt;
free &lt;span class="nt"&gt;-m&lt;/span&gt;
&lt;span class="nb"&gt;uptime
cat &lt;/span&gt;docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You cross-reference logs, parse memory cgroups, try to decipher whether an &lt;strong&gt;Exit Code 137&lt;/strong&gt; was an actual Linux OOM Killer invocation or a manual SIGKILL, and hunt down why your &lt;code&gt;/var/lib/docker&lt;/code&gt; partition climbed from 55% to 89% in two weeks.&lt;/p&gt;

&lt;p&gt;Web dashboards like Portainer exist, but they are heavy web apps that require exposing extra ports, configuring web servers, and opening remote ports. CLI tools like LazyDocker are great, but they are mostly passive viewers—they display tables, but don’t tell you:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;"I detected 6 issues on this host: here are the 3 you must fix right now, why they happened, and how to fix them in one click."&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is why I created &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/dockeretior" rel="noopener noreferrer"&gt;Dockeretior&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚓ What is Dockeretior?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dockeretior&lt;/strong&gt; is an interactive, zero-overhead Terminal UI (TUI) and latent pseudo-terminal (PTY) supervisor written in Go. &lt;/p&gt;

&lt;p&gt;It runs directly in your terminal over SSH or local bash, featuring:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Split-Screen Dashboard:&lt;/strong&gt; A live container list on the left alongside 4 real-time ASCII metric gauges on the right (CPU load &amp;amp; sparkline trends, RAM vs host cgroups, Network RX/TX throughput, Block I/O, PIDs, and uptime).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🩺 AutoDoctor (Intelligent Root-Cause Diagnostics):&lt;/strong&gt; A health diagnostic engine that correlates Exit Codes, OOM Killer cgroups, binary entrypoint failures (126/127), restart loops, and security exposures into a &lt;strong&gt;Server Health Score (0 - 100)&lt;/strong&gt; and a prioritized &lt;strong&gt;Top 3 Remediation Plan&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🐙 Visual Docker Compose Topology:&lt;/strong&gt; Automatically parses multi-service Compose files and draws an ASCII dependency tree mapping services, &lt;code&gt;depends_on&lt;/code&gt; directed graphs, volumes, and networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;💡 1-Click Storage Reclaim:&lt;/strong&gt; Identifies dangling images, orphaned volumes, and build cache (often 30+ GB of hidden reclaimable disk), letting you free it with a single keystroke (c).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🚨 Alert Dispatcher &amp;amp; Drift Tracking:&lt;/strong&gt; Sends structured alerts to &lt;strong&gt;Slack&lt;/strong&gt;, &lt;strong&gt;Discord&lt;/strong&gt;, or &lt;strong&gt;Telegram&lt;/strong&gt;, and tracks historical memory and disk creep across snapshots.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚡ Latent PTY Supervisor (Hot-Toggle):&lt;/strong&gt; Can run completely invisible in the background of your SSH shell, toggled into view in milliseconds using &lt;code&gt;Ctrl + \&lt;/code&gt; or &lt;code&gt;Cmd + Option + Space&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🩺 The Heart of Dockeretior: AutoDoctor
&lt;/h2&gt;

&lt;p&gt;Instead of drowning the user in data, Dockeretior prioritizes actionable intelligence.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;./bin/dockeretior --doctor&lt;/code&gt; or press a inside the TUI, AutoDoctor inspects your host in sub-second time and outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;================================================================================
🩺 AUTODOCTOR - SERVER HEALTH REPORT
================================================================================
Health Score : 58/100 🔴 Critical
Containers   : 3 running, 1 stopped (4 total)
Generated    : 2026-10-01 14:17:01
--------------------------------------------------------------------------------
SUBSYSTEMS STATUS:
  🟢 Docker Engine   : Docker v29.8.1, 16 CPUs, 31.3 GB RAM.
  🟢 Containers      : 3 active, 1 stopped.
  🔴 Storage         : 29.88 GB reclaimable in cache and unused images.
  🟡 Security        : 3 security alerts identified.
--------------------------------------------------------------------------------
TOP 3 PRIORITIZED ACTIONS:
  1. [🔴 CRITICAL] Significant Reclaimable Storage in Docker (29.88 GB) (Docker Storage)
     ↳ Root Cause: Accumulation of 14 dangling images, 11 orphaned volumes, and build cache.
     ↳ Solution  : Press 'c' inside AutoDoctor to reclaim disk space immediately.
     ↳ Command   : docker system prune -a --volumes

  2. [🔴 CRITICAL] Container 'buildkit_builder' running in privileged mode (--privileged)
     ↳ Root Cause: Privileged mode enabled, bypassing standard Docker container isolation.
     ↳ Solution  : Remove 'privileged: true' and grant only required Linux capabilities ('cap_add').

  3. [🟡 WARNING] PostgreSQL port exposed on 0.0.0.0 (5432:5432) on 'app-postgres'
     ↳ Root Cause: Public interface binding allows external connections from any IP.
     ↳ Solution  : Bind to '127.0.0.1:5432:5432' or rely on internal Docker bridge networks.
--------------------------------------------------------------------------------
💡 RECLAIMABLE DISK: 29.88 GB accumulated in unused images and build cache.
   To free space: launch dockeretior (press 'a' then 'c') or run docker system prune -a --volumes.
================================================================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Automatic Correlation of Crash Loops
&lt;/h3&gt;

&lt;p&gt;When a container dies or starts restarting, AutoDoctor doesn't just show a red icon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Exit Code 137:&lt;/strong&gt; Correlates whether the kernel invoked the OOM Killer and compares current RAM usage against the container's hard cgroup limit (e.g. &lt;code&gt;508 MB / 512 MB limit&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exit Code 126 / 127:&lt;/strong&gt; Flags missing binaries or entrypoint script permission issues (&lt;code&gt;chmod +x&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crash Loops:&lt;/strong&gt; Tracks restart frequency and isolates the exact stderr cause from the last seconds of the lifecycle.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🐙 Visual Docker Compose Dependency Tree
&lt;/h2&gt;

&lt;p&gt;Have you ever opened a directory with a 400-line &lt;code&gt;docker-compose.yml&lt;/code&gt; and wished you could just &lt;em&gt;see&lt;/em&gt; the topology?&lt;/p&gt;

&lt;p&gt;Pressing c in Dockeretior (or running &lt;code&gt;dockeretior --compose&lt;/code&gt;) scans local Compose files, analyzes the Directed Acyclic Graph (DAG) of &lt;code&gt;depends_on&lt;/code&gt;, and renders an ASCII architectural diagram:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; 📦 STACK: docker-compose.yml (4 services, 2 networks, 1 volume)

 ── Level 1: Ingress / Frontend / Entrypoint ──
  ┌──────────────────────────────┐  ┌──────────────────────────────┐
  │ 🚀 api                       │  │ 🌐 traefik                  │
  │ img: mycompany/api:v1.0      │  │ img: traefik:v2.10          │
  │ ports: 8080:8080             │  │ ports: 80:80,443:443        │
  └──────────────────────────────┘  └──────────────────────────────┘
            │
            ▼ (depends_on)
 ── Level 3: Databases / Cache / Storage ──
  ┌──────────────────────────────┐  ┌──────────────────────────────┐
  │ 🗄️  postgres                │  │ ⚡ redis                     │
  │ img: postgres:16-alpine      │  │ img: redis:7-alpine         │
  │ vols: 1 mounted              │  │ net: internal               │
  └──────────────────────────────┘  └──────────────────────────────┘

 ── Dependency &amp;amp; Link Matrix ────────────────────────
  • api              ──depends_on──▶ [postgres, redis]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🤖 #BuiltWithAntigravity: How It Came to Life
&lt;/h2&gt;

&lt;p&gt;Building high-performance terminal software in Go is notoriously tricky:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You have to handle &lt;strong&gt;strict ANSI escape sequences&lt;/strong&gt; and raw terminal modes (&lt;code&gt;MakeRaw&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Terminal resize events (&lt;code&gt;SIGWINCH&lt;/code&gt;) must be handled without tearing or buffer scrollbars.&lt;/li&gt;
&lt;li&gt;Go's build system has strict OS rules (e.g., naming a file &lt;code&gt;*_windows.go&lt;/code&gt; excludes it from Linux/macOS builds).&lt;/li&gt;
&lt;li&gt;Concurrency between Docker event streams, PTY forwarders, and UI event loops must be rock-solid.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This entire project was engineered pair-programming with &lt;strong&gt;Google Antigravity&lt;/strong&gt; using the &lt;strong&gt;#builtwithantigravity&lt;/strong&gt; agentic workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  What Google Antigravity enabled:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mathematical Layout Budgeting:&lt;/strong&gt; We ensured that every line rendered in the split-screen view calculates exact cell widths with &lt;code&gt;go-runewidth&lt;/code&gt;, guaranteeing &lt;strong&gt;zero terminal line-wrapping or viewport scroll jumps&lt;/strong&gt; across any window size (from compact 80x24 laptops to 4K ultrawide monitors).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Docker SDK Integration:&lt;/strong&gt; Implementing custom socket discovery (standard Unix socket, Docker Desktop macOS, Colima, OrbStack, and Linux rootless sockets).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;From Idea to Published Release:&lt;/strong&gt; In just a single continuous session, Antigravity helped:

&lt;ul&gt;
&lt;li&gt;Structure the comprehensive 11-phase architecture roadmap.&lt;/li&gt;
&lt;li&gt;Implement the root-cause analysis rules engine.&lt;/li&gt;
&lt;li&gt;Build the Compose DAG parser and ASCII box drawer.&lt;/li&gt;
&lt;li&gt;Write comprehensive unit tests for every package (&lt;code&gt;go test -v ./...&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Package CLI commands (&lt;code&gt;--doctor&lt;/code&gt;, &lt;code&gt;--compose&lt;/code&gt;, &lt;code&gt;--test-alert&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Tag and publish release versions (&lt;code&gt;v1.1.0&lt;/code&gt; through &lt;code&gt;v1.3.0&lt;/code&gt;) directly to GitHub.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pairing with an AI agent that understands deep systems-level programming, TTY intricacies, and Unix semantics was a game-changer for shipping this tool so quickly and robustly.&lt;/p&gt;




&lt;h2&gt;
  
  
  🚀 Quickstart: Try It in 30 Seconds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Option 1: Build from Source (Go 1.22+)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Clone the repository&lt;/span&gt;
git clone https://github.com/mario-ezquerro/dockeretior.git
&lt;span class="nb"&gt;cd &lt;/span&gt;dockeretior

&lt;span class="c"&gt;# 2. Build the binary&lt;/span&gt;
make build

&lt;span class="c"&gt;# 3. Test instant diagnostics&lt;/span&gt;
./bin/dockeretior &lt;span class="nt"&gt;--doctor&lt;/span&gt;

&lt;span class="c"&gt;# 4. Launch the full interactive TUI&lt;/span&gt;
./bin/dockeretior
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Option 2: Install via &lt;code&gt;go install&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/mario-ezquerro/dockeretior/cmd/dockeretior@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  ⌨️ Essential Keyboard Shortcuts
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shortcut&lt;/th&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
F1 / ?
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Help Modal:&lt;/strong&gt; Instant list of all keys and shortcuts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F2 / f
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Filter:&lt;/strong&gt; Toggle between &lt;em&gt;Running only&lt;/em&gt; and &lt;em&gt;All containers&lt;/em&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F3 / l
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Live Logs:&lt;/strong&gt; Real-time container log streaming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F4 / e
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Exec Shell:&lt;/strong&gt; Drop into an interactive container shell (&lt;code&gt;bash&lt;/code&gt;/&lt;code&gt;sh&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F5 / r
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Restart:&lt;/strong&gt; Restart the selected container&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F6 / s
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Stop / Start:&lt;/strong&gt; Gracefully toggle container power state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F7 / p
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Pause / Unpause:&lt;/strong&gt; Freeze or unfreeze container processes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F8 / x
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Delete:&lt;/strong&gt; Delete container (with confirmation dialog or &lt;code&gt;f&lt;/code&gt; to force)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F9 / i
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Inspect:&lt;/strong&gt; View formatted container JSON configuration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
F10 / q
&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Quit:&lt;/strong&gt; Cleanly exit and restore terminal state&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;a&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;AutoDoctor:&lt;/strong&gt; Open server health score &amp;amp; root-cause report&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;c&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Compose / Prune:&lt;/strong&gt; Open Compose topology or assisted 1-click disk cleanup&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;t&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Topology Toggle:&lt;/strong&gt; Switch between visual DAG tree and directory explorer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  💡 What's Coming Next?
&lt;/h2&gt;

&lt;p&gt;The roadmap for Dockeretior includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ephemeral Test-Restore Backups:&lt;/strong&gt; Automated database dumps (PostgreSQL, MySQL) tested in ephemeral scratch containers to verify that your backup can &lt;em&gt;actually&lt;/em&gt; be restored before disaster strikes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explain My Server:&lt;/strong&gt; Natural language host inspection based on real diagnostic data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker Fleet Manager:&lt;/strong&gt; Managing multiple remote Docker hosts from a single central terminal.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out the code, star the project, and give it a spin:&lt;/p&gt;

&lt;p&gt;⭐ &lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/mario-ezquerro/dockeretior" rel="noopener noreferrer"&gt;https://github.com/mario-ezquerro/dockeretior&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;What's the most frustrating Docker issue you run into when administering remote servers? Let me know in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>go</category>
      <category>builtwithantigravity</category>
    </item>
    <item>
      <title>Building File4Base: The Modern, Open-Source Alternative to old file bases (Powered by Antigravity)</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Thu, 24 Sep 2026 22:07:55 +0000</pubDate>
      <link>https://dev.to/gde/building-file4base-the-modern-open-source-alternative-to-file4base-powered-by-antigravity-47g7</link>
      <guid>https://dev.to/gde/building-file4base-the-modern-open-source-alternative-to-file4base-powered-by-antigravity-47g7</guid>
      <description>&lt;p&gt;For decades, platforms like Claris FileMaker, Microsoft Access, and 4D enabled businesses to build tailored database applications rapidly without needing dedicated enterprise engineering teams.&lt;/p&gt;

&lt;p&gt;However, the legacy RAD (Rapid Application Development) ecosystem comes with well-known bottlenecks: proprietary runtimes, opaque file formats, steep licensing costs, and vendor lock-in.&lt;/p&gt;

&lt;p&gt;Today, I’m excited to share &lt;strong&gt;&lt;a href="https://github.com/file4base/file4base-app" rel="noopener noreferrer"&gt;File4Base&lt;/a&gt;&lt;/strong&gt;: an open-source, modern alternative designed to bring back the speed and visual intuition of FileMaker, powered by clean architecture, open databases, and native cross-platform performance.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 The Vision: What is File4Base?
&lt;/h2&gt;

&lt;p&gt;File4Base aims to bridge the gap between relational databases and business users by providing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;A Visual Canvas Layout Engine&lt;/strong&gt;: Design forms, lists, reports, and search queries dynamically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;First-Class Relational Schemas&lt;/strong&gt;: Real PostgreSQL tables and columns under the hood—no black-box database engines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Scripting Workspace&lt;/strong&gt;: Step-based automation (similar to FileMaker’s Script Workspace), serialized in structured JSON and executed deterministically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-Hostable &amp;amp; Zero Lock-in&lt;/strong&gt;: Fully dockerized backend with standard SQL data access.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🏗️ The Modern Stack
&lt;/h2&gt;

&lt;p&gt;Instead of building a monolith, File4Base separates the presentation layer from the database engine using modern industry standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client (Desktop &amp;amp; Tablet)&lt;/strong&gt;: &lt;strong&gt;Flutter&lt;/strong&gt; (macOS, Windows, Linux). Native rendering, fast UI redraws, and cross-platform consistency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend Core&lt;/strong&gt;: &lt;strong&gt;Go (Golang)&lt;/strong&gt;. A lightweight, memory-efficient service managing metadata catalogs, generic dynamic CRUD operations, and permission enforcement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database&lt;/strong&gt;: &lt;strong&gt;PostgreSQL 16&lt;/strong&gt;. Rock-solid reliability with JSONB metadata support, native migrations, and real-time triggers via &lt;code&gt;LISTEN/NOTIFY&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Single command via &lt;code&gt;docker compose up -d&lt;/code&gt; for the server infrastructure.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────────────────────────────────────┐
│        Flutter Desktop Client (Native)       │
│  [Layout Designer]  [Browse]  [Scripts]      │
└──────────────────────┬───────────────────────┘
                       │ REST / WebSockets
┌──────────────────────▼───────────────────────┐
│              Go Backend Engine               │
│   (Schema Manager, CEL Evaluator, Auth)      │
└──────────────────────┬───────────────────────┘
                       │ pgx / SQL
┌──────────────────────▼───────────────────────┐
│                PostgreSQL 16                 │
│      (Dynamic Schemas + System Catalogs)     │
└──────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  🤖 Built with Google Antigravity: Spec-Driven Development
&lt;/h2&gt;

&lt;p&gt;A unique aspect of how File4Base is coming to life is the engineering workflow. We are orchestrating development through &lt;strong&gt;Google Antigravity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Instead of writing repetitive boilerplate manually:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We write rigorous architectural blueprints, JSON schemas, and roadmap documents (&lt;code&gt;.antigravity/rules.md&lt;/code&gt;, &lt;code&gt;docs/specs/*&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Antigravity takes these specifications and iteratively develops tested modules in Go and Flutter.&lt;/li&gt;
&lt;li&gt;The codebase stays decoupled, clean, and strictly aligned with documented architectural standards.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 What's in Progress?
&lt;/h2&gt;

&lt;p&gt;We've already mapped out the foundational layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[x] Monorepo architecture &amp;amp; Dockerized development environment.&lt;/li&gt;
&lt;li&gt;[x] Complete FileMaker Menu &amp;amp; Feature functional reference guide.&lt;/li&gt;
&lt;li&gt;[x] Script Workspace UI specification and mockups (3-panel workflow).&lt;/li&gt;
&lt;li&gt;[ ] Backend metadata catalog (&lt;code&gt;sys_tables&lt;/code&gt;, &lt;code&gt;sys_columns&lt;/code&gt;, &lt;code&gt;sys_layouts&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;[ ] Dynamic JSON layout renderer in Flutter.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🤝 Join the Project!
&lt;/h2&gt;

&lt;p&gt;File4Base is 100% open-source, and we are building it in public from day one.&lt;/p&gt;

&lt;p&gt;If you have experience with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Flutter / Dart&lt;/strong&gt; (Desktop layouts, state management, drag-and-drop engines)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go / Golang&lt;/strong&gt; (Dynamic SQL builders, AST parsers, real-time WebSockets)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FileMaker / Low-Code architecture&lt;/strong&gt; (Feature parity, ergonomic UX workflows)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We would love your feedback, stars, and contributions!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/file4base/file4base-app" rel="noopener noreferrer"&gt;https://github.com/file4base/file4base-app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let us know in the comments: what is the single most critical feature you miss from classic desktop database builders?&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>flutter</category>
      <category>go</category>
      <category>postgres</category>
    </item>
    <item>
      <title>The Only Container Orchestrator with Built-In Compliance: How Gubernator Enforces ENS, NIS 2, DORA, CIS Benchmark, and ISO 27001</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Thu, 17 Sep 2026 09:57:31 +0000</pubDate>
      <link>https://dev.to/gde/the-only-container-orchestrator-with-built-in-compliance-how-gubernator-enforces-ens-nis-2-cis-mbf</link>
      <guid>https://dev.to/gde/the-only-container-orchestrator-with-built-in-compliance-how-gubernator-enforces-ens-nis-2-cis-mbf</guid>
      <description>&lt;h1&gt;
  
  
  🛡️ The Only Container Orchestrator with Built-In Compliance: How Gubernator Enforces ENS, NIS 2, DORA, CIS Benchmark, and ISO 27001
&lt;/h1&gt;

&lt;p&gt;Over the past decade, container orchestration has been polarized into two stark extremes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes (K8s) Overengineering:&lt;/strong&gt; An extraordinarily capable blank canvas, yet born &lt;strong&gt;naked of security and regulatory compliance&lt;/strong&gt;. To bring a Kubernetes cluster into compliance with standards like Spain's &lt;em&gt;Esquema Nacional de Seguridad&lt;/em&gt; (ENS) or the European &lt;em&gt;NIS 2 Directive&lt;/em&gt;, SecOps teams must assemble, configure, and maintain an intricate tapestry of 15+ third-party tools and operators: &lt;em&gt;Trivy, Falco, Kyverno or OPA Gatekeeper, Cosign, cert-manager, Keycloak, Fluentbit, Prometheus, Grafana, OpenTelemetry...&lt;/em&gt; The consequence is astronomical technical debt, operational fragility, and a voracious appetite for RAM and CPU just to run the control plane.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Bare Minimalism of Docker Swarm and HashiCorp Nomad:&lt;/strong&gt; Lightweight and elegant solutions for running containers, yet &lt;strong&gt;entirely devoid of forensic audit trails, admission control, cryptographic image signing, and regulatory compliance engines&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What happens when a public administration, healthcare provider, critical infrastructure operator, or financial institution needs to deploy containerized workloads meeting the strictest cybersecurity regulations without drowning in operational complexity and exorbitant infrastructure costs?&lt;/p&gt;

&lt;p&gt;The answer is &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;Gubernator (&lt;code&gt;gbnt&lt;/code&gt;)&lt;/a&gt;&lt;/strong&gt;: the &lt;strong&gt;first and only container orchestrator designed from the ground up with native enterprise cybersecurity and regulatory compliance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this deep dive, we explore Gubernator’s built-in security architecture, the international compliance frameworks it continuously audits in real time, its degradation-detecting watchdog, and why it represents a paradigm shift in technological sovereignty.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8qey53nzjxg7hvwy26b3.jpg" 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%2F8qey53nzjxg7hvwy26b3.jpg" alt="Gubernator Security &amp;amp; Compliance Suite" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  🏛️ The Core Philosophy: "Secure &amp;amp; Compliant by Design"
&lt;/h2&gt;

&lt;p&gt;Unlike orchestrators where security is an afterthought retrofitted via third-party plugins, in &lt;strong&gt;Gubernator&lt;/strong&gt;, every Centurion (worker node) and Legion (Docker Compose stack) is governed by an unyielding security framework from the moment it boots:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
 │                           GUBERNATOR ENTERPRISE SECURITY &amp;amp; COMPLIANCE ENGINE                           │
 ├────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │  🇪🇸 ENS RD 311/2022  │  🇪🇺 NIS 2 Directive  │  🏛️ DORA Reg. 2022   │  🔒 CIS Benchmark  │  🌐 ISO 27001:2022 │
 ├──────────────────────┼──────────────────────┼──────────────────────┼────────────────────┼────────────────────┤
 │  • op.acc.2 / op.mon │  • Art. 21 Risks     │  • 5 DORA Pillars    │  • Daemon &amp;amp; Host   │  • A.5 Controls    │
 │  • Basic/Medium/High │  • SIEM Syslog Live  │  • ICT Resilience    │  • Kernel Seccomp  │  • A.8 Controls    │
 │  • CCN Evidence      │  • Cyber Hygiene     │  • Third-Party Risk  │  • AppArmor/Caps   │  • Formal SoA Rep. │
 ├──────────────────────┴──────────────────────┴──────────────────────┴────────────────────┴────────────────────┤
 │                    🔄 CONTINUOUS COMPLIANCE WATCHDOG DAEMON (15m Interval)                             │
 │            - Instant reactive re-evaluation upon any security configuration mutation                   │
 │            - Automatic degradation detection (&amp;gt;1.0% drop) -&amp;gt; COMPLIANCE_DEGRADED event                 │
 │            - Native Prometheus gauges: gbnt_compliance_score{framework="..."}                          │
 ├────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │                          🔐 IDENTITY, ACCESS &amp;amp; FORENSIC AUDITING                                       │
 │  • Active Directory / OpenLDAP (LDAPS:636)    • SSO / OIDC (Google, Okta, Keycloak)                   │
 │  • Granular RBAC (Admin, Operator, Auditor)   • MFA/TOTP with Offline Time Beacon                      │
 │  • Cryptographic SHA-256 Tamper-Evident Hash Chain Audit Ledger                                        │
 ├────────────────────────────────────────────────────────────────────────────────────────────────────────┤
 │                    📦 SOFTWARE SUPPLY CHAIN SECURITY &amp;amp; ADMISSION                                       │
 │  • CVE Vulnerability Scanner with CVSS v3     • CycloneDX &amp;amp; SPDX JSON SBOMs                            │
 │  • In-Cluster Cosign ECDSA P-256 Signing      • Gatekeeper Admission Controller                        │
 └────────────────────────────────────────────────────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything runs natively from a &lt;strong&gt;single self-contained Go binary&lt;/strong&gt; with zero heavy external dependencies, managed through a modern, responsive &lt;strong&gt;Flutter Web Dashboard&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 1. Esquema Nacional de Seguridad (ENS - Royal Decree 311/2022)
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Esquema Nacional de Seguridad (ENS)&lt;/strong&gt; regulates the security conditions that Spanish Public Administrations and their technology partners must fulfill to safeguard information systems and services.&lt;/p&gt;

&lt;p&gt;Gubernator natively assesses the operational controls specified by Spain's &lt;strong&gt;CCN-STIC&lt;/strong&gt; standards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;op.acc.2&lt;/code&gt; (Access Control &amp;amp; Credential Hardening):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Configurable minimum password length validation (default 12+ characters).&lt;/li&gt;
&lt;li&gt;Enforced complexity (uppercase, lowercase, digits, and special characters).&lt;/li&gt;
&lt;li&gt;Automatic account lockout after repeated failed login attempts.&lt;/li&gt;
&lt;li&gt;Idle session expiration and timeout enforcement.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;op.acc.6&lt;/code&gt; (Strengthened Authentication):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Mandatory Multi-Factor Authentication (MFA/TOTP RFC 6238) for administrative and operational roles.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;op.mon.1&lt;/code&gt; (System Monitoring &amp;amp; Logging):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Cryptographically signed audit trails and live security event streaming to enterprise SIEM platforms.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;op.exp.8&lt;/code&gt; (Integrity Protection &amp;amp; Cryptographic Chains):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Mathematical integrity verification across the action history via cryptographic hash chains.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Gubernator automatically evaluates compliance across the three official ENS tiers (&lt;strong&gt;Basic, Medium, and High&lt;/strong&gt;) and produces a ready-to-present CCN evidence dossier in a single click.&lt;/p&gt;




&lt;h2&gt;
  
  
  🇪🇺 2. European NIS 2 Directive (EU Directive 2022/2555)
&lt;/h2&gt;

&lt;p&gt;The European Union's &lt;strong&gt;NIS 2 Directive&lt;/strong&gt; establishes a harmonized cybersecurity baseline across essential and important entities, introducing strict penalties for non-compliance with risk management and incident reporting obligations.&lt;/p&gt;

&lt;p&gt;Gubernator directly addresses the requirements of &lt;strong&gt;Article 21 (Cybersecurity risk-management measures)&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Risk Analysis &amp;amp; Information System Security Policies:&lt;/strong&gt; Continuous monitoring of image admission modes and cluster security settings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident Handling &amp;amp; Real-Time SIEM Streaming:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Native RFC 5424 and RFC 3164 Syslog forwarder dispatching security events directly to Splunk, Elastic, Microsoft Sentinel, Wazuh, or QRadar.&lt;/li&gt;
&lt;li&gt;Automatic dispatch on policy violations, brute-force lockouts, and compliance degradation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Business Continuity &amp;amp; Consistent Backups:&lt;/strong&gt; Integrated with Gubernator's &lt;em&gt;The Granaries&lt;/em&gt; subsystem, allowing operators to freeze containers (&lt;code&gt;docker pause&lt;/code&gt;), create encrypted &lt;code&gt;.tar.gz&lt;/code&gt; snapshots verified with SHA-256 digests, and manage automated retention schedules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supply Chain Security:&lt;/strong&gt; Image validation prior to task scheduling to thwart dependency injection attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cryptography &amp;amp; Encryption:&lt;/strong&gt; Enforced mTLS and X.509 certificate lifecycle management on the Ingress proxy with automated certificate renewal.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The dashboard presents dedicated compliance gauges for both &lt;strong&gt;Essential Entities (EE)&lt;/strong&gt; and &lt;strong&gt;Important Entities (IE)&lt;/strong&gt; with live breakdowns of all 10 Article 21 requirements.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔒 3. CIS Docker Benchmark v1.6.0
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Center for Internet Security (CIS)&lt;/strong&gt; maintains the industry benchmark for hardening Docker hosts and container runtimes.&lt;/p&gt;

&lt;p&gt;Gubernator embeds an &lt;strong&gt;automated CIS evaluation engine&lt;/strong&gt; spanning all 6 core benchmark domains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Section 1 (Host Configuration):&lt;/strong&gt; Dedicated partition verification for &lt;code&gt;/var/lib/docker&lt;/code&gt;, &lt;code&gt;auditd&lt;/code&gt; system call tracking, and daemon isolation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Section 2 (Docker Daemon Configuration):&lt;/strong&gt; Inter-container communication restrictions on the default bridge (&lt;code&gt;icc=false&lt;/code&gt;), user namespace remapping (&lt;code&gt;userns-remap&lt;/code&gt;), log rotation policies (&lt;code&gt;max-size&lt;/code&gt;, &lt;code&gt;max-file&lt;/code&gt;), and deprecation of legacy registry support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Section 3 (File Permissions and Ownership):&lt;/strong&gt; Strict permissions verification (&lt;code&gt;0644&lt;/code&gt;, &lt;code&gt;0600&lt;/code&gt;) and &lt;code&gt;root:root&lt;/code&gt; ownership on &lt;code&gt;/etc/docker/daemon.json&lt;/code&gt;, sockets, and TLS keys.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Section 4 (Images and Build Files):&lt;/strong&gt; Verification of non-root &lt;code&gt;USER&lt;/code&gt; execution, detection of embedded credentials, and prevention of compiler binaries inside runtime containers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Section 5 (Runtime Security):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Enforcement of default &lt;strong&gt;AppArmor&lt;/strong&gt; profiles and &lt;strong&gt;Seccomp&lt;/strong&gt; filters.&lt;/li&gt;
&lt;li&gt;Linux capability minimization (&lt;code&gt;--cap-drop=ALL&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Read-only root filesystems (&lt;code&gt;read_only: true&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Prevention of privilege escalation (&lt;code&gt;no-new-privileges: true&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Section 6 (Security Operations):&lt;/strong&gt; Housekeeping for orphaned volumes, zombie containers, and deprecated runtime parameters.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each CIS check outputs its status (&lt;code&gt;PASS&lt;/code&gt;, &lt;code&gt;WARN&lt;/code&gt;, &lt;code&gt;FAIL&lt;/code&gt;, &lt;code&gt;INFO&lt;/code&gt;), alongside raw technical evidence and step-by-step remediation advice.&lt;/p&gt;




&lt;h2&gt;
  
  
  🌐 4. ISO/IEC 27001:2022 (Annex A)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;ISO/IEC 27001&lt;/strong&gt; is the global benchmark for Information Security Management Systems (ISMS).&lt;/p&gt;

&lt;p&gt;Gubernator evaluates the updated &lt;strong&gt;Annex A controls (2022 revision)&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Theme A.5 (Organizational Controls):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A.5.15 / A.5.18:&lt;/strong&gt; Role-based access control and segregation of privileged rights.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A.5.24 - A.5.28:&lt;/strong&gt; Incident management workflow and forensic evidence collection.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Theme A.8 (Technological Controls):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A.8.2:&lt;/strong&gt; Privileged access rights monitored and managed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A.8.8:&lt;/strong&gt; Technical vulnerability remediation across production stacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A.8.9:&lt;/strong&gt; Configuration management and cluster hardening.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A.8.15:&lt;/strong&gt; Tamper-resistant logging and event recording.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A.8.28:&lt;/strong&gt; Secure coding and declarative configuration validation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From the web console, teams can export a formal &lt;strong&gt;Statement of Applicability (SoA)&lt;/strong&gt; with real-time audit statuses ready for external certification audits.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏛️ 5. EU DORA (Regulation (EU) 2022/2554 on Digital Operational Resilience)
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Digital Operational Resilience Act (DORA)&lt;/strong&gt; is the landmark European Union regulation mandating financial entities—including banks, investment firms, insurance companies—and their &lt;strong&gt;critical cloud ICT third-party service providers&lt;/strong&gt; to establish a comprehensive digital operational resilience posture against severe cyber incidents and disruptions.&lt;/p&gt;

&lt;p&gt;Gubernator natively assesses the &lt;strong&gt;5 statutory pillars&lt;/strong&gt; of DORA:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pillar 1: ICT Risk Management Framework (Articles 5 to 16):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Identification of critical and essential functions with dependency mapping across containerized microservices.&lt;/li&gt;
&lt;li&gt;Microservice network segmentation, perimeter firewalling, and traffic isolation.&lt;/li&gt;
&lt;li&gt;Encryption of credentials, secrets, and volume backups using robust cryptographic algorithms.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pillar 2: ICT-Related Incident Management, Classification &amp;amp; Reporting (Articles 17 to 23):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Real-time detection of operational incidents with automated forwarding to enterprise SIEMs via Syslog RFC 5424.&lt;/li&gt;
&lt;li&gt;Tamper-evident SHA-256 cryptographic audit ledger maintaining forensic chain-of-custody for regulatory scrutiny.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pillar 3: Digital Operational Resilience Testing &amp;amp; Failover (Articles 24 to 27):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Backup restoration verification and consistency probing on persistent container data volumes.&lt;/li&gt;
&lt;li&gt;Continuous container health checking and automated rolling restarts to mitigate transient faults.&lt;/li&gt;
&lt;li&gt;Periodic multi-node failover testing across Centurion hosts to guarantee minimal RTO and RPO.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pillar 4: Managing ICT Third-Party Risk &amp;amp; Cloud Exit Strategy (Articles 28 to 44):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Deep software supply chain verification with automated CVE vulnerability scanning and CycloneDX/SPDX SBOM generation.&lt;/li&gt;
&lt;li&gt;Pre-deployment signature verification requiring Cosign ECDSA signatures before container execution.&lt;/li&gt;
&lt;li&gt;Cloud exit strategy and vendor lock-in prevention via shared root storage mobility (&lt;code&gt;/var/contenedores&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pillar 5: Information-Sharing Arrangements &amp;amp; Supervisory Oversight (Articles 45 to 56):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Instant export of technical resilience audit reports in Markdown and structured JSON ready for competent financial authorities and CSIRTs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Via the CLI (&lt;code&gt;gbnt dora&lt;/code&gt; and &lt;code&gt;gbnt dora --report&lt;/code&gt;) or the web dashboard, compliance officers and SRE teams can inspect measure details and trigger remediation fixes in a single click.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔄 6. Continuous Compliance Watchdog: Zero Blind Spots
&lt;/h2&gt;

&lt;p&gt;Traditional compliance auditing relies on periodic, point-in-time reviews: an external auditor visits today, and until the next quarter, nobody knows whether security configurations have quietly drifted out of compliance.&lt;/p&gt;

&lt;p&gt;In Gubernator, compliance is an &lt;strong&gt;active, continuous process&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; [ Security Configuration Mutation ] ──▶ Reactive Out-of-Band Trigger
 (e.g., MFA disabled,                    │
  password policy relaxed,               ▼
  SIEM endpoint altered)      ┌─────────────────────────┐
                              │   Compliance Watchdog   │◀── Background Cron (15m)
                              └────────────┬────────────┘
                                           │
                             Did score drop &amp;gt; 1.0%?
                              ├── YES ──▶ 🚨 Audit Log: COMPLIANCE_DEGRADED (WARNING)
                              └── NO  ──▶ ℹ️ Audit Log: COMPLIANCE_RESTORED (SUCCESS)
                                           │
                                           ▼
                              📊 Prometheus: gbnt_compliance_score
                              🖥️ Web UI: Executive Matrix Synchronized
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happens if an admin relaxes security settings?
&lt;/h3&gt;

&lt;p&gt;If an operator disables MFA for a user or lowers the cluster password complexity threshold:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Instant Reactive Re-evaluation:&lt;/strong&gt; Rather than waiting for the 15-minute background interval, the API immediately fires &lt;code&gt;go security.TriggerComplianceAudit(...)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cryptographic Drift &amp;amp; Degradation Alert:&lt;/strong&gt; The engine compares the previous score with the new evaluation. If it detects a drop greater than 1.0%, it registers a forensic warning:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"event"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COMPLIANCE_DEGRADED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"severity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"WARNING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
     &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Compliance score degraded in Spanish ENS (RD 311/2022): dropped from 96.9% to 88.5% (trigger: MFA_DISABLED)"&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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prometheus Metrics (&lt;code&gt;:4002/metrics&lt;/code&gt;):&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   # HELP gbnt_compliance_score Current compliance score (0.0 to 100.0) evaluated by the continuous compliance audit engine.
   # TYPE gbnt_compliance_score gauge
   gbnt_compliance_score{framework="cis_docker"} 75.0
   gbnt_compliance_score{framework="dora"} 93.8
   gbnt_compliance_score{framework="ens"} 88.5
   gbnt_compliance_score{framework="iso27001"} 97.9
   gbnt_compliance_score{framework="nis2"} 91.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Live Dashboard Executive Matrix:&lt;/strong&gt; The top header badge confirms &lt;code&gt;● WATCHDOG ACTIVE&lt;/code&gt; alongside the &lt;strong&gt;&lt;code&gt;[ 🛡️ Re-evaluate All Compliance ]&lt;/code&gt;&lt;/strong&gt; master button to trigger an on-demand audit cycle in one click.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔐 7. Tamper-Evident Forensic Audit Trail (SHA-256 Hash Chain)
&lt;/h2&gt;

&lt;p&gt;Advanced attackers who breach a system frequently attempt to wipe or modify audit logs to cover their tracks.&lt;/p&gt;

&lt;p&gt;To prevent log tampering, Gubernator implements an &lt;strong&gt;immutable forensic ledger&lt;/strong&gt;:&lt;br&gt;
Every log entry stored in SQLite contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;PreviousHash&lt;/code&gt;: The SHA-256 hash of the immediately preceding event.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EventHash&lt;/code&gt;: The cryptographic checksum computed over the event payload:
$$\text{Hash}&lt;em&gt;n = \text{SHA-256}(\text{Hash}&lt;/em&gt;{n-1} \parallel \text{Timestamp} \parallel \text{Actor} \parallel \text{IP} \parallel \text{Category} \parallel \text{Action} \parallel \text{Status} \parallel \text{Details})$$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Clicking &lt;strong&gt;"Verify Forensic Chain"&lt;/strong&gt; traverses the entire audit history, recalculating every cryptographic link. If an unauthorized actor modifies a row directly in the database, the hash chain breaks instantly, flagging the exact corrupted record.&lt;/p&gt;




&lt;h2&gt;
  
  
  📦 8. Supply Chain Security: SBOMs, CVE Scanning, and Cosign
&lt;/h2&gt;

&lt;p&gt;Software cannot be considered secure if you don't know what is running inside your containers.&lt;/p&gt;

&lt;p&gt;Gubernator delivers deep software supply chain inspection out of the box:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Software Bill of Materials (SBOM):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Instant export in standard &lt;strong&gt;CycloneDX JSON&lt;/strong&gt; and &lt;strong&gt;SPDX JSON&lt;/strong&gt; formats.&lt;/li&gt;
&lt;li&gt;Comprehensive inventory of OS packages, runtime language dependencies (Go, Python, Node.js, Rust, Java), and license compliance (GPL, Apache, MIT).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CVE Vulnerability Scanning:&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Image analysis against official vulnerability feeds with &lt;strong&gt;CVSS v3&lt;/strong&gt; severity scoring and automated patch recommendations.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cryptographic Signing via Cosign (Sigstore):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;In-cluster generation of &lt;strong&gt;ECDSA P-256&lt;/strong&gt; keypairs without external tooling.&lt;/li&gt;
&lt;li&gt;Cryptographic signing and digest verification directly integrated into deployment pipelines.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Gatekeeper (Admission Controller):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Declarative pre-deployment admission policies that &lt;strong&gt;block unsigned images&lt;/strong&gt; or containers containing unpatched critical vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🔑 9. Enterprise Identity, RBAC, and Resilient MFA (Time Beacon)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise Directory Integration (LDAP/LDAPS):&lt;/strong&gt; Direct connection to Microsoft Active Directory and OpenLDAP over LDAPS (port 636) and StartTLS, mapping external directory groups to Gubernator cluster roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single Sign-On (SSO / OIDC):&lt;/strong&gt; Built-in authentication support for Google Workspace, Keycloak, Okta, Authentik, and Azure AD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role-Based Access Control (RBAC):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;👑 &lt;strong&gt;&lt;code&gt;admin&lt;/code&gt;:&lt;/strong&gt; Full administrative control over cluster nodes, signing keys, TLS certs, and security policies.&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;&lt;code&gt;operator&lt;/code&gt;:&lt;/strong&gt; Stack authoring, service scaling, container restarts, and terminal shell access.&lt;/li&gt;
&lt;li&gt;🔍 &lt;strong&gt;&lt;code&gt;auditor&lt;/code&gt;:&lt;/strong&gt; Forensic audit inspection for ENS, NIS 2, DORA, CIS, and ISO 27001 evidence without mutation privileges.&lt;/li&gt;
&lt;li&gt;👁️ &lt;strong&gt;&lt;code&gt;readonly&lt;/code&gt;:&lt;/strong&gt; Visual monitoring of dashboards and telemetry.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Laptop Clock-Drift Compensation (Time Beacon):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;A notorious issue with virtualized environments (Multipass, VMware, VirtualBox) is that closing a laptop lid suspends the host and causes VM clock desynchronization, immediately breaking TOTP MFA codes (RFC 6238).&lt;/li&gt;
&lt;li&gt;Gubernator features a &lt;strong&gt;Time Beacon&lt;/strong&gt; mechanism: the browser transmits a client-side timestamp reference during login. If clock drift is detected, Gubernator validates the token and &lt;strong&gt;hot-syncs the VM host kernel clock&lt;/strong&gt; on the fly—100% offline without needing internet access.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚔️ Comparison Matrix: Why Gubernator Stands Alone
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Security &amp;amp; Compliance Feature&lt;/th&gt;
&lt;th&gt;Kubernetes (K8s)&lt;/th&gt;
&lt;th&gt;Docker Swarm&lt;/th&gt;
&lt;th&gt;HashiCorp Nomad&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Gubernator (&lt;code&gt;gbnt&lt;/code&gt;)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment Simplicity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ Extreme Complexity&lt;/td&gt;
&lt;td&gt;✅ Very Simple&lt;/td&gt;
&lt;td&gt;⚠️ Moderate&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Dead Simple (1 Binary)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native Compose Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No (Requires Kompose/CRDs)&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No (Custom HCL)&lt;/td&gt;
&lt;td&gt;✅ &lt;strong&gt;Yes (Native)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spanish ENS (RD 311/2022)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No (Requires bespoke audits)&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (Basic/Medium/High)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EU NIS 2 Directive (Art. 21)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No native engine&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (EE &amp;amp; IE)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EU DORA Regulation (5 Pillars)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (Digital Resilience)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automated CIS Docker Benchmark&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ Via plugins (Kube-bench)&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (6 CIS Domains)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ISO/IEC 27001 (Automated SoA)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (Annex A)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Continuous Compliance Watchdog&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (Cron + Triggers)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Compliance Degradation Alerts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native (&amp;gt;1% Drop Alert)&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SIEM Syslog Forwarder (RFC 5424)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ Via heavy logging agents&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native in Core&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Tamper-Evident SHA-256 Ledger&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native Hash Chain&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;In-Cluster Cosign ECDSA Signing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ Via Kyverno/Cosign&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native Key Management&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CycloneDX / SPDX SBOM Generator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;⚠️ Via external scanners&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;Native One-Click Export&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Idle Memory Consumption per Node&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~1.5 GB - 3 GB&lt;/td&gt;
&lt;td&gt;~100 MB&lt;/td&gt;
&lt;td&gt;~150 MB&lt;/td&gt;
&lt;td&gt;🟢 &lt;strong&gt;&amp;lt; 60 MB&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  🚀 Conclusion: Sovereign, Simple, and Certified
&lt;/h2&gt;

&lt;p&gt;Gubernator proves that organizations do not have to accept either the runaway complexity of Kubernetes or the security void of minimalist orchestrators.&lt;/p&gt;

&lt;p&gt;By embedding the world's most rigorous compliance frameworks (&lt;strong&gt;Spanish ENS RD 311/2022, European NIS 2, EU DORA Reg. 2022/2554, CIS Docker Benchmark, and ISO/IEC 27001&lt;/strong&gt;) directly alongside a &lt;strong&gt;continuous compliance watchdog&lt;/strong&gt;, &lt;strong&gt;cryptographic Cosign signing&lt;/strong&gt;, &lt;strong&gt;standardized SBOM generation&lt;/strong&gt;, and a &lt;strong&gt;tamper-evident SHA-256 audit ledger&lt;/strong&gt;, Gubernator stands as the &lt;strong&gt;only container orchestrator on the market&lt;/strong&gt; that delivers radical simplicity and certified cybersecurity right out of the box.&lt;/p&gt;

&lt;p&gt;If you operate in regulated industries, government agencies, financial institutions, healthcare, defense, or simply believe your infrastructure security shouldn't rely on 20 fragile plugins stitched together with duct tape, give Gubernator a run:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;Project Repository:&lt;/strong&gt; &lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;https://github.com/mario-ezquerro/gubernator&lt;/a&gt;&lt;br&gt;&lt;br&gt;
⭐ If you find this project valuable, star the repo and join our journey towards sovereign cloud-native computing!&lt;/p&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Autoscaling Docker Containers Without Kubernetes: How Gubernator Scales CPU &amp; GPU Workloads Automatically</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Fri, 11 Sep 2026 06:58:39 +0000</pubDate>
      <link>https://dev.to/gde/autoscaling-docker-containers-without-kubernetes-how-gubernator-scales-cpu-gpu-workloads-1p0b</link>
      <guid>https://dev.to/gde/autoscaling-docker-containers-without-kubernetes-how-gubernator-scales-cpu-gpu-workloads-1p0b</guid>
      <description>&lt;p&gt;When running containerized workloads, every engineering team eventually faces the &lt;strong&gt;scaling dilemma&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Vanilla Docker / Docker Compose&lt;/strong&gt; is lightweight, fast, and wonderfully simple to maintain—but it has &lt;strong&gt;zero native autoscaling&lt;/strong&gt;. If your API traffic triples during a flash sale or your AI inference queue spikes, you must manually run &lt;code&gt;docker compose up --scale api=5&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes (K8s)&lt;/strong&gt; provides Horizontal Pod Autoscaler (HPA)—but it introduces an overwhelming operational tax: &lt;code&gt;metrics-server&lt;/code&gt;, complex CRDs, etcd clusters, steep learning curves, and hundreds of megabytes of baseline overhead per node.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What if you could keep the pure simplicity of standard &lt;strong&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt; files, but gain &lt;strong&gt;true horizontal autoscaling&lt;/strong&gt; across multi-node clusters based on real-time &lt;strong&gt;CPU and NVIDIA GPU utilization&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;That is exactly why we built &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;Gubernator (&lt;code&gt;gbnt&lt;/code&gt;)&lt;/a&gt;&lt;/strong&gt;—the "Goldilocks" container orchestrator that combines the dead-simple developer experience of Docker Swarm with the flexibility of Nomad and the enterprise governance of high-end platforms.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏛️ The Architecture: How Gubernator Autoscaling Works
&lt;/h2&gt;

&lt;p&gt;In Gubernator, nodes are called &lt;strong&gt;Centurions&lt;/strong&gt; (Managers and Workers), and multi-container applications are deployed as &lt;strong&gt;Legions&lt;/strong&gt; (Docker Compose stacks).&lt;/p&gt;

&lt;p&gt;Under the hood, Gubernator's declarative autoscaling engine operates as an autonomous feedback loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                  ┌────────────────────────────────────────┐
                  │       Prometheus Metrics Collector     │
                  │   (cAdvisor CPU % + NVIDIA DCGM GPU %) │
                  └───────────────────┬────────────────────┘
                                      │ Telemetry Polling (10s)
                                      ▼
                  ┌────────────────────────────────────────┐
                  │    Gubernator Autoscaler Engine Core   │
                  │  - Parses 'gbnt.autoscaling.*' labels  │
                  │  - Evaluates Target vs Current Metric  │
                  │  - Applies Cooldown &amp;amp; Damping Windows  │
                  └───────────────────┬────────────────────┘
                                      │ Desired Replicas (±Δ)
                                      ▼
                  ┌────────────────────────────────────────┐
                  │         Centurion Scheduler            │
                  │   (Spread across nodes / GPU Affinity) │
                  └───────────────────┬────────────────────┘
                                      │ Docker Engine API
                                      ▼
            ┌─────────────────────────────────────────────────────┐
            │  Centurion Host 01          Centurion Host 02 (GPU) │
            │  [api-task-1] [api-task-2]  [api-task-3] [llm-task] │
            └─────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every 10 to 15 seconds, the Gubernator Watchdog invokes &lt;code&gt;autoscaler.EvaluateAndAutoscale()&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Telemetry Ingestion:&lt;/strong&gt; Queries Prometheus / cAdvisor for real-time container CPU percentages and NVIDIA DCGM exporter for GPU compute load.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evaluation:&lt;/strong&gt; Averages utilization across all healthy running task replicas for that service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Threshold Calculation:&lt;/strong&gt;
$$\text{Desired Replicas} = \left\lceil \text{Current Replicas} \times \left( \frac{\text{Current Metric Value}}{\text{Target Threshold}} \right) \right\rceil$$&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Guardrails &amp;amp; Cooldown:&lt;/strong&gt; Clamps desired replicas within &lt;code&gt;[min, max]&lt;/code&gt; boundaries and verifies that the &lt;code&gt;cooldown&lt;/code&gt; window (e.g. 60 seconds) has elapsed since the last scale event, preventing erratic flapping or thrashing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligent Node Placement:&lt;/strong&gt; Uses Gubernator's hardware scheduler (&lt;code&gt;Spread&lt;/code&gt; or &lt;code&gt;Binpack&lt;/code&gt;) to assign new container instances to the least-loaded Centurion host—with automatic hardware affinity targeting nodes with physical NVIDIA GPUs when GPU metrics are configured.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  ⚡ Declarative Autoscaling via Compose Labels
&lt;/h2&gt;

&lt;p&gt;You don't need proprietary manifests or extra YAML definitions. You declare autoscaling policies directly inside your standard &lt;code&gt;docker-compose.yml&lt;/code&gt; service definition using the &lt;code&gt;gbnt.autoscaling.*&lt;/code&gt; label prefix:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. High-Traffic Web Service (CPU-Based Scaling)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mycompany/fastapi-gateway:latest&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Enable horizontal autoscaling&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.enable=true"&lt;/span&gt;
        &lt;span class="c1"&gt;# Scale based on CPU utilization&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.metric=cpu"&lt;/span&gt;
        &lt;span class="c1"&gt;# Target: scale up when average CPU exceeds 70%&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.target=70"&lt;/span&gt;
        &lt;span class="c1"&gt;# Boundary constraints&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.min=2"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.max=10"&lt;/span&gt;
        &lt;span class="c1"&gt;# 60-second cooldown between scale events&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.cooldown=60"&lt;/span&gt;
        &lt;span class="c1"&gt;# Spread tasks across all cluster Centurions&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.scope=cluster"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.strategy=spread"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. AI Inference / LLM Service (NVIDIA GPU-Based Scaling)
&lt;/h3&gt;

&lt;p&gt;For heavy AI and machine learning workloads (e.g., vLLM, Ollama, Hugging Face TGI), CPU load is often misleading because the compute bottleneck lives inside the GPU VRAM and Tensor Cores. &lt;/p&gt;

&lt;p&gt;Gubernator natively tracks &lt;strong&gt;NVIDIA DCGM GPU utilization&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;vllm-inference&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;vllm/vllm-openai:latest&lt;/span&gt;
    &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.enable=true"&lt;/span&gt;
        &lt;span class="c1"&gt;# Target GPU Tensor Core load&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.metric=gpu"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.target=80"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.min=1"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.max=4"&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.cooldown=120"&lt;/span&gt;
        &lt;span class="c1"&gt;# Target only Centurion nodes with GPU hardware&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.autoscaling.scope=cluster"&lt;/span&gt;
      &lt;span class="na"&gt;placement&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;constraints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;node.labels.gbnt.node.gpu&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;==&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;nvidia"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When load drops below the target threshold, Gubernator smoothly de-provisions excess containers in reverse order, ensuring zero data loss and respecting container graceful shutdown timeouts (&lt;code&gt;SIGTERM&lt;/code&gt; followed by grace period).&lt;/p&gt;




&lt;h2&gt;
  
  
  🖥️ Full UI Control: Interactive Flutter Web Dashboard
&lt;/h2&gt;

&lt;p&gt;Not a fan of editing raw YAML on the fly? Gubernator includes a full-screen &lt;strong&gt;Material Design 3 Dashboard&lt;/strong&gt; written in Flutter Web:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Interactive &lt;code&gt;AUTOSCALE&lt;/code&gt; Badges:&lt;/strong&gt; In both the &lt;strong&gt;Legions (Stacks)&lt;/strong&gt; overview and the &lt;strong&gt;Containers (Tasks)&lt;/strong&gt; table, every service displays a live clickable chip:

&lt;ul&gt;
&lt;li&gt;⚡ &lt;strong&gt;&lt;code&gt;GPU • Cluster&lt;/code&gt;&lt;/strong&gt; (Glowing amber/purple)&lt;/li&gt;
&lt;li&gt;⚡ &lt;strong&gt;&lt;code&gt;CPU • Cluster&lt;/code&gt;&lt;/strong&gt; (Electric cyan)&lt;/li&gt;
&lt;li&gt;💤 &lt;strong&gt;&lt;code&gt;Off&lt;/code&gt;&lt;/strong&gt; (Muted grey)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autoscale Control Dialog:&lt;/strong&gt; Clicking any chip opens a visual control modal where operators can:

&lt;ul&gt;
&lt;li&gt;Toggle autoscaling ON/OFF in 1 click&lt;/li&gt;
&lt;li&gt;Switch metrics between CPU and GPU&lt;/li&gt;
&lt;li&gt;Adjust the target percentage slider&lt;/li&gt;
&lt;li&gt;Set minimum and maximum replica limits&lt;/li&gt;
&lt;li&gt;Configure cooldown intervals&lt;/li&gt;
&lt;li&gt;Choose cluster-wide vs single-host pinning&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audit Trail &amp;amp; SIEM:&lt;/strong&gt; Every automatic scaling event is cryptographically sealed into Gubernator's immutable &lt;strong&gt;Forensic Audit Log (ENS op.mon.1)&lt;/strong&gt; and forwarded to your enterprise SIEM (Splunk, Wazuh, Elastic) in CEF, RFC 5424 Syslog, or JSON.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  🚀 Quickstart: Try It Yourself in 60 Seconds
&lt;/h2&gt;

&lt;p&gt;Installing Gubernator takes a single binary or automated installer:&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="c"&gt;# Download the latest binary for your architecture (Linux AMD64/ARM64, macOS)&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://github.com/mario-ezquerro/gubernator/releases/latest/download/gbnt-linux-amd64 &lt;span class="nt"&gt;-o&lt;/span&gt; gbnt
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x gbnt
&lt;span class="nb"&gt;sudo mv &lt;/span&gt;gbnt /usr/local/bin/

&lt;span class="c"&gt;# Initialize the manager node and monitoring stack&lt;/span&gt;
gbnt legion init
gbnt monitor init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your browser at &lt;code&gt;http://localhost:4001&lt;/code&gt; (Dashboard) and &lt;code&gt;http://localhost:4002/swagger/index.html&lt;/code&gt; (REST API). Deploy your first compose stack and watch Gubernator seamlessly scale your tasks as traffic surges!&lt;/p&gt;




&lt;h2&gt;
  
  
  🌟 Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Container orchestration doesn't have to be a choice between the primitive limitations of a single Docker daemon and the crushing complexity of Kubernetes. &lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Gubernator&lt;/strong&gt;, you get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native Docker Compose compatibility&lt;/li&gt;
&lt;li&gt;Real-time CPU &amp;amp; NVIDIA GPU Horizontal Autoscaling&lt;/li&gt;
&lt;li&gt;Zero-CGO, single-binary Go engine&lt;/li&gt;
&lt;li&gt;Built-in Caddy Ingress, CoreDNS, GlusterFS storage, and OpenTelemetry SRE stack&lt;/li&gt;
&lt;li&gt;Enterprise Active Directory/LDAP, RBAC, and Spanish ENS forensic security&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Give the project a star on GitHub and let us know your thoughts in the comments below!&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;https://github.com/mario-ezquerro/gubernator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>go</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Building an AI Agent Honeypot &amp; Lead Engine with Model Context Protocol (MCP) &amp; FastAPI</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Mon, 31 Aug 2026 05:46:04 +0000</pubDate>
      <link>https://dev.to/gde/building-an-ai-agent-honeypot-lead-engine-with-model-context-protocol-mcp-fastapi-195e</link>
      <guid>https://dev.to/gde/building-an-ai-agent-honeypot-lead-engine-with-model-context-protocol-mcp-fastapi-195e</guid>
      <description>&lt;h1&gt;
  
  
  Building an AI Agent Honeypot &amp;amp; Lead Engine with Model Context Protocol (MCP) &amp;amp; FastAPI
&lt;/h1&gt;

&lt;p&gt;The way people discover and buy products online is undergoing a massive paradigm shift. Instead of humans manually browsing e-commerce websites and filling out lead forms, &lt;strong&gt;autonomous AI agents&lt;/strong&gt; (such as ChatGPT Shopping, Google Gemini, Perplexity Shopping, and Claude) are now researching, comparing prices, and reserving deals on behalf of users.&lt;/p&gt;

&lt;p&gt;To tap into this agentic economy, we built &lt;strong&gt;MCP Collector&lt;/strong&gt;: an open-standard gateway powered by &lt;strong&gt;FastAPI&lt;/strong&gt;, &lt;strong&gt;FastMCP 2.x&lt;/strong&gt;, and &lt;strong&gt;Google Cloud Run&lt;/strong&gt; that lets autonomous AI agents discover catalogs, invoke structured tools over HTTP/SSE, and stream qualified buyer leads straight into a real-time operator dashboard.&lt;/p&gt;

&lt;p&gt;Here is a deep-dive into how it works and how you can build one.&lt;/p&gt;




&lt;h2&gt;
  
  
  System Architecture
&lt;/h2&gt;

&lt;p&gt;MCP Collector sits between external AI agents and commercial operators:&lt;br&gt;
&lt;/p&gt;

&lt;pre data-lang="mermaid"&gt;&lt;code&gt;flowchart TD
    subgraph AI_Ecosystem [AI Agents &amp;amp; Shopping Bots]
        ChatGPT["ChatGPT (Shopping &amp;amp; Actions)"]
        Gemini["Google Gemini (Shopping Graph)"]
        Perplexity["Perplexity Shopping"]
        Claude["Claude Desktop &amp;amp; Antigravity"]
    end

    subgraph Hub [MCP Collector Hub (FastAPI + FastMCP)]
        Discovery["/llms.txt &amp;amp; /robots.txt &amp;amp; JSON-LD"]
        SSE["/mcp/sse &amp;amp; /mcp/messages (MCP 2.x)"]

        subgraph Tools [FastMCP Tools]
            T1["search_products"]
            T2["reserve_product_offer"]
            T3["request_b2b_quote"]
        end

        DB[(PostgreSQL / SQLite Async)]
        WS["WebSocket Broadcaster: /ws"]
    end

    subgraph Operator [Operator UI]
        Dashboard["Live Web Dashboard"]
    end

    AI_Ecosystem --&amp;gt;|Autodiscover| Discovery
    AI_Ecosystem --&amp;gt;|Connect &amp;amp; Execute| SSE
    SSE --&amp;gt; Tools
    Tools --&amp;gt;|Persist Lead| DB
    Tools --&amp;gt;|Instant Push| WS
    WS --&amp;gt; Dashboard&lt;/code&gt;&lt;/pre&gt;






&lt;h2&gt;
  
  
  Step 1: Making Your Hub Discoverable by LLMs
&lt;/h2&gt;

&lt;p&gt;For AI agents to interact with your server, they must first discover it. We use a 5-layer discovery strategy:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt; &amp;amp; &lt;code&gt;llms-full.txt&lt;/code&gt;&lt;/strong&gt;: Standardized Markdown files placed at the domain root containing catalog summaries, tool schemas, and instructions without wasting context tokens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI-Targeted &lt;code&gt;robots.txt&lt;/code&gt;&lt;/strong&gt;: Explicit crawler permissions for &lt;code&gt;OAI-SearchBot&lt;/code&gt;, &lt;code&gt;ChatGPT-User&lt;/code&gt;, &lt;code&gt;PerplexityBot&lt;/code&gt;, &lt;code&gt;ClaudeBot&lt;/code&gt;, and &lt;code&gt;Amazonbot&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP &lt;code&gt;Link&lt;/code&gt; Headers&lt;/strong&gt;: Every response returns discovery pointers:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;   Link: &amp;lt;/mcp/sse&amp;gt;; rel="mcp-server", &amp;lt;/.well-known/mcp.json&amp;gt;; rel="mcp-manifest"
   X-MCP-Version: 1.2.0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Schema.org JSON-LD&lt;/strong&gt;: Embedded &lt;code&gt;ItemList&lt;/code&gt;, &lt;code&gt;Product&lt;/code&gt;, and &lt;code&gt;Offer&lt;/code&gt; semantic microdata.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Smithery &amp;amp; OpenAPI&lt;/strong&gt;: Standard &lt;code&gt;smithery.yaml&lt;/code&gt; configuration for seamless registry inclusion.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Step 2: Implementing Tools with FastMCP 2.x
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;FastMCP 2.x&lt;/strong&gt;, defining type-safe tools that external LLMs can invoke over Server-Sent Events (SSE) is clean and intuitive:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastmcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastMCP&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pydantic&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Field&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;app.services.lead_service&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;record_lead_and_broadcast&lt;/span&gt;

&lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastMCP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MCP Collector Hub&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&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;search_products&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="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Field&lt;/span&gt;&lt;span class="p"&gt;(...,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Product keyword or SKU&lt;/span&gt;&lt;span class="sh"&gt;"&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;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search promotional hardware and exclusive offers.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;catalog&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&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;sku&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;gpu-h100-sxm5&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;name&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;NVIDIA H100 SXM5 80GB Server (4x Cluster)&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;normal_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;74500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;promo_price&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;48425&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;discount&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;35% OFF&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;stock_status&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;1 unit remaining (EU Warehouse)&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;catalog&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;

&lt;span class="nd"&gt;@mcp.tool&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;reserve_product_offer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sku&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;buyer_name&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;buyer_email&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;company&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;shipping_city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&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;dict&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Reserve a high-demand product offer before it sells out.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# 1. Persist the lead &amp;amp; broadcast via WebSockets to operator dashboard
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;record_lead_and_broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;sku&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sku&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="n"&gt;buyer_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;buyer_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;company&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;shipping_city&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# 2. Return realistic allocation status to the agent
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&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;WAITLIST_PRIORITY_1&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;message&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&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;Unit allocated to next in queue. &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;buyer_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; registered at Priority #1 on VIP Allocation List.&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;h2&gt;
  
  
  Step 3: Real-Time Telemetry with WebSockets
&lt;/h2&gt;

&lt;p&gt;Whenever an agent invokes a tool, the event is immediately pushed to connected browsers via WebSockets without polling:&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;fastapi&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;WebSocketDisconnect&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ConnectionManager&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;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_connections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&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;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&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;disconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_connections&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&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;broadcast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&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;connection&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active_connections&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send_json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;manager&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConnectionManager&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app.websocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/ws&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;websocket_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WebSocket&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&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="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;receive_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;WebSocketDisconnect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;manager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4: Deploying to Google Cloud Run
&lt;/h2&gt;

&lt;p&gt;Deploying to Cloud Run allows the hub to scale to zero when idle and instantly scale up when multiple agents hit the SSE endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gcloud run deploy mcp-collector &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; europe-west1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--platform&lt;/span&gt; managed &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--allow-unauthenticated&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--port&lt;/span&gt; 8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--timeout&lt;/span&gt; 3600 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--min-instances&lt;/span&gt; 1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--session-affinity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Session affinity and a long timeout (&lt;code&gt;3600s&lt;/code&gt;) are crucial for persistent Server-Sent Events (SSE) and WebSocket connections on Cloud Run.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Protocol Standards Matter&lt;/strong&gt;: By implementing &lt;strong&gt;Model Context Protocol (MCP)&lt;/strong&gt;, you build a single backend that works across Claude Desktop, ChatGPT, Gemini, and custom agents without reinventing integration layers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine-Readable Discovery is the New SEO&lt;/strong&gt;: Protocols like &lt;code&gt;llms.txt&lt;/code&gt; and semantic JSON-LD are essential for getting your APIs ingested by autonomous web agents.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Responsiveness&lt;/strong&gt;: Combining asynchronous event loops with WebSockets provides instant visibility into how AI models interact with your tools.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Project Source &amp;amp; Docs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;a href="https://github.com/mario-ezquerro/mcp-collector" rel="noopener noreferrer"&gt;mario-ezquerro/mcp-collector&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protocol Reference&lt;/strong&gt;: &lt;a href="https://modelcontextprotocol.io/" rel="noopener noreferrer"&gt;Model Context Protocol Specification&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>fastapi</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Kubeflow Without Kubernetes? Deploy a Complete MLOps Suite in 60 Seconds with Gubernator</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Fri, 28 Aug 2026 11:28:35 +0000</pubDate>
      <link>https://dev.to/gde/kubeflow-without-kubernetes-deploy-a-complete-mlops-suite-in-60-seconds-with-gubernator-3moo</link>
      <guid>https://dev.to/gde/kubeflow-without-kubernetes-deploy-a-complete-mlops-suite-in-60-seconds-with-gubernator-3moo</guid>
      <description>&lt;h2&gt;
  
  
  The "Kubernetes Tax" on Modern Machine Learning
&lt;/h2&gt;

&lt;p&gt;If you’ve ever tried setting up &lt;strong&gt;Kubeflow&lt;/strong&gt; on Kubernetes, you know the drill:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;30+ Custom Resource Definitions (CRDs)&lt;/li&gt;
&lt;li&gt;Istio Service Mesh + Knative + Cert-Manager + Dex&lt;/li&gt;
&lt;li&gt;16 GB to 32 GB of RAM consumed &lt;strong&gt;before you even write a single line of Python&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Days spent debugging webhook admission controllers and Kustomize overlays.
Kubernetes is great at hyper-scale, but for 95% of engineering teams, researchers, and startups, &lt;strong&gt;Kubernetes for MLOps is massive over-engineering&lt;/strong&gt;.
What if you could have the exact same capabilities — &lt;strong&gt;Interactive JupyterLab with PyTorch, MLflow Experiment Tracking, MinIO S3 Object Storage, and High-Speed LLM Inference&lt;/strong&gt; — deployed in &lt;strong&gt;60 seconds using a single &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt;?
Enter &lt;strong&gt;Gubernator (&lt;code&gt;gbnt&lt;/code&gt;)&lt;/strong&gt;: the lightweight "Goldilocks" container orchestrator.
---&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Gubernator?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;Gubernator&lt;/a&gt; is a single-binary container orchestrator written in Go that combines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The simplicity of Docker Swarm&lt;/strong&gt; (pure Docker Compose syntax, easy multi-node clustering).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The power of Nomad&lt;/strong&gt; (intelligent task scheduling, worker-first load balancing, and GPU hardware targeting).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in Aqueducts&lt;/strong&gt;: Automatic CoreDNS service discovery + multi-node Caddy Ingress with automatic HTTPS/TLS.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;The Granaries&lt;/strong&gt;: Persistent shared storage mobility (&lt;code&gt;/var/contenedores&lt;/code&gt;) across cluster nodes.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Architecture: Kubernetes Kubeflow vs. Gubernator MLOps
&lt;/h2&gt;

&lt;p&gt;┌─────────────────────────────────────────────────────────────┐ │  Data Scientist / AI Engineer │ └──────────────────────────────┬──────────────────────────────┘ │ (https://*.kubeflow.gbnt.local) ▼ ┌─────────────────────────────────────────────────────────────┐ │   Built-in Caddy Ingress &amp;amp; CoreDNS Gateway │ └──────┬──────────────┬──────────────┬──────────────┬─────────┘ │ │ │ │ ▼ ▼ ▼ ▼ ┌──────────────┐┌──────────────┐┌──────────────┐┌──────────────┐ │ JupyterLab ││ MLflow ││ MinIO S3 ││ Ollama / vLLM│ │ Workspace ││ Tracking ││ Artifacts &amp;amp; ││ Inference │ │ (PyTorch) ││ &amp;amp; Registry ││ Datasets ││ Serving │ │ (:8888) ││ (:5000) ││ (:9001) ││ (:11434) │ └──────────────┘└──────────────┘└──────────────┘└──────────────┘&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Capability&lt;/th&gt;
&lt;th&gt;Kubernetes Kubeflow&lt;/th&gt;
&lt;th&gt;Gubernator MLOps (&lt;code&gt;kubeflow-stack&lt;/code&gt;)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Control Plane Overhead&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;16 GB – 32 GB RAM (etcd, Istio, K8s)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;&amp;lt; 200 MB RAM&lt;/strong&gt; (Go binary)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Configuration Format&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Helm / Kustomize / CRD manifests&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Standard &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment Time&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;30–45 minutes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;&amp;lt; 60 seconds&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Experiment Tracking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Katib + Kubeflow Metadata&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MLflow Tracking + Model Registry&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Artifact Store&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;MinIO on PVCs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MinIO S3 with Granaries Storage&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inference Serving&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;KServe + Knative + Istio&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ollama / vLLM (OpenAI API compatible)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Domain Routing &amp;amp; TLS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VirtualServices + IngressGateway&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Automatic Caddy Ingress (&lt;code&gt;*.local&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  The Blueprint: Single-File MLOps Platform
&lt;/h2&gt;

&lt;p&gt;Here is the entire stack defined in standard Docker Compose syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# 1. MinIO S3 Object Storage (Datasets &amp;amp; Model Checkpoints)&lt;/span&gt;
  &lt;span class="na"&gt;minio&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;minio/minio:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server /data --console-address ":9001"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MINIO_ROOT_USER=kubeflow&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MINIO_ROOT_PASSWORD=gubernator123&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9000:9000"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;9001:9001"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/contenedores/kubeflow/minio_data:/data&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ingress.host=minio.kubeflow.gbnt.local"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.caddy.port=9001"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.service.name=minio-s3"&lt;/span&gt;
  &lt;span class="c1"&gt;# 2. MLflow Tracking Server &amp;amp; Model Registry&lt;/span&gt;
  &lt;span class="na"&gt;mlflow&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ghcr.io/mlflow/mlflow:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="s"&gt;mlflow server&lt;/span&gt;
      &lt;span class="s"&gt;--host 0.0.0.0&lt;/span&gt;
      &lt;span class="s"&gt;--port 5000&lt;/span&gt;
      &lt;span class="s"&gt;--workers 1&lt;/span&gt;
      &lt;span class="s"&gt;--allowed-hosts "*"&lt;/span&gt;
      &lt;span class="s"&gt;--backend-store-uri sqlite:////data/mlflow.db&lt;/span&gt;
      &lt;span class="s"&gt;--default-artifact-root s3://mlflow-artifacts/&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID=kubeflow&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY=gubernator123&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MLFLOW_S3_ENDPOINT_URL=http://minio.kubeflow.gbnt.local&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MLFLOW_S3_IGNORE_TLS=true&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MLFLOW_ALLOWED_HOSTS=*&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5000:5000"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/contenedores/kubeflow/mlflow_data:/data&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ingress.host=mlflow.kubeflow.gbnt.local"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.caddy.port=5000"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.service.name=mlflow-tracking"&lt;/span&gt;
  &lt;span class="c1"&gt;# 3. Interactive JupyterLab &amp;amp; PyTorch Workspaces&lt;/span&gt;
  &lt;span class="na"&gt;jupyter-workspace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;quay.io/jupyter/pytorch-notebook:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JUPYTER_TOKEN=gubernator-secret&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;JUPYTER_ENABLE_LAB=yes&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_ACCESS_KEY_ID=kubeflow&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY=gubernator123&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MLFLOW_TRACKING_URI=http://mlflow.kubeflow.gbnt.local&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;MLFLOW_S3_ENDPOINT_URL=http://minio.kubeflow.gbnt.local&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8888:8888"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/contenedores/kubeflow/workspaces:/home/jovyan/work&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/contenedores/kubeflow/cache:/home/jovyan/.cache&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ingress.host=notebooks.kubeflow.gbnt.local"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.caddy.port=8888"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.service.name=jupyterlab"&lt;/span&gt;
  &lt;span class="c1"&gt;# 4. Model Serving &amp;amp; LLM Inference Gateway&lt;/span&gt;
  &lt;span class="na"&gt;inference-engine&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ollama/ollama:latest&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;11434:11434"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;/var/contenedores/kubeflow/models:/root/.ollama&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ingress.host=inference.kubeflow.gbnt.local"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.caddy.port=11434"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gbnt.service.name=model-serving"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🛠️ Deploying in 1 Command&lt;br&gt;
On your Gubernator cluster, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gbnt stack deploy kubeflow-stack &lt;span class="nt"&gt;-c&lt;/span&gt; docker-compose.yml
Or open the Gubernator Web Dashboard &lt;span class="o"&gt;(&lt;/span&gt;http://localhost:4001&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="nb"&gt;head &lt;/span&gt;over to Compose Studio, &lt;span class="k"&gt;select &lt;/span&gt;the Kubeflow MLOps Blueprint, and click Deploy Stack.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Gubernator's scheduler automatically:&lt;/p&gt;

&lt;p&gt;Prioritizes Centurion Worker nodes over the Manager.&lt;br&gt;
Spreads the workloads evenly across available workers.&lt;br&gt;
Automatically sets up internal DNS (CoreDNS) and reverse proxy routes (Caddy Ingress).&lt;br&gt;
Generates instant TLS certificates for all services.&lt;/p&gt;

&lt;p&gt;Instant Endpoints &amp;amp; Access&lt;br&gt;
Immediately after deployment, your MLOps platform is ready:&lt;/p&gt;

&lt;p&gt;JupyterLab Workspace: &lt;a href="https://notebooks.kubeflow.gbnt.local" rel="noopener noreferrer"&gt;https://notebooks.kubeflow.gbnt.local&lt;/a&gt; (Token: gubernator-secret)&lt;/p&gt;

&lt;p&gt;MLflow Experiment Tracking: &lt;a href="https://mlflow.kubeflow.gbnt.local" rel="noopener noreferrer"&gt;https://mlflow.kubeflow.gbnt.local&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MinIO S3 Console: &lt;a href="https://minio.kubeflow.gbnt.local" rel="noopener noreferrer"&gt;https://minio.kubeflow.gbnt.local&lt;/a&gt; (User: kubeflow / Pass: gubernator123)&lt;br&gt;
⚡ Ollama Inference Engine: &lt;a href="https://inference.kubeflow.gbnt.local" rel="noopener noreferrer"&gt;https://inference.kubeflow.gbnt.local&lt;/a&gt; (OpenAI-compatible /v1/chat/completions)&lt;br&gt;
🧪 Testing the End-to-End Pipeline in Python&lt;br&gt;
Data scientists can write normal Python code to log experiments, save models to MinIO S3, and serve predictions:&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="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;mlflow.sklearn&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.ensemble&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RandomForestClassifier&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sklearn.datasets&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_iris&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="c1"&gt;# Connect to the cluster's MLflow server
&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MLFLOW_S3_ENDPOINT_URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://minio.kubeflow.gbnt.local&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kubeflow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gubernator123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_tracking_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://mlflow.kubeflow.gbnt.local&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_experiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;iris-classification-demo&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;load_iris&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;return_X_y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;clf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RandomForestClassifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n_estimators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_depth&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;clf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Log metrics
&lt;/span&gt;    &lt;span class="n"&gt;accuracy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;clf&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;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log_param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;n_estimators&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log_metric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accuracy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;accuracy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Persist model to MinIO S3 and register
&lt;/span&gt;    &lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sklearn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;clf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;registered_model_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;IrisProductionModel&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&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;✅ Training completed! Accuracy: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;accuracy&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&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;&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;Key Takeaways&lt;br&gt;
You don't always need Kubernetes: If you are not running hundreds of parallel multi-step distributed DAG pipelines with Argo, Kubernetes adds unnecessary friction and cost.&lt;br&gt;
Standard Compose is enough: With an orchestrator like Gubernator, you get clustering, load balancing, health checks, automated Ingress, and persistent storage using simple, familiar Docker Compose files.&lt;br&gt;
Resource Efficiency: You save 10x-20x the RAM, allowing you to invest your hardware budget where it actually matters: GPUs and model training.&lt;/p&gt;

&lt;p&gt;🔗 Project Links&lt;br&gt;
🐙 GitHub Repository: mario-ezquerro/gubernator&lt;br&gt;
📖 Documentation: Gubernator Docs&lt;br&gt;
⭐ Give it a star on GitHub if you found this useful!&lt;/p&gt;

</description>
      <category>gubernator</category>
      <category>docker</category>
      <category>antigravity</category>
      <category>orquestador</category>
    </item>
    <item>
      <title>Building Enterprise Storage, Backups &amp; Cosign Image Security in Go &amp; Flutter with Google Antigravity</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Thu, 20 Aug 2026 18:13:27 +0000</pubDate>
      <link>https://dev.to/gde/building-enterprise-storage-backups-cosign-image-security-in-go-flutter-with-google-antigravity-3ao3</link>
      <guid>https://dev.to/gde/building-enterprise-storage-backups-cosign-image-security-in-go-flutter-with-google-antigravity-3ao3</guid>
      <description>&lt;h1&gt;
  
  
  Building Enterprise Storage, Point-in-Time Backups &amp;amp; Cosign Image Security in Go &amp;amp; Flutter with Google Antigravity
&lt;/h1&gt;

&lt;p&gt;When architecting a modern container orchestrator like &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;Gubernator (gbnt)&lt;/a&gt;&lt;/strong&gt; — designed to strike the &lt;strong&gt;Goldilocks balance&lt;/strong&gt; between the simplicity of Docker Swarm and the placement flexibility of Nomad — two major enterprise pillars stand between an MVP and true production readiness:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;State Persistence &amp;amp; Backup Mobility (&lt;em&gt;The Granaries / Horreum&lt;/em&gt;)&lt;/strong&gt;: Moving stateful containers (PostgreSQL, MySQL, Redis, custom data volumes) across worker nodes without data loss, backed by compressed point-in-time snapshots and retention policies.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software Supply Chain Security &amp;amp; Admission Control (&lt;em&gt;The Imperial Seal / Armamentarium&lt;/em&gt;)&lt;/strong&gt;: Detecting CVE vulnerabilities before deployment, cataloging dependencies via Software Bill of Materials (SBOM), signing container images with cryptographic keypairs (Cosign/Sigstore), and enforcing strict Gatekeeper admission policies.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this article, we break down how we designed and implemented these two major subsystems in &lt;strong&gt;Gubernator v2.24.0 &amp;amp; v2.25.0&lt;/strong&gt;, and how we leveraged &lt;strong&gt;Google Antigravity (AGY)&lt;/strong&gt; as an autonomous AI engineering partner to architect, implement, test, and live-deploy Full-Stack features (Go + SQLite + Flutter Web + CLI) across a live 3-node multi-host cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 1: Persistent Storage &amp;amp; The Backup Subsystem (&lt;em&gt;The Granaries&lt;/em&gt;)
&lt;/h2&gt;

&lt;p&gt;Stateful container workloads present a fundamental orchestration challenge: &lt;strong&gt;how can a container move between different physical hosts while maintaining access to its persistent disk storage?&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ┌─────────────────────────────────────────────────────────────────────────┐
 │                   GUBERNATOR STORAGE &amp;amp; BACKUP ENGINE                     │
 ├─────────────────────────────────────────────────────────────────────────┤
 │   /var/contenedores (Shared Mobility Pool: NFS, GlusterFS, CephFS)    │
 │   Point-in-Time Compressed Tarballs (.tar.gz) + SHA-256 Checksums     │
 │   Background Cron Scheduler &amp;amp; Automated Retention Pruning            │
 │   Zero-Downtime Consistent Freeze (docker pause -&amp;gt; tar -&amp;gt; unpause)    │
 └─────────────────┬───────────────────────────────────┬───────────────────┘
                   │                                   │
                   ▼                                   ▼
      ┌─────────────────────────┐         ┌─────────────────────────┐
      │  Centurion 1 (Manager)  │         │  Centurion 2 (Worker 1) │
      │   IP: 192.168.252.27    │         │   IP: 192.168.252.25    │
      │  Mount: /var/contened.. │         │  Mount: /var/contened.. │
      └─────────────────────────┘         └─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Shared Storage Mobility (&lt;code&gt;/var/contenedores&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;Gubernator standardizes volume mobility by designating &lt;code&gt;/var/contenedores&lt;/code&gt; across all cluster nodes. When backed by a distributed file system (NFS, GlusterFS, CephFS, CIFS) or localized volumes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The orchestrator can dynamically schedule database or application containers to any active Centurion host.&lt;/li&gt;
&lt;li&gt;The storage explorer inspects and displays disk utilization (&lt;code&gt;used / total&lt;/code&gt;, percentage, and node read/write mount health).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Database-Consistent Snapshots with Docker Freeze
&lt;/h3&gt;

&lt;p&gt;Backing up a running relational database (PostgreSQL, MariaDB, SQLite) while active transactions are in flight risks data corruption. &lt;/p&gt;

&lt;p&gt;We implemented an optional &lt;strong&gt;Atomic Freeze Strategy&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// internal/storage/backup.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;CreateBackup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stackName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;serviceName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pauseContainer&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Backup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&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;pauseContainer&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;containerID&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;slog&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"backup: pausing container for consistent snapshot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;containerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dockerClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContainerPause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;containerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;dockerClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContainerUnpause&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;containerID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Stream directory to tar.gz with SHA-256 calculation&lt;/span&gt;
    &lt;span class="n"&gt;archiveFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sha256Checksum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sizeBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;archiveDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destFile&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// ... Save record to SQLite ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Automated Cron Policies &amp;amp; Retention Rotation
&lt;/h3&gt;

&lt;p&gt;Gubernator's background backup daemon evaluates standard cron expressions (e.g. &lt;code&gt;0 2 * * *&lt;/code&gt; for nightly 2:00 AM backups) and automatically prunes older snapshots according to a configured retention count (e.g. keep last 7 copies).&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 2: Image Security, SBOM &amp;amp; Cosign Cryptography (&lt;em&gt;The Imperial Seal&lt;/em&gt;)
&lt;/h2&gt;

&lt;p&gt;Deploying third-party container images blindly introduces severe supply-chain risks. In &lt;strong&gt;v2.25.0&lt;/strong&gt;, we introduced a complete &lt;strong&gt;Pre-Deployment Admission Gatekeeper&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                         [ Stack Deploy / Container Run Request ]
                                          │
                                          ▼
                 ┌──────────────────────────────────────────────────┐
                 │     GUBERNATOR ADMISSION GATEKEEPER (Port 4000)   │
                 │     - Evaluates Cluster &amp;amp; Stack Security Policy  │
                 └────────────────────────┬─────────────────────────┘
                                          │
          ┌───────────────────────────────┴───────────────────────────────┐
          ▼                                                               ▼
 ┌───────────────────────────┐                                 ┌───────────────────────────┐
 │  1. Cryptographic Sign  │                                 │ 🔍 2. CVE Vulnerability   │
 │    (Cosign / Sigstore)    │                                 │    Scanning &amp;amp; CVSS Scores │
 ├───────────────────────────┤                                 ├───────────────────────────┤
 │ Is the image signed with  │                                 │ Does image exceed Max     │
 │ a trusted cluster key?    │                                 │ Severity (Critical/High)? │
 └─────────────┬─────────────┘                                 └─────────────┬─────────────┘
               │                                                             │
               ├───────── ❌ Unsigned / Invalid                              ├───────── ❌ Exceeds Threshold
               │          (If policy = 'ENFORCE')                            │          (If policy = 'BLOCK')
               ▼                                                             ▼
 ╔═══════════════════════════╗                                 ╔═══════════════════════════╗
 ║  ⛔ DEPLOYMENT REJECTED   ║                                 ║   ⛔ DEPLOYMENT BLOCKED   ║
 ║ "Signature check failed"  ║                                 ║ "Found 2 Critical CVEs"   ║
 ╚═══════════════════════════╝                                 ╚═══════════════════════════╝
               │                                                             │
               └──────────────────────────┬──────────────────────────────────┘
                                          │ ✅ Passes All Admission Checks
                                          ▼
                         ╔═════════════════════════════════╗
                         ║ 🚀 Container Scheduled on Hosts ║
                         ╚═════════════════════════════════╝
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1. Pure Go Cosign ECDSA Keypair Generation &amp;amp; Signing
&lt;/h3&gt;

&lt;p&gt;To eliminate heavy external binary dependencies like &lt;code&gt;cosign&lt;/code&gt; or CGO toolchains, we implemented the cryptographic signing engine using Go's standard library (&lt;code&gt;crypto/ecdsa&lt;/code&gt;, &lt;code&gt;crypto/elliptic&lt;/code&gt;, &lt;code&gt;crypto/x509&lt;/code&gt;, &lt;code&gt;crypto/sha256&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// internal/security/signing.go&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GenerateCosignKeypair&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pubPEM&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;privPEM&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;privKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ecdsa&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GenerateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;elliptic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P256&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;privBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;x509&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalECPrivateKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;privKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;privPEMBlock&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"EC PRIVATE KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;privBytes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;privPEM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeToMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;privPEMBlock&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;pubBytes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;x509&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarshalPKIXPublicKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;privKey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PublicKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pubPEMBlock&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"PUBLIC KEY"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pubBytes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;pubPEM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EncodeToMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pubPEMBlock&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;pubPEM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;privPEM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Multi-Standard SBOM Generator (CycloneDX &amp;amp; SPDX)
&lt;/h3&gt;

&lt;p&gt;For software inventory audits and compliance, Gubernator automatically analyzes container image layers, extracts packages and OS libraries (musl, glibc, OpenSSL, busybox), and exports standardized Software Bill of Materials in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CycloneDX 1.5 JSON&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SPDX 2.3 JSON&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Cluster-Wide Auto-Discovery &amp;amp; Host Mapping
&lt;/h3&gt;

&lt;p&gt;Rather than requiring users to register images manually, Gubernator continuously discovers all container images running across every node in the cluster (&lt;code&gt;Manager&lt;/code&gt;, &lt;code&gt;Worker 1&lt;/code&gt;, &lt;code&gt;Worker 2&lt;/code&gt;). The UI dynamically renders &lt;strong&gt;host badges and service tags&lt;/strong&gt; indicating where every container instance is hosted.&lt;/p&gt;




&lt;h2&gt;
  
  
  Part 3: The Flutter Web Dashboard Visualization
&lt;/h2&gt;

&lt;p&gt;Gubernator's Web Dashboard (Port 4001) provides two rich Material Design 3 interfaces:&lt;/p&gt;

&lt;h3&gt;
  
  
  Storage &amp;amp; Backups (The Granaries)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Volumes Table&lt;/strong&gt;: Displays Named Volumes, Shared Pools, and Host Bind Mounts with live disk usage calculations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snapshot Manager&lt;/strong&gt;: 1-click on-demand backup creation, direct &lt;code&gt;.tar.gz&lt;/code&gt; browser downloads, and backup restore modals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pool Health Matrix&lt;/strong&gt;: Validates mount availability, read/write permissions, and free disk space across all cluster hosts.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Image Security &amp;amp; SBOM (The Imperial Seal)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;** Vulnerabilities Tab**: Real-time image catalog displaying Critical, High, Medium, Low CVE counts, verified signature badges, and host mappings (&lt;code&gt;Used in: caddy, promtail on Manager, Worker 1, Worker 2&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;** SBOM Explorer Tab**: Component dependency tree with license compliance auditing and 1-click CycloneDX/SPDX downloads.&lt;/li&gt;
&lt;li&gt;** Signatures &amp;amp; Keys Tab**: In-cluster Cosign ECDSA keypair generator and image signing terminal.&lt;/li&gt;
&lt;li&gt;** Gatekeeper Policies Tab**: Interactive admission policy switches (&lt;code&gt;Audit / Warn Only&lt;/code&gt; vs &lt;code&gt;Strict Enforcement&lt;/code&gt;, CVE severity threshold blocking).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  ⚡ Part 4: Full CLI Parity
&lt;/h2&gt;

&lt;p&gt;Every capability is accessible directly through the &lt;code&gt;gbnt&lt;/code&gt; CLI:&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="c"&gt;# === Storage &amp;amp; Backups ===&lt;/span&gt;
gbnt volume &lt;span class="nb"&gt;ls
&lt;/span&gt;gbnt backup &lt;span class="nb"&gt;ls
&lt;/span&gt;gbnt backup create &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"postgres-nightly"&lt;/span&gt; &lt;span class="nt"&gt;--pause&lt;/span&gt; /var/contenedores/postgres
gbnt backup restore &amp;lt;backup-id&amp;gt; &lt;span class="nt"&gt;--target&lt;/span&gt; /var/contenedores/postgres

&lt;span class="c"&gt;# === Image Security &amp;amp; SBOM ===&lt;/span&gt;
gbnt scan
gbnt scan postgres:16-alpine
gbnt sbom postgres:16-alpine &lt;span class="nt"&gt;--format&lt;/span&gt; cyclonedx-json &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; sbom.json

&lt;span class="c"&gt;# === Cosign Signing &amp;amp; Verification ===&lt;/span&gt;
gbnt security key generate &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"prod-release-key"&lt;/span&gt;
gbnt image sign company/payments:2.1.0 &lt;span class="nt"&gt;--key&lt;/span&gt; /path/to/private.key
gbnt image verify company/payments:2.1.0

&lt;span class="c"&gt;# === Cluster Gatekeeper Policy ===&lt;/span&gt;
gbnt security policy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Part 5: How We Built This with Google Antigravity (AGY)
&lt;/h2&gt;

&lt;p&gt;Building a distributed orchestrator with state synchronization, cryptographic operations, cross-compilation, and Full-Stack Web UIs is an intricate endeavor. Here is how &lt;strong&gt;Google Antigravity&lt;/strong&gt; accelerated development:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Specification-Driven Engineering
&lt;/h3&gt;

&lt;p&gt;Before writing code, we used Antigravity to formalize comprehensive architectural blueprints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator/blob/main/SPEC-storage-backups.md" rel="noopener noreferrer"&gt;&lt;code&gt;SPEC-storage-backups.md&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator/blob/main/SPEC-image-security.md" rel="noopener noreferrer"&gt;&lt;code&gt;SPEC-image-security.md&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Having structured specifications allowed the AI to implement the entire pipeline (GORM database schemas, pure Go cryptography, REST API routes, Flutter Dart models, and CLI flags) with complete architectural alignment.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Autonomous Root-Cause Debugging
&lt;/h3&gt;

&lt;p&gt;During initial testing of the backup scheduler, we encountered a recursive mutex deadlock: &lt;code&gt;StartBackupScheduler()&lt;/code&gt; was holding &lt;code&gt;cronMutex.Lock()&lt;/code&gt; while calling &lt;code&gt;SyncSchedules()&lt;/code&gt;, which also attempted to acquire &lt;code&gt;cronMutex.Lock()&lt;/code&gt;. Antigravity inspected the call graph, refactored &lt;code&gt;syncSchedulesLocked()&lt;/code&gt;, and verified thread-safety without human intervention.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Live Cluster Deployment &amp;amp; Verification
&lt;/h3&gt;

&lt;p&gt;Antigravity seamlessly built Linux ARM64 binaries (&lt;code&gt;CGO_ENABLED=0 GOOS=linux GOARCH=arm64&lt;/code&gt;), transferred them to a live 3-node Multipass virtualized cluster (&lt;code&gt;gbnt-manager&lt;/code&gt;, &lt;code&gt;gbnt-worker1&lt;/code&gt;, &lt;code&gt;gbnt-worker2&lt;/code&gt;), and executed live HTTP and CLI verification checks against Port 4000, 4001, and 4002.&lt;/p&gt;




&lt;h2&gt;
  
  
  🏁 Conclusion &amp;amp; What's Next
&lt;/h2&gt;

&lt;p&gt;With &lt;strong&gt;Storage &amp;amp; Backups (v2.24.0)&lt;/strong&gt; and &lt;strong&gt;Image Security &amp;amp; Cosign (v2.25.0)&lt;/strong&gt;, Gubernator bridges the gap between lightweight simplicity and enterprise-grade resilience.&lt;/p&gt;

&lt;p&gt;Whether you are running a single-node homelab or an edge-distributed cluster, you can now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run stateful databases with confidence using point-in-time compressed backups.&lt;/li&gt;
&lt;li&gt;Secure your software supply chain with automated CVE scanning and Cosign cryptographic signatures.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Explore the project on GitHub:&lt;br&gt;
 &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;GitHub: mario-ezquerro/gubernator&lt;/a&gt;&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;&lt;a href="https://mario-ezquerro.github.io/gubernator/" rel="noopener noreferrer"&gt;Official Documentation &amp;amp; Guides&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have you implemented image signing or shared volume mobility in your container setups? Share your thoughts in the comments below!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gubernator</category>
      <category>docker</category>
      <category>antigravity</category>
    </item>
    <item>
      <title>Building Enterprise Active Directory, LDAP &amp; Dynamic RBAC in Go &amp; Flutter with Google Antigravity</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Mon, 17 Aug 2026 09:00:16 +0000</pubDate>
      <link>https://dev.to/gde/building-enterprise-active-directory-ldap-dynamic-rbac-in-go-flutter-with-google-antigravity-4al4</link>
      <guid>https://dev.to/gde/building-enterprise-active-directory-ldap-dynamic-rbac-in-go-flutter-with-google-antigravity-4al4</guid>
      <description>&lt;h1&gt;
  
  
  Building Enterprise Active Directory, LDAP &amp;amp; Dynamic RBAC in Go &amp;amp; Flutter with Google Antigravity
&lt;/h1&gt;

&lt;p&gt;When building a lightweight container orchestrator like &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;Gubernator (gbnt)&lt;/a&gt;&lt;/strong&gt; — designed to strike the perfect balance between the &lt;strong&gt;simplicity of Docker Swarm&lt;/strong&gt; and the &lt;strong&gt;flexibility of Nomad&lt;/strong&gt; under a Roman Empire theme — a critical milestone inevitably emerges: &lt;strong&gt;Enterprise Security and Access Control&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While a default &lt;code&gt;admin&lt;/code&gt; credential works well for local dev environments, moving into enterprise production with multi-disciplinary engineering teams demands:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Corporate Single Sign-On (SSO)&lt;/strong&gt; with Microsoft Active Directory and OpenLDAP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Role-Based Access Control (RBAC)&lt;/strong&gt; to clearly segregate who can deploy stacks, restart containers, or audit telemetries in read-only mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Group Mapping&lt;/strong&gt; from corporate security groups (&lt;code&gt;memberOf&lt;/code&gt;) to orchestrator roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emergency Break-Glass Access&lt;/strong&gt; (Local Administrator) in case network directory controllers are unreachable.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this article, we explore the complete architecture of the enterprise security engine introduced in &lt;strong&gt;Gubernator v2.20.0&lt;/strong&gt;, and how we leveraged &lt;strong&gt;Google Antigravity (AGY)&lt;/strong&gt; as an autonomous AI pair programmer to design, implement, test, and verify this Full-Stack feature (Go + Flutter Web) across a live 3-node cluster.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Security Architecture
&lt;/h2&gt;

&lt;p&gt;We designed a decoupled, asymmetric architecture connecting identity providers, REST API middleware, and the Flutter Web UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; ┌────────────────────────────────────────────────────────┐
 │                   GUBERNATOR WEB UI                    │
 │   - Modern Login Screen with Domain / AD Selector      │
 │   - Header Role Badge: Admin |  Ops |  Read-Only.      │
 └──────────────────────────┬─────────────────────────────┘
                            │ (REST /api/auth/login)
                            ▼
 ┌────────────────────────────────────────────────────────┐
 │             GUBERNATOR CORE AUTH ENGINE (Go)           │
 │  - Local Emergency Admin (admin / admin fallback)      │
 │  - Multi-Server Active Directory / OpenLDAP Dialers    │
 │  - LDAPS (Port 636) &amp;amp; StartTLS (Port 389) Handshake    │
 │  - Dynamic Group DN -&amp;gt; RBAC Role Resolution            │
 │  - Cryptographic HMAC-SHA256 JWT Token Signing         │
 └─────────────┬────────────────────────────┬─────────────┘
               │                            │
               ▼                            ▼
 ┌───────────────────────────┐ ┌──────────────────────────┐
 │  Primary Active Directory │ │ Secondary LDAP Server    │
 │   dc1.corporate.local     │ │   dc2.dr-site.local      │
 └───────────────────────────┘ └──────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Role-Based Access Control (RBAC) Matrix
&lt;/h3&gt;

&lt;p&gt;We established three distinct operational tiers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operational Capability&lt;/th&gt;
&lt;th&gt;&lt;code&gt;admin&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;operator&lt;/code&gt;&lt;/th&gt;
&lt;th&gt;&lt;code&gt;readonly&lt;/code&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overview, Metrics &amp;amp; SRE Telemetry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deploy Stacks (&lt;code&gt;docker-compose.yml&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redeploy &amp;amp; Duplicate Stacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Delete Stacks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Task Lifecycle (Start / Stop / Restart)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container &amp;amp; Node Terminal Shell&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node Fleet Management (Drain / Activate / Leave)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caddy TLS Certificates &amp;amp; Ingress Routes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Active Directory &amp;amp; LDAP Directory Settings&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;td&gt;❌ Restricted&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Grafana, Jaeger &amp;amp; Weave Scope Dashboards&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;td&gt;✅ Full&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  💻 The Go Backend Engine (&lt;code&gt;internal/auth/&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;For LDAP/Active Directory interactions, we used &lt;code&gt;github.com/go-ldap/ldap/v3&lt;/code&gt;, and for session management &lt;code&gt;github.com/golang-jwt/jwt/v5&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Two-Phase Bind &amp;amp; Credential Verification
&lt;/h3&gt;

&lt;p&gt;Authentication follows a secure two-phase pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect and perform a &lt;strong&gt;Service Account Bind&lt;/strong&gt; (&lt;code&gt;BindDN&lt;/code&gt; / &lt;code&gt;BindPassword&lt;/code&gt;) to query the directory.&lt;/li&gt;
&lt;li&gt;Search for the user object using a configurable LDAP filter (defaulting to &lt;code&gt;(&amp;amp;(objectClass=user)(sAMAccountName=%s))&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Open a secondary connection and perform a &lt;strong&gt;Direct User Bind&lt;/strong&gt; with the user-submitted password against the domain controller.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AuthenticateLDAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LDAPConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;AuthResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConnectLDAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// 1. Initial service account bind&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindDN&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindPassword&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindDN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BindPassword&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"service account bind failed: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="c"&gt;// 2. Search for the user&lt;/span&gt;
    &lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserFilter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ldap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EscapeFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;searchReq&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ldap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewSearchRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ldap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ScopeWholeSubtree&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ldap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NeverDerefAliases&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"dn"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"displayName"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"memberOf"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;searchReq&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user not found in directory"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;userEntry&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c"&gt;// 3. Direct user bind to verify password&lt;/span&gt;
    &lt;span class="n"&gt;userConn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ConnectLDAP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;userConn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;userConn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid credentials"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// 4. Map groups to RBAC role&lt;/span&gt;
    &lt;span class="n"&gt;groups&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;userEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAttributeValues&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"memberOf"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;role&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ResolveRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;AuthResult&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;UserDN&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;userEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Username&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;DisplayName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;userEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAttributeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"displayName"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;userEntry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAttributeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"mail"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Groups&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;groups&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Role&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="n"&gt;role&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Dynamic Group-to-Role Mapping
&lt;/h3&gt;

&lt;p&gt;Gubernator inspects the user's &lt;code&gt;memberOf&lt;/code&gt; group list and matches them against the configured group DNs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;ResolveRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LDAPConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userGroups&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Role&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;matchesGroup&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetGroup&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&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;targetGroup&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;targetGroup&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;userGroups&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;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strings&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TrimSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&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="no"&gt;false&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;matchesGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AdminGroupDN&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;RoleAdmin&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;matchesGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OperatorGroupDN&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;RoleOperator&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;matchesGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadOnlyGroupDN&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;RoleReadOnly&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;NormalizeRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cfg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultRole&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;h2&gt;
  
  
  The Flutter Web UI Experience
&lt;/h2&gt;

&lt;p&gt;Gubernator's Web Dashboard is built with &lt;strong&gt;Flutter Web&lt;/strong&gt; and &lt;strong&gt;Material Design 3&lt;/strong&gt;, compiled and embedded directly into the Go binary (&lt;code&gt;go:embed&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Modern Login Screen with Domain Selector
&lt;/h3&gt;

&lt;p&gt;Operators can select their target authentication provider (&lt;code&gt;Corporate Active Directory&lt;/code&gt;, &lt;code&gt;DR Site LDAP&lt;/code&gt;, or &lt;code&gt;Local Administrator&lt;/code&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzko6ykwioskjaydd6fqg.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%2Fzko6ykwioskjaydd6fqg.png" alt="Login Screen" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Active Directory Management &amp;amp; Diagnostics
&lt;/h3&gt;

&lt;p&gt;In the new &lt;strong&gt;Seguridad &amp;amp; AD&lt;/strong&gt; tab, cluster administrators can configure directory servers, TLS certificates, and run a live &lt;strong&gt;"Test Connection"&lt;/strong&gt; diagnostic tool:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs0y8lv3qbyxlf6lxadyb.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%2Fs0y8lv3qbyxlf6lxadyb.png" alt="Security &amp;amp; AD Management" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Real-Time Role Badges &amp;amp; Contextual Guards
&lt;/h3&gt;

&lt;p&gt;The dashboard header displays the active user and their assigned role (&lt;code&gt;ADMIN&lt;/code&gt;, &lt;code&gt;⚡ OPERATOR&lt;/code&gt;, &lt;code&gt;READ-ONLY&lt;/code&gt;). Mutating actions (e.g., Delete Stack, Drain Node, Shell) are automatically disabled for read-only audit accounts.&lt;/p&gt;




&lt;h2&gt;
  
  
  How Google Antigravity Accelerated Development
&lt;/h2&gt;

&lt;p&gt;We utilized &lt;strong&gt;Google Antigravity (AGY)&lt;/strong&gt; as an autonomous AI pair programmer to build this feature end-to-end. AGY accelerated the development cycle through several key workflows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architectural Planning&lt;/strong&gt;:&lt;br&gt;
Before writing code, Antigravity produced a comprehensive implementation plan (&lt;code&gt;implementation_plan.md&lt;/code&gt;) outlining the GORM schema changes (&lt;code&gt;LDAPConfig&lt;/code&gt;), RBAC authorization matrix, and API routes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Synchronized Full-Stack Implementation&lt;/strong&gt;:&lt;br&gt;
In a single coordinated session, Antigravity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Built the Go &lt;code&gt;internal/auth/&lt;/code&gt; engine with LDAP dialers, JWT session handlers, and Gin middlewares.&lt;/li&gt;
&lt;li&gt;Applied SQLite database auto-migrations.&lt;/li&gt;
&lt;li&gt;Implemented the Flutter Web UI (&lt;code&gt;login_screen.dart&lt;/code&gt;, &lt;code&gt;security_page.dart&lt;/code&gt;, and state models).&lt;/li&gt;
&lt;li&gt;Updated existing views (&lt;code&gt;legions_page.dart&lt;/code&gt;, &lt;code&gt;tasks_page.dart&lt;/code&gt;, &lt;code&gt;centurions_page.dart&lt;/code&gt;) with RBAC permission guards.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Live Cluster Testing &amp;amp; Verification&lt;/strong&gt;:&lt;br&gt;
Using automated commands across a 3-node multipass cluster (&lt;code&gt;gbnt-manager&lt;/code&gt;, &lt;code&gt;gbnt-worker1&lt;/code&gt;, &lt;code&gt;gbnt-worker2&lt;/code&gt;), Antigravity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployed and hot-restarted the ARM64 binaries.&lt;/li&gt;
&lt;li&gt;Tested REST endpoints via &lt;code&gt;curl&lt;/code&gt; (valid login, invalid login, LDAP connection tests, configuration lifecycle).&lt;/li&gt;
&lt;li&gt;Executed Go unit tests (&lt;code&gt;go test ./internal/auth/...&lt;/code&gt;) with 100% pass rates.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automated Documentation &amp;amp; Release&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generated high-fidelity visual UI showcases.&lt;/li&gt;
&lt;li&gt;Authored complete documentation in &lt;a href="https://mario-ezquerro.github.io/gubernator/auth-rbac/" rel="noopener noreferrer"&gt;&lt;code&gt;docs/auth-rbac.md&lt;/code&gt;&lt;/a&gt; and validated MkDocs builds in strict mode.&lt;/li&gt;
&lt;li&gt;Bumped the version to &lt;code&gt;v2.20.0&lt;/code&gt;, created git release tags, and triggered GitHub Pages publishing.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion &amp;amp; Open Source
&lt;/h2&gt;

&lt;p&gt;Adding Active Directory SSO and RBAC allows teams to deploy Gubernator in enterprise production environments that require enterprise security compliance without the operational overhead of Kubernetes.&lt;/p&gt;

&lt;p&gt;Check out Gubernator and try it out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/mario-ezquerro/gubernator" rel="noopener noreferrer"&gt;github.com/mario-ezquerro/gubernator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Official Documentation:&lt;/strong&gt; &lt;a href="https://mario-ezquerro.github.io/gubernator/" rel="noopener noreferrer"&gt;mario-ezquerro.github.io/gubernator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Active Directory &amp;amp; RBAC Guide:&lt;/strong&gt; &lt;a href="https://mario-ezquerro.github.io/gubernator/auth-rbac/" rel="noopener noreferrer"&gt;docs/auth-rbac.md&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What do you think about this hybrid approach to container orchestration? Let us know your thoughts and suggestions in the comments! &lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>flutter</category>
      <category>ai</category>
    </item>
    <item>
      <title>Reviving Open Source Giants: How I Brought Weave Scope Back with Multi-Platform Docker Support in One Afternoon Using Antigravity</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Fri, 14 Aug 2026 16:36:10 +0000</pubDate>
      <link>https://dev.to/gde/reviving-open-source-giants-how-i-brought-weave-scope-back-with-multi-platform-docker-support-in-cmo</link>
      <guid>https://dev.to/gde/reviving-open-source-giants-how-i-brought-weave-scope-back-with-multi-platform-docker-support-in-cmo</guid>
      <description>&lt;p&gt;The open-source ecosystem is full of architectural masterpieces that—due to corporate pivots, lack of maintainers, or shifting market focus—eventually get frozen in time. One of the most prominent examples is &lt;strong&gt;&lt;a href="https://github.com/weaveworks/scope" rel="noopener noreferrer"&gt;Weave Scope&lt;/a&gt;&lt;/strong&gt;: a legendary tool for visual monitoring, real-time mapping, and debugging container clusters.&lt;/p&gt;

&lt;p&gt;When the original repository was archived and left unmaintained, its dependency tree froze and it remained strictly tied to &lt;code&gt;x86_64&lt;/code&gt; architectures. In today’s world, with the widespread adoption of ARM servers (AWS Graviton, Apple Silicon, Raspberry Pi clusters, etc.), running the original build has become nearly impossible.&lt;/p&gt;

&lt;p&gt;I set out to rescue it, modernize its build pipelines, and create multi-platform Docker images. &lt;strong&gt;The result?&lt;/strong&gt; The project is back to life at &lt;strong&gt;&lt;a href="https://github.com/mario-ezquerro/scope" rel="noopener noreferrer"&gt;github.com/mario-ezquerro/scope&lt;/a&gt;&lt;/strong&gt; with multi-arch Docker images live on &lt;strong&gt;Docker Hub&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The best part: &lt;strong&gt;the entire journey took a single afternoon and a few tokens thanks to Antigravity.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Challenge: Brilliant Code Locked in the Past
&lt;/h2&gt;

&lt;p&gt;Weave Scope is far from a trivial codebase. Its architecture integrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Low-level kernel probes and agents written in &lt;strong&gt;Go&lt;/strong&gt; and &lt;strong&gt;eBPF&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;A reactive, interactive web UI.&lt;/li&gt;
&lt;li&gt;Complex legacy Makefiles and container toolchains originally engineered exclusively for &lt;code&gt;amd64/x86_64&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Manually upgrading this stack to modern &lt;code&gt;docker buildx&lt;/code&gt; workflows with native support for both &lt;strong&gt;ARM64&lt;/strong&gt; and &lt;strong&gt;AMD64&lt;/strong&gt; would traditionally mean days of painful software archaeology: resolving broken Go packages, outdated C libraries, incompatible packaging scripts, and compilation errors.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Catalyst: Antigravity as a Software Rescue Agent
&lt;/h2&gt;

&lt;p&gt;This is where &lt;strong&gt;Antigravity&lt;/strong&gt; makes an extraordinary difference.&lt;/p&gt;

&lt;p&gt;Instead of spending days fighting legacy &lt;code&gt;Makefiles&lt;/code&gt; and deprecated toolchains, I leveraged Antigravity to parse the repository structure, diagnose build blockers, and modernize the compilation and packaging pipeline for multi-architecture targets.&lt;/p&gt;

&lt;p&gt;What used to be a tedious migration became an agile, iterative session:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Audit &amp;amp; Fixes:&lt;/strong&gt; Identifying system calls and C bindings that prevented cross-compilation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dockerfile &amp;amp; Buildx Refactoring:&lt;/strong&gt; Modernizing the multi-stage build pipeline to compile native binaries for both &lt;code&gt;linux/amd64&lt;/code&gt; and &lt;code&gt;linux/arm64&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Publishing:&lt;/strong&gt; Generating multi-arch manifest lists and pushing them directly to Docker Hub.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Modernized Multi-Arch Scope
&lt;/h2&gt;

&lt;p&gt;The revived project is ready for the community:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/mario-ezquerro/scope" rel="noopener noreferrer"&gt;https://github.com/mario-ezquerro/scope&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Original Repository (Legacy):&lt;/strong&gt; &lt;a href="https://github.com/weaveworks/scope" rel="noopener noreferrer"&gt;https://github.com/weaveworks/scope&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Docker Hub Multi-Arch Images:&lt;/strong&gt; Ready to deploy on both x86 and ARM infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Quick Start
&lt;/h3&gt;

&lt;p&gt;Run the probe and visualization UI on any local machine or server (including Apple Silicon and Raspberry Pi clusters):&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="c"&gt;# Pull and run Scope with multi-arch support&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; weave-scope &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--net&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;host &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--privileged&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; /var/run/docker.sock:/var/run/docker.sock &lt;span class="se"&gt;\&lt;/span&gt;
  marioezquerro/scope:latest
Open your browser at http://localhost:4040 to see your real-time container topology &lt;span class="k"&gt;in &lt;/span&gt;action.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Takeaway: A Golden Era for Open Source Maintenance&lt;br&gt;
The true power of modern AI platforms like Antigravity isn't just generating boilerplate code from scratch—it is their astonishing capability for software restoration and modernization.&lt;/p&gt;

&lt;p&gt;GitHub contains thousands of brilliant, abandoned projects that simply need an afternoon of care, dependency updates, and container modernization. With a single afternoon and a handful of tokens, any developer now has the superpower to revive forgotten open-source gems and give them back to the global community.&lt;/p&gt;

&lt;p&gt;What abandoned open-source project is on your wishlist to revive next? Let me know in the comments!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>devops</category>
      <category>docker</category>
      <category>ai</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Tue, 11 Aug 2026 08:43:08 +0000</pubDate>
      <link>https://dev.to/marioezquerro/-52j2</link>
      <guid>https://dev.to/marioezquerro/-52j2</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac" class="crayons-story__hidden-navigation-link"&gt;Gubernator v2.13.0: Google SRE SLOs, Native CoreDNS Suite &amp;amp; Caddy Ingress for Docker Compose&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;
          &lt;a class="crayons-logo crayons-logo--l" href="/gde"&gt;
            &lt;img alt="Google Developer Experts logo" 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%2Forganization%2Fprofile_image%2F11939%2Fe3080d5b-ecde-42a8-b089-bafecc31fa97.png" class="crayons-logo__image" width="800" height="800"&gt;
          &lt;/a&gt;

          &lt;a href="/marioezquerro" class="crayons-avatar  crayons-avatar--s absolute -right-2 -bottom-2 border-solid border-2 border-base-inverted  "&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%2Fuser%2Fprofile_image%2F878530%2F7288c9b0-63e5-4a85-b7a1-be9f1234dfbd.jpeg" alt="marioezquerro profile" class="crayons-avatar__image" width="368" height="368"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/marioezquerro" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Mario Ezquerro
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Mario Ezquerro
                
              
              &lt;div id="story-author-preview-content-4366126" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/marioezquerro" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F878530%2F7288c9b0-63e5-4a85-b7a1-be9f1234dfbd.jpeg" class="crayons-avatar__image" alt="" width="368" height="368"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Mario Ezquerro&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;span&gt;
              &lt;span class="crayons-story__tertiary fw-normal"&gt; for &lt;/span&gt;&lt;a href="/gde" class="crayons-story__secondary fw-medium"&gt;Google Developer Experts&lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Aug 11&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac" id="article-link-4366126"&gt;
          Gubernator v2.13.0: Google SRE SLOs, Native CoreDNS Suite &amp;amp; Caddy Ingress for Docker Compose
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devops"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devops&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/docker"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;docker&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/sre"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;sre&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/go"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;go&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>Gubernator v2.13.0: Google SRE SLOs, Native CoreDNS Suite &amp; Caddy Ingress for Docker Compose</title>
      <dc:creator>Mario Ezquerro</dc:creator>
      <pubDate>Tue, 11 Aug 2026 06:14:53 +0000</pubDate>
      <link>https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac</link>
      <guid>https://dev.to/gde/gubernator-v2130-google-sre-slos-native-coredns-suite-caddy-ingress-for-docker-compose-1bac</guid>
      <description>&lt;p&gt;If you love the &lt;strong&gt;simplicity of Docker Swarm&lt;/strong&gt; (native Compose files, lightweight single binary) but miss the &lt;strong&gt;advanced capabilities of Kubernetes&lt;/strong&gt; (targeted label placement, SRE-grade observability, built-in DNS service discovery, and zero-trust ingress), meet &lt;strong&gt;Gubernator (gbnt)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We are excited to release &lt;strong&gt;Gubernator v2.13.0&lt;/strong&gt;, introducing three massive feature suites natively integrated into a single binary and a modern Material Design 3 Flutter Web Dashboard:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Google SRE Multi-Burn-Rate SLO Engine &amp;amp; Interactive Suite&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CoreDNS 4-Tab Management Suite &amp;amp; Interactive Dig Playground&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Caddy Ingress &amp;amp; Zero-Trust Reverse Proxy Suite&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Fun Fact: The entirety of Gubernator's codebase, multi-node deployment pipelines, and SRE features were designed, built, and pair-programmed using **Google Antigravity (AGY)&lt;/em&gt;&lt;em&gt;, Google DeepMind's agentic AI coding assistant!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Let's dive into what's new and how you can level up your self-hosted or production container clusters!&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Google SRE Multi-Burn-Rate SLO Engine &amp;amp; Web Suite
&lt;/h2&gt;

&lt;p&gt;Defining &lt;strong&gt;Service Level Objectives (SLOs)&lt;/strong&gt; and tracking &lt;strong&gt;Error Budgets&lt;/strong&gt; is the gold standard of Site Reliability Engineering. Until now, implementing SLOs meant running heavy Kubernetes CRDs (via tools like Sloth or Pyrra) or using costly SaaS platforms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gubernator v2.13.0&lt;/strong&gt; brings Google SRE Workbook (Chapter 5) compliant multi-burn-rate alerting straight to simple &lt;code&gt;docker-compose.yml&lt;/code&gt; services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.8"&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;payment-api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;hashicorp/http-echo:latest&lt;/span&gt;
    &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;gbnt.slo.enable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
      &lt;span class="na"&gt;gbnt.slo.target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;99.9"&lt;/span&gt;
      &lt;span class="na"&gt;gbnt.slo.window&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;30d"&lt;/span&gt;
      &lt;span class="na"&gt;gbnt.slo.template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;caddy-http"&lt;/span&gt;
      &lt;span class="na"&gt;gbnt.slo.journey&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checkout&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Flow"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What makes Gubernator's SLO Suite unique?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Multi-Burn-Rate Alerting&lt;/strong&gt;: Automatically generates standard 4-window Prometheus recording and alert rules (&lt;strong&gt;Critical Page 1h/6h&lt;/strong&gt; &amp;amp; &lt;strong&gt;Warning Ticket 3d/14d&lt;/strong&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic "No-Code" Management&lt;/strong&gt;: Click &lt;strong&gt;"+ Configure / Add SLO"&lt;/strong&gt; in the Web UI or call &lt;code&gt;POST /v1/slo/edit&lt;/code&gt; to create, edit, or disable SLOs on the fly without editing Compose files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composite User Journeys&lt;/strong&gt;: Group multi-service SLOs into end-to-end flows (&lt;em&gt;Checkout Flow: API Gateway + Payment + DB&lt;/em&gt;) and automatically identify the weakest-link &lt;strong&gt;bottleneck service&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment Correlation Timeline&lt;/strong&gt;: Cross-reference real-time burn rate spikes against stack updates and container restarts to answer &lt;em&gt;"Did our last deploy burn the budget?"&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PromQL Dry-Run Backtesting&lt;/strong&gt;: Validate Compose YAML syntax and test PromQL queries against historical Prometheus metrics prior to deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automated Grafana Dashboards&lt;/strong&gt;: Automatically generates &lt;code&gt;/data/monitor/grafana/dashboards/slo_dashboard.json&lt;/code&gt; on rule sync.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  SLO Ecosystem Comparison Matrix
&lt;/h2&gt;

&lt;p&gt;Here is how Gubernator compares to other popular open-source and commercial SLO tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature / Capability&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Gubernator&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Sloth&lt;/strong&gt; (&lt;code&gt;slok/sloth&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;Pyrra&lt;/strong&gt; (&lt;code&gt;pyrra-dev/pyrra&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;OpenSLO / Nobl9&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Native Runtime Environment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Docker Compose / Swarm / Bare Metal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Kubernetes / OpenSLO CLI&lt;/td&gt;
&lt;td&gt;Kubernetes CRDs / Filesystem&lt;/td&gt;
&lt;td&gt;Multi-Cloud / SaaS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Declarative Spec&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;docker-compose.yml&lt;/code&gt; labels (&lt;code&gt;gbnt.slo.*&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;K8s CRDs / Sloth YAML&lt;/td&gt;
&lt;td&gt;Custom Resources (&lt;code&gt;ServiceLevelObjective&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;OpenSLO YAML Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SRE Calculation Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Google SRE Multi-Burn-Rate&lt;/strong&gt; (via Sloth Engine)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Google SRE Multi-Burn-Rate&lt;/strong&gt; (4 windows)&lt;/td&gt;
&lt;td&gt;Prometheus Multi-Burn-Rate&lt;/td&gt;
&lt;td&gt;Proprietary / Custom&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Integrated Web Dashboard&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Flutter Web 5-Tab Suite)&lt;/td&gt;
&lt;td&gt;No (CLI / Operator only)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (React/Go UI)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (SaaS Console)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dynamic Hot-Editing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Web UI Modal &amp;amp; REST API)&lt;/td&gt;
&lt;td&gt;No (Requires re-applying YAMLs)&lt;/td&gt;
&lt;td&gt;No (Read-only from K8s/Files)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (SaaS Console)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Journeys (Composite SLOs)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Aggregation &amp;amp; Bottleneck Analysis)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Related Services)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Deployment Correlation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Real-time Timeline of Stacks/Restarts)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial (CI/CD Webhooks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Built-in SLI Templates&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (&lt;code&gt;caddy-http&lt;/code&gt;, &lt;code&gt;http-status&lt;/code&gt;, &lt;code&gt;latency-p99&lt;/code&gt;, &lt;code&gt;grpc&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Partial (Sloth Libraries)&lt;/td&gt;
&lt;td&gt;No (Raw PromQL)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dry-Run PromQL Backtesting&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Pre-deploy Validation)&lt;/td&gt;
&lt;td&gt;Partial (&lt;code&gt;validate&lt;/code&gt; command)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RED Metrics Breakdown&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (RPS, Error Rate, P99 Latency Cards)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Partial (RPS &amp;amp; Errors)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Yes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Automated Grafana Provisioning&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Yes&lt;/strong&gt; (Auto-generates &lt;code&gt;slo_dashboard.json&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Partial (Generic Rules)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  2. Native CoreDNS 4-Tab Suite &amp;amp; Interactive Dig Playground
&lt;/h2&gt;

&lt;p&gt;Internal container service discovery should "just work." In Gubernator, every deployed container automatically receives &lt;code&gt;--dns &amp;lt;CoreDNS_IP&amp;gt;&lt;/code&gt;, enabling seamless &lt;code&gt;*.gbnt&lt;/code&gt; internal resolution across multi-node clusters.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;v2.13.0&lt;/strong&gt;, we are expanding CoreDNS into a full &lt;strong&gt;4-Tab Management Suite&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------------------------------------------------------------+
|                      GUBERNATOR COREDNS SUITE                           |
|                                                                         |
|  [Tab 1: Auto-Discovered] [Tab 2: Custom Records] [Tab 3: DNS Playground] [Tab 4: Config]
+-------------------------------------------------------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tab 1: Auto-Discovered Stacks (&lt;code&gt;*.gbnt&lt;/code&gt;)&lt;/strong&gt;: Real-time table mapping running containers to &lt;code&gt;&amp;lt;service&amp;gt;.&amp;lt;stack&amp;gt;.gbnt&lt;/code&gt; with copyable &lt;code&gt;curl&lt;/code&gt; commands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tab 2: Custom Static DNS Records&lt;/strong&gt;: Manage custom &lt;code&gt;A&lt;/code&gt;, &lt;code&gt;AAAA&lt;/code&gt;, &lt;code&gt;CNAME&lt;/code&gt;, &lt;code&gt;TXT&lt;/code&gt;, and &lt;code&gt;PTR&lt;/code&gt; records stored in SQLite and merged into CoreDNS on the fly (&lt;code&gt;POST /v1/coredns/custom-records&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tab 3: Interactive Dig Playground&lt;/strong&gt;: A built-in terminal console to run DNS queries against local CoreDNS (&lt;code&gt;127.0.0.1:5354&lt;/code&gt;), benchmark query latency in milliseconds, and inspect raw &lt;code&gt;nslookup&lt;/code&gt; output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tab 4: Upstream Forwarders &amp;amp; Corefile Editor&lt;/strong&gt;: One-click upstream DNS presets (&lt;strong&gt;Cloudflare 1.1.1.1&lt;/strong&gt;, &lt;strong&gt;Google 8.8.8.8&lt;/strong&gt;, &lt;strong&gt;Quad9 9.9.9.9&lt;/strong&gt;) and a live Corefile editor with container reload.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Caddy Ingress Suite &amp;amp; Zero-Trust Reverse Proxy
&lt;/h2&gt;

&lt;p&gt;Gubernator packages &lt;strong&gt;Caddy&lt;/strong&gt; as its default edge proxy, handling HTTPS certificate provisioning, reverse proxying, and access logging across multi-node setups.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features in the Caddy Suite:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;7-Tab Management Visualizer&lt;/strong&gt;: Dashboard, Dynamic Routes Matrix, Corefile Preview, TLS Certs Inspector, Real-time Access Logs, Log Config, and Prometheus Metrics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Root CA Trust Installation&lt;/strong&gt;: One-click download of Gubernator's internal Root CA certificate for local TLS trust across your developer devices.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Ingress Label Routing&lt;/strong&gt;: Simply add &lt;code&gt;ingress.host=my-app.example.com&lt;/code&gt; to your Compose service, and Gubernator reconfigures Caddy route matrices across all cluster nodes automatically.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Getting Started in Under 60 Seconds
&lt;/h2&gt;

&lt;p&gt;You can spin up a complete Gubernator cluster with full observability, CoreDNS, Caddy, and Prometheus/Grafana in seconds:&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="c"&gt;# 1. Download binary &amp;amp; start Gubernator Manager&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/mario-ezquerro/gubernator/main/install.sh | bash
gbnt serve

&lt;span class="c"&gt;# 2. Deploy the SRE Monitoring Stack (Prometheus, Grafana, Loki, cAdvisor, Jaeger)&lt;/span&gt;
gbnt monitor init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  3. Access Web Dashboards
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Web UI Dashboard -&amp;gt; &lt;a href="http://localhost:4001" rel="noopener noreferrer"&gt;http://localhost:4001&lt;/a&gt;
&lt;/h1&gt;

&lt;h1&gt;
  
  
  Grafana           -&amp;gt; &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt;
&lt;/h1&gt;

&lt;h1&gt;
  
  
  CoreDNS Playground -&amp;gt; &lt;a href="http://localhost:4001" rel="noopener noreferrer"&gt;http://localhost:4001&lt;/a&gt; (CoreDNS tab)
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


---

## Built Autonomous with Google Antigravity

A special shoutout to **Google Antigravity (AGY)**! The entire architecture of Gubernator -- from Go backend REST APIs, SQLite ORMs, Caddy route management, CoreDNS hosts sync, Sloth SLO rule compilation, down to the 5-tab Flutter Web UI -- was built autonomously in pair-programming sessions with Google Antigravity AI.

---

## Conclusion &amp;amp; Open Source

Gubernator aims to make container orchestration **fast, resilient, and enjoyable** again -- without the steep operational overhead of Kubernetes.

- **GitHub Repository**: [mario-ezquerro/gubernator](https://github.com/mario-ezquerro/gubernator)
- **Documentation &amp;amp; Guides**: [https://mario-ezquerro.github.io/gubernator/](https://mario-ezquerro.github.io/gubernator/)
- **Give us a Star**: If you find Gubernator useful, drop a star on GitHub!

*What are your thoughts on native SLO tracking for Docker Compose? Let us know in the comments below!*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>devops</category>
      <category>docker</category>
      <category>sre</category>
      <category>go</category>
    </item>
  </channel>
</rss>
