The Simple System I Use to Never Miss a Deadline

Here's a simple system I've developed over the years that helps me never miss a deadline, even when juggling multiple projects. It's a practical approach tailored for developers and freelancers, combining a few powerful tools with some solid time management techniques.

## Prioritization: The Foundation of Success

Starting off, prioritize your tasks effectively. The Eisenhower Box is an excellent method to categorize tasks based on their urgency and importance. By doing so, you ensure that you tackle high-priority tasks promptly without getting overwhelmed by less pressing matters.

## Breaking Down Large Projects

Large projects can often seem intimidating, but breaking them down into smaller, manageable chunks makes them easier to handle. This technique is commonly known as "divide and conquer." For example, if you're working on a complex feature for an application:

bash
Feature Development
├── Design Research
│ ├── Competitor Analysis
│ └── User Interviews
├── Prototyping
│ ├── Low-fidelity wireframes
│ └── High-fidelity mockups
├── Implementation
│ ├── Frontend development
│ └── Backend development
├── Testing
│ ├── Unit tests
│ └── Integration tests
└── Deployment
├── Staging environment setup
└── Production deployment


Breaking a project down in this way allows you to focus on one task at a time, making it more achievable and less overwhelming.

## Time Blocking: Mastering Your Calendar

Time blocking is an effective strategy for managing your time efficiently. Assign specific time slots to tasks throughout the day, ensuring that you dedicate concentrated blocks of time to each task without interruptions. For example, I block out two hours every morning for focused coding and save email checking for designated breaks.

## Using Tools to Stay Organized

Staying organized is crucial in meeting deadlines. Here are some popular tools that can help you manage your workload:

1. **Trello**: A flexible project management tool that allows you to organize tasks into boards, lists, and cards. Great for tracking the progress of multiple projects at once.

2. **Jira**: Popular among Agile teams for managing software development tasks, Jira offers features like customizable workflows, issue tracking, and reporting.

3. **Notion**: A powerful all-in-one workspace that includes note-taking, task management, wikis, databases, and more. It's perfect for freelancers who need an organized hub for their projects.

## Establishing a Buffer Zone

Always build a buffer zone into your schedule to accommodate unexpected issues that might arise. This ensures you stay on track even when obstacles present themselves. I usually allocate an extra day or two for each project, which gives me room to maneuver if necessary.

## The Power of Focus

Avoid distractions during focused work sessions by turning off notifications, using browser extensions like Freedom or Cold Turkey, and practicing mindfulness techniques to maintain your focus. Remember, uninterrupted work allows you to complete tasks more quickly and with fewer errors.

## Setting Realistic Deadlines

When estimating project timelines, err on the side of caution. It's better to under-promise and over-deliver than the other way around. By setting realistic deadlines, you reduce the chances of missing them or compromising quality.

## Takeaway

Developing a system that prevents missed deadlines is crucial for any developer or freelancer. Prioritize tasks effectively, break down large projects, time block your calendar, use organizational tools like Trello, Jira, and Notion, establish a buffer zone, stay focused, and set realistic deadlines. With these tips in hand, you're well on your way to mastering deadline management and delivering top-notch work consistently.

Further Reading

OpenTelemetry Has a Free Observability Standard — Traces, Metrics, and Logs Without Vendor Lock-in

Datadog costs $23/host/month. New Relic’s free tier ends fast. OpenTelemetry sends your data to ANY backend — switch providers without changing your code.

What is OpenTelemetry?

OpenTelemetry (OTel) is a vendor-neutral observability standard. It provides APIs, SDKs, and a collector for traces, metrics, and logs. Your instrumentation stays the same — only the backend changes.

Why OpenTelemetry Is the Standard

1. Instrument Once, Export Anywhere

import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://localhost:4318/v1/traces',
    // Switch backends by changing this URL:
    // Grafana Tempo, Jaeger, Zipkin, Datadog, Honeycomb, etc.
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

2. Auto-Instrumentation

npm install @opentelemetry/auto-instrumentations-node

This ONE package automatically instruments:

  • HTTP/HTTPS requests
  • Express/Fastify/Koa routes
  • PostgreSQL/MySQL queries
  • Redis commands
  • MongoDB operations
  • gRPC calls
  • AWS SDK calls

Zero code changes in your application.

3. Custom Spans

import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('my-service');

async function processOrder(orderId: string) {
  return tracer.startActiveSpan('processOrder', async (span) => {
    span.setAttribute('order.id', orderId);

    const items = await tracer.startActiveSpan('fetchItems', async (childSpan) => {
      const result = await db.query('SELECT * FROM items WHERE order_id = $1', [orderId]);
      childSpan.setAttribute('items.count', result.length);
      childSpan.end();
      return result;
    });

    await tracer.startActiveSpan('chargePayment', async (childSpan) => {
      await stripe.charges.create({ amount: calculateTotal(items) });
      childSpan.end();
    });

    span.setStatus({ code: SpanStatusCode.OK });
    span.end();
  });
}

4. Metrics

import { metrics } from '@opentelemetry/api';

const meter = metrics.getMeter('my-service');

const requestCounter = meter.createCounter('http_requests_total', {
  description: 'Total HTTP requests',
});

const latencyHistogram = meter.createHistogram('http_request_duration_ms', {
  description: 'HTTP request latency',
});

