<?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: Jatin Mehrotra</title>
    <description>The latest articles on DEV Community by Jatin Mehrotra (@jatinmehrotra).</description>
    <link>https://dev.to/jatinmehrotra</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%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg</url>
      <title>DEV Community: Jatin Mehrotra</title>
      <link>https://dev.to/jatinmehrotra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jatinmehrotra"/>
    <language>en</language>
    <item>
      <title>AWS Now Gives You a Free Sandbox Account - No Credit Card, No Cost, 8 Hours to Build (2026)</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Thu, 09 Jul 2026 08:59:39 +0000</pubDate>
      <link>https://dev.to/aws/aws-now-gives-you-a-free-sandbox-account-no-credit-card-no-cost-8-hours-to-build-2026-973</link>
      <guid>https://dev.to/aws/aws-now-gives-you-a-free-sandbox-account-no-credit-card-no-cost-8-hours-to-build-2026-973</guid>
      <description>&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%2Fzlhpei1tnlhzvc236yjh.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%2Fzlhpei1tnlhzvc236yjh.png" alt="annoucement" width="800" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AWS just announced &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/07/aws-builder-center-sandbox/" rel="noopener noreferrer"&gt;free Sandbox environments&lt;/a&gt; which lets any AWS Builder Center user to provision time limited free AWS account &lt;strong&gt;without any credit card, personal account or any sort of cost involved&lt;/strong&gt;. ABSOLUTELY FREE!!!&lt;/p&gt;

&lt;p&gt;In this short blog i will walk through &lt;em&gt;how you can use Sandbox Account and start learning on AWS Absolutely free through Workshops in &lt;strong&gt;just 5 steps&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Don't miss the important caveats around Sandbox environment in the last section.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 1 Log in to Builder Center
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Log into &lt;a href="https://builder.aws.com/" rel="noopener noreferrer"&gt;Builder Center&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You need to have AWS Builder Center Account in order to access Free Sandbox AWS Account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2 Access Workshops for Sandbox Env
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In order to access sandbox AWS Account, you need to navigate to Workshops &lt;/li&gt;
&lt;/ul&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%2F2zrajjcceld8215b9djr.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%2F2zrajjcceld8215b9djr.png" alt="workshops to access aws account" width="800" height="782"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can choose which category, level, type of workshop based on your preference under &lt;code&gt;Discover&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&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%2F69dvvo22cbwlsce6l3zd.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%2F69dvvo22cbwlsce6l3zd.png" alt="Choose workshop preference" width="800" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 Choose Workshops
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3jxyeb2dkvsvl26461ho.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%2F3jxyeb2dkvsvl26461ho.png" alt="choose workshops" width="800" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Once you selected your choice of workshop, click on &lt;code&gt;Request free sandbox environment&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; At a time you can only choose 1 Workshop as Sandbox environment is limited to 1 at a time&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;In my case i chose &lt;code&gt;Building and scaling Agentic AI workflows&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click on Request&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fkuhgpdm0130b6wd07d8r.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%2Fkuhgpdm0130b6wd07d8r.png" alt="Click on Request" width="654" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You will get &lt;em&gt;2 notification of environment being prepared and when it is ready to use&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 4 Accessing workshop
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqzfu1o3g9fv2tyt31ycc.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%2Fqzfu1o3g9fv2tyt31ycc.png" alt="Access workshop" width="800" height="520"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Under &lt;code&gt;Your Workshops&lt;/code&gt; click on &lt;code&gt;Go to Free sandbox environment&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Complete the steps of joining workshop (accept the terms), you will be asked for email or builder center ID to recieve a code&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2F1d430hxp087r1i2kjlay.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%2F1d430hxp087r1i2kjlay.png" alt="join workshop" width="800" height="397"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdxpdh5jztj1fiiurtipk.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%2Fdxpdh5jztj1fiiurtipk.png" alt="access code for workshop" width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5 Access AWS Account through Console
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once you recieve code for workshop, you will see workshop screen, &lt;em&gt;explaining about the workshop&lt;/em&gt; and &lt;strong&gt;how to proceed with workshop like actual building steps like clicking on Lab 1 to explain different modules&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;And from there you can access the &lt;code&gt;AWS account through Console&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&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%2Fb770n4cvuyxeila1ra1p.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%2Fb770n4cvuyxeila1ra1p.png" alt="aws console access" width="800" height="399"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6 Go build on AWS
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Once you are inside AWS console, you can follow the steps mentioned in the workshop and start learning and building on AWS &lt;/li&gt;
&lt;/ul&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%2Fpg8qkc7s6ubvtgtfkd4f.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%2Fpg8qkc7s6ubvtgtfkd4f.png" alt="workshop steps" width="799" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can see &lt;strong&gt;resources are already created for you in your account for the workshop&lt;/strong&gt;. This happened while account was being prepared &lt;/li&gt;
&lt;/ul&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%2Fdzfo6a7n17mfe13iufla.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%2Fdzfo6a7n17mfe13iufla.png" alt="aws account cosole with resources" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Few things to Note about sandbox accounts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;At the time of launch you can &lt;strong&gt;only create, read, modify and delete  resources mentioned in the workshop&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Account permissions are scoped only to those resources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Your AWS account is  time-boxed to 8 hours&lt;/strong&gt;, starting from when the environment is prepared&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One sandbox environment per week limit&lt;/strong&gt;: You can request 1 sandbox environment per week. The weekly limit &lt;strong&gt;resets every Sunday&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>awsbuildercenter</category>
      <category>freeawsaccount</category>
      <category>learnwithaws</category>
    </item>
    <item>
      <title>I Built PR Preview Environments With AWS Lambda MicroVMs and Cut Staging Costs by 78%</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Tue, 07 Jul 2026 04:15:07 +0000</pubDate>
      <link>https://dev.to/aws/i-built-pr-preview-environments-with-aws-lambda-microvms-and-cut-staging-costs-by-78-2d3i</link>
      <guid>https://dev.to/aws/i-built-pr-preview-environments-with-aws-lambda-microvms-and-cut-staging-costs-by-78-2d3i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;On June 22, 2026, AWS released Lambda MicroVMs and &lt;a href="https://dev.to/aws-builders/aws-lambda-microvms-your-ai-agent-can-write-code-but-should-it-execute-it-1ja4"&gt;I also covered how it works and how your agents can use it&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That got me thinking, &lt;strong&gt;if Lambda MicroVMs suspend when idle and cost $0 while paused, why not use them as pull request preview environments?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your typical staging runs 730 hours/month while reviewers use it for 50 minutes. &lt;strong&gt;You're paying for 93% idle time. Lambda MicroVMs flip this. Suspend when idle, resume in under 2 seconds, pay $0 while paused.&lt;/strong&gt; The result: &lt;code&gt;saves 78% vs standalone staging&lt;/code&gt; and &lt;code&gt;93% vs EKS&lt;/code&gt;, with zero infrastructure to manage, no cluster upgrades, no ALB configuration.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;In this blog, I'll show you how to build dynamic PR environments with Lambda MicroVMs, &lt;strong&gt;real cost breakdown&lt;/strong&gt;, and &lt;strong&gt;share the production lessons I learned building this solution&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the people who want to jump straight in to trying the solution, &lt;a href="https://github.com/jatinmehrotra/DA_content/tree/master/Blog/dynamic-pr-environment" rel="noopener noreferrer"&gt;follow my repo here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The Staging Bottleneck Problem&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Solution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to Test This&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost: Lambda MicroVMs vs Shared Staging vs EKS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Production Tips for Lambda MicroVMs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From DevOps Perspective&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The Staging Bottleneck Problem
&lt;/h2&gt;

&lt;p&gt;Most enterprise teams have the same problem where &lt;strong&gt;staging environments are a bottleneck&lt;/strong&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%2Frseb4e2ibzox43k322dq.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%2Frseb4e2ibzox43k322dq.png" alt="staging problem" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Developer A deploys their feature and QA starts testing. &lt;strong&gt;Developer B has to wait&lt;/strong&gt;, then Developer C deploys another change. Suddenly, reviewers are testing multiple developers' code instead of a single pull request. &lt;strong&gt;Debugging becomes harder, feedback slows down, and the staging environment keeps running 24/7 even when nobody is using it&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Existing solutions all had trade-offs&lt;/code&gt;; shared staging, Kubernetes namespaces  with always-on costs, or frontend-only preview platforms like Vercel and Netlify.&lt;/p&gt;

