Field Notes Blog cover
Architecture

EKS or Managed Agent Runtime? A Framework for the Decision You'll Face Twice

The migration looked straightforward. Then we found five categories of blockers. Here's the framework we wish we'd had before we started.

A
Ashutosh Upadhyay
Platform Engineering · Johnson & Johnson Innovative Medicine · August 2026

Updated 4 October 2026 with technical corrections.

We run a live multi-agent AI research system on self-managed EKS. It handles a 4-stage pipeline — Data Scout, Analyst, Synthesizer, Critic — each running in its own Kubernetes pod, communicating over HTTP with circuit breakers, instrumented with OpenTelemetry traces flowing through an ADOT sidecar into both CloudWatch and a Langfuse instance we control.

When a managed agent runtime became available, the pitch was compelling: no Kubernetes manifests, no Karpenter NodePools, no HPA tuning, built-in session state, managed identity, automatic scaling. We spent two weeks building a structured comparison. We found five categories of blockers that no single page of the documentation spells out. This is the framework.

What "Managed Runtime" Actually Means

Before getting to the blockers, it's worth being precise about what you're trading. Most teams entering this comparison have a fuzzy mental model that leads to surprises in both directions.

What you give up:

What you gain:

What stays your problem regardless of which path you take:

The key insight: the hard parts of running an AI agent system are mostly in your tool code, your prompts, and your data pipelines. The managed/self-managed boundary sits above all of that. Don't expect a runtime migration to simplify the parts that are actually hard.

The Five Blocker Categories

We categorize blockers by what they require to resolve, not by how alarming they sound. A blocker that requires a two-line IAM change is different from one that requires re-architecting your observability stack.

Blocker Category Severity Resolution Cost
① Multi-agent operational multiplication Multi-agent orchestration High Validate against your specific framework before any migration work
② Observability routing Backend fan-out constraint Medium Choose CloudWatch (default) or custom backend; dual in-process export unverified
③ Admin API surface Operational workflow disruption Medium Separate deployment for admin services, new authentication wiring
④ Identity federation IAM trust policy change Medium Add service principal to existing role; review policies conditioned on network origin or session name
⑤ Cold start Latency regression risk Medium Session reuse via runtimeSessionId eliminates within-session cold starts; benchmark across sessions

Blocker 1: Multi-Agent Migration Cost

If your agent uses an orchestration framework — Strands, LangGraph, CrewAI, or a custom multi-agent pattern — the managed runtime does support multi-agent architectures, but the migration is not a simple port. Our system runs a four-stage pipeline where each stage is a separate pod: Data Scout gathers evidence from 20+ data sources, Analyst runs statistical analysis, Synthesizer integrates evidence, Critic adversarially verifies the synthesis before it reaches the user.

In a managed runtime, four pipeline stages map to four runtimes — each needing its own artifact (container image or code bundle), its own execution role, and its own deployment. The first-class A2A (Agent-to-Agent) protocol is supported natively (port 9000, agent cards at /.well-known/agent-card.json), and on the instance-based compute type, agents can share a session to collaborate. But the in-cluster HTTP mesh with custom circuit breakers becomes InvokeAgentRuntime API calls whose retry semantics you don't own. That's real migration cost — multiplied by N stages — even though the architecture isn't fundamentally flattened.

Check before you start: Map your multi-agent topology to the managed runtime's execution model before writing a single line of migration code. If your stages have different tool registries, different LLM models, or different concurrency policies, count the number of runtimes × artifacts × roles you'll need to maintain. The architecture survives; the operational surface multiplies.

Blocker 2: Observability Routing Choice