app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    requestCounter.add(1, { method: req.method, path: req.path, status: res.statusCode });
    latencyHistogram.record(Date.now() - start, { method: req.method });
  });
  next();
});

5. The Collector (Route Data Anywhere)

# otel-collector-config.yaml
receivers:
  otlp:
    protocols:
      http:
        endpoint: 0.0.0.0:4318

processors:
  batch:
    timeout: 5s

exporters:
  otlp/jaeger:
    endpoint: jaeger:4317
  prometheus:
    endpoint: 0.0.0.0:8889

service:
  pipelines:
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp/jaeger]
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus]

Free Backends

Backend Type Free Tier
Jaeger Traces Self-hosted (free)
Grafana Tempo Traces 50GB/month
Zipkin Traces Self-hosted (free)
Prometheus Metrics Self-hosted (free)
Grafana Loki Logs 50GB/month

Getting Started

npm install @opentelemetry/sdk-node 
  @opentelemetry/auto-instrumentations-node 
  @opentelemetry/exporter-trace-otlp-http

The Bottom Line

OpenTelemetry is the CNCF standard for observability. Instrument once, switch backends freely. No vendor lock-in, no $23/host/month surprise bills.

Need data tools? I build scraping solutions. Check my Apify actors or email [email protected].

The Real Stack Behind AI Agents in Production — MCP, Kubernetes, and What Nobody Tells You

Every team I talk to is building AI agents. They’ve got LangChain running, a vector database humming, and a demo that impresses the CEO.

Then someone asks: “Cool. How do we run this for 10,000 users?”

That’s where things get quiet.

I’ve spent the last year deploying agentic AI systems on Kubernetes — the kind that actually serve real traffic, not just notebook demos. And I’ve learned that the gap between “it works on my laptop” and “it runs in production” is enormous.

This post is about the real stack behind production AI agents in 2026. Not the LLM part — everyone covers that. I’m talking about the infrastructure layer that nobody writes about but everyone desperately needs.

The Problem Nobody Talks About

Here’s a typical conversation I have at least once a week:

Engineer: “We built an AI agent that can query our database, search documents, and draft reports.”

Me: “How does it connect to those systems?”

Engineer: “Custom Python scripts. Different ones for each tool.”

Me: “How do you deploy it?”

Engineer: “Docker container on a single VM.”

Me: “What happens when you need to add a new tool?”

Engineer: silence

The fundamental issue is that most AI agent architectures look like this:

LLM ──→ Hardcoded Tool A (custom REST client)
    ──→ Hardcoded Tool B (custom gRPC wrapper)
    ──→ Hardcoded Tool C (custom DB connector)
    ──→ Hardcoded Tool D (custom file reader)

Every tool integration is bespoke. Every deployment is fragile. Every new capability means rewriting half the agent. This doesn’t scale.

Enter MCP: The USB-C Port for AI Agents

The Model Context Protocol (MCP) changes this equation entirely. Think of it as USB-C for AI — one standardized interface that connects any model to any tool.

Instead of custom integrations for each tool, MCP provides:

LLM ──→ MCP Client ──→ MCP Server: Database
                   ──→ MCP Server: Search
                   ──→ MCP Server: Kubernetes
                   ──→ MCP Server: Slack
                   ──→ MCP Server: (anything)

Here’s a minimal MCP server definition that exposes a Kubernetes health check as a tool:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import * as k8s from "@kubernetes/client-node";

const server = new McpServer({
  name: "k8s-health",
  version: "1.0.0",
});