&lt;p&gt;What I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Each PR gets its own isolated environment&lt;/strong&gt; (VM-level, not container)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reviewers click a link in the PR comment&lt;/strong&gt; and see the app running with that PR's code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR closes, environment dies&lt;/strong&gt; (data cleaned up, nothing left running)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;$0 compute cost while idle&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lambda MicroVMs gave me exactly this&lt;/strong&gt;. Suspend/resume is the killer feature here. The MicroVM suspends after 5 minutes of no traffic and resumes in under 2 seconds when the reviewer comes back. While suspended: $0 compute.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnllqfyo0p85fnbjjnppz.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%2Fnllqfyo0p85fnbjjnppz.png" alt="architecture" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Every pull request creates its own MicroVM, receives a unique preview URL, automatically suspends when idle, and is destroyed when the PR closes.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dynamic-pr-environment/
├── microvm-image/
│   ├── app.py              # Flask app + lifecycle hooks
│   ├── Dockerfile          # Based on al2023-minimal
│   └── requirements.txt    # flask, gunicorn, boto3
├── proxy/
│   └── handler.py          # Auth proxy Lambda (token validation + JWE forwarding)
├── infra/
│   ├── main.tf             # S3, DynamoDB, OIDC, IAM roles
│   ├── proxy.tf            # Proxy Lambda + Function URL + permissions
│   ├── outputs.tf
│   └── variables.tf
└── .github/workflows/
    ├── pr-deploy.yml        # Deploy on PR open/push
    └── pr-cleanup.yml       # Cleanup on PR close
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every pull request creates its own MicroVM, receives a unique preview URL, automatically suspends when idle, and is destroyed when the PR closes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The App
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;The demo application is a full-stack task manager&lt;/strong&gt;. &lt;a href="https://github.com/jatinmehrotra/DA_content/blob/master/Blog/dynamic-pr-environment/microvm-image/app.py" rel="noopener noreferrer"&gt;A Flask web app&lt;/a&gt; serving HTML on the frontend with a REST API (POST/DELETE) that persists tasks to DynamoDB. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Each PR gets its own DynamoDB partition (PR#), so reviewers see only that PR's data. Reviewers can add and delete tasks directly in the preview environment&lt;/strong&gt;. Once the PR is closed, all DynamoDB data for that partition is automatically cleaned up&lt;/p&gt;

&lt;h3&gt;
  
  
  App code
&lt;/h3&gt;

&lt;p&gt;Two Flask servers in one process:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Port 9000&lt;/strong&gt; (hooks server, started first in background thread): Handles &lt;code&gt;/ready&lt;/code&gt;, &lt;code&gt;/run&lt;/code&gt;, &lt;code&gt;/suspend&lt;/code&gt;, &lt;code&gt;/resume&lt;/code&gt;, &lt;code&gt;/terminate&lt;/code&gt; hooks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Port 8080&lt;/strong&gt; (app server, main thread): Serves the actual web app
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# First Hooks server starts FIRST (Lambda sends /ready here during image build)
&lt;/span&gt;&lt;span class="n"&gt;hooks_thread&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&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;start_hooks_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daemon&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;hooks_thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Second Then app server
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Lifecycle Hooks?
&lt;/h3&gt;

&lt;p&gt;Lambda MicroVMs are snapshot-based. The image is frozen during build and restored whenever a MicroVM starts. &lt;strong&gt;Hooks let you customize each lifecycle stage.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Role of hooks in this solution:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;/ready (during image build)&lt;/strong&gt; - Flask app starts, responds 200, Lambda snapshots it. Build fails without this.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/run (MicroVM starts)&lt;/strong&gt; - Receives PR number + branch + author, writes config to disk. One image, every PR.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/suspend (5 min idle, no reviewer)&lt;/strong&gt; - MicroVM pauses. No reviewer = no cost.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/resume (reviewer comes back)&lt;/strong&gt; - Reload config from disk. App resumes in under 2s.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;/terminate (PR closed)&lt;/strong&gt; - Delete all tasks in PR# from DynamoDB. Zero leftovers.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Without hooks, no way to configure a generic image per-PR at runtime or clean up data on shutdown.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@hooks_app.route&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/lambda-microvms/runtime/v1/run&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;hook_run&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;runHookPayload&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;{}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pr_number&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pr_number&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;branch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;branch&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;dynamodb_table&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dynamodb_table&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;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CONFIG_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&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;ready&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Auth Proxy (proxy/handler.py)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/jatinmehrotra/DA_content/blob/master/Blog/dynamic-pr-environment/proxy/handler.py" rel="noopener noreferrer"&gt;A proxy Lambda behind a Function URL&lt;/a&gt;. Validates the access token, generates a short-lived JWE auth token, and forwards the request to the MicroVM.&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="c1"&gt;# 1. Validate access token from DynamoDB
&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;PK&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;TOKEN#&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;microvm_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SK&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;ACCESS&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Item&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;token&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text/plain&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;Access denied&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 2. Generate JWE auth token for MicroVM
&lt;/span&gt;&lt;span class="n"&gt;token_resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_microvm_auth_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;microvmIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;microvm_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;expirationInMinutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allowedPorts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# 3. Forward request with auth
&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-aws-proxy-auth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the demo, &lt;em&gt;each PR gets a random access token stored in DynamoDB.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;For production, replace this with GitHub OAuth or another identity provider to verify reviewers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; For the demo i am using Lambda Function URL for simplicity but you can use API Gateway + Lambda Authorizer or CloudFront + Lambda@Edge if you need custom domains, rate limiting. &lt;/p&gt;

&lt;h3&gt;
  
  
  The GHA Workflow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/jatinmehrotra/DA_content/blob/master/.github/workflows/pr-deploy.yml" rel="noopener noreferrer"&gt;.github/workflows/pr-deploy.yml&lt;/a&gt; is Triggered on &lt;code&gt;pull_request: [opened, synchronize]&lt;/code&gt; with path filter on &lt;code&gt;Blog/dynamic-pr-environment/**&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Deployment Workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;OIDC authenticate to AWS (no long-lived secrets)&lt;/li&gt;
&lt;li&gt;Zip and upload code to S3&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;update-microvm-image&lt;/code&gt; (triggers new snapshot build)&lt;/li&gt;
&lt;li&gt;Wait for &lt;code&gt;UPDATED&lt;/code&gt; state&lt;/li&gt;
&lt;li&gt;Terminate old MicroVM&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run-microvm&lt;/code&gt; with &lt;code&gt;runHookPayload&lt;/code&gt; containing PR metadata&lt;/li&gt;
&lt;li&gt;Generate access token, store in DynamoDB&lt;/li&gt;
&lt;li&gt;Post preview URL with token to PR comment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://github.com/jatinmehrotra/DA_content/blob/master/.github/workflows/pr-cleanup.yml" rel="noopener noreferrer"&gt;.github/workflows/pr-cleanup.yml&lt;/a&gt; does the cleanup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Terraform code
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/jatinmehrotra/DA_content/tree/master/Blog/dynamic-pr-environment/infra" rel="noopener noreferrer"&gt;Terraform creates&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;S3 bucket (code artifacts)&lt;/li&gt;
&lt;li&gt;DynamoDB table (&lt;code&gt;pr-environments&lt;/code&gt;, PAY_PER_REQUEST, partition key &lt;code&gt;PK&lt;/code&gt;, sort key &lt;code&gt;SK&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;GitHub OIDC provider + IAM role&lt;/li&gt;
&lt;li&gt;MicroVM build role + execution role&lt;/li&gt;
&lt;li&gt;Auth proxy Lambda + Function URL&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Test This
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Understanding of Lambda MicroVMs, &lt;a href="https://dev.to/aws-builders/aws-lambda-microvms-your-ai-agent-can-write-code-but-should-it-execute-it-1ja4"&gt;covered in my previous blog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS account with Lambda MicroVMs access&lt;/li&gt;
&lt;li&gt;Terraform &amp;gt;= 1.9&lt;/li&gt;
&lt;li&gt;GitHub repo with Actions enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Deploy Infrastructure
&lt;/h3&gt;

&lt;p&gt;Edit terraform.tfvars with your values for &lt;code&gt;github org&lt;/code&gt; and &lt;code&gt;repo&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;infra
&lt;span class="nb"&gt;cp &lt;/span&gt;terraform.tfvars.example terraform.tfvars
terraform init &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; terraform apply
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Configure GitHub Secrets
&lt;/h3&gt;

&lt;p&gt;From Terraform outputs, set these in your &lt;code&gt;repo's Settings &amp;gt; Secrets&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Secret&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;AWS_ROLE_ARN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;GitHub Actions IAM role ARN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;S3_BUCKET&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Artifacts bucket name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MICROVM_BUILD_ROLE_ARN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Build role ARN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MICROVM_EXECUTION_ROLE_ARN&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Execution role ARN&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PROXY_URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Auth proxy Function URL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 3: Create a PR
&lt;/h3&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%2Ft1g4ojkak73weng4rqn7.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%2Ft1g4ojkak73weng4rqn7.png" alt="changes for PR" width="800" height="556"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make any change to a file under &lt;code&gt;Blog/dynamic-pr-environment/&lt;/code&gt; and open a PR. The workflow will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Build the MicroVM image (~2-3 min first time, faster after)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo5esodqnx7oy49rzs4pa.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%2Fo5esodqnx7oy49rzs4pa.png" alt="GHA" width="800" height="502"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run the MicroVM&lt;/li&gt;
&lt;li&gt;Post a comment with the preview URL&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foam01kktqpg52jt8thlt.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%2Foam01kktqpg52jt8thlt.png" alt="pr comment" width="800" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Click the Preview URL
&lt;/h3&gt;

&lt;p&gt;You should see your app running with the PR banner showing the branch name and PR number. Any code changes you push will trigger a new deployment automatically.&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%2Fiplq30c3ndsj5klzi3r5.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%2Fiplq30c3ndsj5klzi3r5.png" alt="dark mode" width="799" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also raise parallel PR with different feature&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%2Fe4p5evskor5fjcjokn76.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%2Fe4p5evskor5fjcjokn76.png" alt="parallel pr" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4sw2zbnh41a8n18n07vh.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%2F4sw2zbnh41a8n18n07vh.png" alt="green PR" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You can also review them together as each microvm is isolated per PR&lt;/strong&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%2Fw37m5tmcksetgzagh5cm.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%2Fw37m5tmcksetgzagh5cm.png" alt="parallel PR" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Close the PR
&lt;/h3&gt;

&lt;p&gt;The cleanup workflow terminates the MicroVM&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%2Fxphd717h24c5hxn1ocho.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%2Fxphd717h24c5hxn1ocho.png" alt="GHA" width="687" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;deletes all DynamoDB data for that PR, and removes S3 artifacts.&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%2Fel0ucgi3980jt0hjmk0a.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%2Fel0ucgi3980jt0hjmk0a.png" alt="dynamodb" width="800" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost: Lambda MicroVMs vs Shared Staging vs EKS
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Scenario&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Region:&lt;/strong&gt; us-east-1&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developers:&lt;/strong&gt; 5&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pull Requests:&lt;/strong&gt; 40/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PR Lifetime:&lt;/strong&gt; 2 days&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Active Usage:&lt;/strong&gt; 50 minutes per PR (3 review sessions)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Application:&lt;/strong&gt; Flask (2 GB RAM, 1 vCPU baseline)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; t4g.small is the smallest Graviton instance with 2 GB RAM, matching the MicroVM's 2 GB memory baseline.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Per raw compute-hour, Lambda MicroVMs cost more than equivalent EC2.&lt;/em&gt; But &lt;strong&gt;with MicroVMs you're not managing instances, patching AMIs, configuring ALBs, debugging security groups, or upgrading K8s clusters&lt;/strong&gt;. One API call to create, one to destroy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The operational overhead of EC2/EKS staging is invisible&lt;/strong&gt; on the invoice but real on your team's time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where the savings actually come from; pay for active minutes, not uptime
&lt;/h3&gt;

&lt;p&gt;Here's the part that matters: a PR sits open for 2 days, but reviewers only interact with it for ~50 minutes total. &lt;em&gt;Lambda MicroVMs suspend after 5 minutes idle and bill &lt;code&gt;$0&lt;/code&gt; while suspended, &lt;strong&gt;so you're paying for 33.3 active hours across the whole month (40 PRs x 50 min), not 730&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monthly Cost Breakdown
&lt;/h3&gt;

&lt;p&gt;All three solutions use the same app (Flask, 2GB RAM) with DynamoDB and S3. The difference is how the preview environment is hosted: MicroVM (suspend/resume, Function URL) vs EC2 (always-on, ALB) vs EKS (always-on, ALB, control plane).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resource&lt;/th&gt;
&lt;th&gt;Lambda MicroVMs&lt;/th&gt;
&lt;th&gt;Shared Staging&lt;/th&gt;
&lt;th&gt;EKS&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compute&lt;/td&gt;
&lt;td&gt;$4.20 (33.3 active hrs)&lt;/td&gt;
&lt;td&gt;$12.26 (t4g.small 24/7)&lt;/td&gt;
&lt;td&gt;$12.26 (t4g.small 24/7)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Snapshot (storage + read/write)&lt;/td&gt;
&lt;td&gt;$2.63&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load Balancer / Proxy&lt;/td&gt;
&lt;td&gt;~$0.01 (Lambda + Function URL)&lt;/td&gt;
&lt;td&gt;$16.93 (ALB)&lt;/td&gt;
&lt;td&gt;$16.93 (ALB)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EBS Storage (20GB gp3)&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;$2.40&lt;/td&gt;
&lt;td&gt;$2.40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EKS Control Plane&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;$73.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DynamoDB&lt;/td&gt;
&lt;td&gt;~$0.01&lt;/td&gt;
&lt;td&gt;~$0.01&lt;/td&gt;
&lt;td&gt;~$0.01&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S3&lt;/td&gt;
&lt;td&gt;~$0.05&lt;/td&gt;
&lt;td&gt;~$0.05&lt;/td&gt;
&lt;td&gt;~$0.05&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$6.90&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$31.65&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$104.65&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Savings vs MicroVM&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;78%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;93%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; These numbers are &lt;strong&gt;specific to this scenario&lt;/strong&gt;. Your savings will vary based on active usage time, number of PRs, and suspend/resume frequency. &lt;em&gt;The breakeven guidance below helps you estimate for your own workload&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When does this stop making sense?&lt;/strong&gt; MicroVMs break even with shared staging at ~290 min active per PR (~5 hrs), and with EKS at ~1000 min (~16 hrs).If reviewers spend 5+ active hours per PR, always-on staging becomes cheaper. Typical PR reviews (30–60 minutes) stay well within the MicroVM sweet spot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;The takeaway:&lt;/strong&gt; Lambda MicroVMs don't win because they're cheap compute, they're actually pricier per vCPU-hour than plain EC2. &lt;strong&gt;They win because the billing model matches the &lt;em&gt;actual usage pattern&lt;/em&gt; of a PR preview: mostly idle, briefly active&lt;/strong&gt;. Shared staging and EKS pay the same 24/7 whether anyone's looking or not. And you're not paying for an ALB or EBS volume that sits idle all weekend.&lt;/p&gt;

&lt;h2&gt;
  
  
  Production Tips for Lambda MicroVMs
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Hooks must run on a separate port&lt;/strong&gt;: Lambda routes user traffic to port &lt;code&gt;8080&lt;/code&gt; by default. Lifecycle hooks (&lt;code&gt;/ready&lt;/code&gt;, &lt;code&gt;/run&lt;/code&gt;, &lt;code&gt;/suspend&lt;/code&gt;, &lt;code&gt;/resume&lt;/code&gt;, &lt;code&gt;/terminate&lt;/code&gt;) should run on a separate port such as &lt;code&gt;9000&lt;/code&gt;, otherwise the image build can fail.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Treat deployments as immutable&lt;/strong&gt;: Every new commit creates a new MicroVM image snapshot. Instead of updating a running MicroVM, terminate the old one and start a new instance from the latest snapshot.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid network calls in the &lt;code&gt;/run&lt;/code&gt; hook&lt;/strong&gt;: The hook has a strict timeout of &lt;strong&gt;1–60 seconds&lt;/strong&gt;. DynamoDB cold connections can exceed that, so initialize data lazily after the application starts serving requests.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;runHookPayload&lt;/code&gt; for per-PR configuration&lt;/strong&gt;: Pass values such as the PR number, branch name, or environment settings when starting the MicroVM instead of baking them into the image.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;readyTimeoutInSeconds&lt;/code&gt; can cause build failures&lt;/strong&gt;: Setting this too aggressively may cause image builds to fail before the application is ready. Omitting it uses Lambda's default timeout, which is usually sufficient.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Default quotas are low&lt;/strong&gt;: &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/gettingstarted-limits.html#microvms-quotas" rel="noopener noreferrer"&gt;Lambda MicroVMs have conservative limits on concurrent MicroVMs&lt;/a&gt;. Small teams are unlikely to notice, but larger teams should request a quota increase.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ARM only (Graviton)&lt;/strong&gt;: Lambda MicroVMs currently support only &lt;code&gt;arm64&lt;/code&gt;. Most Python, Node.js, and Go applications work without changes, but workloads with x86-only binaries will need to be ported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use relative URLs behind the proxy&lt;/strong&gt;: If your application is served from a path such as &lt;code&gt;/microvm-123/&lt;/code&gt;, use relative paths (&lt;code&gt;fetch("tasks")&lt;/code&gt;) instead of absolute ones (&lt;code&gt;fetch("/tasks")&lt;/code&gt;) so requests continue to work correctly.&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  From DevOps Perspective
&lt;/h2&gt;

&lt;p&gt;In this blog we saw &lt;strong&gt;how Lambda MicroVMs turn preview environments into an on-demand resource, every PR gets an isolated environment, reviewers test changes independently, and compute costs drop to $0 while idle&lt;/strong&gt;. Combined with lifecycle hooks, they provide a surprisingly practical foundation for production-grade preview environments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Curious whether teams running Kubernetes-based preview environments today would actually switch, or if the 8-hour runtime cap on MicroVMs is a dealbreaker for long-lived PRs. What's blocking you?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>serverless</category>
      <category>devops</category>
    </item>
    <item>
      <title>AWS Lambda MicroVMs: Your AI Agent Can Write Code. But Should It Execute It?</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Fri, 26 Jun 2026 11:54:18 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-lambda-microvms-your-ai-agent-can-write-code-but-should-it-execute-it-1ja4</link>
      <guid>https://dev.to/aws-builders/aws-lambda-microvms-your-ai-agent-can-write-code-but-should-it-execute-it-1ja4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Amazon Web Services(AWS) launched &lt;a href="https://aws.amazon.com/about-aws/whats-new/2026/06/aws-lambda-microvms/" rel="noopener noreferrer"&gt;Lambda MicroVMs&lt;/a&gt; a new serverless compute primitive that provides &lt;strong&gt;VM level isolation, near-instant startup, suspend/resume, and state preservation&lt;/strong&gt; for running untrusted or AI-generated code.&lt;/p&gt;

&lt;p&gt;This blog will explain why do we need Lambda MicroVMs, how does it work &amp;amp; &lt;em&gt;&lt;strong&gt;demo on how to build ephemeral sandboxes for safely executing the code by an AI agent&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;People can also jump straight in to the Demo: Build Ephemeral Sandboxes for AI Agent Code Execution plus there is &lt;a href="https://github.com/jatinmehrotra/DA_content/tree/master/Blog/lambda-microvm-sandbox" rel="noopener noreferrer"&gt;working code as well to build lambda microvm and executing agent code in the microvm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end &lt;strong&gt;&lt;em&gt;shared Developer Perspective on how this changes the way we build modern application &amp;amp; its a must read&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Developer's Problem in 2026&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The trade off before Lambda MicroVMs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is Lambda MicroVM&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Core Concepts for Lambda MicroVMs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Demo: Build Ephemeral Sandboxes for AI Agent Code Execution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost and Sizing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developer Perspective&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fw0pd68nqyfqeh3iwqyl0.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%2Fw0pd68nqyfqeh3iwqyl0.jpg" alt="architecture" width="799" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Developer's Problem in 2026
&lt;/h2&gt;

&lt;p&gt;If you've ever built an application &lt;strong&gt;where users run code you didn't write&lt;/strong&gt; like &lt;em&gt;a data analytics platform, an interactive coding environment, a CI/CD runner, or even a coding assistant&lt;/em&gt;, &lt;strong&gt;you'll realise these type of applications have one thing in common&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;They're executing code that isn't part of your application.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Code supplied by end users, generated by AI, or pulled from external sources. And they all share the same three requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Isolation:&lt;/strong&gt; One user's execution can't see, affect, or access another's&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Speed:&lt;/strong&gt; Environments need to start instantly because users won't wait&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;State that survives:&lt;/strong&gt; Real work is multi-step. A user installs a package in step 1, loads data in step 2, and builds on that in step 3. If state resets between steps, the experience is broken. And when users go idle (switching tabs, taking a break), the environment should pause not die. When they come back, everything should be exactly where they left it.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The trade off before Lambda MicroVMs
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Isolation&lt;/th&gt;
&lt;th&gt;Startup Speed&lt;/th&gt;
&lt;th&gt;State Across Steps&lt;/th&gt;
&lt;th&gt;State Preserved on Idle (Suspend/Resume)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;EC2 instance per user&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong (full VM)&lt;/td&gt;
&lt;td&gt;30-60 seconds&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Manual (hibernate setup, EBS backed only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Containers (ECS/Fargate)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Moderate (shared kernel)&lt;/td&gt;
&lt;td&gt;5-10 seconds&lt;/td&gt;
&lt;td&gt;Within container lifetime&lt;/td&gt;
&lt;td&gt;No container stops, state gone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong (Firecracker)&lt;/td&gt;
&lt;td&gt;Sub-second&lt;/td&gt;
&lt;td&gt;Stateless between invocations&lt;/td&gt;
&lt;td&gt;No execution env frozen/recycled unpredictably&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lambda MicroVMs&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Strong (Firecracker)&lt;/td&gt;
&lt;td&gt;Sub-second&lt;/td&gt;
&lt;td&gt;Up to 8 hours&lt;/td&gt;
&lt;td&gt;Auto suspend/resume memory + disk snapshotted&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;EC2 provides strong isolation but starts slowly and hibernation is a hack.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Containers are fast, but sharing a kernel with untrusted code means significant hardening work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lambda Functions are instant and isolated, but they're designed for event driven request response not multi step sessions where step 2 depends on what was installed in step 1.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lambda MicroVMs&lt;/strong&gt; give you all four: &lt;em&gt;&lt;strong&gt;strong isolation, sub-second start, persistent state across steps, and automatic suspend/resume&lt;/strong&gt; that preserves everything while you stop paying for compute&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What is Lambda MicroVm
&lt;/h2&gt;

&lt;p&gt;Think of &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-microvms-guide.html" rel="noopener noreferrer"&gt;serverless compute environment&lt;/a&gt; which provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VM-level isolation:&lt;/strong&gt; Each sandbox runs its own kernel (Firecracker) with full operating system capabilities (for e.g. installing system packages or mounting filesystems). No shared memory, no shared filesystem&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;snapshot-based rapid startup speeds&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State persistence up to 8 hours:&lt;/strong&gt; Memory, disk, running processes all preserved across interactions within a session.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto suspend/resume:&lt;/strong&gt; When idle, MicroVMs suspend. When traffic returns, they resume with everything intact.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fine-grained control over ingress networking&lt;/strong&gt; (port access, support for HTTP/2, gRPC, WebSockets) and &lt;strong&gt;egress networking&lt;/strong&gt; (public internet access and VPC access).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; It's &lt;strong&gt;not a replacement for Lambda Functions&lt;/strong&gt;, but a sibling designed for a different workload which also means &lt;em&gt;no infrastructure to manage&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Core Concepts for Lambda MicroVMs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-how-it-works.html" rel="noopener noreferrer"&gt;AWS Lambda MicroVMs uses several resource types&lt;/a&gt; that &lt;strong&gt;as a dev we need to create and manage&lt;/strong&gt;. &lt;em&gt;Understanding the following provides the foundation for building applications with MicroVMs.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MicroVM:&lt;/strong&gt; isolated compute environment for a single tenant, user session, or job with full operating system capabilities, providing near-instant launch and resume&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MicroVM Image:&lt;/strong&gt; Defines the application environment of a MicroVM. When you create an image, &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-how-it-works.html#microvms-build-process" rel="noopener noreferrer"&gt;Lambda builds it into a snapshot&lt;/a&gt; that enables near instant launch&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Snapshot:&lt;/strong&gt; A freeze of &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-images-snapshots.html" rel="noopener noreferrer"&gt;memory + disk + running processes + network connections&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Connectors:&lt;/strong&gt; Controls inbound &amp;amp; outbound traffic for MicroVM. You associate connectors with a MicroVM at run time. Traffic can be flown to VPC with custom connector.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Auth Token:&lt;/strong&gt; A short-lived JWE token scoped to a specific MicroVM + allowed ports + expiry. Required in &lt;code&gt;X-aws-proxy-auth&lt;/code&gt; header for every inbound request.&lt;/p&gt;

&lt;h3&gt;
  
  
  How the MicroVM Image Build Works
&lt;/h3&gt;

&lt;p&gt;This is the part that makes sub-second startup possible. &lt;em&gt;When you create or update a &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-images.html" rel="noopener noreferrer"&gt;MicroVM image&lt;/a&gt;, Lambda doesn't just store your Dockerfile it runs through the entire build, starts your app, and freezes everything in place&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here's what happens behind the scenes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lambda spins up a fresh VM using the base image you specified (&lt;code&gt;al2023-minimal&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Runs your Dockerfile instructions like installs packages, copies files, configures the environment&lt;/li&gt;
&lt;li&gt;Starts your application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optionally&lt;/strong&gt; waits for your app to signal it's ready (HTTP 200 on the &lt;code&gt;/ready&lt;/code&gt; hook)&lt;/li&gt;
&lt;li&gt;Takes a full Firecracker snapshot of memory, disk, running processes, network connections&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;strong&gt;resulting snapshot becomes your image&lt;/strong&gt;. Future MicroVMs restore directly from it instead of booting from scratch, which is why startup is nearly instantaneous.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The gotcha:&lt;/strong&gt; Since all MicroVMs from the same image start from identical state, &lt;strong&gt;anything unique you create during build&lt;/strong&gt; (UUIDs, secrets, random seeds, DB connections) gets shared across every MicroVM. The fix: &lt;strong&gt;don't generate unique stuff at build time. Do it in the &lt;code&gt;/run&lt;/code&gt; lifecycle hook which runs after each individual MicroVM starts.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  MicroVM Lifecycle States &amp;amp; Hooks [IMP to build reliable applications]
&lt;/h3&gt;

&lt;p&gt;A MicroVM transitions through these &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-how-it-works.html#microvms-lifecycle-overview" rel="noopener noreferrer"&gt;states&lt;/a&gt;: &lt;strong&gt;PENDING → RUNNING → SUSPENDED → RESUME → TERMINATED&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Each transition has a corresponding &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-how-it-works.html" rel="noopener noreferrer"&gt;lifecycle hook&lt;/a&gt;, places where you plug in your setup or cleanup code:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hook&lt;/th&gt;
&lt;th&gt;When it runs&lt;/th&gt;
&lt;th&gt;Use it for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;After snapshot restore, before accepting traffic&lt;/td&gt;
&lt;td&gt;Generate per instance unique IDs, reestablish DB connections, seed random values/payload that shouldn't be shared across MicroVMs from the same image&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/resume&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;After waking from SUSPENDED state&lt;/td&gt;
&lt;td&gt;Refresh expired tokens, reconnect pools that timed out during suspend&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/suspend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Before memory+disk gets checkpointed&lt;/td&gt;
&lt;td&gt;Flush write buffers, gracefully close connections you don't want frozen mid handshake&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/terminate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Before resources are released&lt;/td&gt;
&lt;td&gt;Persist final results to S3 or external DB, send completion callbacks&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If your &lt;code&gt;/run&lt;/code&gt; hook fails or times out, &lt;strong&gt;the MicroVM goes straight to TERMINATED without ever reaching RUNNING, your users won't see an error&lt;/strong&gt;. Always add timeout handling and logging inside your hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo: Build Ephemeral Sandboxes for AI Agent Code Execution
&lt;/h2&gt;

&lt;p&gt;I have created a &lt;a href="https://github.com/jatinmehrotra/DA_content/tree/master/Blog/lambda-microvm-sandbox" rel="noopener noreferrer"&gt;repo&lt;/a&gt; &lt;strong&gt;which has the working script to try the following demo. Choice is yours you can use the console or the script&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;┌───────────────────────────────────────────────────────────────┐
│              YOUR APPLICATION                                   │
│                                                                │
│   1. create sandbox  ─── boto3 API call ──▶  Lambda Control   │
│   2. send work       ─── HTTPS POST ──────▶  MicroVM endpoint │
│   3. destroy sandbox ─── boto3 API call ──▶  Lambda Control   │
│                                                                │
└───────────────────────────────────────────────────────────────┘
                                                     │
                     ┌───────────────────────────────▼───────────┐
                     │         Firecracker MicroVMs              │
                     │                                           │
                     │  ┌──────────┐  ┌──────────┐ ┌──────────┐│
                     │  │ User A   │  │ User B   │ │ Job X    ││
                     │  │ (Python  │  │ (Node.js │ │ (CI run) ││
                     │  │  REPL)   │  │  IDE)    │ │          ││
                     │  └──────────┘  └──────────┘ └──────────┘│
                     │  Separate kernel, memory, disk per VM    │
                     └──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For this demo, &lt;strong&gt;&lt;em&gt;I'm building an AI coding assistant that creates sandboxes on demand, executes generated code in them, and destroys them after&lt;/em&gt;&lt;/strong&gt;. But same pattern works for any use case like web app backend, CI runner, or interactive platform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pre-requisites:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS account with access to a supported region (us-east-1, us-east-2, us-west-2, ap-northeast-1, eu-west-1)&lt;/li&gt;
&lt;li&gt;Python 3.12+, &lt;code&gt;strands-agents&lt;/code&gt; SDK installed (&lt;code&gt;pip install strands-agents&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;S3 bucket for the code artifact&lt;/li&gt;
&lt;li&gt;Update aws-cli to &lt;code&gt;2.35.11&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: The Sandbox Image (Dockerfile)
&lt;/h3&gt;

&lt;p&gt;This defines what's &lt;strong&gt;available&lt;/strong&gt; inside every sandbox. Think of it like setting up a workspace with all the tools someone might need. You don't know what they'll build but you know what they'll have access to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; public.ecr.aws/lambda/microvms:al2023-minimal&lt;/span&gt;

&lt;span class="c"&gt;# System dependencies (curl-minimal is already in the base image)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;microdnf &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; python3 python3-pip git &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; microdnf clean all

&lt;span class="c"&gt;# Python packages available to AI-generated code&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="c"&gt;# Code executor&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /sandbox&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; executor.py .&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8080&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python3", "executor.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Step 2: The Executor (Runs Inside the MicroVM)
&lt;/h3&gt;

&lt;p&gt;A HTTP server that receives code, runs it as a subprocess, and returns output. This is the "interface" between the outside world and the sandbox interior.&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;subprocess&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jsonify&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;Flask&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;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;WORK_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/workspace&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="nf"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORK_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&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="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/execute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&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="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&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;=== Incoming request: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; chars, timeout: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s ===&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&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;Code:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;code_file&lt;/span&gt; &lt;span class="o"&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;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WORK_DIR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;run.py&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="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;w&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&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;python3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;code_file&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;capture_output&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;text&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;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;cwd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;WORK_DIR&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="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stderr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exit_code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;returncode&lt;/span&gt;&lt;span class="p"&gt;,&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;subprocess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimeoutExpired&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stdout&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="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stderr&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;Execution timed out after &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;s&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;exit_code&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="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt; &lt;span class="mi"&gt;408&lt;/span&gt;

&lt;span class="nd"&gt;@app.route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;GET&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;health&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;jsonify&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;ready&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__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;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0.0.0.0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;The security doesn't come from this code, it comes from the VM boundary around it. Even if submitted code achieves root inside the sandbox, it's root of an isolated Linux with no visibility into other MicroVMs.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 3: Build the MicroVM Image
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Console way
&lt;/h4&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%2F8mba4mkr3sz17jkir2un.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%2F8mba4mkr3sz17jkir2un.png" alt="Creating microvm image" width="799" height="377"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you need to mention s3 bucket where zip of DOCKERFILE is present.&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%2Fh76ah7fcwbzfo51fd496.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%2Fh76ah7fcwbzfo51fd496.png" alt="options" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;If you are using hooks then you need to enable ports for these hooks in step 2 in your application code&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  CLI method
&lt;/h4&gt;

&lt;p&gt;Package, upload, and build:&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;# Package&lt;/span&gt;
zip sandbox-code.zip Dockerfile executor.py requirements.txt

&lt;span class="c"&gt;# Upload to S3&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp &lt;/span&gt;sandbox-code.zip s3://my-bucket/sandbox-code.zip

&lt;span class="c"&gt;# Create the MicroVM image&lt;/span&gt;
aws lambda-microvms create-microvm-image &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; python-sandbox &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--code-artifact&lt;/span&gt; &lt;span class="nv"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;s3://my-bucket/sandbox-code.zip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--base-image-arn&lt;/span&gt; arn:aws:lambda:us-east-1:aws:microvm-image:al2023-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--build-role-arn&lt;/span&gt; arn:aws:iam::123456789:role/MicroVMBuildRole &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fdlx4wuty3rm9hwo2awwo.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%2Fdlx4wuty3rm9hwo2awwo.png" alt="image attributes" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lambda builds the container, starts Flask, confirms it's listening, and takes the Firecracker snapshot&lt;/strong&gt;. Build logs go to CloudWatch under &lt;code&gt;/aws/lambda-microvms/python-sandbox&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Once status is &lt;code&gt;SUCCESSFUL&lt;/code&gt;, every future MicroVM launched from this image starts preinitialized.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 4: Wire It Into Your Application
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Console
&lt;/h4&gt;

&lt;p&gt;You can run microvm manually as well, configure it as per your needs and even pass payload during &lt;code&gt;/run&lt;/code&gt; hook. &lt;em&gt;For our demo i am controlling all this aspect within agent sandbox code.&lt;/em&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%2F9o5djdfuehebxgf9qadp.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%2F9o5djdfuehebxgf9qadp.png" alt="creating microvm" width="799" height="356"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;Execution role decide what the microvm can access within AWS. For the blog my role provide ADMIN priveleges but for production permission needs to be trimmed down.&lt;/em&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%2F1alavpqp8x1pef3oq1l6.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%2F1alavpqp8x1pef3oq1l6.png" alt="microvm configuration" width="799" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  CLI/Code way
&lt;/h3&gt;

&lt;p&gt;Here's where your application creates, uses, and destroys sandboxes. I'm using Strands Agents SDK for this demo to build the agent directly manages MicroVM lifecycle through three tool functions.&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="c1"&gt;# agent.py
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;

&lt;span class="c1"&gt;# --- Configuration ---
&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;IMAGE_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;python-sandbox&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;STACK_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;microvm-sandbox-roles&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="c1"&gt;# Auto fetch ARNs from AWS
&lt;/span&gt;&lt;span class="n"&gt;sts_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sts&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cfn_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cloudformation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ACCOUNT_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sts_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_caller_identity&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Account&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;SANDBOX_IMAGE_ARN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;arn:aws:lambda:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ACCOUNT_ID&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:microvm-image:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IMAGE_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;stack_outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cfn_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe_stacks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StackName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;STACK_NAME&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Stacks&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Outputs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;SANDBOX_ROLE_ARN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OutputValue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stack_outputs&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OutputKey&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;ExecutionRoleArn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;lambda_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;lambda-microvms&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;REGION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_sandbox&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;Create an isolated MicroVM sandbox for executing code.
    Returns sandbox_id and endpoint URL.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run_microvm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;imageIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SANDBOX_IMAGE_ARN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;executionRoleArn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;SANDBOX_ROLE_ARN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;idlePolicy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;maxIdleDurationSeconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;suspendedDurationSeconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1800&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;autoResumeEnabled&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sandbox_id&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;microvmId&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;endpoint&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;https://&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;endpoint&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sandbox_id&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;endpoint&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;code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;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;Execute Python code in the isolated sandbox.
    State persists between calls files and packages carry over.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;token_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_microvm_auth_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;microvmIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sandbox_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;expirationInMinutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;allowedPorts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;token_response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authToken&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;X-aws-proxy-auth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&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="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;/execute&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-aws-proxy-auth&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-aws-proxy-port&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;8080&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;code&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&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;resp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;destroy_sandbox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sandbox_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Terminate the sandbox. All memory, disk, and processes destroyed.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;terminate_microvm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;microvmIdentifier&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sandbox_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sandbox terminated. All state destroyed.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="c1"&gt;# The agent — decides what code to write based on user's question
&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us.anthropic.claude-sonnet-4-5-20250929-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are a data analysis assistant. When the user asks you
    to analyze data, write code, or compute anything:
    1. Create a sandbox with create_sandbox()
    2. Write Python code and execute it with run_code()
    3. You can call run_code() multiple times state persists
    4. When finished, destroy the sandbox with destroy_sandbox()
    Always run code in the sandbox. Never just describe what code would do.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;create_sandbox&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;run_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;destroy_sandbox&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;This same pattern without an agent would be a direct &lt;code&gt;boto3&lt;/code&gt; call from your web backend, the three API calls are the same regardless of what's triggering them&lt;/em&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  Step 5: See It Work (Multi-Step State Persistence)
&lt;/h3&gt;

&lt;p&gt;Try these 3 prompts each one validates a different MicroVM capability:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt 1: Prove it's running in an isolated VM (not locally)&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;You: Run code to print os.uname() and the contents of /etc/os-release
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2F61ubbnfvekd6kwif0sco.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%2F61ubbnfvekd6kwif0sco.png" alt="prompt1" width="799" height="390"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F51ft1h0l5gzf76zgmefj.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%2F51ft1h0l5gzf76zgmefj.png" alt="prompt 1 vm" width="785" height="18"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvm0caf1y6pyvxl0z0apq.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%2Fvm0caf1y6pyvxl0z0apq.png" alt="cw logs" width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can also see the logs of what code is being executed using the microvm image logs &lt;/p&gt;

&lt;p&gt;This proves &lt;strong&gt;VM-level isolation&lt;/strong&gt;. The response will shows &lt;code&gt;Linux aarch64 Amazon Linux 2023&lt;/code&gt; instead of your local macOS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt 2: Prove filesystem state persists between calls&lt;/strong&gt;&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="n"&gt;You&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Write&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="nb"&gt;file&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;workspace&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt; &lt;span class="n"&gt;timestamp&lt;/span&gt;

     &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="n"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;~&lt;/span&gt;&lt;span class="mi"&gt;70&lt;/span&gt; &lt;span class="nf"&gt;seconds &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MicroVM&lt;/span&gt; &lt;span class="n"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;suspends&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;idle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;

&lt;span class="n"&gt;You&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Read&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;workspace&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;txt&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="k"&gt;print&lt;/span&gt; &lt;span class="n"&gt;its&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fi52v7lzmdeh56vsuyyqc.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%2Fi52v7lzmdeh56vsuyyqc.png" alt="prompt2" width="800" height="401"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Micromvm automatically suspends after &lt;code&gt;maxIdleDurationSeconds&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%2Flq329v8flusjtjanreev.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%2Flq329v8flusjtjanreev.png" alt="suspended microvm" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When user sends prompt again it resumes instaneously.&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%2Fjmzd63uqpwrz4odi6ea9.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%2Fjmzd63uqpwrz4odi6ea9.png" alt="prompt 2 resume" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After suspension the microvm resumes for the above request&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%2Fxixeatjkjwr7r1de57a2.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%2Fxixeatjkjwr7r1de57a2.png" alt="mivrovm resumes" width="799" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MicroVM wrote a file, went idle, auto suspended (memory + disk snapshotted), and when you came back with a new request it auto resumed with the file still there.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This uses &lt;code&gt;agent_suspend_demo.py&lt;/code&gt; which has a 1 minute idle timeout (instead of the default 5 minutes) so you can see the suspend/resume cycle quickly. Run it with &lt;code&gt;python agent_suspend_demo.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prompt 3: Prove packages are pre installed from the snapshot&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;You: Create a CSV file at /workspace/sales.csv with columns: product, revenue, region for 10 sample rows. Then read it back with pandas and tell me the top product by total revenue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fxydna70x70h8qf25x9lu.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%2Fxydna70x70h8qf25x9lu.png" alt="prompt 3" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbjxlv6s8hge342h0dl5r.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%2Fbjxlv6s8hge342h0dl5r.png" alt="prompt. 3 vm" width="800" height="53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;cw logs&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%2F98pulsl9qpr9w609db21.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%2F98pulsl9qpr9w609db21.png" alt="cw logs 2" width="799" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This proves &lt;strong&gt;snapshot based startup&lt;/strong&gt;. Pandas is immediately available because it was installed during image build and captured in the Firecracker snapshot.&lt;/p&gt;

&lt;p&gt;After each prompt the agent calls &lt;code&gt;destroy_sandbox()&lt;/code&gt; proving &lt;strong&gt;lifecycle control&lt;/strong&gt; (one API call, all state gone, no residual data).&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost and Sizing
&lt;/h2&gt;

&lt;p&gt;In our demo we used the default MicroVM size (2 GB / 1 vCPU). Lambda MicroVMs uses a &lt;strong&gt;baseline peak sizing model&lt;/strong&gt;. You configure a baseline, and the MicroVM can burst up to 4x during peak load:&lt;/p&gt;

&lt;p&gt;Baseline is set via the &lt;code&gt;memory parameter&lt;/code&gt; when creating your MicroVM image. &lt;/p&gt;

&lt;p&gt;Mimimum baseline size starts with &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-images.html#microvms-images-sizing" rel="noopener noreferrer"&gt;0.5 GB &amp;amp; max memory upto 8 GB&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you actually pay:&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;MicroVM State&lt;/th&gt;
&lt;th&gt;What You Pay&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Running&lt;/strong&gt; (executing code)&lt;/td&gt;
&lt;td&gt;Baseline compute rate per second&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Burst&lt;/strong&gt; (CPU exceeds baseline)&lt;/td&gt;
&lt;td&gt;Per second charge for resources above baseline&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Suspended&lt;/strong&gt; (idle, state snapshotted)&lt;/td&gt;
&lt;td&gt;Snapshot storage only nearly free&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Terminated&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For detailed pricing, see &lt;a href="https://aws.amazon.com/lambda/pricing/" rel="noopener noreferrer"&gt;Lambda MicroVMs pricing&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Perspective
&lt;/h2&gt;

&lt;p&gt;In this blog we saw how AWS Lambda MicroVMs is solving the fundamental problem of modern applications; &lt;strong&gt;WHERE DOES THAT UNTRUSTED CODE EXECUTE SAFELY?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With the rise of coding assistants, autonomous agents, and platforms that let users run arbitrary scripts this problem isn't going away. It's getting worse. &lt;strong&gt;Lambda MicroVMs gives that answer without making you build the isolation layer yourself&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The scary cases haven't gone away, users discovering &lt;code&gt;/proc&lt;/code&gt;, AI agents executing &lt;code&gt;rm -rf /&lt;/code&gt;, malicious packages attempting container escapes. The difference is these are now AWS's problem. The blast radius is a disposable VM that you terminate with one API call.&lt;/p&gt;

&lt;p&gt;The fastest way to build with Lambda MicroVMs with &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/microvms-best-practices.html" rel="noopener noreferrer"&gt;best practices&lt;/a&gt; would be to use the skill provided by lambda team wi to your agent like Kiro or Claude&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add https://github.com/aws/agent-toolkit-for-aws/tree/main/skills/specialized-skills/serverless-skills/aws-lambda-microvms &lt;span class="nt"&gt;--yes&lt;/span&gt; &lt;span class="nt"&gt;--global&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me know what you think in the comments and if you build something with Lambda MicroVMs, I'd genuinely love to see it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>AWS DevOps Agent is not here to replace you! It's here to compliment you by acting like 24/7 on call engineers finding root cause for issues while you build new feature and innovate. More details in the blog on how to setup with 2 Demo.</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Mon, 08 Dec 2025 11:56:45 +0000</pubDate>
      <link>https://dev.to/jatinmehrotra/aws-devops-agent-is-not-here-to-replace-you-its-here-to-compliment-you-by-acting-like-247-on-1e32</link>
      <guid>https://dev.to/jatinmehrotra/aws-devops-agent-is-not-here-to-replace-you-its-here-to-compliment-you-by-acting-like-247-on-1e32</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" class="crayons-story__hidden-navigation-link"&gt;AWS DevOps Agent Explained: Architecture, Setup, and Real Root-Cause Demo (CloudWatch + EKS)&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="/aws-builders"&gt;
            &lt;img alt="AWS Community Builders  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.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2794%2F88da75b6-aadd-4ea1-8083-ae2dfca8be94.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jatinmehrotra" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg" alt="jatinmehrotra profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jatinmehrotra" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jatin Mehrotra
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jatin Mehrotra
                
              
              &lt;div id="story-author-preview-content-3087487" 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="/jatinmehrotra" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jatin Mehrotra&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="/aws-builders" class="crayons-story__secondary fw-medium"&gt;AWS Community Builders &lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 6 '25&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/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" id="article-link-3087487"&gt;
          AWS DevOps Agent Explained: Architecture, Setup, and Real Root-Cause Demo (CloudWatch + EKS)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/aws"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;aws&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/agents"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;agents&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/awsdevopsagent"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;awsdevopsagent&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/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" 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/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;41&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              12&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&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;
            8 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>
      <category>ai</category>
      <category>aws</category>
      <category>agents</category>
      <category>awsdevopsagent</category>
    </item>
    <item>
      <title>AWS DevOps Agent is not here to replace you! It's here to compliment you by acting like 24/7 on call engineers finding root cause for issues while you build new feature and innovate. More details in the blog on how to setup with 2 Demo.</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Mon, 08 Dec 2025 10:56:34 +0000</pubDate>
      <link>https://dev.to/jatinmehrotra/aws-devops-agent-is-not-here-to-replace-you-its-here-to-compliment-you-by-acting-like-247-on-7dc</link>
      <guid>https://dev.to/jatinmehrotra/aws-devops-agent-is-not-here-to-replace-you-its-here-to-compliment-you-by-acting-like-247-on-7dc</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" class="crayons-story__hidden-navigation-link"&gt;AWS DevOps Agent Explained: Architecture, Setup, and Real Root-Cause Demo (CloudWatch + EKS)&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="/aws-builders"&gt;
            &lt;img alt="AWS Community Builders  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.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2794%2F88da75b6-aadd-4ea1-8083-ae2dfca8be94.png" class="crayons-logo__image"&gt;
          &lt;/a&gt;

          &lt;a href="/jatinmehrotra" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg" alt="jatinmehrotra profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jatinmehrotra" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jatin Mehrotra
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jatin Mehrotra
                
              
              &lt;div id="story-author-preview-content-3087487" 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="/jatinmehrotra" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jatin Mehrotra&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="/aws-builders" class="crayons-story__secondary fw-medium"&gt;AWS Community Builders &lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 6 '25&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/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" id="article-link-3087487"&gt;
          AWS DevOps Agent Explained: Architecture, Setup, and Real Root-Cause Demo (CloudWatch + EKS)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/aws"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;aws&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/agents"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;agents&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/awsdevopsagent"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;awsdevopsagent&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/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7" 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/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;41&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              12&lt;span class="hidden s:inline"&gt;&amp;nbsp;comments&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;
            8 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>
      <category>ai</category>
      <category>aws</category>
      <category>agents</category>
      <category>awsdevopsagent</category>
    </item>
    <item>
      <title>AWS DevOps Agent Explained: Architecture, Setup, and Real Root-Cause Demo (CloudWatch + EKS)</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Sat, 06 Dec 2025 22:19:36 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7</link>
      <guid>https://dev.to/aws-builders/aws-devops-agent-explained-architecture-setup-and-real-root-cause-demo-cloudwatch-eks-ng7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Amazon Web Services(AWS) launched &lt;a href="https://aws.amazon.com/ai/frontier-agents/" rel="noopener noreferrer"&gt;Frontier agents&lt;/a&gt; that are &lt;strong&gt;autonoumous systems&lt;/strong&gt; during re:Invent 2025 &lt;em&gt;which achieve various use cases goals, scale massively to tackle concurrent tasks, and run persistently for hours or days without intervention&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In this blog we will talk about one of the frontier agents i.e &lt;strong&gt;&lt;em&gt;AWS DevOps Agent !!!&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This blog will explain what is AWS DevOps Agent, its architecture &amp;amp; components, security &amp;amp; &lt;strong&gt;demo for investigating Ec2 CPU spike (CW alarm) and EKS Pod error&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;People can also jump straight in to investigating Cloudwatch alarms or EKS errors plus there is &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2025/tree/master/devops-agent/eks-devops-agent" rel="noopener noreferrer"&gt;tf repo as well for EKS&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the end also &lt;strong&gt;&lt;em&gt;shared DevOps Engineer Perspective on the fear of being replaced and its a must read&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is AWS DevOps Agent&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to maximize Agent's Effectiveness&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS DevOps Agent working architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resource Discovery by AWS DevOps Agent&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt; Demo 1: Investigate Cloudwatch Alarm&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Demo 2: Investigate EKS errors&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DevOps Engineer perspective&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

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

&lt;h2&gt;
  
  
  What is AWS DevOps Agent
&lt;/h2&gt;

&lt;p&gt;Think of AWS DevOps Agent like an 24/7 continuously learning Autonomous on call Engineer which has all the &lt;strong&gt;tools(more about it later)&lt;/strong&gt; primarily to investigate incidents, finds root causes, provides mitigation plan and provide you Prevention as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;At the moment it cannot fix the incidents on its own. Of course a &lt;strong&gt;human will be needed to fix the root cause&lt;/strong&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How it investigates and find the root cause
&lt;/h3&gt;

&lt;p&gt;To investigate root cause and give recommendations it needs understanding and relationships of the infrastructure &amp;amp; applications &lt;code&gt;called as topology&lt;/code&gt; inside AWS account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The understanding of infrastructure holistically becomes the &lt;code&gt;CONTEXT&lt;/code&gt; for this DevOps Agent&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to maximize Agent's Effectiveness
&lt;/h2&gt;

&lt;p&gt;While the topology provides important context during investigations, AWS DevOps Agent is &lt;strong&gt;not limited to investigating only the resources shown in the topology&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;The agent may use additional data sources, such as AWS service APIs or connected observability tools, to investigate resources that are not in the application topology.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;And that is why AWS has given option to add &lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/configuring-capabilities.html" rel="noopener noreferrer"&gt;capabilities&lt;/a&gt; to maximize Agent's effectiveness by :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Connect multiple AWS accounts&lt;/li&gt;
&lt;li&gt;Connect CI/CD pipelines through repo like Github/GitLab&lt;/li&gt;
&lt;li&gt;MCP servers&lt;/li&gt;
&lt;li&gt;Telemetry sources like Datadog, New Relic&lt;/li&gt;
&lt;li&gt;Ticketing and chat like serviceNow and slack&lt;/li&gt;
&lt;li&gt;Even EKS (demo over here)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: We can also provide &lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/userguide-devops-agent-runbooks.html" rel="noopener noreferrer"&gt;runbooks&lt;/a&gt; as pre-loaded guidance/hints to enhance investigation performance to provide investigation hints and guidance.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;&lt;em&gt;IN THE END IT ALL ABOUT UNDERSTANDING RELATIONSHIPS ABOUT YOUR RESOURCES&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS DevOps Agent working architecture [IMP]
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Operates through a &lt;strong&gt;dual-console architecture&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Admins uses management Console to create and manage Agent Spaces,configure capabilities &amp;amp; set up access controls.&lt;/li&gt;
&lt;li&gt;Operations teams uses AWS Agent web app to interact with agent and start investigation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DevOps Agent Spaces
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/userguide-what-are-devops-agent-spaces.html" rel="noopener noreferrer"&gt;DevOps Agent spaces&lt;/a&gt; &lt;strong&gt;is logical container/boundary that defines what tools and infrastructure AWS DevOps Agent has access to&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;When you create an Agent Space, you define which AWS accounts the agent can access, which external tools it can connect to, and which users in your organization can interact with the agent.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Admins configure the Agent Space&lt;/code&gt; through the AWS Management Console&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/userguide-what-are-devops-agent-spaces.html#how-agent-spaces-are-isolated" rel="noopener noreferrer"&gt;Security Aspect of Agent Spaces&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each Agent Space uses dedicated IAM roles that grant access only to specific AWS accounts and resources&lt;/li&gt;
&lt;li&gt;You control which users or groups can access each Agent Space.&lt;/li&gt;
&lt;li&gt;Information from one Agent Space is not visible or accessible from another Agent Space&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  DevOps Agent Web App
&lt;/h3&gt;

&lt;p&gt;Operations team uses web apps for daily incident response activities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/userguide-what-is-a-devops-agent-web-app.html#authentication" rel="noopener noreferrer"&gt;Security Aspect of Web Apps&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IAM identity Center (user Access):&lt;/strong&gt; centrally manage user access to the DevOps Agent Space web apps even federate with external identity providers. MFA support is included&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IAM authentication link (Admin access):&lt;/strong&gt; direct access to the web app from the AWS Management Console using your existing console session.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Resource Discovery by AWS DevOps Agent
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Until this point we understand Agent's context starts with Resource discovery(topology) and it does by 2 ways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CloudFormation stacks:&lt;/strong&gt; By default Agent will list all of the CloudFormation stacks and their resources. Resources created by CDK is also supported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resource Tags:&lt;/strong&gt; Resources not deployed from CloudFormation (like Console or TF), will be discovered by AWS Tag Key and value pairs to include in topology. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo 1: Investigate Cloudwatch Alarm
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pre-requisite
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For the brevity of the blog I won't cover &lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/getting-started-creating-an-agent-space.html" rel="noopener noreferrer"&gt;how to create agent space&lt;/a&gt;. Pretty straightforward and you don't need aws organizations to do this.&lt;/li&gt;
&lt;li&gt;Cloudformation basics&lt;/li&gt;
&lt;li&gt;Access to us-east-1 region. DevOps agent is available only in this region.&lt;/li&gt;
&lt;li&gt;I used single standalone account.&lt;/li&gt;
&lt;/ul&gt;

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

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

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

&lt;h3&gt;
  
  
  1) Investigate Cloudwatch Alarm
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Deploy the &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2025/blob/master/devops-agent/AWS-AIDevOps-ec2-test.yaml" rel="noopener noreferrer"&gt;cloudformation stack&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;This CFN template is creating an security group, key-pair for ssh &lt;strong&gt;ec2 instance with startup script to do CPU stress test&lt;/strong&gt;, CW alarm for CPU utilization, auto shutdown ec2 instances after 2 hours.&lt;/li&gt;
&lt;li&gt;After ec2 instance is created wait for 5-10 minutes to trigger cloudwatch alarm&lt;/li&gt;
&lt;li&gt;You can also SSH into instance and run the stress test manually as well &lt;code&gt;./cpu-stress-test.sh&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once stack is deployed DevOps Agent automatically identifies the new resources.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Access Web App
&lt;/h3&gt;

&lt;p&gt;After creating agent spaces click on &lt;code&gt;View Details&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.amazonaws.com%2Fuploads%2Farticles%2Fc9ivzc6se0bv3mggnlf8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc9ivzc6se0bv3mggnlf8.png" alt="Agent creation spaces" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on Web app or directly &lt;code&gt;Operator Access&lt;/code&gt; link&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Investigation Root Cause
&lt;/h3&gt;

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

&lt;p&gt;Once your Cloudwatch Alarm is triggered go to Web app and under &lt;code&gt;incident Response&lt;/code&gt; click on &lt;code&gt;latest alarm&lt;/code&gt; and hit on Start Investigation&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;_DevOps Agent is smart enough to fill the completed prompt. Agent will figure out the steps on its own and give you the final ROOT CAUSE&lt;br&gt;
_&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;Well I also found an interesting finding when the time between 2 alarms was around 40 minutes agent was unable to find the root cause and I had to rerun the investigation.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Mitigation plan
&lt;/h3&gt;

&lt;p&gt;Well since it was user initiated agent was smart enough to give no mitigation plan&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Prevention
&lt;/h3&gt;

&lt;p&gt;Since it was a very straightforward demo with user initiated errors so it wasn't enough to generate prevention recommendations&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Investigation gaps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;One of my favorite feature which even docs does not cover is Investigation gaps.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No investigation can be perfect and that's what investigation gaps fill in to tell when it cannot cover extreme details due to absence of resource at infrastructure level for example in this absence of ssh agent, CloudWatch log groups then it tells those details. &lt;/p&gt;

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

&lt;h3&gt;
  
  
  Using Chat
&lt;/h3&gt;

&lt;p&gt;You can ask more detailed questions using chat in natural language &lt;/p&gt;

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

&lt;h2&gt;
  
  
  Demo 2: Investigate EKS errors
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Adding Capability;Give DevOps Agent access to EKS clusters
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Go to Capabilities and click &lt;code&gt;Edit&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;As we learned earlier Agent space IAM role control the access of AWS resources of Agent, &lt;code&gt;Click view role permissions&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Cope the IAM Role ARN. You will need to add an access entry in the EKS cluster with &lt;code&gt;AmazonEKSAdminViewPolicy&lt;/code&gt; ( we have tf code for it)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Go to terraform code and replace the arn in terraform.vars&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After the terraform code is finished you can see nginx has imagePullBack Error which is intentional&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;As we learn earlier we are deploying resources by terraform so we need to add tags in the Agent space so that DevOps agent can find the resources.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I am using the same tags in my terraform code as well. Click &lt;code&gt;Save&lt;/code&gt;. You will see Agent Space automatically finds the Newly created resources.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Go to Web App
&lt;/h3&gt;

&lt;p&gt;Now we will ask the AWS DevOps Agent what is the cause of this error.&lt;/p&gt;

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

&lt;p&gt;Agent successfully investigated the EKS cluster and find out the root cause&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Not only it found out the root cause it also gave the mitigation steps also rollback steps if mitigation cause issues.&lt;/strong&gt;&lt;/p&gt;

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

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

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

&lt;h2&gt;
  
  
  DevOps Engineer perspective
&lt;/h2&gt;

&lt;p&gt;We explored how the AWS DevOps Agent reduces MTTR, prevents future incidents through recommendations, and pinpoints root causes. &lt;/p&gt;

&lt;p&gt;The Agent’s effectiveness comes from its deep understanding of your infrastructure—both inside AWS accounts and across external systems. &lt;em&gt;It would be interesting to connect MCP server to enhance context even further.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Though Devops Agent is in preview and its free but has &lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/userguide-public-preview-pricing-and-limits.html" rel="noopener noreferrer"&gt;some limits&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is it secure? if configured Absolutely yes!&lt;/strong&gt; because administrators control what &lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/security-and-access-control-limiting-agent-access-in-an-aws-account.html" rel="noopener noreferrer"&gt;DevOps Agent can access in AWS account&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/devopsagent/latest/userguide/security-and-access-control-devops-agent-iam-permissions.html" rel="noopener noreferrer"&gt;Agent IAM permissions control access to its feature and capabilities&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Will it replace you? Absolutely not!&lt;/strong&gt; because still need an engineer to fix the issues, an engineer to build new features for the infrastructure &amp;amp; need that understanding of infrastructure how to rollback if things goes wrong.&lt;/p&gt;

&lt;p&gt;Let me know what do you think?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>agents</category>
      <category>awsdevopsagent</category>
    </item>
    <item>
      <title>AWS launched EKS Capabilities to simplify Kubernetes with a quick on/off model. It runs Argo CD, ACK, and kro for you—no installs or upgrades. I tested it by deploying an S3 bucket using ACK + Argo CD using EKS Capabilities. Terraform Repo link inside.</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Wed, 03 Dec 2025 16:40:44 +0000</pubDate>
      <link>https://dev.to/jatinmehrotra/aws-launched-eks-capabilities-to-simplify-kubernetes-with-a-quick-onoff-model-it-runs-argo-cd-2dp1</link>
      <guid>https://dev.to/jatinmehrotra/aws-launched-eks-capabilities-to-simplify-kubernetes-with-a-quick-onoff-model-it-runs-argo-cd-2dp1</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0" class="crayons-story__hidden-navigation-link"&gt;I Created S3 Buckets Using ArgoCD , ACK with EKS Capabilities—No Controllers Installed.&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="/aws-builders"&gt;
            &lt;img alt="AWS Community Builders  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.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F2794%2F88da75b6-aadd-4ea1-8083-ae2dfca8be94.png" class="crayons-logo__image" width="350" height="350"&gt;
          &lt;/a&gt;

          &lt;a href="/jatinmehrotra" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg" alt="jatinmehrotra profile" class="crayons-avatar__image" width="800" height="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/jatinmehrotra" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Jatin Mehrotra
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Jatin Mehrotra
                
              
              &lt;div id="story-author-preview-content-3076889" 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="/jatinmehrotra" 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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1349181%2F49ff3e61-e8bd-463a-9c7f-8925c1e1254f.jpg" class="crayons-avatar__image" alt="" width="800" height="800"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Jatin Mehrotra&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="/aws-builders" class="crayons-story__secondary fw-medium"&gt;AWS Community Builders &lt;/a&gt;
            &lt;/span&gt;
          &lt;/div&gt;
          &lt;a href="https://dev.to/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Dec 1 '25&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/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0" id="article-link-3076889"&gt;
          I Created S3 Buckets Using ArgoCD , ACK with EKS Capabilities—No Controllers Installed.
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/aws"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;aws&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/kubernetes"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;kubernetes&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/eks"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;eks&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/reinvent2025"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;reinvent2025&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/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0" 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/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="24" height="24"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="24" height="24"&gt;
                  &lt;/span&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;12&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0#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;
            9 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

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

&lt;/div&gt;


</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>eks</category>
      <category>reinvent2025</category>
    </item>
    <item>
      <title>I Created S3 Buckets Using ArgoCD , ACK with EKS Capabilities—No Controllers Installed.</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Mon, 01 Dec 2025 15:08:10 +0000</pubDate>
      <link>https://dev.to/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0</link>
      <guid>https://dev.to/aws-builders/i-created-s3-buckets-using-argocd-ack-with-eks-capabilities-no-controllers-installed-cm0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Amazon Web Services (AWS) EKS team has introduced &lt;strong&gt;EKS capabilities&lt;/strong&gt; on &lt;strong&gt;Dec 1, 2025&lt;/strong&gt; to help developers for writing their code by offloading Kubernetes management of resources like Argo CD, ACK, kro by a simple turn/off switch.&lt;/p&gt;

&lt;p&gt;Amazon EKS Capabilities is a new set of fully managed features designed to make running Kubernetes easier and faster for developers. Think of it as a &lt;strong&gt;on-off button&lt;/strong&gt; on top of your EKS cluster that removes a lot of the heavy lifting for you.&lt;br&gt;
These capabilities give you Kubernetes-native tools for things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deploying your apps continuously (Argo CD)&lt;/li&gt;
&lt;li&gt;managing AWS resources directly from Kubernetes (ACK)&lt;/li&gt;
&lt;li&gt;creating and organizing your Kubernetes objects (kro)
And the best part? AWS manages all of this for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Instead of installing, updating, and scaling these tools on your worker nodes, EKS now runs them for you. That means less time fighting with cluster operations and more time actually building and scaling the applications.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the people who wants to jump straight in to trying the solution can follow &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2025/tree/master/eks-capabilities" rel="noopener noreferrer"&gt;my repo here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I tested this setup today and here’s how I deployed an S3 bucket with ACK and GitOps using Argo CD and EKS Capabilities.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Bonus&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pricing&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is EKS capability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prerequisites&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform Code Walkthrough&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;DevOps and Platform Engineering perspective&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Bonus
&lt;/h2&gt;

&lt;p&gt;I have found a bug which does not allow ArgoCD to get in healthy state, follow along to find out what that bug is and how to fix that bug.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This blog assumes that you have fundamental knowledge on how &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argocd-concepts.html" rel="noopener noreferrer"&gt;Argo CD&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/ack-concepts.html" rel="noopener noreferrer"&gt;ACK&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/kro-concepts.html" rel="noopener noreferrer"&gt;kro&lt;/a&gt; works conceptually.&lt;/em&gt;&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Available capabilities
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ACK:&lt;/strong&gt; ACK enables the management of AWS resources using Kubernetes APIs, allowing you to create and manage S3 buckets, RDS databases, IAM roles, and other AWS resources using Kubernetes custom resources.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Argo CD:&lt;/strong&gt; GitOps-based continuous deployment for your applications, using Git repositories as the source of truth for your workloads and system state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;kro:&lt;/strong&gt; Create custom Kubernetes APIs that compose multiple resources into higher-level abstractions, allowing platform teams to define reusable patterns for common resource combinations-cloud building blocks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pricing [IMP]
&lt;/h2&gt;

&lt;p&gt;Well the &lt;a href="https://aws.amazon.com/eks/pricing/" rel="noopener noreferrer"&gt;pricing&lt;/a&gt; is tricky. You pay for EKS Capabilities based on two components that are both billed hourly: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;a base hourly rate for each enabled capability&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;hourly usage charges based on the quantity of resources managed by each capability&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;In short base charge + usage charge.&lt;/strong&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;For Argo CD, you pay hourly for each Argo CD Application managed. For AWS Controllers for Kubernetes (ACK), you pay hourly for each ACK resource managed. For Kubernetes Resource Orchestrator (KRO), you pay hourly for each KRO Resource Graph Definition (RGD) instance managed.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is EKS Capability?
&lt;/h2&gt;

&lt;p&gt;It is basically an AWS resource managed by AWS including its scaling, lifecycle, security but runs inside your EKS cluster but not on your worker nodes.&lt;/p&gt;

&lt;p&gt;Basically Capabilities run in EKS, &lt;strong&gt;&lt;em&gt;eliminating the need to install and maintain controllers and other operational components on your worker nodes&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resources That can be created by Capability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;For ArgoCD&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application&lt;/li&gt;
&lt;li&gt;ApplicationSet&lt;/li&gt;
&lt;li&gt;AppProject&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;For kro&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ResourceGraphDefinition (RGD)&lt;/li&gt;
&lt;li&gt;Custom resource instances&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;For ACK&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When you enable the ACK capability, you can create and manage AWS resources using Kubernetes custom resources. ACK provides over 200 CRDs for more than 50 AWS services,&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Capability IAM Role [IMP]
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Each EKS capability resource has a configured capability IAM role. &lt;/li&gt;
&lt;li&gt;&lt;p&gt;The capability role is used to grant AWS service permissions for EKS capabilities to act on your behalf. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For example, to use the EKS Capability for ACK to manage Amazon S3 Buckets, you will grant S3 Bucket administrative permissions to the capability, enabling it to create and manage buckets.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;In order to follow along make sure you have following prerequisites met. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common to all 3 capabilities&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An EKS cluster&lt;/li&gt;
&lt;li&gt;An IAM Capability Role with permissions for ACK, ArgoCD, kro &lt;/li&gt;
&lt;li&gt;Sufficient IAM permissions to create capability resources on EKS clusters&lt;/li&gt;
&lt;li&gt;(For CLI/eksctl) The appropriate CLI tool installed and configured&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Argo CD capability specific&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Identity Center configured - Required for Argo CD authentication (local users are not supported)&lt;/li&gt;
&lt;li&gt;kubectl configured to communicate with your cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Terraform Code Walkthrough
&lt;/h2&gt;

&lt;p&gt;Terraform code for this repo lies in this &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2025/tree/master/eks-capabilities" rel="noopener noreferrer"&gt;repo&lt;/a&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Just run &lt;code&gt;terraform apply&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Demo: Creating S3 buckets with ACK and ArgoCD using EKS Capabilities
&lt;/h2&gt;

&lt;p&gt;The whole process of giving this managed platform capabilities is simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create IAM Capability Role -&amp;gt; Enable Capabilities (ACK and ArgoCD for this Demo) -&amp;gt; Register cluster to ArgoCD -&amp;gt; add ArgoCD applications to track Git repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;We create an capability IAM role with &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/capability-role.html" rel="noopener noreferrer"&gt;trust policies as mentioned in the docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;We add permissions for the role like if we want to create s3 bucket using ACK we add s3 policy to the role so that ack can talk to AWS Services.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For kro and ArgoCD &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/capability-role.html#capability-permissions" rel="noopener noreferrer"&gt;the role does not need any permissions&lt;/a&gt; because when you enable capability adds access entries policies which add permissions for these capabilities to interact with EKS cluster. &lt;/p&gt;

&lt;h3&gt;
  
  
  The Capability Role
&lt;/h3&gt;

&lt;p&gt;For this we create a trust relationship which allows capabilities to assume role.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Version": "2012-10-17",               
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "capabilities.eks.amazonaws.com"
      },
      "Action": [
        "sts:AssumeRole",
        "sts:TagSession"
      ]
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now based on the capability you add permissions to it, for the brevity of this blog ACK and ArgoCD capability will use the same role and in the &lt;a&gt;tf code&lt;/a&gt; I have added full s3 permissions for ACK to create S3 bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  ArgoCD IAM Identity Center Integration
&lt;/h3&gt;

&lt;p&gt;The Argo CD managed capability &lt;strong&gt;integrates with AWS Identity Center for authentication and uses built-in RBAC roles for authorization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That is why IAM identity Center is a prerequisite.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is how permissions work with ArgoCD. When a user accesses Argo CD UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They authenticate using AWS Identity Center (which can federate to your corporate identity provider)&lt;/li&gt;
&lt;li&gt;AWS Identity Center provides user and group information to Argo CD&lt;/li&gt;
&lt;li&gt;Argo CD maps users and groups to RBAC roles based on your configuration&lt;/li&gt;
&lt;li&gt;Users see only the applications and resources they have permission to access&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is exactly what I have done in my &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2025/blob/master/eks-capabilities/data.tf" rel="noopener noreferrer"&gt;terraform code&lt;/a&gt;, &lt;strong&gt;accessing IAM identity center instance and user details and passing to the argoCD capability and configuring RBAC role for my user as ADMIN role&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;data "aws_ssoadmin_instances" "main" {}

data "aws_identitystore_user" "admin" {
  identity_store_id = tolist(data.aws_ssoadmin_instances.main.identity_store_ids)[0]

  alternate_identifier {
    unique_attribute {
      attribute_path  = "UserName"
      attribute_value = var.idc_username
    }
  }
}

resource "null_resource" "eks_capability_argocd" {
  depends_on = [module.eks]

  provisioner "local-exec" {
    command = &amp;lt;&amp;lt;-EOT
      aws eks create-capability \
        --region ${local.region} \
        --cluster-name ${local.cluster_name} \
        --capability-name my-argocd \
        --type ARGOCD \
        --role-arn ${aws_iam_role.eks_capability_role.arn} \
        --delete-propagation-policy RETAIN \
        --configuration '{
          "argoCd": {
            "awsIdc": {
              "idcInstanceArn": "${tolist(data.aws_ssoadmin_instances.main.arns)[0]}",
              "idcRegion": "${local.region}"
            },
            "rbacRoleMappings": [{
              "role": "ADMIN",
              "identities": [{
                "id": "${data.aws_identitystore_user.admin.user_id}",
                "type": "SSO_USER"
              }]
            }]
          }
        }' \
        --profile jj
    EOT
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To restrict for your use- case see &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argocd-permissions.html#_built_in_rbac_roles" rel="noopener noreferrer"&gt;built-in RBAC roles&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  EKS cluster and installing capabilities]
&lt;/h3&gt;

&lt;p&gt;I am using EKS auto mode for this blog. As this is fresh update I am using aws cli commands to enable capabilities.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;1) Capabilities are not &lt;code&gt;ACTIVE&lt;/code&gt; instantly so we need to wait until they become &lt;code&gt;ACTIVE&lt;/code&gt; for next operation.&lt;/p&gt;

&lt;p&gt;2) Behind the scenes after enabling capabilities, an access entry is created for the capability role with access entries like &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#_amazoneksargocdpolicy" rel="noopener noreferrer"&gt;AmazonEKSArgoCDPolicy&lt;/a&gt;,&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#_amazoneksackpolicy" rel="noopener noreferrer"&gt;AmazonEKSACKPolicy &lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#_amazoneksargocdclusterpolicy" rel="noopener noreferrer"&gt;AmazonEKSArgoCDClusterPolicy&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "null_resource" "eks_capability_ack" {
  depends_on = [module.eks]

  provisioner "local-exec" {
    command = &amp;lt;&amp;lt;-EOT
      aws eks create-capability \
        --region ${local.region} \
        --cluster-name ${local.cluster_name} \
        --capability-name my-ack \
        --type ACK \
        --role-arn ${aws_iam_role.eks_capability_role.arn} \
        --delete-propagation-policy RETAIN \
        --profile jj
    EOT
  }
}