ADOT (AWS Distro for OpenTelemetry) is supported inside the managed runtime — you add aws-opentelemetry-distro>=0.18.0 to your requirements and run under opentelemetry-instrument python main.py (the platform's CLI does this for you). What is not supported is the ADOT Collector sidecar, because there's no pod to attach it to.

The constraint this creates is routing: the collector sidecar pattern lets you fan-out to multiple backends simultaneously — CloudWatch for infra metrics, Langfuse for LLM traces, X-Ray for distributed tracing — from a single collector config. Without the sidecar, you must choose. The runtime's default ADOT configuration exports to CloudWatch. If you want a different backend (Langfuse, Honeycomb, Grafana Cloud), set DISABLE_ADOT_OBSERVABILITY=true and export directly from your application using an instrumentation library. AWS explicitly supports OpenInference, Openllmetry, OpenLit, and Traceloop — all of which are Langfuse-ingestible.

Dual in-process exporters (CloudWatch and Langfuse simultaneously via code) are undocumented and unverified at scale. If you've built your debugging workflow around correlating Langfuse LLM spans with CloudWatch infra metrics, you'll need to validate that the in-process pattern replicates that correlation before committing to migration.

Blocker 3: Admin API Routes

Production agent systems accumulate operational APIs alongside the core agent: prompt editing interfaces, skill management, usage dashboards, feedback review, rate limit controls. On EKS, these run as routes on the same FastAPI app or as separate services in the same namespace, all sharing the pod's IRSA credentials and reachable via the same ingress.

In a managed runtime, there is no "same pod." Your admin endpoints need their own deployment — a separate service with its own authentication, its own scaling policy, and its own path through your VPN/proxy. The operational burden doesn't disappear; it moves to a second surface you now have to maintain separately from the agent.

Blocker 4: Identity Federation

On EKS, IRSA (IAM Roles for Service Accounts) works by attaching a role annotation to the Kubernetes service account. The trust policy on the IAM role names the EKS cluster's OIDC provider as the trusted principal.

# EKS IRSA: pod assumes role via OIDC web identity
"Action": "sts:AssumeRoleWithWebIdentity",
"Principal": {
    "Federated": "arn:aws:iam::ACCOUNT_ID:oidc-provider/oidc.eks.REGION.amazonaws.com/id/CLUSTER_ID"
},
"Condition": {
    "StringEquals": {
        "oidc.eks.REGION.amazonaws.com/id/CLUSTER_ID:sub": "system:serviceaccount:NAMESPACE:SERVICEACCOUNT"
    }
}

In a managed runtime, the trusted principal is the runtime service itself, not an OIDC provider:

# Managed runtime: service assumes role directly
"Action": "sts:AssumeRole",
"Principal": {
    "Service": "bedrock-agentcore.amazonaws.com"
},
"Condition": {
    "StringEquals": {
        "aws:SourceAccount": "ACCOUNT_ID"
    },
    "ArnLike": {
        # Use wildcard at creation time — runtime ID isn't known yet (chicken-and-egg)
        "aws:SourceArn": "arn:aws:bedrock-agentcore:REGION:ACCOUNT_ID:*"
    }
}

The key difference: EKS uses sts:AssumeRoleWithWebIdentity via OIDC; managed runtime uses sts:AssumeRole directly from the service principal. You can keep the same role ARN — just add bedrock-agentcore.amazonaws.com as a second trusted principal. Most downstream identity-based policies (DynamoDB, Bedrock) need no changes at all since the role ARN stays the same. Resource-based policies that name the role ARN keep working too — the role hasn't changed. What needs checking is anything keyed to how the call arrives: bucket and key policies with VPC-endpoint, VPC or source-IP conditions (a runtime outside your VPC won't satisfy them), policies that name an assumed-role session, and organisation-level data-perimeter policies. Count those conditions before estimating migration cost; it's usually far fewer than the full list of AWS services your agent touches.

Blocker 5: Cold Start

EKS pods are always warm as long as they're running — no first-request penalty per turn. The first invocation to a new managed runtime session loads the execution environment, which adds latency. For research-oriented workloads where queries take 30–120 seconds, a cold start is negligible. For conversational agents with a <2 second response SLA, it matters.

AgentCore's main mitigation is session reuse: a dedicated microVM is kept alive for invocations that share the same runtimeSessionId. While a session is active, subsequent turns skip the cold start entirely. The practical implication: design your session lifecycle carefully — a session that idles out forces the next turn to cold-start. Benchmark your actual p50/p95 latency across session boundaries before committing to a latency SLA. I found no published cold-start figure, so your own numbers are the only ones that count — and test the snapshot-based platform version, which exists to keep cold starts consistent for large images.

What Changes and What Doesn't

The managed runtime genuinely improves a specific set of problems:

What doesn't change:

The managed runtime solves infrastructure operations, not agent quality. If your team spends most of its time on K8s operations, you'll get significant relief. If your team spends most of its time on prompt engineering, tool correctness, and evaluation, the managed runtime doesn't move that needle.

The Hybrid Answer

For most production teams with existing EKS investments, the right answer isn't "migrate" or "don't migrate" — it's hybrid.