server.tool(
  "check_pod_status",
  "Check the health status of pods in a namespace",
  { namespace: { type: "string", description: "Kubernetes namespace" } },
  async ({ namespace }) => {
    const kc = new k8s.KubeConfig();
    kc.loadFromDefault();
    const k8sApi = kc.makeApiClient(k8s.CoreV1Api);

    const res = await k8sApi.listNamespacedPod({ namespace });
    const unhealthy = res.items.filter(
      (p) => p.status?.phase !== "Running" && p.status?.phase !== "Succeeded"
    );

    return {
      content: [
        {
          type: "text",
          text: unhealthy.length === 0
            ? `All pods in ${namespace} are healthy.`
            : `Found ${unhealthy.length} unhealthy pods:n` +
              unhealthy
                .map((p) => `- ${p.metadata?.name}: ${p.status?.phase}`)
                .join("n"),
        },
      ],
    };
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

The agent doesn’t need to know how Kubernetes works. It just calls check_pod_status through MCP, and the server handles the rest.

Now here’s where it gets interesting: the MCP ecosystem has exploded. As of March 2026, there are over 10,000 public MCP servers, 97M+ monthly SDK downloads, and adoption by Claude, ChatGPT, Gemini, VS Code, and Cursor. OpenAI, Google, and Microsoft all support it. It’s not a bet anymore — it’s infrastructure.

The Part Everyone Skips: Running This on Kubernetes

So you’ve got MCP wiring up your agent to tools. Great. But where do these MCP servers actually run? How do you manage GPU resources for your LLM? What happens when traffic spikes?

This is where Kubernetes becomes the AI infrastructure OS.

Architecture: Agent Stack on Kubernetes

Here’s the production architecture I deploy:

┌──────────────────────────────────────────────────────┐
│              Kubernetes Cluster                       │
│                                                      │
│  ┌──────────────────────────────────────────────┐    │
│  │       Ingress / Gateway API                  │    │
│  │  Inference Gateway · model-aware routing     │    │
│  └───────────────────┬──────────────────────────┘    │
│                      │                               │
│  ┌─────────────┐ ┌───┴──────────┐ ┌──────────────┐  │
│  │ Agent API   │─│MCP Server    │ │ Key Metrics  │  │
│  │ FastAPI +   │ │Pool          │ │ TTFT <500ms  │  │
│  │ LangGraph   │ │ mcp-postgres │ │ GPU >70%     │  │
│  └──────┬──────┘ │ mcp-search   │ │ Tool >99.5%  │  │
│         │        │ mcp-k8s      │ │ Cost -39%    │  │
│         │        └──────┬───────┘ └──────────────┘  │
│  ┌──────┴──────┐ ┌──────┴───────┐                    │
│  │ LLM Server  │ │ Vector DB   │                    │
│  │ vLLM + DRA  │ │ Weaviate    │                    │
│  │ Llama-70B   │ │ Hybrid Srch │                    │
│  └─────────────┘ └─────────────┘                    │
│                                                      │
│  ┌──────────────────────────────────────────────┐    │
│  │ Observability: OTel → Prometheus → Grafana   │    │
│  └──────────────────────────────────────────────┘    │
└──────────────────────────────────────────────────────┘

Let me walk through each layer.

Layer 1: GPU Scheduling with Dynamic Resource Allocation

The biggest pain point in AI infrastructure is GPU management. Before DRA (Dynamic Resource Allocation), you were stuck with device plugins — crude, all-or-nothing GPU assignments.

DRA reached GA in Kubernetes 1.34 and changes the game. Here’s a ResourceClaim for an inference workload:

apiVersion: resource.k8s.io/v1beta2
kind: ResourceClaim
metadata:
  name: llm-inference-gpu
  namespace: ai-agents
spec:
  devices:
    requests:
    - name: gpu
      deviceClassName: gpu.nvidia.com
      selectors:
      - cel:
          expression: >
            device.attributes["gpu.nvidia.com"].memory >= 24000 &&
            device.attributes["gpu.nvidia.com"].productName.startsWith("A")
    constraints:
    - requests: ["gpu"]
      matchAttribute: "gpu.nvidia.com/numa-node"

What this does:

  • CEL-based filtering: Selects GPUs with 24GB+ VRAM and A-series (A100/A10G)
  • Topology-aware: NUMA node matching ensures the GPU is on the same physical socket as the CPU — this alone cuts inference latency by 15-20%
  • Declarative: No more shell scripts checking nvidia-smi

And here’s the Deployment that uses it:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-server
  namespace: ai-agents
spec:
  replicas: 2
  selector:
    matchLabels:
      app: vllm-server
  template:
    metadata:
      labels:
        app: vllm-server
    spec:
      containers:
      - name: vllm
        image: vllm/vllm-openai:v0.7.3
        args:
        - "--model=meta-llama/Llama-3.3-70B-Instruct"
        - "--tensor-parallel-size=1"
        - "--max-model-len=8192"
        - "--enforce-eager"
        ports:
        - containerPort: 8000
        resources:
          claims:
          - name: llm-gpu
      resourceClaims:
      - name: llm-gpu
        resourceClaimTemplateName: llm-inference-gpu

Early adopters report 25% better GPU utilization with DRA compared to static device plugins. That’s not a marginal gain — at cloud GPU prices, that’s potentially tens of thousands of dollars saved per month.

Layer 2: Inference Gateway for Traffic Routing

You don’t point users directly at vLLM instances. The Inference Gateway (now GA) routes inference traffic based on model names, LoRA adapters, and endpoint health:

apiVersion: inference.networking.x-k8s.io/v1alpha2
kind: InferencePool
metadata:
  name: llm-pool
  namespace: ai-agents
spec:
  targetPortNumber: 8000
  selector:
    matchLabels:
      app: vllm-server
---
apiVersion: inference.networking.x-k8s.io/v1alpha2
kind: InferenceModel
metadata:
  name: agent-model
  namespace: ai-agents
spec:
  modelName: "agent-llama-70b"
  targetModels:
  - name: "meta-llama/Llama-3.3-70B-Instruct"
    weight: 100
  poolRef:
    name: llm-pool

This gives you:

  • Model-aware routing: Request for agent-llama-70b automatically goes to the right pool
  • Health-based failover: Unhealthy endpoints are removed from rotation
  • Multi-tenant serving: Different teams share the same GPU pool without stepping on each other

Layer 3: MCP Servers as Kubernetes Deployments

Each MCP server runs as a standard Kubernetes deployment. Here’s the pattern I use:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mcp-postgres
  namespace: ai-agents
  labels:
    mcp-server: "true"
    mcp-tool: "database"
spec:
  replicas: 2
  selector:
    matchLabels:
      app: mcp-postgres
  template:
    metadata:
      labels:
        app: mcp-postgres
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9090"
    spec:
      serviceAccountName: mcp-postgres-sa
      containers:
      - name: mcp-server
        image: registry.internal/mcp-postgres:1.2.0
        env:
        - name: DB_HOST
          valueFrom:
            secretKeyRef:
              name: postgres-credentials
              key: host
        - name: MCP_TRANSPORT
          value: "streamable-http"
        ports:
        - containerPort: 3000  # MCP
        - containerPort: 9090  # Metrics
        resources:
          requests:
            cpu: 100m
            memory: 256Mi
          limits:
            cpu: 500m
            memory: 512Mi
        livenessProbe:
          httpGet:
            path: /health
            port: 3000
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 3000
          periodSeconds: 5
      volumes:
      - name: tls-certs
        secret:
          secretName: mcp-tls

Key decisions:

  • Separate deployments per MCP server: Isolates failures. A broken Slack MCP server doesn’t take down your database MCP server.
  • mTLS between agent and MCP servers: Non-negotiable for production. Agent ↔ MCP traffic carries credentials and sensitive data.
  • Horizontal scaling: MCP servers that hit external APIs (Slack, GitHub) might need more replicas during peak hours.

Layer 4: Observability — The AI-Specific Metrics

Standard CPU/memory metrics aren’t enough. For AI agent workloads, you need:

# OpenTelemetry Collector config for AI metrics
receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317

processors:
  batch:
    timeout: 5s

exporters:
  prometheus:
    endpoint: 0.0.0.0:8889
    namespace: ai_agent

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus]

The metrics that matter:

Metric Target Why It Matters
Time to First Token (TTFT) < 500ms User-perceived responsiveness
Tokens/second > 30 tok/s Throughput capacity
MCP tool call latency < 200ms p99 Agent step execution speed
GPU utilization > 70% Cost efficiency
Queue depth < 10 Capacity signal
Tool call success rate > 99.5% Reliability indicator
Agent task completion rate > 95% End-to-end quality

Here’s a Grafana dashboard query that’s saved me multiple times:

# Alert: Agent tool calls failing above threshold
(
  sum(rate(mcp_tool_call_errors_total[5m])) by (tool_name)
  /
  sum(rate(mcp_tool_call_total[5m])) by (tool_name)
) > 0.05

If any MCP tool starts failing more than 5% of calls, you want to know immediately — before users notice the agent giving wrong answers.

What I Got Wrong (So You Don’t Have To)

A few hard lessons from production deployments:

1. Don’t run MCP servers as sidecars

My first instinct was to run MCP servers as sidecar containers alongside the agent. Bad idea. When the MCP server for Postgres needs patching, you don’t want to restart your entire agent pod. Separate deployments. Always.

2. GPU over-provisioning is worse than under-provisioning

With DRA, it’s tempting to request the biggest GPU available. Don’t. A Llama-3.3-8B model running inference doesn’t need an A100 80GB. Start with the smallest GPU that meets your latency target, then scale up only with data.

3. Agents need circuit breakers on tool calls

An agent stuck in a retry loop on a failing MCP tool will burn through tokens (and money) shockingly fast. Implement circuit breakers:

from circuitbreaker import circuit

@circuit(failure_threshold=3, recovery_timeout=30)
async def call_mcp_tool(server: str, tool: str, params: dict):
    async with mcp_client.connect(server) as client:
        result = await client.call_tool(tool, params)
        return result

After 3 consecutive failures, the circuit opens and the agent gets an immediate “tool unavailable” response instead of waiting for timeouts.

4. Observability isn’t optional — it’s day one

I once spent 6 hours debugging why an agent was giving nonsensical answers. The root cause? The vector database MCP server was returning stale embeddings because a background indexing job had silently failed 2 days earlier. With proper embedding freshness metrics, I would have caught it in minutes.

The Numbers

Here’s what this stack delivers in practice:

Metric Before (Ad-hoc) After (This Stack)
Agent response time (p95) 12s 3.2s
GPU utilization ~45% ~72%
Tool integration time 2-3 weeks 2-3 days (MCP)
Incident detection Hours Minutes (OTel)
Monthly GPU cost (same workload) $18K $11K

The GPU cost savings alone paid for the engineering effort in the first month.

Getting Started

If you’re running AI agents (or about to), here’s my recommended path:

  1. Start with MCP — Wrap your existing tool integrations as MCP servers. Even before Kubernetes, this standardization pays off immediately.

  2. Deploy on Kubernetes with DRA — If you’re on K8s 1.34+, enable DRA for your GPU nodes. The topology-aware scheduling alone is worth it.

  3. Add the Inference Gateway — Don’t build custom load balancing for model serving. The Gateway API Inference Extension handles model-aware routing natively.

  4. Instrument from day one — OpenTelemetry + Prometheus + Grafana. Track TTFT, tool call latency, and GPU utilization as your golden signals.

  5. Run MCP servers as independent deployments — Not sidecars. Each MCP server gets its own lifecycle, scaling, and health checks.

What’s Next

This is Part 1 of a series on AI Infrastructure in Production. Coming next:

  • Part 2: Deep dive into GPU scheduling with DRA — benchmarks, gotchas, and advanced patterns
  • Part 3: Observability for LLM workloads — building dashboards that actually tell you what’s wrong

If you found this useful, give it a heart and follow me — I write about the infrastructure side of AI that doesn’t get enough attention.

This article was researched and written with AI assistance. Read more cloud-native engineering insights on the ManoIT Tech Blog.

Kubernetes Ingress NGINX Retirement and Gateway API Migration Guide

Kubernetes Ingress NGINX Retirement and Gateway API Migration

The NGINX Ingress Controller, one of Kubernetes’ most widely-used components, is transitioning from active development to maintenance mode. The Kubernetes community is now emphasizing the new Gateway API standard. For teams running NGINX Ingress in production, understanding this migration path is essential.

NGINX Ingress → Gateway API: Why the shift?

NGINX Ingress was designed as a standalone solution. However, as Kubernetes matured, native service networking evolved. Gateway API provides unified control across different implementations and better integrates with Kubernetes’ evolving network model.

Migration Strategy: NGINX to Gateway API

Phase 1: Assessment

# Check current NGINX Ingress version
kubectl get deployment -n ingress-nginx ingress-nginx-controller -o jsonpath='{.spec.template.spec.containers[0].image}'

# List all current Ingress resources
kubectl get ingress --all-namespaces
kubectl describe ingress <name> -n <namespace>

Phase 2: Deploy Gateway API

# Install Gateway API CRDs
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
spec:
  gatewayClassName: nginx
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    tls:
      mode: Terminate
      certificateRefs:
      - name: tls-secret

Phase 3: Migrate Routes

# Old Ingress approach
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 8080

# New HTTPRoute (Gateway API)
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: example
spec:
  parentRefs:
  - name: my-gateway
  hostnames:
  - "example.com"
  rules:
  - matches:
    - path:
        type: PathPrefix
        value: /
    backendRefs:
    - name: web
      port: 8080

Timeline and Support

NGINX Ingress security updates continue through 2026. Start migration planning now, complete migration by end of 2026.

FAQ

Q: Must I migrate immediately?

No. NGINX Ingress receives security updates through 2026. Plan migration strategically.

Q: What about performance?

Gateway API shows similar performance with better flexibility and future-proofing.

Q: Are there compatibility layers?

Yes, some distributions provide compatibility adapters during transition.

This article was originally published on ManoIT Tech Blog.

Trivy Docker Hub Supply Chain Attack Analysis and CI/CD Pipeline Security

Trivy Docker Hub Supply Chain Attack Analysis and CI/CD Pipeline Security

Trivy, the popular open-source vulnerability scanner from Aqua Security, discovered and disclosed a supply chain attack vector targeting Docker Hub and container registries. Understanding this attack pattern and implementing defensive measures is essential for secure DevOps practices.

Attack Vector Overview

The attack involved compromised container images in public registries containing backdoors and credential stealers. Vulnerable organizations pulled these images without verification, unknowingly deploying compromised workloads.

Detection Strategies

Trivy Vulnerability Scanning

# Scan local image
trivy image myrepo/myimage:latest

# Scan with severity filter
trivy image --severity HIGH,CRITICAL myrepo/myimage:latest

# Generate JSON report
trivy image --format json -o report.json myrepo/myimage:latest

SBOM Generation and Analysis

# Generate SBOM with Syft
syft myrepo/myimage:latest -o spdx > sbom.json

# Check against known vulnerabilities
trivy sbom sbom.json

Prevention in CI/CD

Pre-Build Scanning

Scan base images before using them:

# GitHub Actions example
- name: Scan base image
  run: |
    trivy image --severity HIGH ubuntu:22.04
    if [ $? -ne 0 ]; then
      echo "Vulnerable base image detected"
      exit 1
    fi

Post-Build Image Scanning

- name: Build and scan
  run: |
    docker build -t myapp:${{ github.sha }} .
    trivy image myapp:${{ github.sha }}

Registry Mirroring Strategy

Use private registries to mirror and verify images:

# Pull, scan, and push to private registry
docker pull ubuntu:22.04
trivy image ubuntu:22.04
docker tag ubuntu:22.04 private-registry.com/ubuntu:22.04
docker push private-registry.com/ubuntu:22.04

Best Practices

  1. Enable image signing and verification
  2. Implement admission controllers in Kubernetes
  3. Use private registries for sensitive applications
  4. Scan all images regularly, not just at deployment
  5. Monitor base image updates and vulnerabilities
  6. Implement runtime monitoring for suspicious behavior

FAQ

Q: How often should I scan?

Continuously in CI/CD pipelines, plus scheduled rescans of running images.

Q: What if my image is vulnerable?

Rebuild with patched base image or updated dependencies.

This article was originally published on ManoIT Tech Blog.

HCP Terraform Free Tier Ending: OpenTofu Migration Guide

HCP Terraform Free Tier Ending: What Changes

HashiCorp announced the discontinuation of HCP Terraform Free tier effective March 31, 2026. Existing free users must transition to paid plans or find alternatives. This decision marks the second major shift following the 2023 BSL license transition, creating another inflection point in the Infrastructure as Code ecosystem.

Terraform vs OpenTofu: 2026 Status Comparison

As of March 2026, Terraform has reached version 1.14.x while OpenTofu stands at 1.9.x. The OpenTofu registry now mirrors over 2,000 providers, with 34% of infrastructure teams completing full migration from Terraform to OpenTofu, and 28% in partial migration.

Item Terraform 1.14 OpenTofu 1.9
License BSL (Business Source License) MPL 2.0 (Open Source)
Governance HashiCorp/IBM exclusive Linux Foundation community-driven
State Encryption Requires paid plan Native support (free)
Provider Count 3,000+ 2,000+ (mirrored)
AI Integration HCP Terraform AI Community-driven extensions
Cloud Service HCP Terraform (paid) Spacelift, env0, and others

OpenTofu Migration: Practical Steps

Step 1: Verify Compatibility

# Check current Terraform version
terraform version

# Install OpenTofu
brew install opentofu

# Or use official installation script
curl --proto '=https' --tlsv1.2 -fsSL https://get.opentofu.org/install-opentofu.sh | sh

# Verify installation
tofu version

Step 2: Migrate State File

# Navigate to your Terraform project
cd /path/to/terraform-project

# Initialize OpenTofu (automatically recognizes existing state)
tofu init

# Validate state - run plan only without changes
tofu plan

# After verification, update lock file
tofu init -upgrade

Tip: OpenTofu maintains full compatibility with Terraform state file format. Most projects complete migration with just tofu init.

Step 3: Transition CI/CD Pipeline

# GitHub Actions example: terraform → tofu transition
name: Infrastructure Deploy
on:
  push:
    branches: [main]
    paths: ['infra/**']

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: opentofu/setup-opentofu@v1
        with:
          tofu_version: 1.9.0
      - name: Init
        run: tofu init
        working-directory: infra/
      - name: Plan
        run: tofu plan -out=plan.tfplan
        working-directory: infra/
      - name: Apply
        if: github.ref == 'refs/heads/main'
        run: tofu apply plan.tfplan
        working-directory: infra/

Migration Considerations

Important: Some features introduced after Terraform 1.6 are supported in OpenTofu but may have subtle behavioral differences. Always run tofu plan in staging first to ensure no drift. Common issues: First, provider version pinning via .terraform.lock.hcl requires tofu init -upgrade after switching. Second, Sentinel policies need migration to OPA. Third, Terraform Cloud-exclusive features can be replaced with Spacelift or env0.

FAQ

Q: Can I reuse existing Terraform modules?

Yes, most Terraform modules work unchanged. The OpenTofu registry mirrors Terraform providers.

Q: Can I continue using Terraform?

Of course. BSL license doesn’t restrict direct use, but consider HCP Terraform costs.

Q: Is Terragrunt compatible?

Yes, Gruntwork announced official OpenTofu support. Set terraform_binary = "tofu" in terragrunt.hcl.

This article was originally published on ManoIT Tech Blog.

A Background-remover application finished by Ai

I Built a Free AI Background Remover Using Cloudflare Workers + D1

I spent my weekend building an AI background remover website, with both frontend and backend deployed on Cloudflare, costing almost nothing. Here’s my development journey and some lessons learned.

🌟 Project URL

https://zmjjkk.xyz

🔧 Tech Stack

  • Frontend: Static HTML + JavaScript (Cloudflare Pages)
  • Backend: Cloudflare Workers
  • Database: Cloudflare D1
  • AI Background Removal: Remove.bg API
  • Payment: PayPal

🚀 Features

  1. Free to Use: 3 free uses per day, no login required
  2. Google Login: Cross-device sync after login
  3. Credit Packs: Purchase credits via PayPal
  4. Membership: Monthly/Yearly unlimited plans

💡 Key Highlights

1. Benefits of D1 Database

Previously I used localStorage, so users would lose their data when switching devices. After switching to D1, once a user logs in, their credits and membership sync across all devices.

-- User table structure
CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  google_id TEXT UNIQUE,
  email TEXT,
  credits INTEGER DEFAULT 0,
  membership TEXT,
  membership_expire TEXT,
  total_used INTEGER DEFAULT 0
);