resource "null_resource" "eks_capability_argocd" {
  depends_on = [module.eks]

  provisioner "local-exec" {
    command = &amp;lt;&amp;lt;-EOT
      aws eks create-capability \
        --region ${local.region} \
        --cluster-name ${local.cluster_name} \
        --capability-name my-argocd \
        --type ARGOCD \
        --role-arn ${aws_iam_role.eks_capability_role.arn} \
        --delete-propagation-policy RETAIN \
        --configuration '{
          "argoCd": {
            "awsIdc": {
              "idcInstanceArn": "${tolist(data.aws_ssoadmin_instances.main.arns)[0]}",
              "idcRegion": "${local.region}"
            },
            "rbacRoleMappings": [{
              "role": "ADMIN",
              "identities": [{
                "id": "${data.aws_identitystore_user.admin.user_id}",
                "type": "SSO_USER"
              }]
            }]
          }
        }' \
        --profile jj
    EOT
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Registering the eks cluster to ArgoCD to deploy applications
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argocd-concepts.html#_getting_started_with_argo_cd" rel="noopener noreferrer"&gt;Docs &lt;/a&gt;suggest to use argocd cli but it never succeeded as it always timed out s&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argocd-register-clusters.html#_register_the_local_cluster" rel="noopener noreferrer"&gt;o I register the secret using K8 Secret&lt;/a&gt;. &lt;em&gt;This is possible because of the new access entry(&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#_amazoneksargocdpolicy" rel="noopener noreferrer"&gt;AmazonEKSArgoCDPolicy&lt;/a&gt;) policy which ArgoCD capability to read the K8 secrets&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "null_resource" "argocd_add_cluster" {
  depends_on = [null_resource.wait_for_argocd]

  provisioner "local-exec" {
    command = &amp;lt;&amp;lt;-EOT
      aws eks update-kubeconfig \
        --name ${local.cluster_name} \
        --region ${local.region} \
        --profile jj

      kubectl apply -f - &amp;lt;&amp;lt;EOF
apiVersion: v1
kind: Secret
metadata:
  name: ${local.cluster_name}-cluster
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: cluster
stringData:
  name: ${local.cluster_name}
  server: ${module.eks.cluster_arn}
  project: default
EOF
    EOT
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create an ArgoCD Application
&lt;/h3&gt;

&lt;p&gt;This demo uses a public GitHub repository, so no repository configuration is required. For private repositories, configure access using AWS Secrets Manager, CodeConnections, or Kubernetes Secrets&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: eks-capability
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/jatinmehrotra/aws-reinvent-2025
    targetRevision: HEAD
    path: eks-capabilities/ack_yaml
  destination:
    name: reinvent-2025
    namespace: ack
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
    - CreateNamespace=true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Over this path there is yaml file to create S3 bucket using ACK which will be synced and applied to cluster and then ACK will create this bucket in our AWS Account&lt;/em&gt;&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;s3.services.k8s.aws/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bucket&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-test-bucket&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jj-bucket-name-12345&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fixing the Bug
&lt;/h3&gt;

&lt;p&gt;Even after doing all this or following AWS docs this won't run because the access entries(&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/access-policy-permissions.html#_amazoneksargocdclusterpolicy" rel="noopener noreferrer"&gt;AmazonEKSArgoCDClusterPolicy&lt;/a&gt;) policies created by AWS for ArgoCD Capability lacks permissions to list the cluster resources.&lt;/p&gt;

&lt;p&gt;SO added cluster admin permission for the blog&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;horizontalpodautoscalers.autoscaling is forbidden: 
User "arn:aws:sts::xxxxxxx:assumed-role/eks-capability-role/aws-go-sdk-1764587162523491382" 
cannot list resource "horizontalpodautoscalers" in API group "autoscaling" at the cluster scope
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;So to fix that we need to import the access entry created by AWS and add the Cluster Admin Access entry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Import the access entry created by EKS capability
resource "null_resource" "import_access_entry" {
  depends_on = [null_resource.wait_for_argocd]

  provisioner "local-exec" {
    command = &amp;lt;&amp;lt;-EOT
      terraform import -input=false \
        aws_eks_access_entry.capability_role \
        "${local.cluster_name}:${aws_iam_role.eks_capability_role.arn}" || true
    EOT
  }
}

resource "aws_eks_access_entry" "capability_role" {
  cluster_name  = module.eks.cluster_name
  principal_arn = aws_iam_role.eks_capability_role.arn
  type          = "STANDARD"

  lifecycle {
    ignore_changes = [kubernetes_groups]
  }

  depends_on = [null_resource.import_access_entry]
}

# Add ClusterAdmin policy to fix insufficient ArgoCD permissions
resource "aws_eks_access_policy_association" "capability_role_admin" {
  cluster_name  = module.eks.cluster_name
  principal_arn = aws_iam_role.eks_capability_role.arn
  policy_arn    = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"

  access_scope {
    type = "cluster"
  }

  depends_on = [aws_eks_access_entry.capability_role]
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;You can access ArgoCD UI from console -&amp;gt; Capabilities and Under Argo CD&lt;/p&gt;

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

&lt;p&gt;You can login using your IAM identity Center&lt;/p&gt;

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

&lt;p&gt;Argo CD successfully sync the application for Git repository and then ACK creates the S3 bucket&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;

&lt;p&gt;For cleanup before running terraform destroy. Read the &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/working-with-capabilities.html#_delete_a_capability" rel="noopener noreferrer"&gt;delete docs&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Delete the s3 bucket first &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;run the &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2025/blob/master/eks-capabilities/cleanup-capabilities.sh" rel="noopener noreferrer"&gt;cleanup script&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then run &lt;code&gt;terraform destroy&lt;/code&gt;.Because cluster won't be deleted if capabilities are not deleted.&lt;/p&gt;

&lt;h2&gt;
  
  
  DevOps and Platform Engineering perspective
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In this blog we saw the Use case of &lt;em&gt;&lt;strong&gt;GitOps for Applications and Infrastructure&lt;/strong&gt;&lt;/em&gt; where Use Argo CD to deploy applications and ACK to provision infrastructure, both from Git repositories. Your entire stack—applications, databases, storage, and networking—is defined as code and automatically deployed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;We just push the AWS infra yaml files to Git and ArgoCD deploys the updated application, and ACK provisions a new S3 bucket with the correct configuration. &lt;br&gt;
All changes are auditable, reversible, and consistent across environments.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/capabilities.html#_common_use_cases" rel="noopener noreferrer"&gt;can be many use cases &lt;/a&gt; for these capabilities like Account and regional Bootstrapping, Modernization of EKS resources &lt;/p&gt;

&lt;p&gt;Its very interesting to see how they are compared to self managed versions &lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/ack-comparison.html" rel="noopener noreferrer"&gt;ack&lt;/a&gt;,&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/argocd-comparison.html" rel="noopener noreferrer"&gt;argocd&lt;/a&gt;,&lt;a href="https://docs.aws.amazon.com/eks/latest/userguide/kro-comparison.html" rel="noopener noreferrer"&gt;kro&lt;/a&gt;. Ofcourse there are limitations like ArgoCD right now supper single namespace deployment or Notifications Controller in ArgoCD isn't supported&lt;/p&gt;

&lt;p&gt;But overall a great update for Platform engineering which offloads the setup, complexity and management of Kubernetes resources to AWS and lets developers focus on their productivity and applications. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>eks</category>
      <category>reinvent2025</category>
    </item>
    <item>
      <title>Cut CI/CD Costs by 77% &amp; 2x Deployment Speed with GitHub Actions on EKS Auto Mode</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Mon, 21 Apr 2025 00:18:08 +0000</pubDate>
      <link>https://dev.to/aws-builders/cut-cicd-costs-by-77-2x-deployment-speed-with-github-actions-on-eks-auto-2ob2</link>
      <guid>https://dev.to/aws-builders/cut-cicd-costs-by-77-2x-deployment-speed-with-github-actions-on-eks-auto-2ob2</guid>
      <description>&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/s23QvNz2WuY"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;On April 5, 2025 I did a live stream on &lt;a href="https://www.youtube.com/live/s23QvNz2WuY?si=nfqgSid8w1Lm7Epj" rel="noopener noreferrer"&gt;how to run Github Actions Self Hosted Runners on EKS Auto&lt;/a&gt; with AWS Heroes &lt;a href="https://www.linkedin.com/in/arshad-zackeriya-713b821b/" rel="noopener noreferrer"&gt;Arshad Zackeriya&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/jones-zachariah-noel-n/" rel="noopener noreferrer"&gt;Jones Zachariah Noel&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; 🐶 No Beagles were harmed. Slightly annoyed, maybe — but unharmed.&lt;/p&gt;

&lt;p&gt;The results &lt;code&gt;{Performance, Speed, Cost}&lt;/code&gt; were not only astonishing but impeccable and &lt;strong&gt;&lt;em&gt;promising enough to adopt this solution at the enterprise level&lt;/em&gt;&lt;/strong&gt;. This solution isn't just AWS agnostic, with the knowledge gained in this blog can be extended to Azure(AKS), google(GKE) or if you are running K8 on your own bare metal servers.&lt;/p&gt;

&lt;p&gt;For the people who wants to jump straight in to trying the solution can follow &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners" rel="noopener noreferrer"&gt;my repo here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is going to be a bit of a long one, so grab a coffee, get comfy, and make sure you're sitting in your optimal developer position™ — you know the one.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Why this solution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Self Hosted Runner Concept on K8&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terraform Code Walkthrough&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How to test this solution&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Github Large Hosted Runner vs Running Runners on EKS Auto&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;From a solutions architect perspective&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




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

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

&lt;h2&gt;
  
  
  Why this solution
&lt;/h2&gt;

&lt;p&gt;I work as a senior DevOps Engineer at &lt;a href="https://www.colorkrew.com" rel="noopener noreferrer"&gt;Colorkrew&lt;/a&gt; where we have a lot of products and to support the development workflow we have lot of GitHub repositories.&lt;/p&gt;

&lt;p&gt;As we started to increase our product portfolio, our CI/CD pipelines also started to become more complex, concurrent and frequent leading to the need of more computation power and eventually more robust infrastructure layer which supports our growing needs.&lt;/p&gt;

&lt;p&gt;Running Github Actions on default free machines (called as runners) started to become slow and the initial solution was to either use Large hosted runners by GitHub which are paid or run the runners on our Infrastructure like Kubernetes.&lt;/p&gt;

&lt;p&gt;So I started to &lt;code&gt;compare both solutions on performance, speed and cost&lt;/code&gt; and this lead to the inception of this running GitHub's self hosted runners on EKS Auto.&lt;/p&gt;




&lt;h2&gt;
  
  
  Self Hosted Runner Concept on K8
&lt;/h2&gt;

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

&lt;p&gt;&lt;strong&gt;Runners:&lt;/strong&gt; The machines (servers or virtual environments) that actually execute the jobs defined in your workflows. When you manage called as Self Hosted runners otherwise GitHub Hosted runners. Runners are ephemeral in nature. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runner Scale Sets:&lt;/strong&gt; Think of it as a logical grouping of runners that are homogeneous in nature which means all runners under a particular group will have same configuration. Can be installed at repository, organization or enterprise level. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want heterogeneous setup which means different configuration for runners for different ci/cd jobs then you need a multiple runner scale sets.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Another important thing to know about Runner scale sets are that you configure how many minimum and maximum runners you want all the time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Name of Runner Scale Sets:&lt;/strong&gt; Runner scale sets are addressable by their name so remember it because when you need to specify that name of runner scale set in the &lt;code&gt;runs on:&lt;/code&gt; property of GHA to assign that workflow on on a particular runner scale set.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Endpoints:&lt;/strong&gt; ARC talks to two endpoints &lt;code&gt;api.github.com&lt;/code&gt; and &lt;code&gt;pipelines.actions.githubusercontent.com&lt;/code&gt;. Make sure your organization's firewall, proxies, nat gateway whatever being used to access internet should be configured to allow the above endpoints for ARC controller.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ARC controller:&lt;/strong&gt; contains of 2 elements/pods.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;controller-manager&lt;/code&gt;: First pod that comes online. This has different controllers managing different resources in the cluster. Important one to understand is &lt;code&gt;AutoScalingListener&lt;/code&gt; Controller manages the listener pod. 

&lt;ul&gt;
&lt;li&gt;Responsible for creating the resources and making sure that match the desired count and state.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt; &lt;code&gt;Runner ScaleSet Listener&lt;/code&gt;: Manages the decision making about scaling needs. Responsible to decide how many runners to create. Each listener has its own pod which means 1 listener pod per runner scale set. If you have 2 runner scale set then 2 listener pods either on same namespace like controller manager or different namespace ( configurable)&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;I thought should give easier explanation in my own analogies 😋🫣&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/actions/actions-runner-controller" rel="noopener noreferrer"&gt;Actions Runner Controller (ARC&lt;/a&gt;&lt;/strong&gt; &lt;em&gt;is like the manager of a smart, automated coffee shop — it watches how many customers are coming in (workflows) and instantly hires or releases baristas (runners) as needed.&lt;br&gt;
Instead of having baristas standing around all day just in case, ARC spins up temporary baristas (containers in Kubernetes) only when customers arrive, and lets them go when the work is done. This keeps the system fast, efficient, and cost-effective.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;With &lt;strong&gt;&lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners/about-self-hosted-runners" rel="noopener noreferrer"&gt;Runner Scale Sets&lt;/a&gt;,&lt;/strong&gt; you can define the rules for how many baristas you want at any given time, based on how busy your shop is — and ARC handles the rest.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can read more about detailed end to end workflow over &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/about-actions-runner-controller#about-actions-runner-controller" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Terraform Code Walkthrough
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/jatin-mehrotra-personal" rel="noopener noreferrer"&gt;
        jatin-mehrotra-personal
      &lt;/a&gt; / &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners" rel="noopener noreferrer"&gt;
        eks-auto-self-hosted-runners
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Run GitHub Actions Self Hosted Runners on EKS Auto Mode&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;This repository provides infrastructure as code (IaC) to deploy auto-scaling GitHub Actions self-hosted runners on Amazon EKS using GitHub's Actions Runner Controller (ARC).&lt;/p&gt;
&lt;p&gt;detailed blog: &lt;a href="https://dev.to/aws-builders/cut-cicd-costs-by-77-2x-deployment-speed-with-github-actions-on-eks-auto-2ob2" rel="nofollow"&gt;https://dev.to/aws-builders/cut-cicd-costs-by-77-2x-deployment-speed-with-github-actions-on-eks-auto-2ob2&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;See it in action: &lt;a href="https://www.youtube.com/live/s23QvNz2WuY?si=08n0qCVpMYC1qTKc" rel="nofollow noopener noreferrer"&gt;https://www.youtube.com/live/s23QvNz2WuY?si=08n0qCVpMYC1qTKc&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This solution allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deploy a fully managed EKS cluster with auto-scaling capabilities&lt;/li&gt;
&lt;li&gt;Set up GitHub Actions Runner Controller (ARC) for managing self-hosted runners&lt;/li&gt;
&lt;li&gt;Configure auto-scaling runner sets that scale based on workflow demand&lt;/li&gt;
&lt;li&gt;Support Docker-in-Docker (DinD) runners for container-based workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Architecture&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/./architecture/self-hosted-runner-eks-auto.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2Fjatin-mehrotra-personal%2Feks-auto-self-hosted-runners%2FHEAD%2F.%2Farchitecture%2Fself-hosted-runner-eks-auto.png" alt="arch-image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The infrastructure consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Amazon EKS cluster running in a custom VPC&lt;/li&gt;
&lt;li&gt;GitHub Actions Runner Controller deployed via Helm&lt;/li&gt;
&lt;li&gt;Auto-scaling runner sets configured to scale from 0 to meet demand&lt;/li&gt;
&lt;li&gt;Optional Docker-in-Docker (DinD) runner support&lt;/li&gt;
&lt;li&gt;Karpenter for node auto-scaling (configured but optional)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Prerequisites&lt;/h2&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;AWS CLI configured with appropriate permissions&lt;/li&gt;
&lt;li&gt;Terraform v1.0.0+&lt;/li&gt;
&lt;li&gt;kubectl&lt;/li&gt;
&lt;li&gt;Helm v3+&lt;/li&gt;
&lt;li&gt;A GitHub repository or organization where you want to deploy runners&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Setting Up Auto-Scaling GitHub Actions Self-Hosted Runners on Amazon EKS
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Introduction
&lt;/h4&gt;

&lt;p&gt;In this walkthrough, we'll set up GitHub Actions Runner Controller (ARC) on Amazon EKS to automatically scale self-hosted runners based on workflow demand.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;

&lt;p&gt;Here's the structure of our implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eks-auto-self-hosted-runners/
├── README.md
├── architecture/
├── commit_log.txt
├── scripts/
└── terraform/
    ├── base/
    └── modules/
        ├── arc/
        ├── eks/
        ├── karpenter_config/
        └── vpc/

1. Root directory - Contains the main README and architecture diagrams
2. scripts/ - Contains utility scripts for cleanup and performance testing
3. terraform/ - The main infrastructure code
   base/ - The entry point for Terraform deployment
   modules/ - Reusable Terraform modules:
   arc/ - Actions Runner Controller configuration
   eks/ - EKS cluster configuration
   karpenter_config/ - Node auto-scaling configuration
   vpc/ - Network infrastructure configuration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Architecture Overview
&lt;/h3&gt;

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

&lt;p&gt;Our solution uses the following components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Amazon EKS Auto: Managed Kubernetes service to host our runner infrastructure with Karpenter for provisioning nodes on-demand for runners compute&lt;/li&gt;
&lt;li&gt;GitHub Actions Runner Controller (ARC): Kubernetes controller that manages self-hosted runners&lt;/li&gt;
&lt;li&gt;Terraform: Infrastructure as Code tool to deploy and manage all components&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The architecture allows GitHub Actions workflows to dynamically request runners, which are provisioned on-demand in our EKS cluster and automatically scaled down when not needed.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1: Setting Up the Infrastructure
&lt;/h4&gt;

&lt;h5&gt;
  
  
  VPC Configuration
&lt;/h5&gt;

&lt;p&gt;We start by creating a VPC with public and private subnets. Our VPC configuration uses a CIDR block of 10.0.0.0/16 with subnets spread across two availability zones. The &lt;br&gt;
private subnets host our EKS nodes, while public subnets are used for NAT gateways and load balancers.&lt;/p&gt;

&lt;p&gt;The configuration in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/base/vpc.tf" rel="noopener noreferrer"&gt;terraform/base/vpc.tf&lt;/a&gt; references the VPC module and sets up all necessary networking components with appropriate tagging for Kubernetes integration.&lt;/p&gt;
&lt;h5&gt;
  
  
  EKS Cluster Setup
&lt;/h5&gt;

&lt;p&gt;Next, we create an EKS cluster using the EKS module defined in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/tree/master/terraform/modules/eks" rel="noopener noreferrer"&gt;terraform/modules/eks&lt;/a&gt;. Our cluster runs Kubernetes version 1.31 and includes a system node group for running &lt;br&gt;
essential cluster services.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/base/eks.tf" rel="noopener noreferrer"&gt;terraform/base/eks.tf&lt;/a&gt; file configures the cluster with public endpoint access and places the worker nodes in the private subnets for enhanced security.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Configuring EKS Auto's pre-installed Karpenter for Auto-Scaling
&lt;/h4&gt;

&lt;p&gt;EKS Auto comes with Karpenter pre-installed. We leverage Karpenter to  provision and auto scale Ec2 spot instances from our desired Ec2 type, capacity and configuration for our GHA runner's compute.&lt;/p&gt;

&lt;p&gt;Our Karpenter configuration in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/base/karpenter_config.tf" rel="noopener noreferrer"&gt;terraform/base/karpenter_config.tf &lt;/a&gt;uses m7a instance types with spot pricing for cost efficiency. The consolidation policy is set to "WhenEmpty" with a 5-minute timeout, which means nodes will be removed when they're no longer needed.&lt;/p&gt;

&lt;p&gt;Key configuration parameters include:&lt;br&gt;
• Instance types: m7a family with 8 CPUs&lt;br&gt;
• Capacity type: Spot instances for cost savings&lt;br&gt;
• Storage: 300GB with 5000 IOPS&lt;br&gt;
• Availability zones: us-east-1a and us-east-1b&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3: Deploying Actions Runner Controller (ARC)
&lt;/h4&gt;

&lt;p&gt;Now we deploy the GitHub Actions Runner Controller using the ARC module defined in terraform/modules/arc. The module is referenced in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/base/arc.tf" rel="noopener noreferrer"&gt;terraform/base/arc.tf&lt;/a&gt; with configuration parameters from &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/base/locals.tf" rel="noopener noreferrer"&gt;locals.tf&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The ARC deployment consists of two main components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Controller: Manages the lifecycle of runner pods&lt;/li&gt;
&lt;li&gt;Runner Sets: Define the configuration for the runners&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;
  
  
  Controller Deployment
&lt;/h5&gt;

&lt;p&gt;The controller is deployed using a Helm chart from the official GitHub Actions Runner Controller repository. The configuration is defined in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/controller.tf" rel="noopener noreferrer"&gt;terraform/modules/arc/controller.tf&lt;/a&gt; and uses values from &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/helm/controller_values.yaml" rel="noopener noreferrer"&gt;helm/controller_values.yaml&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;
  
  
  Runner Sets Configuration
&lt;/h5&gt;

&lt;p&gt;We deploy two types of runner sets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Standard Runners: For general workflow jobs&lt;/li&gt;
&lt;li&gt;Docker-in-Docker (DinD) Runners: For jobs that need to build Docker images

&lt;ul&gt;
&lt;li&gt;There is also another type of runner set called &lt;code&gt;Kubernetes mode&lt;/code&gt; &lt;strong&gt;which should be used when organizations cannot afford to run docker with superuser context as in case DinD runners then use Kubernetes mode&lt;/strong&gt; ( not covered in this blog) &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The runner sets are defined in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/runner_sets.tf" rel="noopener noreferrer"&gt;terraform/modules/arc/runner_sets.tf&lt;/a&gt; and use values from &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/helm/arc_listener_values.yaml" rel="noopener noreferrer"&gt;helm/arc_listener_values.yaml&lt;/a&gt; and &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/helm/arc_listener_values_dind.yaml" rel="noopener noreferrer"&gt;helm/arc_listener_values_dind.yaml&lt;/a&gt; respectively.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is very important that &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/2e5c6488350feadef130a883e56c5c07ad0494bf/terraform/modules/arc/helm/controller_values.yaml#L69-L74" rel="noopener noreferrer"&gt;Controller pod &lt;/a&gt;and &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/2e5c6488350feadef130a883e56c5c07ad0494bf/terraform/modules/arc/helm/arc_listener_values.yaml#L109-L113" rel="noopener noreferrer"&gt;runner scale set pod&lt;/a&gt; should be configured to be deployed on on-demand ec2 instance for reliability and ephermal runner pods should be configured to run spot instances.&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="c1"&gt;# controller config for on demand node&lt;/span&gt;

&lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;karpenter.sh/nodepool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;

&lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CriticalAddonsOnly"&lt;/span&gt;
  &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exists"&lt;/span&gt;

&lt;span class="c1"&gt;# listener config for on demand node&lt;/span&gt;

&lt;span class="na"&gt;listenerTemplate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;karpenter.sh/nodepool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;system&lt;/span&gt;
    &lt;span class="na"&gt;tolerations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CriticalAddonsOnly"&lt;/span&gt;
      &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Exists"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 4: GitHub Authentication Setup
&lt;/h4&gt;

&lt;p&gt;ARC authenticates with GitHub using a GitHub App. The credentials are stored in Kubernetes secrets and used by the runner controller to authenticate with GitHub.&lt;/p&gt;

&lt;p&gt;To set up authentication:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a GitHub App with the necessary permissions&lt;/li&gt;
&lt;li&gt;Generate a private key for the app&lt;/li&gt;
&lt;li&gt;Store the app ID, installation ID, and private key in the terraform/modules/arc/secrets &lt;strong&gt;(Don't forget to create it, gitignored)&lt;/strong&gt; the directory &lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/secrets.tf" rel="noopener noreferrer"&gt;terraform/modules/arc/secrets.tf&lt;/a&gt; file creates a Kubernetes secret with these credentials&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 5: Namespace Management
&lt;/h4&gt;

&lt;p&gt;We create dedicated namespaces for ARC components:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;arc-systems: For the controller components&lt;/li&gt;
&lt;li&gt;arc-runners: For the runner pods&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These namespaces are defined in &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/terraform/modules/arc/namespaces.tf" rel="noopener noreferrer"&gt;terraform/modules/arc/namespaces.tf&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 6: Cleanup Handling
&lt;/h4&gt;

&lt;p&gt;To ensure proper cleanup of resources, we've included a cleanup script in scripts/cleanup-finalizers.sh that removes finalizers from Kubernetes resources. This script is called during the Terraform destroy process to ensure resources are properly cleaned up.&lt;/p&gt;

&lt;p&gt;The script handles various resource types including:&lt;br&gt;
• AutoscalingRunnerSet&lt;br&gt;
• EphemeralRunnerSet&lt;br&gt;
• AutoscalingListener&lt;br&gt;
• ServiceAccounts&lt;br&gt;
• RoleBindings&lt;br&gt;
• Roles&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;When a GitHub Actions workflow runs, it requests a runner with specific labels&lt;/li&gt;
&lt;li&gt;The ARC controller detects this request and creates a runner pod in the EKS cluster&lt;/li&gt;
&lt;li&gt;If needed, Karpenter provisions a new EC2 instance to host the runner pod&lt;/li&gt;
&lt;li&gt;The runner registers with GitHub and runs the workflow job&lt;/li&gt;
&lt;li&gt;After the job completes, the runner pod is terminated&lt;/li&gt;
&lt;li&gt;When no more runners are needed, Karpenter consolidates and removes unused nodes&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Benefits of This Approach
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Cost Efficiency:&lt;/strong&gt; Runners are only provisioned when needed and automatically scaled down when idle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flexibility:&lt;/strong&gt; Custom runner environments can be defined to meet specific workflow requirements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; The system can handle large numbers of concurrent workflows&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Runners run in isolated Kubernetes pods with defined security contexts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reliability:&lt;/strong&gt; Failed runners are automatically replaced, ensuring workflow reliability&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How to test this solution
&lt;/h2&gt;

&lt;p&gt;I have created &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/actions" rel="noopener noreferrer"&gt;3 GHA of different types&lt;/a&gt; to test different scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple test
&lt;/h3&gt;

&lt;p&gt;The first type is the simple GHA but important point to pay attention is &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/952ce8e4636a47c8eb448c495651322dc02ada6d/.github/workflows/test-gha.yml#L8" rel="noopener noreferrer"&gt;runs-on&lt;/a&gt; parameter which uses &lt;code&gt;arc-runner-set&lt;/code&gt; label.&lt;/p&gt;

&lt;p&gt;The moment you run the first workflow it takes around 1 minute because &lt;code&gt;Karpenter&lt;/code&gt; is provisioning an Ec2 instance.&lt;/p&gt;

&lt;p&gt;Once it is provisioned and if you run the workflow again because Ec2 instance is already present the action completes its execution immediately.&lt;/p&gt;

&lt;p&gt;Karpenter will delete the node if it's unused for at least 5 minutes.&lt;/p&gt;

&lt;p&gt;Now if you have latency sensitive requirement of running your actions immediately then set &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/952ce8e4636a47c8eb448c495651322dc02ada6d/terraform/modules/arc/runner_sets.tf#L21-L24" rel="noopener noreferrer"&gt;minRunners&amp;gt;0 for the runner scale set configuration&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Concurrent job test
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/master/.github/workflows/short-sleepy-matrix.yml" rel="noopener noreferrer"&gt;In this GHA&lt;/a&gt; I am running 5 concurrent jobs running for exactly 1 minute each triggered either through push or manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  DinD job test
&lt;/h3&gt;

&lt;p&gt;There are times when we want to run microservice in container like redis and do e2e testing.&lt;/p&gt;

&lt;p&gt;That's where we need Docker Inside Docker kind of GHA.&lt;/p&gt;

&lt;p&gt;Important point to pay attention here is &lt;a href="https://github.com/jatin-mehrotra-personal/eks-auto-self-hosted-runners/blob/952ce8e4636a47c8eb448c495651322dc02ada6d/.github/workflows/dind-gha.yml#L14" rel="noopener noreferrer"&gt;runs-on parameter&lt;/a&gt; which uses different runner set configured especially for dind workflows&lt;/p&gt;

&lt;p&gt;In this workflow busy box container runs the main job which can talk to redis service container.&lt;/p&gt;




&lt;h2&gt;
  
  
  Github Large Hosted Runner vs Running Runners on EKS Auto
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Performance &amp;amp; Speed
&lt;/h3&gt;

&lt;p&gt;I tried to do the performance and speed comparison of 8 Core CPU vs our solution. &lt;/p&gt;

&lt;p&gt;I tried to run the sleep-matrix GHA using auto-commit script for 10 minutes and every commit happening in every 45 seconds effectively simulating a concurrent job situations for both EKS Auto solution and Github large Runners and results were hands down in favor of our solution&lt;/p&gt;

&lt;p&gt;Our solutions has stable performance with constant 1 minute 8 seconds Execution time throughout.&lt;/p&gt;

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

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

&lt;h3&gt;
  
  
  Price
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Update [21st April 2025]&lt;/strong&gt; : I did a mistake in EKS Auto node management price earlier but after correction our solution makes it even cheaper&lt;/p&gt;

&lt;p&gt;This is little tricky and may not be 100% accurate comparison but still can be considered 70-80% accurate.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Assume over a 30‑day month with 1&amp;nbsp;hour of concurrent CI workloads per day (12 jobs running in parallel). Lets calculate the cost on our solution and as well on Github's self hosted runners&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  For our solution
&lt;/h4&gt;

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

&lt;h4&gt;
  
  
  For Github's large runner
&lt;/h4&gt;

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

&lt;p&gt;There is also a cost Github Teams/Enterprise subscription. I am assuming it's on cheaper side i.e Team's plan for a team of 10 developer&lt;/p&gt;

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

&lt;p&gt;self‑hosting on EKS with m7a.2xlarge Spot nodes costs approximately &lt;strong&gt;$170.38/month​&lt;/strong&gt;, while same GitHub’s 8‑core large hosted runners cost &lt;strong&gt;$731.20/month&lt;/strong&gt;, &lt;strong&gt;&lt;em&gt;so my solution on EKS Auto is YIELDING A WHOOPING SAVINGS OF 76.7%.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;Even if we add Github Team's for EKS solution i.e $40 more which is 170+40 =$210/month which is still a whooping savings of 72%&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Lets assume it's not 1 hour, it's 2&amp;nbsp;hour of concurrent CI workloads per day (12 jobs running in parallel)&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kvlupxutd29ctxllvd8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6kvlupxutd29ctxllvd8.png" alt="Github Large runners cost" width="800" height="515"&gt;&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;&lt;em&gt;yielding a savings of 84%&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; I know I haven't added the networking components cost like &lt;code&gt;nat gateway&lt;/code&gt; even if we add up it will still be cheaper GitHub's large runners :D&lt;/p&gt;




&lt;h2&gt;
  
  
  From a solutions architect perspective
&lt;/h2&gt;

&lt;p&gt;By combining Amazon EKS Auto and GitHub Actions Runner Controller, we've created a solution that aligns with the AWS Well-Architected Framework:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operational Excellence:&lt;/strong&gt;&lt;br&gt;
•  Infrastructure as code through Terraform ensures consistent deployments&lt;br&gt;
• Auto-scaling runners eliminate manual capacity management&lt;br&gt;
• Clean separation of components improves maintainability&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security:&lt;/strong&gt;&lt;br&gt;
• GitHub App authentication with scoped access&lt;br&gt;
• EKS security groups and IAM roles enforce least-privilege&lt;br&gt;
• Private subnets reduce attack surface&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reliability:&lt;/strong&gt;&lt;br&gt;
• Multi-AZ deployment ensures high availability&lt;br&gt;
• Auto-scaling from zero accommodates varying workloads without manual intervention&lt;br&gt;
• EKS Auto's Karpenter provides intelligent node provisioning, ensuring resources are available when needed&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Performance Efficiency:&lt;/strong&gt;&lt;br&gt;
• On-demand scaling ensures resources are used only when needed&lt;br&gt;
• Spot instances reduce costs while maintaining performance&lt;br&gt;
• Customizable instance types allow optimization for specific workload requirements&lt;br&gt;
• Docker-in-Docker support enables container-based workflows with minimal overhead&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost Optimization:&lt;/strong&gt;&lt;br&gt;
• Scale-to-zero capability eliminates costs when no workflows are running&lt;br&gt;
• Spot instances provide significant cost savings (up to 90%) compared to on-demand instances&lt;br&gt;
• Resource consolidation through Karpenter's WhenEmpty policy reduces idle resources&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sustainability:&lt;/strong&gt;&lt;br&gt;
• Efficient resource utilization through auto-scaling minimizes environmental impact&lt;br&gt;
• Scale-to-zero capability reduces energy consumption during idle periods&lt;br&gt;
• Reduced idle resources lower energy consumption&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This solution provides organizations with a scalable, cost-effective platform for running GitHub Actions workflows while maintaining full control over their infrastructure. The architecture can easily scale from small development teams to enterprise-level deployments, adapting to changing workflow requirements without compromising on security or performance.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;By leveraging AWS managed services like EKS and implementing infrastructure as code through Terraform, this solution reduces operational overhead while providing the flexibility needed &lt;br&gt;
for modern CI/CD pipelines. The result is a robust, efficient platform that enables teams to focus on delivering value rather than managing infrastructure.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Follow &lt;a href="https://www.youtube.com/@thezacsshowtalkingaws" rel="noopener noreferrer"&gt;The Zacs' Show Talking AWS&lt;/a&gt; on YouTube or reach out to them if you want to share your knowledge on AWS.&lt;/p&gt;

&lt;p&gt;Have some questions on this solution reach out to me over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>eks</category>
      <category>githubactions</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>AWS CodePipeline + EKS Action: The Easiest Way to Deploy Containers Yet!</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Tue, 25 Feb 2025 06:26:06 +0000</pubDate>
      <link>https://dev.to/aws-builders/aws-codepipeline-eks-action-the-easiest-way-to-deploy-containers-yet-51g9</link>
      <guid>https://dev.to/aws-builders/aws-codepipeline-eks-action-the-easiest-way-to-deploy-containers-yet-51g9</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Amazon Web Services (AWS) CodePipeline Team has simplified Developer, DevOps engineers operational overhead and streamlined the Deployment process to EKS by &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/02/aws-codepipeline-native-amazon-eks-deployment-support/" rel="noopener noreferrer"&gt;introducing an CodePipeline action&lt;/a&gt; to deploy directly to your EKS cluster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Why does it matter to you?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Previously&lt;/strong&gt; if I had to deploy resources to EKS using DevOps approach, &lt;strong&gt;I had to manage codebuild project, permissions to access eks, kubectl, helm commands, other horrific shell commands and still it wont be perfect in one shot&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;I tried this out today so &lt;strong&gt;let me show you how you can simplify your deployment pipeline for EKS by 100%&lt;/strong&gt;, say goodbye to codebuild and remove all the complex process, scripts and command!!!&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EKS cluster with public endpoint.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Kubernetes resource like &lt;code&gt;deployment.yaml&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;You can also helm chart if you wish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you want to try this update with &lt;strong&gt;EKS private Endpoint&lt;/strong&gt; then checkout &lt;a href="https://blog.awsfanboy.com/aws-codepipeline-now-includes-native-support-for-deploying-to-amazon-eks" rel="noopener noreferrer"&gt;this blog&lt;/a&gt; by AWS Hero &lt;a href="https://www.linkedin.com/in/arshad-zackeriya-713b821b/" rel="noopener noreferrer"&gt;Arshad Zackeriya&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Whichever you prefer I have provided both &lt;a href="https://github.com/jatinmehrotra/codepipeline-eks-deployment/tree/master" rel="noopener noreferrer"&gt;(helm chart and deployment.yaml) in this repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the Scenes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  In case of kubernetes manifest file
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;This action logs into eks cluster, set kubeconfig context&lt;/li&gt;
&lt;li&gt;Installs kubectl&lt;/li&gt;
&lt;li&gt;Applies Kubernetes manifests&lt;/li&gt;
&lt;li&gt;Rollout resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  In case of helm chart
&lt;/h3&gt;

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

&lt;ul&gt;
&lt;li&gt;This action logs into eks cluster, set kubeconfig context&lt;/li&gt;
&lt;li&gt;Instals helm &lt;/li&gt;
&lt;li&gt;Instal Helm charts&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create an EKS cluster
&lt;/h2&gt;

&lt;p&gt;Your cluster can be public or private (including those in private VPCs).The pipeline will automatically establish a connection into your private network to deploy your container application, without additional infrastructure needed.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have used eks auto using &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks" rel="noopener noreferrer"&gt;terraform eks module &lt;/a&gt;which is quick and easy with &lt;em&gt;EKS endpoint as public&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  eks.tf
&lt;/h3&gt;



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

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~&amp;gt; 20.31"

  cluster_name                   = local.cluster_name
  cluster_version                = "1.32"
  cluster_endpoint_public_access = true


  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  cluster_compute_config = {
    enabled    = true
    node_pools = ["general-purpose"]
  }

  # Cluster access entry
  # To add the current caller identity as an administrator
  enable_cluster_creator_admin_permissions = true


  tags = {
    Environment = "dev"
    Terraform   = "true"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  vpc.tf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "5.19.0"

  name = "codepipeline-eks-action"
  cidr = "10.0.0.0/16"

  azs             = ["us-east-1a", "us-east-1b"]
  private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
  public_subnets  = ["10.0.4.0/24", "10.0.5.0/24"]

  enable_nat_gateway     = true
  single_nat_gateway     = true
  one_nat_gateway_per_az = false

  enable_dns_hostnames = true
  enable_dns_support   = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = "1"
  }
  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = "1"
  }

  tags = {
    Environment = "terraform-playground"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  pod_identity.tf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data "aws_iam_policy_document" "allow_pod_identity" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }

    actions = [
      "sts:AssumeRole",
      "sts:TagSession"
    ]
  }
}

resource "aws_iam_role" "read_ecr" {
  name               = "read-ecr-role"
  assume_role_policy = data.aws_iam_policy_document.allow_pod_identity.json
}

resource "aws_iam_role_policy_attachment" "read_ecr" {
  role       = aws_iam_role.read_ecr.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
}

resource "aws_eks_pod_identity_association" "read_ecr" {
  cluster_name    = local.cluster_name
  namespace       = "default"
  service_account = "ecr-sa"
  role_arn        = aws_iam_role.read_ecr.arn
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I am using pod identity with ecr repository permission to obtain ecr image for deployment.yaml.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you want complete code for cluster, you can follow this &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/tree/master/eks-auto-mode-terraform-module-support" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create pipeline with EKS deployment action
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Case 1: when kubectl configuration is used.
&lt;/h3&gt;

&lt;p&gt;I am using the source as GitHub using code start connection and code resides in this &lt;a href="https://github.com/jatinmehrotra/codepipeline-eks-deployment/tree/master" rel="noopener noreferrer"&gt;repo&lt;/a&gt;&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Select the cluster&lt;/li&gt;
&lt;li&gt;Provide the path for your &lt;code&gt;deployment.yaml&lt;/code&gt; file (in my case its &lt;a href="https://github.com/jatinmehrotra/codepipeline-eks-deployment/blob/master/deployment.yaml" rel="noopener noreferrer"&gt;deployment.yaml&lt;/a&gt; file)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Case 2: When Helm chart is used
&lt;/h4&gt;

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

&lt;ul&gt;
&lt;li&gt;Enter the release name &lt;/li&gt;
&lt;li&gt;Enter the helm chart (in my case its the &lt;a href="https://github.com/jatinmehrotra/codepipeline-eks-deployment/tree/master/test-chart" rel="noopener noreferrer"&gt;test-chart&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Important step
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Once pipeline is created you need to edit the pipeline service role or update the existing one and add the following permissions to avoid error.&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="o"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;"Statement"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"iam:PassRole"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Condition"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"StringEqualsIfExists"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"iam:PassedToService"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"cloudformation.amazonaws.com"&lt;/span&gt;,
                        &lt;span class="s2"&gt;"elasticbeanstalk.amazonaws.com"&lt;/span&gt;,
                        &lt;span class="s2"&gt;"ec2.amazonaws.com"&lt;/span&gt;,
                        &lt;span class="s2"&gt;"ecs-tasks.amazonaws.com"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"codecommit:CancelUploadArchive"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codecommit:GetBranch"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codecommit:GetCommit"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codecommit:GetRepository"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codecommit:GetUploadArchiveStatus"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codecommit:UploadArchive"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"codedeploy:CreateDeployment"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codedeploy:GetApplication"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codedeploy:GetApplicationRevision"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codedeploy:GetDeployment"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codedeploy:GetDeploymentConfig"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codedeploy:RegisterApplicationRevision"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"codestar-connections:UseConnection"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"elasticbeanstalk:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ec2:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"elasticloadbalancing:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"autoscaling:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudwatch:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"s3:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"sns:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"rds:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"sqs:*"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ecs:*"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"lambda:InvokeFunction"&lt;/span&gt;,
                &lt;span class="s2"&gt;"lambda:ListFunctions"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"opsworks:CreateDeployment"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:DescribeApps"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:DescribeCommands"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:DescribeDeployments"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:DescribeInstances"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:DescribeStacks"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:UpdateApp"&lt;/span&gt;,
                &lt;span class="s2"&gt;"opsworks:UpdateStack"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"cloudformation:CreateStack"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:DeleteStack"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:DescribeStacks"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:UpdateStack"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:CreateChangeSet"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:DeleteChangeSet"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:DescribeChangeSet"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:ExecuteChangeSet"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:SetStackPolicy"&lt;/span&gt;,
                &lt;span class="s2"&gt;"cloudformation:ValidateTemplate"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"codebuild:BatchGetBuilds"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codebuild:StartBuild"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codebuild:BatchGetBuildBatches"&lt;/span&gt;,
                &lt;span class="s2"&gt;"codebuild:StartBuildBatch"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"devicefarm:ListProjects"&lt;/span&gt;,
                &lt;span class="s2"&gt;"devicefarm:ListDevicePools"&lt;/span&gt;,
                &lt;span class="s2"&gt;"devicefarm:GetRun"&lt;/span&gt;,
                &lt;span class="s2"&gt;"devicefarm:GetUpload"&lt;/span&gt;,
                &lt;span class="s2"&gt;"devicefarm:CreateUpload"&lt;/span&gt;,
                &lt;span class="s2"&gt;"devicefarm:ScheduleRun"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"servicecatalog:ListProvisioningArtifacts"&lt;/span&gt;,
                &lt;span class="s2"&gt;"servicecatalog:CreateProvisioningArtifact"&lt;/span&gt;,
                &lt;span class="s2"&gt;"servicecatalog:DescribeProvisioningArtifact"&lt;/span&gt;,
                &lt;span class="s2"&gt;"servicecatalog:DeleteProvisioningArtifact"&lt;/span&gt;,
                &lt;span class="s2"&gt;"servicecatalog:UpdateProduct"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"cloudformation:ValidateTemplate"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"ecr:DescribeImages"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"states:DescribeExecution"&lt;/span&gt;,
                &lt;span class="s2"&gt;"states:DescribeStateMachine"&lt;/span&gt;,
                &lt;span class="s2"&gt;"states:StartExecution"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"appconfig:StartDeployment"&lt;/span&gt;,
                &lt;span class="s2"&gt;"appconfig:StopDeployment"&lt;/span&gt;,
                &lt;span class="s2"&gt;"appconfig:GetDeployment"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"logs:CreateLogGroup"&lt;/span&gt;,
                &lt;span class="s2"&gt;"logs:CreateLogStream"&lt;/span&gt;,
                &lt;span class="s2"&gt;"logs:PutLogEvents"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"arn:aws:logs:us-east-1:xxxx:log-group:/aws/codepipeline/eks-deploy-codepipeline"&lt;/span&gt;,
                &lt;span class="s2"&gt;"arn:aws:logs:us-east-1:xxxxx:log-group:/aws/codepipeline/eks-deploy-codepipeline:log-stream:*"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Sid"&lt;/span&gt;: &lt;span class="s2"&gt;"EksClusterPolicy"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="s2"&gt;"eks:DescribeCluster"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"*"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Sid"&lt;/span&gt;: &lt;span class="s2"&gt;"EksVpcClusterPolicy"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"ec2:DescribeDhcpOptions"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ec2:DescribeNetworkInterfaces"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ec2:DescribeRouteTables"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ec2:DescribeSubnets"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ec2:DescribeSecurityGroups"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ec2:DescribeVpcs"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"*"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="s2"&gt;"ec2:CreateNetworkInterface"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Condition"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"StringEqualsIfExists"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"ec2:Subnet"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"arn:aws:ec2:us-east-1:292170836962:subnet/subnet-example1"&lt;/span&gt;,
                        &lt;span class="s2"&gt;"arn:aws:ec2:us-east-1:292170836962:subnet/subnet-example2"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="s2"&gt;"ec2:CreateNetworkInterfacePermission"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Condition"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"ArnEquals"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"ec2:Subnet"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example1"&lt;/span&gt;,
                        &lt;span class="s2"&gt;"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example2"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;,
        &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="s2"&gt;"ec2:DeleteNetworkInterface"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Condition"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="s2"&gt;"StringEqualsIfExists"&lt;/span&gt;: &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="s2"&gt;"ec2:Subnet"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                        &lt;span class="s2"&gt;"arn:aws:ec2:us-east-1:xxxxx:subnet/subnet-example1"&lt;/span&gt;,
                        &lt;span class="s2"&gt;"arn:aws:ec2:us-east-1:xxxx:subnet/subnet-example2"&lt;/span&gt;
                    &lt;span class="o"&gt;]&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;]&lt;/span&gt;,
    &lt;span class="s2"&gt;"Version"&lt;/span&gt;: &lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create a access entry in eks cluster with &lt;code&gt;AmazonEKSClusterAdminPolicy&lt;/code&gt; &lt;strong&gt;for the above codepipeline service role.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Run the pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Case when kubectl manifest is updated
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(base) jatin.mehrotra@CK0662-001 codepipeline-eks-deployment-no-github % kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
hello-k8s-74fd98b69b-2pwrv   1/1     Running   0          2m37s
hello-k8s-74fd98b69b-g876f   1/1     Running   0          2m37s
hello-k8s-74fd98b69b-phs77   1/1     Running   0          2m37s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Case when helm chart manifest is updated
&lt;/h3&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(base) jatin.mehrotra@CK0662-001 codepipeline-eks-deployment-no-github % kubectl get pods                             
NAME                    READY   STATUS    RESTARTS   AGE
test-67cbfddc66-2gcvj   1/1     Running   0          10m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  From Developer, DevOps perspective
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;With this update I don't have to manage codebuild projects or any kind of compute environment and manage complex scripts, permissions and tool installations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;Following is the image of the setup which I used to have with codebuild before this update. Such a complex mess.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;This is surely a game changer for developers, devops engineers and infra engineers who wants to focus on business problem, their applications and other kubernetes issue like monitoring and scaling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not GitOps approach which is followed by Flux/ArgoCD but the best DevOps approach for EKS cluster in my view.&lt;/p&gt;

&lt;p&gt;Will you use this action for your eks clusters? Let me know in the comments!!!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>codepipeline</category>
      <category>eks</category>
    </item>
    <item>
      <title>CodePipeline EC2 Action: Simplify your EC2 application deployment pipeline by 90%!</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Mon, 24 Feb 2025 03:48:57 +0000</pubDate>
      <link>https://dev.to/aws-builders/simplify-your-ec2-application-deployment-pipeline-by-90-2mbk</link>
      <guid>https://dev.to/aws-builders/simplify-your-ec2-application-deployment-pipeline-by-90-2mbk</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Amazon Web Services (AWS) CodePipeline Team has simplified Developer, DevOps engineers operational overhead and streamlined the Deployment process to EC2 by &lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/02/aws-codepipeline-native-ec2-deployment-support/" rel="noopener noreferrer"&gt;introducing an CodePipeline action&lt;/a&gt; to deploy directly to your EC2 instances.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Why does it matter to you?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Previously, if you wanted to deploy to EC2 instances, you had to use CodeDeploy with an AppSpec file to configure the deployment.&lt;/em&gt; &lt;strong&gt;After this update NO NEED TO MANAGE CODEDEPLOY RESOURCE AND APPSPEC FILE&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I tried this out today so let me show you how you can simplify your deployment pipeline by 90% and remove all the complex process and scripts!!!&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;supports only Linux instance types&lt;/li&gt;
&lt;li&gt;maximum fleet size supported is 500 instances.&lt;/li&gt;
&lt;li&gt;Pipeline V2 only supported&lt;/li&gt;
&lt;li&gt;SSM Agent must be installed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Behind the Scenes
&lt;/h2&gt;

&lt;p&gt;This action performs a &lt;a href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ssm/send-command.html" rel="noopener noreferrer"&gt;send-command using SSM&lt;/a&gt; to execute the script in the instance.&lt;/p&gt;

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

&lt;h2&gt;
  
  
  Create an EC2 instance with Apache
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are creating an instance then you need to create a role with &lt;code&gt;AmazonSSMManagedInstanceCore&lt;/code&gt;, &lt;code&gt;AmazonS3ReadOnlyAccess&lt;/code&gt; and attach to ec2 instance.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add ssm agent to the instance manually either using &lt;code&gt;user data&lt;/code&gt; or logging into existing instance and then running the commands.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;If you are using existing instance then you need to reboot the instance after adding the ssm agent.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have created EC2 with Apache web server for the brevity of the blog.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;su
yum update &lt;span class="nt"&gt;-y&lt;/span&gt;
yum &lt;span class="nb"&gt;install &lt;/span&gt;httpd &lt;span class="nt"&gt;-y&lt;/span&gt;
service httpd start
chkconfig httpd on
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"codepipeline ec2 deployment action"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /var/www/html/index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Create pipeline with Ec2 deployment action
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Here we need to select instance using tags; I have used name tag to identify my instance. &lt;/li&gt;
&lt;li&gt;Then you need to provide the target directory in ec2 instance where you want to deploy.&lt;/li&gt;
&lt;li&gt;Finally path to the executable script file that runs AFTER the Deploy phase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Once pipeline is created you need to edit the pipeline service role and add the following permissions to avoid error.&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="o"&gt;{&lt;/span&gt;
            &lt;span class="s2"&gt;"Effect"&lt;/span&gt;: &lt;span class="s2"&gt;"Allow"&lt;/span&gt;,
            &lt;span class="s2"&gt;"Action"&lt;/span&gt;: &lt;span class="o"&gt;[&lt;/span&gt;
                &lt;span class="s2"&gt;"ssm:CancelCommand"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ssm:DescribeInstanceInformation"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ssm:ListCommandInvocations"&lt;/span&gt;,
                &lt;span class="s2"&gt;"ssm:SendCommand"&lt;/span&gt;
            &lt;span class="o"&gt;]&lt;/span&gt;,
            &lt;span class="s2"&gt;"Resource"&lt;/span&gt;: &lt;span class="s2"&gt;"*"&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Run the pipeline
&lt;/h2&gt;

&lt;p&gt;I am using the source as GitHub using code start connection and code resides in &lt;a href="https://github.com/jatinmehrotra/codepipeline-eks-deployment/blob/master/script.sh" rel="noopener noreferrer"&gt;this repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;a href="https://docs.aws.amazon.com/codepipeline/latest/userguide/tutorials-ec2-deploy.html" rel="noopener noreferrer"&gt;aws guide&lt;/a&gt; mentioned about adding &lt;code&gt;AWSSystemsManagerDefaultEC2InstanceManagementRoleeployAction&lt;/code&gt; to the ec2 instance role but in my environment I didn't needed that permission&lt;/p&gt;

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

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

&lt;h2&gt;
  
  
  Some advanced options for this action
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;You can specify number of instances in number or percentages to deploy to in parallel.&lt;/li&gt;
&lt;li&gt;You can specify number of instances in number or percentages to stop the task after the task fails.&lt;/li&gt;
&lt;li&gt;You can specify load balancer which will block the traffic Toi the instance when deployment is taking for that instance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  From Developer, DevOps perspective
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;With this update I can have an END-to-END AWS native Continuous deployment on EC2 without managing CodeDeploy resources.&lt;/li&gt;
&lt;li&gt;This is surely a game changer for developers and devops engineers who wants to focus on business problem, their applications and not on their complex deployment process.&lt;/li&gt;
&lt;li&gt;Of course this experience of simplifying can be augmented even further to 100% if AWS can add necessary permissions for the role.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After reading this, do you wish to migrate to this action and simplifying your deployment process? Let me know in the comments!!!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I share such amazing &lt;strong&gt;AWS updates on DevOps, Kubernetes and GenAI&lt;/strong&gt; daily over &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt;. Follow me over there so that I can make your life more easy.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>ec2</category>
      <category>codepipeline</category>
      <category>cicd</category>
    </item>
    <item>
      <title>EKS Auto Mode Unlocked for Existing Clusters with Terraform</title>
      <dc:creator>Jatin Mehrotra</dc:creator>
      <pubDate>Fri, 13 Dec 2024 05:59:47 +0000</pubDate>
      <link>https://dev.to/aws-builders/eks-auto-mode-unlocked-for-existing-clusters-with-terraform-545i</link>
      <guid>https://dev.to/aws-builders/eks-auto-mode-unlocked-for-existing-clusters-with-terraform-545i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;In the &lt;a href="https://dev.to/aws-builders/eks-auto-mode-arrives-in-terraform-simplify-kubernetes-today-bgl"&gt;previous blog&lt;/a&gt;, I explained that EKS Auto mode is now supported by terraform-eks-module and &lt;strong&gt;illustrated how we can create new cluster with EKS Auto Mode&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;In this blog, we’ll learn how to enable EKS Auto Mode on existing clusters and migrate workloads from EKS Managed Node Groups to EKS Auto nodes with ZERO DOWNTIME and continued application availability &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/tree/master/eks-auto-mode-existing-cluster-terraform-support" rel="noopener noreferrer"&gt;using my terraform code&lt;/a&gt;.&lt;/em&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I have also added a &lt;strong&gt;BONUS section&lt;/strong&gt; which explains &lt;strong&gt;how we can control our pod's deployments&lt;/strong&gt; on EKS Auto Mode nodes or other compute types.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Motivation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Terraform-provider-aws released a new version &lt;a href="https://github.com/hashicorp/terraform-provider-aws/releases/tag/v5.81.0" rel="noopener noreferrer"&gt;v5.8.1&lt;/a&gt; which &lt;a href="https://github.com/hashicorp/terraform-provider-aws/issues/40411" rel="noopener noreferrer"&gt;allows to enabled EKS Auto with built-in NodePools on existing cluster&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;ul&gt;
&lt;li&gt;Terraform-aws-eks release a new version &lt;a href="https://github.com/terraform-aws-modules/terraform-aws-eks/releases/tag/v20.31.1" rel="noopener noreferrer"&gt;v20.31.1&lt;/a&gt; which allows to use custom NodeClass/NodePools when EKS Auto is enabled without built-in NodePools.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;em&gt;I want this blog to be really short, crisp and efficient so lets jump  into actual steps!&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploy Terraform cluster without EKS Auto Mode
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We want to create the use case where we have an existing cluster WITHOUT EKS Auto Mode using EKS MNG.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use this &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/tree/master/eks-auto-mode-existing-cluster-terraform-support" rel="noopener noreferrer"&gt;repository code&lt;/a&gt; to deploy EKS cluster with Managed node group.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;em&gt;I am attaching policies to the node IAM role for EKS MNG - this is too permissive, better to use EKS Pod Identity (or IRSA, but EKS Pod Identity is preferred). Feel free to send a PR to the repo&lt;/em&gt; :)&lt;/p&gt;

&lt;h3&gt;
  
  
  Deploy  workload or pods
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We will automate this as well using terraform's &lt;code&gt;kubectl_manifest&lt;/code&gt; resource, we will deploy workload yaml code using terraform&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; During cluster creation, &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/blob/master/eks-auto-mode-existing-cluster-terraform-support/sample_app.tf" rel="noopener noreferrer"&gt;test workload(pods)&lt;/a&gt; were not deployed because kubectl context was not set locally. So run the following command to set the &lt;code&gt;kubectl context&lt;/code&gt; and run &lt;code&gt;terraform apply&lt;/code&gt; again once cluster is created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws eks --region us-east-1 update-kubeconfig --name eks-existing-cluster-tf-test --profile &amp;lt;your-profile-name&amp;gt; ; terraform apply

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Current state of EKS cluster before EKS Auto Mode
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Let's verify the current state of eks cluster when EKS Auto mode is not enabled.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EKS Auto mode is disabled. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;EKS Auto Managed Node group created by me is running. &lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Pods are running on EKS managed node group&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;h2&gt;
  
  
  Enable EKS Auto Mode on Existing Cluster
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Uncomment the following code to the eks.tf and &lt;code&gt;terraform apply&lt;/code&gt; to enable EKS Auto Mode
&lt;/li&gt;
&lt;/ul&gt;

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

cluster_compute_config = {
   enabled = true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;bootstrap_self_managed_addons = true&lt;/code&gt; is very important &lt;strong&gt;&lt;em&gt;otherwise you will face error where terraform tries to recreate the cluster again&lt;/em&gt;&lt;/strong&gt;. &lt;em&gt;I literally cried over this&lt;/em&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Current state of EKS cluster after EKS Auto Mode
&lt;/h3&gt;

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

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

&lt;ul&gt;
&lt;li&gt;As expected built-in NodePools are empty&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migrate workload(pods) from EKS MNG to EKS Auto Node
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There are &lt;a href="https://repost.aws/knowledge-center/eks-worker-node-actions" rel="noopener noreferrer"&gt;couple of ways&lt;/a&gt; to smoothly migrate existing workloads from MNG to EKS Auto with minimal disruption while maintaining application’s availability throughout the migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Copy the EKS MNG node group name.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using eksctl tool
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The following &lt;a href="https://eksctl.io/usage/nodegroups/#deleting-and-draining-nodegroups" rel="noopener noreferrer"&gt;command&lt;/a&gt; &lt;em&gt;will cordon all nodes and all pods are evicted from a nodegroup&lt;/em&gt; and &lt;strong&gt;EKS will provision pods to node managed by EKS Auto.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eksctl drain nodegroup --cluster=&amp;lt;clusterName&amp;gt; --name=&amp;lt;copiedNodegroupName&amp;gt;  --region us-east-1 --profile=&amp;lt;profile&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;eksctl command evicts pod one at a time which I have tested so application availability is maintained.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;But if you still want to be 100% sure, you can use the best practice of using &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/blob/master/eks-auto-mode-existing-cluster-terraform-support/pdb.tf" rel="noopener noreferrer"&gt;pod Disruption budget&lt;/a&gt;. We will automate this using terraform so run &lt;code&gt;terraform apply&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "kubectl_manifest" "test_pdb" {
  yaml_body = &amp;lt;&amp;lt;YAML
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: test-pdb
  labels:
    environment: test
spec:
  minAvailable: 1
  selector:
    matchLabels:
      environment: test
YAML
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

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

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;After migrating; If we want to allow scheduling pods to EKS MNG we need to uncordon the EKS MNG or you can delete the Node group&lt;/em&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;eksctl drain nodegroup --cluster=&amp;lt;clusterName&amp;gt; --name=&amp;lt;copiedNodegroupName&amp;gt;  --region us-east-1 --profile=&amp;lt;profile&amp;gt; --undo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h3&gt;
  
  
  Using kubectl
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;we can use the following command to drain the nodes using kubectl
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl drain --ignore-daemonsets &amp;lt;node name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Once it returns (without giving an error), you can delete the node or you want to tell Kubernetes that it can resume scheduling new pods onto the node
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl uncordon &amp;lt;node name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  [ BONUS ] How to schedule Pods always on EKS Auto Nodes?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;There are 2 options to achieve this :&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Either delete The NodeGroup and let EKS Auto handle the scheduling on EKS Auto Nodes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using labels and NodeAffinity &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Control if a workload is deployed on EKS Auto Mode nodes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There is concept called mix-mode cluster where you’re running both EKS Auto Mode and other compute types, such as self-managed Karpenter provisioners or EKS Managed Node Groups.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In mix mode clusters by default deployment is deployed to EKS MNG nodes and not EKS Auto Nodes&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In such case we can use labels and nodeAffinity.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Using NodeSelector label
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Use the label &lt;code&gt;eks.amazonaws.com/compute-type: auto&lt;/code&gt; &lt;strong&gt;when you want a workload is deployed to EKS Auto Node.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;This nodeSelector value is only relevant if you are running a cluster in a mixed mode, node types not managed by EKS Auto Mode
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
spec:
      nodeSelector:
        eks.amazonaws.com/compute-type: auto
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I have an added the above configuration in &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/blob/master/eks-auto-mode-existing-cluster-terraform-support/sample_app_on_eks_auto_nodes.tf" rel="noopener noreferrer"&gt;sample_app_on_eks_auto_nodes.tf&lt;/a&gt; file. We are automating using Terraform so uncomment and run `terraform apply.&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;h4&gt;
  
  
  Using nodeAffinity
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You can add this nodeAffinity to Deployments or other workloads to require Kubernetes to not schedule them onto EKS Auto Mode nodes&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;I have added the workload with nodeAffinity in &lt;a href="https://github.com/jatinmehrotra/aws-reinvent-2024/blob/master/eks-auto-mode-existing-cluster-terraform-support/sample_app_not_on_eks_auto_nodes.tf" rel="noopener noreferrer"&gt;sample_app_not_on_eks_auto_nodes.tf&lt;/a&gt; . We are automating using Terraform so uncomment and  run &lt;code&gt;terraform apply&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;h2&gt;
  
  
  From DevOps, IaC Perspective
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We saw how we can enable EKS Auto mode for Existing clusters with built-in NodePools using terraform-eks-module &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We also saw how we can migrate our existing workload from EKS Managed Group to EKS Auto Nodes without any down time as EKS Auto node respect PodDisruptionBudget.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We also saw how we can use nodeSelector Labels and nodeAffinity to control deployment of workload in case of mixed-mode EKS clusters. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Currently &lt;strong&gt;EKS Auto deploys EC2 of instance type c6a.large which can be also customized using nodeClass and NodePool&lt;/strong&gt; which we will see in the next blog. Follow me on &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or on &lt;a href="https://dev.to/jatinmehrotra"&gt;dev.to&lt;/a&gt; so that you get timely updates of what I share.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Feel free to reach out to me on &lt;a href="https://www.linkedin.com/in/jatinmehrotra/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;, &lt;a href="https://x.com/imjatinmehrotra" rel="noopener noreferrer"&gt;X&lt;/a&gt; if you face any error migrating your Existing workloads to EKS Auto Mode Nodes using terraform.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>kubernetes</category>
      <category>terraform</category>
      <category>eks</category>
    </item>
  </channel>
</rss>