Use the managed platform's Gateway: expose a subset of your agent's tools as an MCP (Model Context Protocol) server. Other agents — internal tools, partner integrations, automated pipelines — can call your agent's capabilities without needing direct API access. The Gateway layer handles authentication, rate limiting, and tool schema publication. Your core agent keeps running on EKS where you have full observability and control.

The hybrid pattern in practice: managed Gateway exposes 3–5 high-value tools (your primary query interface, a key data source, a synthesis capability) as MCP endpoints. Policy and guardrails attach to the Gateway layer. Your main agent on EKS calls the Gateway when acting as an agent consumer, and the Gateway calls back into EKS when external agents need your capabilities. You get the ecosystem integration benefits without the migration risk.

That is the split I'd recommend for a system like ours: AgentCore Gateway as the MCP exposure layer, with the core research agent on EKS — revisit it when the trade-offs above change for your workload.

The Decision Matrix

Use this to locate yourself in the decision space. For each dimension, the cells indicate which migration path is appropriate — not as an absolute rule, but as a starting signal.

Dimension Migrate Now Hybrid Stay on EKS
Cold start tolerance ✓ >5s acceptable ≈ session reuse covers within-session turns ✗ <2s SLA required
Observability stack ✓ CloudWatch-only is fine ≈ re-instrument non-critical paths ✗ CloudWatch+Langfuse fan-out via single collector non-negotiable
Multi-agent framework ✓ Single-agent or simple ≈ Gateway for tool exposure ✗ Complex pipeline with separate pods
Admin API surface ✓ Minimal or none ≈ acceptable to split deployment ✗ Heavy operational UI on same surface
Identity model ✓ Simple, few downstream services ≈ re-wire in phases ✗ Complex OIDC federation across many services
Team K8s burden ✓ >20% of time on infra ops ≈ moderate K8s overhead ✗ <5% time on K8s, features dominate

When to Migrate: Clear Signals

There are scenarios where a full migration is the right call:

Do not migrate if:

The Blockers We Didn't Expect

The five categories above come from mapping the documentation onto our architecture. But we also found issues that weren't documentation problems — they were architectural assumptions we'd made that the managed runtime invalidates.

Port-forwarded admin access. We use kubectl port-forward to access internal admin endpoints from local machines during debugging. In a managed runtime, port-forwarding doesn't exist. You need a proper bastion or VPN path to every management endpoint before you migrate — not after.

PrivateLink setup timeline. Private connectivity is three separate pieces: PrivateLink endpoints for inbound calls, network interfaces in your subnets for runtime egress, and VPC Lattice resource gateways for the tool gateway and identity egress. In practice, provisioning the necessary VPC endpoints, service policies, and DNS records requires networking team involvement and takes 3–5 working days at most enterprise organizations. Budget for this in your migration timeline, not as a same-day task.

Governance sign-off. In a managed runtime, conversation data flows through a vendor-managed execution environment. For healthcare and pharmaceutical organizations, this requires explicit governance review of where data lands, who can access it, and how it's retained. The correct technical answer depends on the compute type: with the Instances compute type, workloads run on EC2 in your account and your VPC. With the default serverless microVM type, your agent runs under your account's execution role — calls are authorised and logged in your account — but the payload is processed in AWS-operated compute, and anything the service stores uses AWS-owned keys by default. If keeping the data in your own account is a requirement, that points to the Instances compute type. Start the governance review early and be precise about which compute type you're evaluating.

Looking Back

The two weeks we spent on the comparison matrix weren't wasted — they surfaced decisions that would have taken months to find in production. The hybrid answer we landed on (Gateway for MCP exposure, EKS for the core agent) is better architecture than either pure option would have been, precisely because the comparison forced us to articulate what we actually need from each layer.

The managed runtime is genuinely good for the problems it solves. It just doesn't solve the problems that are actually hard. For teams evaluating this decision: be honest about where your operational burden lives. If it's in Kubernetes, you'll get significant relief. If it's in agent quality — prompt reliability, tool correctness, evaluation — you'll be just as busy after the migration as before, with a different infrastructure to learn.

Key Takeaways

AWS EKS Agent Runtime Architecture Multi-Agent IAM Migration Kubernetes Observability
Share

Disclaimer: The views and opinions expressed in this post are my own and do not represent those of my employer or any organisation I am associated with.

Comments & Discussion