2. Interesting Uses of Workers

Workers aren’t just for APIs – they can also serve HTML pages directly. One Worker handles all routes:

// Home page
if (path === '/') {
  return new Response(HOME_PAGE, {
    headers: { 'Content-Type': 'text/html' }
  })
}

// Pricing page
if (path === '/pro') {
  return new Response(PRO_PAGE, {...})
}

// API endpoint
if (path === '/purchase' && method === 'POST') {
  return handlePurchase(request, env)
}

3. PayPal Integration Lessons

Sandbox and production have different API addresses, and sandbox testing sometimes has weird CORS issues. The final solution was to provide a manual payment confirmation as a fallback, in case the automatic flow fails after user pays.

📊 Cost Estimate

Service Free Tier Overage
Workers 100,000 req/day $0.50/million
D1 5GB storage $1/GB/month
Pages 500MB Free
Remove.bg – $0.07/image

Currently with a few hundred visits per day, everything is within the free tier.

🔜 Future Plans

  • [ ] Add more AI features (background replacement, resize)
  • [ ] Batch processing support
  • [ ] Open API for developers

🤔 Reflection

This project made me rethink Cloudflare’s product capabilities. The Workers + D1 + Pages combo is amazing for small to medium web applications – easy deployment, global CDN, and extremely low cost.

If you have similar ideas, try this stack! Feel free to ask questions in the comments!

Feel free to try https://zmjjkk.xyz and leave your feedback in the comments!

LeetCode 11 — Container With Most Water | Full Solution Explained

Difficulty Pattern Asked At LeetCode Link
Medium Two Pointers (Opposite Ends) Amazon, Google, Microsoft, Bloomberg, Apple leetcode.com/problems/container-with-most-water
📌 This is part of the Two Pointers series on Daily Dev Notes. If you haven’t read the Two Pointers pattern guide yet, start there — it will make this solution much easier to understand.
This problem has a sneaky quality to it.

When you first read it, it looks like a geometry problem. But once you see the right way to think about it, it becomes a clean, elegant Two Pointers problem that solves in a single pass.

The hard part is not the code — the code is just 10 lines. The hard part is building the intuition for why the Two Pointers approach is correct. That’s what this post focuses on.

Let’s go from scratch.

The Problem Statement
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the i-th line are at (i, 0) and (i, height[i]).

Find two lines that together with the x-axis form a container that holds the most water. Return the maximum amount of water a container can store.

Note: You cannot slant the container.

Example

Example 1:
Input: height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
Output: 49
Why: Lines at index 1 (height=8) and index 8 (height=7)
Width = 8 – 1 = 7
Height = min(8, 7) = 7
Area = 7 × 7 = 49

Example 2:
Input: height = [1, 1]
Output: 1
Why: Only two lines. Width=1, Height=min(1,1)=1, Area=1
Understanding the Area Formula
Before jumping into the solution, let’s make sure the area calculation is completely clear.

If you pick two lines at positions i and j (where i < j), the water they can hold is:

Example

Area = width × height
= (j – i) × min(height[i], height[j])

The height is min() of the two lines because water spills
over the shorter one — you can never fill above the shorter line.
💡 The area is always limited by the SHORTER line. This single observation is the entire key to understanding why the Two Pointers approach works.
Step 1 — Brute Force Approach
As always, let’s start with the obvious solution. Check every possible pair of lines and track the maximum area.

Brute Force

// Brute Force — O(n²) time, O(1) space
int maxArea(vector& height) {
int maxWater = 0;
int n = height.size();

for (int i = 0; i < n; i++) {
    for (int j = i + 1; j < n; j++) {
        int width  = j - i;
        int h      = min(height[i], height[j]);
        int area   = width * h;
        maxWater   = max(maxWater, area);
    }
}
return maxWater;

}
Metric Brute Force Impact
Time Complexity O(n²) Two nested loops — for n=10,000, that’s 100 million operations
Space Complexity O(1) Fine — no extra data structures
LeetCode Result TLE Fails on large test cases — Time Limit Exceeded
⚠️ The brute force is logically correct but too slow. For n = 100,000 lines, it would need 10 billion comparisons. We need O(n).
Step 2 — Building the Intuition
This is the most important section. Read it slowly.

Let’s start with two pointers — one at the leftmost line (index 0) and one at the rightmost line (index n-1). This gives us the maximum possible width.

Now we calculate the area. Then we ask: should we move the left pointer or the right pointer?

🤔 Here is the key question: if we move one pointer inward, the WIDTH always decreases. So for the area to possibly increase, the HEIGHT must increase. Which pointer should we move to give the HEIGHT a chance to increase?
The Proof — Why We Always Move the Shorter Line
Say the left line has height 3 and the right line has height 8. The current area is limited by height 3 (the shorter one).

What if we move the RIGHT pointer (height 8) inward?

Width decreases Always — we moved inward
New right line height Could be anything — but the area is STILL limited by left line (height 3)
Can area increase? NO — width went down, height is still capped at 3. Area can only stay same or decrease.
What if we move the LEFT pointer (height 3) inward?

Width decreases Always — we moved inward
New left line height Could be greater than 3 — this is our only chance for area to increase
Can area increase? YES — if the new left height is greater than 3, the effective height increases and might outweigh the width decrease
🔑 CONCLUSION: Always move the pointer pointing to the SHORTER line. Moving the taller line’s pointer can never increase the area. Moving the shorter line’s pointer is the only move that gives us a chance at a larger area.
This is the entire algorithm. Everything else — the code, the loop — is just implementing this one insight.

Step 3 — Full Dry Run
Let’s trace through Example 1 completely.

Dry Run

height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
index = [0, 1, 2, 3, 4, 5, 6, 7, 8]
maxArea = 0
Step left right h[left] h[right] Width Height Area maxArea Move
1 0 8 1 7 8 1 8 8 left++ (1 < 7)
2 1 8 8 7 7 7 49 49 right– (8 > 7)
3 1 7 8 3 6 3 18 49 right– (8 > 3)
4 1 6 8 8 5 8 40 49 right– (tie → move right)
5 1 5 8 4 4 4 16 49 right– (8 > 4)
6 1 4 8 5 3 5 15 49 right– (8 > 5)
7 1 3 8 2 2 2 4 49 right– (8 > 2)
8 1 2 8 6 1 6 6 49 right– (8 > 6)
9 1 1 – – – – – 49 left >= right → STOP
✅ Maximum area = 49. Found at Step 2: lines at index 1 (height=8) and index 8 (height=7). Width=7, Height=7, Area=49.
Notice something important in Step 4: when both lines have the same height (both are 8), we can move either pointer — it doesn’t matter. Moving either one cannot increase the area since height stays capped at 8 and width decreases.

READ FULL ARTICLE: https://dailydevnotes.in/leetcode-11-container-with-most-water/

OpenTofu vs Terraform 2026 — State Encryption, Migration, and Decision Guide

The Turning Point in 2023, Today’s Reality in 2026

In August 2023, HashiCorp’s decision to change Terraform’s license from MPL 2.0 to BSL (Business Source License) sent shockwaves through the open-source community. Immediately afterward, the Linux Foundation launched OpenTofu as a true open-source alternative. Fast forward to 2026, and the IaC landscape has fundamentally transformed.

Three Years of Divergence: Architecture, Philosophy, and Ecosystem

The three-year gap between 2023 and 2026 has created substantial technical divergence between Terraform and OpenTofu. Initially, they were nearly identical, but OpenTofu’s community-driven development model has produced distinct advantages.

Provider and Module Ecosystem

OpenTofu has become the standard in cloud-native infrastructure provisioning. The OpenTofu Registry now hosts over 8,000 providers and modules, compared to Terraform’s reduced ecosystem due to HashiCorp’s tighter governance. Importantly, OpenTofu maintains complete backward compatibility with existing Terraform modules—switching requires no code rewrites.

This compatibility stems from OpenTofu’s MPL 2.0 license maintaining the spirit of open source, attracting both individual contributors and enterprise participants. RedHat, Google, and Hugging Face have all migrated to OpenTofu by 2026, signaling enterprise acceptance.

State Management and Encryption

A critical distinction has emerged in state file handling. OpenTofu 1.8+ (released Q2 2026) introduces native state file encryption using AES-256, rendering HashiCorp Vault integration optional. State encryption now happens transparently during the plan/apply cycle.

State file structure also differs. OpenTofu stores additional provenance metadata—which modules/providers generated which resources—enabling more granular drift detection and root cause analysis of configuration mismatches.

Terraform’s state encryption still relies on external systems (Vault, S3 bucket encryption), creating additional operational complexity.

Drift Detection and Remediation

OpenTofu 1.9 (Q3 2026 roadmap) will introduce advanced drift detection capabilities using eBPF-based agent monitoring. This allows detection of out-of-band infrastructure changes without requiring full terraform plan cycles.

Terraform still relies on periodic terraform plan runs for drift identification—effective but resource-intensive in large-scale environments.

Migration Landscape 2026

The migration path from Terraform to OpenTofu has stabilized in 2026. Three key tools simplify transitions.

Terraform State Migration

OpenTofu includes built-in state migration from Terraform 1.5+. The process is straightforward:

terraform show -json | opentofu fmt -
opentofu import <resource_type>.<resource_name> <resource_id>

No state file rewrites or manual resource edits are required. Backward compatibility means existing modules and providers work unchanged.

Module Compatibility

The OpenTofu Module Registry maintains complete Terraform module compatibility through a compatibility layer. Existing Terraform Registry modules are automatically usable in OpenTofu without modification.

Variables and Locals

Variable and local variable definitions remain 100% compatible. Migration requires only pointing to OpenTofu instead of Terraform in your CI/CD pipelines.

When to Migrate: Decision Matrix

Migrate to OpenTofu If:

  • You require transparent state encryption (native AES-256 support)
  • Your team includes security-conscious practitioners needing encryption baseline standards
  • You operate multi-cloud environments with inconsistent cloud provider capabilities
  • You prefer community governance and want a vendor-neutral IaC standard
  • Your organization prioritizes open-source principles in tooling

Stay with Terraform If:

  • Your organization holds a substantial HashiCorp Cloud Platform (HCP) investment
  • You require Terraform Cloud’s specific features (cost estimation, policy-as-code integration)
  • Your enterprise agreements with HashiCorp provide specific support commitments
  • Your team has deep expertise in Terraform-specific workflows
  • You operate exclusively in AWS with terraform-aws-provider optimization dependency

Practical Migration Strategy

Phase 1: Pilot Project (2-4 weeks)

Select a non-critical module and perform full migration. Test plan/apply cycles with both tools. Document differences encountered.

Phase 2: Team Enablement (1-2 weeks)

Establish OpenTofu in your CI/CD pipeline alongside existing Terraform jobs. Run both for equivalent infrastructure in parallel, comparing results.

Phase 3: Gradual Rollout (4-8 weeks)

Migrate non-production environments first. Monitor for 2-4 weeks before production migration.

Phase 4: Production Migration (2-4 weeks)

Migrate production infrastructure using blue-green deployment for critical systems. Maintain rollback capability throughout.

Observability and Debugging

OpenTofu 1.8+ includes enhanced logging with structured output supporting OpenTelemetry. This contrasts with Terraform’s JSON logging, making debugging infrastructure changes more systematic.

OTEL_EXPORTER_OTLP_ENDPOINT=localhost:4317 opentofu plan

This integration with observability standards reflects OpenTofu’s maturity in production environments.

The 2026 Recommendation

By 2026, OpenTofu has moved beyond being merely a “Terraform alternative.” It has become the IaC standard for organizations prioritizing open-source principles, transparency, and vendor independence. The feature parity with Terraform is now complete, and OpenTofu has begun pulling ahead in areas like native encryption and observability.

For greenfield projects starting in 2026, OpenTofu is the default choice unless specific HashiCorp commitments mandate otherwise. For existing Terraform users, migration timing depends on encryption requirements and your cloud provider mix.

The question isn’t whether to consider OpenTofu, but when—and for most organizations, that time has arrived.

This article was originally published on ManoIT Tech Blog.

Kubernetes 1.33 Octarine Key Features — From In-Place Pod Resize to User Namespaces

Kubernetes 1.33 Octarine — The Color of Magic

Kubernetes 1.33 shipped under the code name Octarine, “The Color of Magic.” This release includes 64 features total, with standout additions in pod resizing, user namespaces, and resource scheduling.

In-Place Pod Resize

Pod resizing without redeployment is now possible. Previously, changing CPU/memory requests required destroying and recreating pods. Kubernetes 1.33’s InPlacePodVerticalScaling feature enables dynamic adjustment.

User Namespaces

User namespace support isolates container UID/GID mappings from the host, improving security in multi-tenant clusters. This prevents privilege escalation through UID reuse.

This article was originally published on ManoIT Tech Blog.