<?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: Tetsuya KIKUCHI</title>
    <description>The latest articles on DEV Community by Tetsuya KIKUCHI (@t-kikuc).</description>
    <link>https://dev.to/t-kikuc</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2606492%2F4c1eaa70-d647-427d-ab88-13282297ce84.jpeg</url>
      <title>DEV Community: Tetsuya KIKUCHI</title>
      <link>https://dev.to/t-kikuc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/t-kikuc"/>
    <language>en</language>
    <item>
      <title>ECS Native Blue/Green is Here! With Strong Hooks and Dark Canary</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Sun, 20 Jul 2025 05:42:48 +0000</pubDate>
      <link>https://dev.to/aws-builders/ecs-native-bluegreen-is-here-with-strong-hooks-and-dark-canary-8ff</link>
      <guid>https://dev.to/aws-builders/ecs-native-bluegreen-is-here-with-strong-hooks-and-dark-canary-8ff</guid>
      <description>&lt;p&gt;On July 18, 2025, Amazon ECS received a major deployment enhancement. It's not just about native Blue/Green support - there's much more to it!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is translated from &lt;a href="https://zenn.dev/cadp/articles/ecs-builtin-blue-green" rel="noopener noreferrer"&gt;my article&lt;/a&gt; in Japanese.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Points
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Native Blue/Green is now available &lt;strong&gt;without CodeDeploy&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Various validation timings through &lt;strong&gt;lifecycle hooks&lt;/strong&gt; with Lambda&lt;/li&gt;
&lt;li&gt;Pre-validation in production environment with zero user impact (&lt;strong&gt;Dark Canary&lt;/strong&gt;) using test listeners/listener rules&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Blue/Green is now supported &lt;strong&gt;with Service Connect&lt;/strong&gt;
&lt;/li&gt;

&lt;li&gt;Deployment controller can be changed after service creation&lt;/li&gt;

&lt;li&gt;You should &lt;strong&gt;avoid CodeDeploy-based Blue/Green&lt;/strong&gt; (migration guide available)&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This article does not cover Blue/Green with Service Connect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2025/07/amazon-ecs-built-in-blue-green-deployments/" rel="noopener noreferrer"&gt;https://aws.amazon.com/about-aws/whats-new/2025/07/amazon-ecs-built-in-blue-green-deployments/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Blue/Green deployment is now available as a built-in ECS feature without requiring CodeDeploy.&lt;br&gt;
You can select it directly from the console:&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%2Fwv748kipri20e81m2zbw.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%2Fwv748kipri20e81m2zbw.png" width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This B/G deployment comes with two optional features that make automated and safe deployments easier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment lifecycle hooks for custom validation&lt;/li&gt;
&lt;li&gt;Test listener / listener rules for Dark Canary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, there's a subtle but significant update: "deployment controller can be changed after service creation."&lt;/p&gt;
&lt;h3&gt;
  
  
  Previous Situation
&lt;/h3&gt;

&lt;p&gt;When implementing Blue/Green in ECS, combining with CodeDeploy was common but had several pain points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Required cumbersome CodeDeploy setup&lt;/li&gt;
&lt;li&gt;Couldn't switch between rolling update ↔ B/G after service creation&lt;/li&gt;
&lt;li&gt;Had various constraints when combined with CodeDeploy

&lt;ul&gt;
&lt;li&gt;Example: Couldn't use Service Connect&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rolling updates also had challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Limited flexibility in success/failure determination (despite having CloudWatch alarms and deployment circuit breakers)&lt;/li&gt;
&lt;li&gt;Time-consuming rollbacks (requiring new task launches)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Benefits of This Update
&lt;/h3&gt;

&lt;p&gt;The update brings several significant improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Easy Blue/Green deployment without CodeDeploy setup.&lt;/li&gt;
&lt;li&gt;Able to switch between rolling update and B/G &lt;strong&gt;even after service creation&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Basically just change the &lt;code&gt;strategy&lt;/code&gt;. No service recreation &amp;amp; migration needed.&lt;/li&gt;
&lt;li&gt;Easy to "start simple with rolling update, switch to B/G when needed".&lt;/li&gt;
&lt;li&gt;Detailed migration guide in &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/migrate-deployment-strategies.html" rel="noopener noreferrer"&gt;this documentation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Also includes B/G → rolling update migration, suggesting rolling updates aren't deprecated.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Features from CodeDeploy are available, making it convenient + easy to migrate from CodeDeploy.

&lt;ul&gt;
&lt;li&gt;Flexible validation with Lambda.&lt;/li&gt;
&lt;li&gt;Zero-impact new version testing in production environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Being a native feature, likely to have fewer constraints than CodeDeploy integration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blue/Green deployment now works with Service Connect&lt;/strong&gt;.

&lt;ul&gt;
&lt;li&gt;Removes one drawback of Service Connect and shows it's being actively maintained.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Detailed Features
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Deployment Lifecycle Hooks
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-lifecycle-hooks.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-lifecycle-hooks.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In native Blue/Green, you can validate deployment success using custom logic through Lambda functions at various stages.&lt;br&gt;
For example, you can monitor service status, access endpoints, or check telemetry data.&lt;/p&gt;

&lt;p&gt;This is similar to &lt;a href="https://docs.aws.amazon.com/codedeploy/latest/userguide/reference-appspec-file-structure-hooks.html#appspec-hooks-ecs" rel="noopener noreferrer"&gt;CodeDeploy's hooks feature&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;
  
  
  Lifecycle Stages
&lt;/h4&gt;

&lt;p&gt;There are 7 hook timings (lifecycle stages):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;PRE_SCALE_UP&lt;/code&gt;: Before new tasks launch&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST_SCALE_UP&lt;/code&gt;: After new tasks launch and become healthy&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;TEST_TRAFFIC_SHIFT&lt;/code&gt;: During test traffic shift to Green (0-&amp;gt;100%)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST_TEST_TRAFFIC_SHIFT&lt;/code&gt;: After test traffic is 100% on Green&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PRODUCTION_TRAFFIC_SHIFT&lt;/code&gt;: During production traffic shift to Green&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST_PRODUCTION_TRAFFIC_SHIFT&lt;/code&gt;: After production traffic shift to Green&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RECONCILE_SERVICE&lt;/code&gt;: When deployment starts with multiple ACTIVE service revisions

&lt;ul&gt;
&lt;li&gt;Not selectable in console but available via CLI. Purpose unclear.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;During rollback, &lt;code&gt;TEST_TRAFFIC_SHIFT&lt;/code&gt; and &lt;code&gt;PRODUCTION_TRAFFIC_SHIFT&lt;/code&gt; are hooked.&lt;/p&gt;
&lt;h4&gt;
  
  
  Event Payload
&lt;/h4&gt;

&lt;p&gt;The event payload includes service ARN and weight information, allowing validation logic based on these values.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;Event:&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"executionDetails"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"testTrafficWeights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"productionTrafficWeights"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account-id&amp;gt;:service-revision/my-cluster/native-bg-1/9942985458929989075"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account-id&amp;gt;:service-revision/my-cluster/native-bg-1/2948000638822554633"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"serviceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account-id&amp;gt;:service/my-cluster/native-bg-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"targetServiceRevisionArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account-id&amp;gt;:service-revision/my-cluster/native-bg-1/2948000638822554633"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"executionId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"06a4bc13-a7fa-4281-ab04-3aa34234ddxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"lifecycleStage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PRODUCTION_TRAFFIC_SHIFT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resourceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account-id&amp;gt;:service-deployment/my-cluster/native-bg-1/PNpQryOI09kD3iMrxsoxx"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Function Return Values
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;hookStatus=SUCCEEDED&lt;/code&gt;: Validation successful, deployment proceeds&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hookStatus=FAILED&lt;/code&gt;: Triggers rollback&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hookStatus=IN_PROGRESS&lt;/code&gt;: Function called again after a delay

&lt;ul&gt;
&lt;li&gt;Useful for long-running checks or when validation data isn't yet available&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://aws.amazon.com/blogs/aws/accelerate-safe-software-releases-with-new-built-in-blue-green-deployments-in-amazon-ecs/" rel="noopener noreferrer"&gt;Official blog&lt;/a&gt; mentions 30-second intervals, confirmed in testing
&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%2Fm8ue00eebz8o2nmt1nms.png" width="800" height="323"&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Note: Partially Available in Rolling Update??
&lt;/h4&gt;

&lt;p&gt;While the console doesn't show lifecycle hooks or bake time settings for rolling updates,&lt;br&gt;
CLI allows selecting these with rolling updates. LB settings from B/G remain.&lt;/p&gt;

&lt;p&gt;In actual deployment, only the &lt;code&gt;PRE_SCALE_UP&lt;/code&gt; hook triggered Lambda. Unclear if this is intended behavior.&lt;/p&gt;
&lt;h3&gt;
  
  
  Test Listener / Listener Rule (Dark Canary)
&lt;/h3&gt;

&lt;p&gt;Using test listeners/listener rules, developers/testers can access the Green environment before production traffic shifts.&lt;br&gt;
This is called "Dark Canary" as end users don't access it.&lt;/p&gt;
&lt;h4&gt;
  
  
  Benefits
&lt;/h4&gt;

&lt;p&gt;Compared to simple Blue/Green, this reduces the risks of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete disaster when 100% traffic is shifted to Green, even temporarily&lt;/li&gt;
&lt;li&gt;"Works in staging but fails in production" scenarios&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Usage
&lt;/h4&gt;

&lt;p&gt;Create separate access routes for developers using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listeners with different ports&lt;/li&gt;
&lt;li&gt;Listener rules with conditions (headers, source IPs, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This phase is validated by &lt;code&gt;TEST_TRAFFIC_SHIFT&lt;/code&gt; and &lt;code&gt;POST_TEST_TRAFFIC_SHIFT&lt;/code&gt; hooks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Return &lt;code&gt;hookStatus=IN_PROGRESS&lt;/code&gt; for zero-impact rollback&lt;/li&gt;
&lt;li&gt;Deployment stays &lt;code&gt;IN_PROGRESS&lt;/code&gt; while returning &lt;code&gt;hookStatus=IN_PROGRESS&lt;/code&gt; (timeout unknown, confirmed &amp;gt;3 hours)

&lt;ul&gt;
&lt;li&gt;For manual validation, consider having Lambda monitor a flag and return &lt;code&gt;hookStatus=SUCCEEDED&lt;/code&gt; when set&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Additionally, Deployment Controller Now Updatable Post-Creation
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/update-service-parameters.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/update-service-parameters.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A subtle but important documentation update.&lt;/p&gt;

&lt;p&gt;Background: There are 3 &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeploymentController.html" rel="noopener noreferrer"&gt;deployment controllers&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ECS&lt;/code&gt; (Enhanced now, most common)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CODE_DEPLOY&lt;/code&gt; (Traditional B/G deployment)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXTERNAL&lt;/code&gt; (For customization. Details: &lt;a href="https://zenn.dev/cadp/articles/ecs-external" rel="noopener noreferrer"&gt;ECS External Deployment &amp;amp; TaskSet Guide&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Previously unchangeable after service creation, now supports 4 update patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CODE_DEPLOY&lt;/code&gt; -&amp;gt; &lt;code&gt;ECS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CODE_DEPLOY&lt;/code&gt; -&amp;gt; &lt;code&gt;EXTERNAL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ECS&lt;/code&gt; -&amp;gt; &lt;code&gt;EXTERNAL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXTERNAL&lt;/code&gt; -&amp;gt; &lt;code&gt;ECS&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Hmm?&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Signs of &lt;code&gt;CODE_DEPLOY&lt;/code&gt; Type Deprecation &lt;em&gt;Not CodeDeploy itself&lt;/em&gt;
&lt;/h4&gt;

&lt;p&gt;Notice no update patterns TO &lt;code&gt;CODE_DEPLOY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;CODE_DEPLOY&lt;/code&gt; docs &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-bluegreen.html" rel="noopener noreferrer"&gt;clearly recommend&lt;/a&gt; the new native B/G:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We recommend that you use the Amazon ECS blue/green deployment.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;CODE_DEPLOY&lt;/code&gt; option removed from console.&lt;br&gt;
Migration docs provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/migrate-codedeploy-to-ecs-bluegreen.html" rel="noopener noreferrer"&gt;To native B/G&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/migrate-code-deploy-to-ecs-rolling.html" rel="noopener noreferrer"&gt;To rolling update&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This likely prompted deployment controller update support.&lt;/p&gt;

&lt;p&gt;No deprecation notices or migration guides for &lt;code&gt;EXTERNAL&lt;/code&gt;, suggesting it's safe.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Like EKS on Fargate Auto Mode, nice to see deprecation/removal after superior alternatives emerge. Unlike certain other cases...&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Benefits of This Update
&lt;/h4&gt;

&lt;p&gt;Makes &lt;code&gt;CODE_DEPLOY&lt;/code&gt; to &lt;code&gt;ECS&lt;/code&gt; migration easier.&lt;/p&gt;

&lt;p&gt;Also greatly simplifies &lt;a href="https://pipecd.dev/" rel="noopener noreferrer"&gt;PipeCD&lt;/a&gt; migration for ECS.&lt;/p&gt;

&lt;p&gt;PipeCD uses &lt;code&gt;EXTERNAL&lt;/code&gt; for ECS deployments.&lt;br&gt;
Previously, migrating from rolling update(&lt;code&gt;ECS&lt;/code&gt;) or &lt;code&gt;CODE_DEPLOY&lt;/code&gt; required service recreation.&lt;br&gt;
For running services, complex ALB listener-based migration was needed.&lt;/p&gt;

&lt;p&gt;Now possible without service recreation (both to and from PipeCD).&lt;/p&gt;

&lt;p&gt;Also enables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Switch from &lt;code&gt;ECS&lt;/code&gt; to &lt;code&gt;EXTERNAL&lt;/code&gt; for customization"&lt;/li&gt;
&lt;li&gt;"Try &lt;code&gt;EXTERNAL&lt;/code&gt;, revert to &lt;code&gt;ECS&lt;/code&gt; if too complex"&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Note
&lt;/h4&gt;

&lt;p&gt;Can't migrate from &lt;code&gt;ECS&lt;/code&gt; if using VPC Lattice or Service Connect:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can't update the deployment controller of a service from the ECS deployment controller to any of the other controllers if it uses VPC Lattice or Amazon ECS Service Connect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  How It Works (ALB Case)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/bluegreen-how-it-works.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/bluegreen-how-it-works.html&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Deployment Flow
&lt;/h3&gt;

&lt;p&gt;Created diagram as &lt;a href="https://docs.aws.amazon.com/images/AmazonECS/latest/developerguide/images/bluegreen.png" rel="noopener noreferrer"&gt;official one&lt;/a&gt; felt incomplete:&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%2Fw47osduoiqknr8ri1fu3.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%2Fw47osduoiqknr8ri1fu3.png" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Initial State ~ Green Environment Launch

&lt;ol&gt;
&lt;li&gt;Initial state: Blue environment receiving 100% traffic&lt;/li&gt;
&lt;li&gt;Launch Green tasks, attach to Green target group&lt;/li&gt;
&lt;li&gt;ALB health checks Green environment&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Internal Green environment testing (no production traffic)&lt;/li&gt;
&lt;li&gt;Switch production traffic to Green

&lt;ul&gt;
&lt;li&gt;Brief for "All at once"&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Post-Green Switch ~ Deployment Complete

&lt;ol&gt;
&lt;li&gt;Monitor: Watch CloudWatch alarms, auto-rollback if issues

&lt;ul&gt;
&lt;li&gt;Continues until &lt;strong&gt;Bake Time&lt;/strong&gt; parameter expires&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Delete Blue tasks&lt;/li&gt;
&lt;li&gt;Deployment complete&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Next deployment reverses Blue/Green, moving from Target Group Green to Blue.&lt;/p&gt;
&lt;h3&gt;
  
  
  During Rollback
&lt;/h3&gt;

&lt;p&gt;Rollback simply returns traffic to coexisting Blue environment via listener rules.&lt;br&gt;
Faster than rolling update as no task launches needed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Hands-On Testing
&lt;/h2&gt;

&lt;p&gt;Following this official blog:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/blogs/aws/accelerate-safe-software-releases-with-new-built-in-blue-green-deployments-in-amazon-ecs/" rel="noopener noreferrer"&gt;https://aws.amazon.com/blogs/aws/accelerate-safe-software-releases-with-new-built-in-blue-green-deployments-in-amazon-ecs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Resource details here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/alb-resources-for-blue-green.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/alb-resources-for-blue-green.html&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Service Update
&lt;/h3&gt;

&lt;p&gt;Configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;task definition: httpd → nginx&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deployment options&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Deployment controller type: &lt;code&gt;ECS&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Previously chose between &lt;code&gt;ECS&lt;/code&gt; or &lt;code&gt;CODE_DEPLOY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;strategy&lt;/strong&gt;: Blue/Green&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bake time&lt;/strong&gt;: 5 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lifecycle hooks&lt;/strong&gt;:&lt;/li&gt;
&lt;li&gt;Lambda function: Simple function returning &lt;code&gt;"hookStatus": "SUCCEEDED"&lt;/code&gt; after accessing ALB URL
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;urllib3&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;import&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;
  &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

  &lt;span class="c1"&gt;# Configure logging
&lt;/span&gt;  &lt;span class="n"&gt;logger&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="nf"&gt;getLogger&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;setLevel&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="n"&gt;DEBUG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# Initialize HTTP client
&lt;/span&gt;  &lt;span class="n"&gt;http&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urllib3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PoolManager&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;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
      &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
     Validation hook that tests the green environment by accessing &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="s"&gt;
      &lt;/span&gt;&lt;span class="sh"&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;Event: &lt;/span&gt;&lt;span class="si"&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;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&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="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;Context: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;context&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="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
     &lt;span class="n"&gt;test_endpoint&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="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;APP_URL&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="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&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="n"&gt;test_endpoint&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="mi"&gt;30&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;GET / response status: &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="n"&gt;status&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="c1"&gt;# Check if response has OK status code (200-299 range)
&lt;/span&gt;          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;300&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;test passed - received OK status code&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="p"&gt;{&lt;/span&gt;
                  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hookStatus&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;SUCCEEDED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="k"&gt;else&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;error&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;test failed - status code: &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="n"&gt;status&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="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;hookStatus&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;FAILED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&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;error&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;test failed: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&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="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;hookStatus&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;FAILED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;ul&gt;
&lt;li&gt;Role: Role with &lt;code&gt;lambda:InvokeFunction&lt;/code&gt;. &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/blue-green-permissions.html" rel="noopener noreferrer"&gt;Reference&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Role for ECS to invoke Lambda&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lifecycle stages&lt;/strong&gt;: All 6 selected&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Load balancing&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role: Policy based on &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AmazonECSInfrastructureRolePolicyForLoadBalancers.html" rel="noopener noreferrer"&gt;this doc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Role for ECS to update listener rules&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;elasticloadbalancing&lt;/code&gt; permissions (&lt;code&gt;DescribeTargetGroups&lt;/code&gt;, &lt;code&gt;DescribeTargetHealth&lt;/code&gt;,&lt;code&gt;RegisterTargets&lt;/code&gt;,&lt;code&gt;DeregisterTargets&lt;/code&gt;) due to permission errors&lt;/li&gt;
&lt;li&gt;Load balancer type: ALB&lt;/li&gt;
&lt;li&gt;Listener (production): HTTP:80&lt;/li&gt;
&lt;li&gt;Production listener rule: Listener default&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test listener&lt;/strong&gt; (Green test access): Different port HTTP:81&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test listener rule&lt;/strong&gt;: Listener default&lt;/li&gt;
&lt;li&gt;Target group (Blue): IP type with HTTP:80&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alternate target group&lt;/strong&gt; (Green): Same settings as Blue&lt;/li&gt;
&lt;li&gt;"Create alternate target group" option creates with just naming&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Deployment
&lt;/h3&gt;
&lt;h4&gt;
  
  
  2-1. Test Traffic
&lt;/h4&gt;

&lt;p&gt;First, Green tasks launched and &lt;code&gt;POST_SCALE_UP&lt;/code&gt; lifecycle hooks succeeded.&lt;br&gt;
Green accessible via test listener (HTTP:81).&lt;/p&gt;

&lt;p&gt;Green port 81 showed nginx:&lt;br&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%2Fpi3iutke9t8jbwwnrgwb.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%2Fpi3iutke9t8jbwwnrgwb.png" width="800" height="393"&gt;&lt;/a&gt;&lt;br&gt;
Blue port 80 showed httpd:&lt;br&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%2F3ythl7t8ybgfmdp30vp6.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%2F3ythl7t8ybgfmdp30vp6.png" width="800" height="396"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ALB test listener (port 81) rule changed to Green (group2):&lt;br&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%2Fboxbw22vsha8l6b7qzhd.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%2Fboxbw22vsha8l6b7qzhd.png" width="800" height="84"&gt;&lt;/a&gt;&lt;br&gt;
Production listener (port 80) rule still Blue:&lt;br&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%2Ffeafv2qyml11vspumv95.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%2Ffeafv2qyml11vspumv95.png" width="800" height="87"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST_TEST_TRAFFIC_SHIFT&lt;/code&gt; lifecycle hooks succeeded.&lt;/p&gt;
&lt;h4&gt;
  
  
  2-2. Production Traffic Switch
&lt;/h4&gt;

&lt;p&gt;Production traffic switches to Green.&lt;/p&gt;

&lt;p&gt;Port 80 access switched to nginx:&lt;br&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%2Frdz6v40ujcu3ke91py3p.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%2Frdz6v40ujcu3ke91py3p.png" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ALB production listener rule switched to Green:&lt;br&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%2Frna5mcibzljtidwy3v79.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%2Frna5mcibzljtidwy3v79.png" width="800" height="81"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test listener still accessed Green environment.&lt;/p&gt;
&lt;h4&gt;
  
  
  2-3. Bake Time
&lt;/h4&gt;

&lt;p&gt;Blue(Source) tasks still running for fast rollback, no production traffic:&lt;br&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%2Fw9o5sboa7nq9clrdjajs.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%2Fw9o5sboa7nq9clrdjajs.png" width="800" height="123"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After bake time, Blue tasks deleted:&lt;br&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%2Fq0l7s67q8r1tt1yckz6y.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%2Fq0l7s67q8r1tt1yckz6y.png" width="800" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Event history shows:&lt;br&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%2F5xozu3u9v2hlkdylf14c.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%2F5xozu3u9v2hlkdylf14c.png" width="800" height="54"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Deployment Status Monitoring
&lt;/h4&gt;

&lt;p&gt;Current stage visible in Deployments screen:&lt;br&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%2Frh8u46rqy7c1q9l4458e.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%2Frh8u46rqy7c1q9l4458e.png" width="800" height="180"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click stage to see hook-Lambda function mappings:&lt;br&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%2F897x05hr21t3ou6kfa99.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%2F897x05hr21t3ou6kfa99.png" width="774" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Personally, stage start/end status in Events would help track timing and troubleshoot.&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Testing Hook Failure
&lt;/h3&gt;

&lt;p&gt;Testing rollback by failing &lt;code&gt;POST_SCALE_UP&lt;/code&gt; lifecycle hooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Replace Lambda function&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use this always failing function:&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;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;

&lt;span class="n"&gt;logger&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="nf"&gt;getLogger&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;setLevel&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="n"&gt;DEBUG&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;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;context&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;always return failure&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="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hookStatus&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;FAILED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Change Lifecycle hooks to &lt;code&gt;POST_SCALE_UP&lt;/code&gt; only&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Avoid "Rollback failed" from hook failures during rollback's &lt;code&gt;PRODUCTION_TRAFFIC_SHIFT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Update service to trigger deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Changed task definition revision.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;POST_SCALE_UP&lt;/code&gt; failed, triggering rollback:&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%2Ftvdmhosuoz843afes7v0.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%2Ftvdmhosuoz843afes7v0.png" width="800" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;No Canary support&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CodeDeploy had Canary option, hopefully added later&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Traffic shifting&lt;/code&gt; section looks ready for options...
&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%2Fxifk8aid7mteg8bssgu9.png" width="800" height="83"&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Auto Scaling warning:&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If your service uses auto scaling, be aware that auto scaling is not blocked during a blue/green deployment, but the deployment might fail under certain circumstances.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-bluegreen.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-bluegreen.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Note: "Rolling Update" Deployment Type Naming Issue
&lt;/h2&gt;

&lt;p&gt;What should we call deployment type &lt;code&gt;ECS&lt;/code&gt; now?&lt;br&gt;
Previously "ECS (rolling update)", but now includes B/G.&lt;/p&gt;

&lt;p&gt;Documentation still refers to "using rolling update" likely meaning deployment type=&lt;code&gt;ECS&lt;/code&gt;. Awaiting updates. Example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Only services that use rolling deployments are supported with Service Connect.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect-concepts-deploy.html#service-connect-considerations" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect-concepts-deploy.html#service-connect-considerations&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is one of ECS's most significant updates recently, including changing deployment controller.&lt;br&gt;
I'm curious about Service Connect's Blue/Green implementation.&lt;/p&gt;

&lt;p&gt;I'm relieved about the continued support for Service Connect and External deployment. However, the &lt;code&gt;CODE_DEPLOY&lt;/code&gt; type should probably be avoided going forward.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ecs</category>
      <category>devops</category>
      <category>bluegreen</category>
    </item>
    <item>
      <title>Comparing 5 Methods of ECS Interservice Communication Including VPC Lattice</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Tue, 22 Apr 2025 04:46:13 +0000</pubDate>
      <link>https://dev.to/aws-builders/comparing-5-methods-of-ecs-interservice-communication-including-vpc-lattice-51f0</link>
      <guid>https://dev.to/aws-builders/comparing-5-methods-of-ecs-interservice-communication-including-vpc-lattice-51f0</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is translated from &lt;a href="https://zenn.dev/cadp/articles/ecs-service-mesh-compare" rel="noopener noreferrer"&gt;my original article&lt;/a&gt; in Japanese.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;This article compares five options for ECS service-to-service communication: &lt;strong&gt;ALB, VPC Lattice, ECS Service Discovery, ECS Service Connect, and App Mesh (scheduled for deprecation)&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Background
&lt;/h3&gt;

&lt;p&gt;Following the &lt;a href="https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect/" rel="noopener noreferrer"&gt;App Mesh deprecation announcement&lt;/a&gt; and VPC Lattice enhancements at re:Invent 2024 (&lt;a href="https://aws.amazon.com/jp/about-aws/whats-new/2024/11/amazon-vpc-lattice-elastic-container-service/" rel="noopener noreferrer"&gt;ECS native integration&lt;/a&gt;, &lt;a href="https://aws.amazon.com/about-aws/whats-new/2024/12/vpc-lattice-tcp-vpc-resources/" rel="noopener noreferrer"&gt;TCP support&lt;/a&gt;), I wanted to provide an overview of the future landscape of ECS interservice communication.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is based on specifications as of December 18, 2024.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ALB&lt;/th&gt;
&lt;th&gt;VPC Lattice&lt;/th&gt;
&lt;th&gt;ECS Service Discovery&lt;/th&gt;
&lt;th&gt;ECS Service Connect&lt;/th&gt;
&lt;th&gt;App Mesh (Deprecated)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;In short&lt;/td&gt;
&lt;td&gt;Stable &amp;amp; versatile&lt;/td&gt;
&lt;td&gt;Evolution of ALB that connects everything&lt;/td&gt;
&lt;td&gt;Simple name resolution&lt;/td&gt;
&lt;td&gt;ECS-specific, easy &amp;amp; feature-rich&lt;/td&gt;
&lt;td&gt;Complex &amp;amp; feature-rich mesh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Release (GA)&lt;/td&gt;
&lt;td&gt;2016&lt;/td&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;2019&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ease of setup &amp;amp; management&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;👍👍Easy&lt;/td&gt;
&lt;td&gt;👍Relatively easy&lt;/td&gt;
&lt;td&gt;👿👿Complex&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;💰Cost&lt;/td&gt;
&lt;td&gt;Time + LCU&lt;/td&gt;
&lt;td&gt;Time + traffic + request count&lt;/td&gt;
&lt;td&gt;👍👍Very cost-effective&lt;/td&gt;
&lt;td&gt;Sidecar&lt;/td&gt;
&lt;td&gt;Sidecar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔭Logs &amp;amp; Metrics&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🔭Tracing&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛡️Health Check&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported (container level)&lt;/td&gt;
&lt;td&gt;👍Partially supported&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛡️Auto Retry&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🛡️Circuit Breaker&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;Partial&lt;br&gt;(outlier detection)&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚢Supported Deployment Types&lt;/td&gt;
&lt;td&gt;👍All&lt;/td&gt;
&lt;td&gt;Technically all&lt;/td&gt;
&lt;td&gt;👍All&lt;/td&gt;
&lt;td&gt;👿&lt;code&gt;ECS&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;👍All&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🚢Canary Deployment&lt;/td&gt;
&lt;td&gt;👍Easy&lt;/td&gt;
&lt;td&gt;👍Easy&lt;/td&gt;
&lt;td&gt;👿Tricky&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🐙Name Resolution from non-ECS&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🐙Cross-VPC Communication&lt;/td&gt;
&lt;td&gt;👍Possible (requires VPC Peering)&lt;/td&gt;
&lt;td&gt;👍👍Specialty&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;🐙Cross-Account Communication&lt;/td&gt;
&lt;td&gt;👍Possible (requires VPC Peering)&lt;/td&gt;
&lt;td&gt;👍👍Specialty&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here are some example selection criteria:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I want something with decent features, familiar, and won't disappear"
-&amp;gt; &lt;strong&gt;ALB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;"I use various services like EKS and Lambda besides ECS, and want to connect many VPCs/accounts"
-&amp;gt; &lt;strong&gt;VPC Lattice&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;"Simple name resolution is enough. Reliability and observability are not needed or will be implemented separately"
-&amp;gt; &lt;strong&gt;Service Discovery&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;"I want to connect ECS services with high reliability and observability. Communication with non-ECS services is minimal"
-&amp;gt; &lt;strong&gt;Service Connect&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;"I have many microservices and strong requirements for reliability and observability. Need to connect non-ECS services too"
-&amp;gt; &lt;strong&gt;App Mesh&lt;/strong&gt; (Scheduled for deprecation, so consider VPC Lattice or Service Connect)&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  What is ECS Interservice Communication?
&lt;/h1&gt;

&lt;p&gt;It refers to communication between ECS services.&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%2F6ybv6xerqi5t5cyd0400.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%2F6ybv6xerqi5t5cyd0400.png" width="380" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's not just about "how to find the access target" but also includes considerations like "what to do if the target is down" and "how to observe the communication".&lt;/p&gt;

&lt;p&gt;In reality, there are cases where Lambda or EC2 needs to access ECS, so we'll touch on this as one of the comparison points.&lt;/p&gt;

&lt;h1&gt;
  
  
  Overview of Each Method
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. ALB
&lt;/h2&gt;

&lt;p&gt;ALB is an L7 load balancer that can also connect to non-ECS services.&lt;br&gt;
Its main strengths are being the most "mature" with abundant information and the confidence that "ALB won't be discontinued".&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Method
&lt;/h3&gt;

&lt;p&gt;Create an ALB for service-to-service communication and access it using its domain name.&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%2Fkigrxnwucr4olgwhn5c6.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%2Fkigrxnwucr4olgwhn5c6.png" width="800" height="257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can set multiple path-based routing rules on the ALB to avoid creating many ALBs.&lt;br&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%2F4qa4n5po78bygt4t3cfi.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%2F4qa4n5po78bygt4t3cfi.png" width="800" height="295"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Example: &lt;code&gt;/web&lt;/code&gt; routes to service-web, &lt;code&gt;/app&lt;/code&gt; routes to service-app&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. VPC Lattice
&lt;/h2&gt;

&lt;p&gt;VPC Lattice is an application connectivity service that abstracts ALB functionality, which became GA in March 2023.&lt;br&gt;
It can connect EC2, EKS, and Lambda, with cross-VPC and cross-account communication as its key strengths.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Method
&lt;/h3&gt;

&lt;p&gt;Access using the Lattice Service domain name + port,&lt;br&gt;
which routes to ECS services associated with the Lattice Target Group defined in the Listener.&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%2Fy1gw8hzu8sp6tl0oekn1.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%2Fy1gw8hzu8sp6tl0oekn1.png" width="800" height="225"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;ECS Service Integration via VPC Lattice&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lattice Service Network: Logical collection of Lattice Services&lt;/li&gt;
&lt;li&gt;Lattice Service: Similar to "one ALB", can have domain name and &lt;strong&gt;multiple Listeners&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Lattice Target Group: Almost the same as ELB target groups, but not compatible&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Before Native ECS Integration
&lt;/h4&gt;

&lt;p&gt;Previously, ALB was required in front of ECS, but this became unnecessary with the &lt;a href="https://aws.amazon.com/about-aws/whats-new/2024/11/amazon-vpc-lattice-elastic-container-service/?nc1=h_ls" rel="noopener noreferrer"&gt;November 18, 2024 update&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%2F4puwbh5y3910j1dbw1ex.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%2F4puwbh5y3910j1dbw1ex.png" width="800" height="225"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Previously: ALB was required in front of ECS&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Associating Multiple ECS Services
&lt;/h4&gt;

&lt;p&gt;Each Listener can have multiple ListenerRules like ALB.&lt;br&gt;
By setting path-based routing, you can associate multiple ECS services with one Lattice Service.&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%2Frmtfpxr8ek29txi8ac6e.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%2Frmtfpxr8ek29txi8ac6e.png" width="800" height="224"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Associating multiple ECS services with one Lattice Service&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This improves manageability and potentially reduces costs.&lt;br&gt;
As discussed later, there's a time-based charge per Lattice Service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IAM authentication can be used to restrict communication sources.

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/vpc-lattice/latest/ug/auth-policies.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/vpc-lattice/latest/ug/auth-policies.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;TCP support allows access to DBs etc. (though expensive)

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2024/12/vpc-lattice-tcp-vpc-resources/" rel="noopener noreferrer"&gt;https://aws.amazon.com/about-aws/whats-new/2024/12/vpc-lattice-tcp-vpc-resources/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. ECS Service Discovery
&lt;/h2&gt;

&lt;p&gt;ECS Service Discovery provides a simple name resolution mechanism.&lt;br&gt;
While it lacks reliability and observability features, it offers simplicity and cost-effectiveness.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-discovery.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-discovery.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Method
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Client resolves &lt;code&gt;&amp;lt;service namespace&amp;gt;.&amp;lt;hosted-zone name&amp;gt;&lt;/code&gt; to get backend Task IP addresses&lt;/li&gt;
&lt;li&gt;Access using those IP addresses&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.amazonaws.com%2Fuploads%2Farticles%2Ft1kwedhl53hcs1sbofkn.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%2Ft1kwedhl53hcs1sbofkn.png" width="800" height="526"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unlike other methods, containers can communicate directly with target services.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. ECS Service Connect
&lt;/h2&gt;

&lt;p&gt;Service Connect, launched in November 2022, combines features from ELB, Service Discovery, and App Mesh.&lt;br&gt;
It specializes in ECS-to-ECS communication and provides easy setup for reliability and observability features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connection Method
&lt;/h3&gt;

&lt;p&gt;An Envoy-based sidecar container (&lt;a href="https://github.com/aws/amazon-ecs-service-connect-agent" rel="noopener noreferrer"&gt;Service Connect Agent&lt;/a&gt;) handles communication.&lt;br&gt;
It automatically handles Cloud Map registration, target discovery via Cloud Map, and access.&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%2Fc8jsocetjixwmh8nzjrn.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%2Fc8jsocetjixwmh8nzjrn.png" width="800" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Side Note: Integration with Lambda and VPC Lattice
&lt;/h3&gt;

&lt;p&gt;There are requests to integrate Service Connect with &lt;a href="https://github.com/aws/containers-roadmap/issues/1960" rel="noopener noreferrer"&gt;Lambda&lt;/a&gt; and &lt;a href="https://github.com/aws/containers-roadmap/issues/2149" rel="noopener noreferrer"&gt;VPC Lattice&lt;/a&gt;.&lt;br&gt;
While this might be challenging due to architectural and conceptual reasons, if realized, it would significantly expand Service Connect's possibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. App Mesh (Scheduled for Deprecation)
&lt;/h2&gt;

&lt;p&gt;App Mesh is a feature-rich service mesh service consisting of [1]managed Envoy control plane and [2]Envoy sidecar containers.&lt;/p&gt;

&lt;p&gt;It's scheduled for deprecation by September 30, 2026. Two migration paths are recommended:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-ecs-service-connect/" rel="noopener noreferrer"&gt;Migration to Service Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/blogs/containers/migrating-from-aws-app-mesh-to-amazon-vpc-lattice/" rel="noopener noreferrer"&gt;Migration to VPC Lattice&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Connection Method
&lt;/h3&gt;

&lt;p&gt;Like Service Connect, the sidecar handles various tasks.&lt;br&gt;
Since it's scheduled for deprecation, we'll omit detailed mechanism explanations.&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%2Fbjpkwyznh3i05psy7d4l.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%2Fbjpkwyznh3i05psy7d4l.png" width="800" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Comparison by Aspect
&lt;/h1&gt;

&lt;p&gt;From here, we'll mostly exclude App Mesh.&lt;br&gt;
It's scheduled for deprecation and is generally powerful except for its complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost💰
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ALB&lt;/th&gt;
&lt;th&gt;VPC Lattice&lt;/th&gt;
&lt;th&gt;👑ECS Service Discovery&lt;/th&gt;
&lt;th&gt;ECS Service Connect&lt;/th&gt;
&lt;th&gt;App Mesh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Time + LCU&lt;/td&gt;
&lt;td&gt;Time + traffic + request count&lt;/td&gt;
&lt;td&gt;👍👍Very cost-effective&lt;/td&gt;
&lt;td&gt;Sidecar&lt;/td&gt;
&lt;td&gt;Sidecar&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Service Discovery is extremely cost-effective as it doesn't require sidecars&lt;/li&gt;
&lt;li&gt;ALB requires complex cost calculations based on LCU&lt;/li&gt;
&lt;li&gt;VPC Lattice has time-based charges per Lattice Service

&lt;ul&gt;
&lt;li&gt;Time-based charges alone cost approximately $23.4 per month per Service (\$0.0325/h x 24 x 30)&lt;/li&gt;
&lt;li&gt;For cost efficiency, it's better to associate multiple ECS services with one Lattice Service rather than creating a separate Lattice Service per ECS service (similar to ALB)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Service Connect charges for sidecar resources

&lt;ul&gt;
&lt;li&gt;With minimum recommended specs for x86 Fargate, it costs about $9.1 per task per month (\$0.05056/h x 0.25 x 24 x 30)&lt;sup id="fnref2"&gt;2&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;Of course, larger sizes may be needed depending on traffic&lt;/li&gt;
&lt;li&gt;May be cost-prohibitive with many tasks&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Observability🔭
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ALB&lt;/th&gt;
&lt;th&gt;VPC Lattice&lt;/th&gt;
&lt;th&gt;ECS Service Discovery&lt;/th&gt;
&lt;th&gt;ECS Service Connect&lt;/th&gt;
&lt;th&gt;App Mesh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Logs &amp;amp; Metrics&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracing&lt;/td&gt;
&lt;td&gt;👿None (ID is assigned)&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Service Discovery is designed without observability features, and this is unlikely to change&lt;/li&gt;
&lt;li&gt;Tracing is App Mesh's specialty, with Envoy sidecars capable of sending data to X-Ray or Datadog&lt;/li&gt;
&lt;li&gt;Service Connect, being Envoy-based, might support tracing in the future

&lt;ul&gt;
&lt;li&gt;There are feature requests for this
&lt;a href="https://github.com/aws/containers-roadmap/issues/2369" rel="noopener noreferrer"&gt;https://github.com/aws/containers-roadmap/issues/2369&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;ALB adds &lt;code&gt;X-Amzn-Trace-Id&lt;/code&gt; to request headers, but this alone doesn't enable rich distributed tracing&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reliability🛡️
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ALB&lt;/th&gt;
&lt;th&gt;VPC Lattice&lt;/th&gt;
&lt;th&gt;ECS Service Discovery&lt;/th&gt;
&lt;th&gt;👑ECS Service Connect&lt;/th&gt;
&lt;th&gt;App Mesh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Health Check&lt;/td&gt;
&lt;td&gt;👍&lt;br&gt;Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;br&gt;(container level)&lt;/td&gt;
&lt;td&gt;👍Partially supported&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto Retry&lt;/td&gt;
&lt;td&gt;👿&lt;br&gt;None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Circuit Breaker&lt;/td&gt;
&lt;td&gt;👿&lt;br&gt;None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;👿None&lt;/td&gt;
&lt;td&gt;Partial(outlier detection)&lt;/td&gt;
&lt;td&gt;👍Supported&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Health checks are essential, but auto retry and circuit breakers aren't mandatory&lt;/li&gt;
&lt;li&gt;Service Connect has advantages in auto retry and outlier detection

&lt;ul&gt;
&lt;li&gt;Auto retry retries on different tasks if the original task fails&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;App Mesh's circuit breaker consists of &lt;strong&gt;[1]outlier detection&lt;/strong&gt; + &lt;strong&gt;[2]connection pool&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Outlier detection(&lt;a href="https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/outlier" rel="noopener noreferrer"&gt;outlier detection&lt;/a&gt;): Monitors actual traffic to stop routing to hosts with many errors&lt;/li&gt;
&lt;li&gt;Connection pool: Limits concurrent connections or requests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/11/aws-app-mesh-introduces-circuit-breaker-capabilities/?nc1=h_ls" rel="noopener noreferrer"&gt;https://aws.amazon.com/about-aws/whats-new/2020/11/aws-app-mesh-introduces-circuit-breaker-capabilities/?nc1=h_ls&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment🚢
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;👑ALB&lt;/th&gt;
&lt;th&gt;VPC Lattice&lt;/th&gt;
&lt;th&gt;ECS Service Discovery&lt;/th&gt;
&lt;th&gt;ECS Service Connect&lt;/th&gt;
&lt;th&gt;App Mesh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Supported Deployment Types&lt;/td&gt;
&lt;td&gt;👍&lt;br&gt;All&lt;/td&gt;
&lt;td&gt;Technically all&lt;/td&gt;
&lt;td&gt;👍All&lt;/td&gt;
&lt;td&gt;👿&lt;code&gt;ECS&lt;/code&gt; only&lt;/td&gt;
&lt;td&gt;👍All&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canary Deployment&lt;/td&gt;
&lt;td&gt;👍&lt;br&gt;Easy&lt;/td&gt;
&lt;td&gt;👍Easy&lt;/td&gt;
&lt;td&gt;👿Tricky&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Easy&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;※ ECS &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeploymentController.html" rel="noopener noreferrer"&gt;deployment types&lt;/a&gt; are &lt;code&gt;ECS&lt;/code&gt;(rolling update), &lt;code&gt;CODE_DEPLOY&lt;/code&gt;(Blue/Green), and &lt;code&gt;EXTERNAL&lt;/code&gt;(&lt;a href="https://dev.to/t-kikuc/ecs-external-deployment-taskset-complete-guide-21dl"&gt;external deployment&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ALB is the most straightforward to handle. It's well integrated with ECS and has minimal constraints&lt;/li&gt;
&lt;li&gt;VPC Lattice can perform Canary deployments similar to ALB by manipulating ListenerRules

&lt;ul&gt;
&lt;li&gt;When using Internal-ALB, it's still ALB, so it supports all deployment types and enables flexible deployment&lt;/li&gt;
&lt;li&gt;However, with native ECS integration, only the &lt;code&gt;ECS&lt;/code&gt; deployment type can be selected&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Service Discovery supports all deployment types but lacks flexible routing control, making Canary deployments challenging&lt;/li&gt;

&lt;li&gt;Service Connect can only use the &lt;code&gt;ECS&lt;/code&gt; deployment type, limiting deployment flexibility&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Connection Breadth🐙
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ALB&lt;/th&gt;
&lt;th&gt;👑VPC Lattice&lt;/th&gt;
&lt;th&gt;ECS Service Discovery&lt;/th&gt;
&lt;th&gt;ECS Service Connect&lt;/th&gt;
&lt;th&gt;App Mesh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Name Resolution from non-ECS&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-VPC&lt;/td&gt;
&lt;td&gt;👍Possible (requires VPC Peering)&lt;/td&gt;
&lt;td&gt;👍👍Specialty&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cross-Account&lt;/td&gt;
&lt;td&gt;👍Possible (requires VPC Peering)&lt;/td&gt;
&lt;td&gt;👍👍Specialty&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👿Not possible&lt;/td&gt;
&lt;td&gt;👍Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;This is VPC Lattice's core strength and unique selling point&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;ALB is a standard VPC resource, requiring VPC Peering or something for cross-VPC/account communication&lt;/li&gt;
&lt;li&gt;Service Discovery cannot cross VPCs or accounts, but this helps maintain its simplicity&lt;/li&gt;
&lt;li&gt;Service Connect is ECS-specific and has the most limitations

&lt;ul&gt;
&lt;li&gt;A separate method is needed for the "initial entry point from outside to ECS"&lt;/li&gt;
&lt;li&gt;Cross-account communication might be supported in the future
&lt;a href="https://github.com/aws/containers-roadmap/issues/2148" rel="noopener noreferrer"&gt;https://github.com/aws/containers-roadmap/issues/2148&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Considering costs and complexity, "reducing ECS interservice communication in the first place" might also be an option.&lt;/p&gt;

&lt;p&gt;I'll continue to watch the growth of VPC Lattice and Service Connect.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Currently, there are cases where "routing occurs before tasks become HEALTHY" &lt;a href="https://github.com/aws/containers-roadmap/issues/2334" rel="noopener noreferrer"&gt;https://github.com/aws/containers-roadmap/issues/2334&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Minimum 256CPU(=0.25vCPU) and 64MiB additional resources per task are recommended for sidecars. &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect-concepts-deploy.html#service-connect-concepts-proxy" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect-concepts-deploy.html#service-connect-concepts-proxy&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>ecs</category>
      <category>servicemesh</category>
      <category>vpclattice</category>
    </item>
    <item>
      <title>Introduction to Gitless GitOps: A New OCI-Centric and Secure Architecture</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Thu, 17 Apr 2025 03:19:50 +0000</pubDate>
      <link>https://dev.to/t-kikuc/introduction-to-gitless-gitops-a-new-oci-centric-and-secure-architecture-2pgi</link>
      <guid>https://dev.to/t-kikuc/introduction-to-gitless-gitops-a-new-oci-centric-and-secure-architecture-2pgi</guid>
      <description>&lt;p&gt;&lt;em&gt;This article is translated and edited from &lt;a href="https://zenn.dev/cadp/articles/gitless-gitops-intro" rel="noopener noreferrer"&gt;my own article in Japanese&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I learned about &lt;strong&gt;Gitless GitOps&lt;/strong&gt; at &lt;a href="https://events.linuxfoundation.org/kubecon-cloudnativecon-europe/" rel="noopener noreferrer"&gt;KubeCon EU 2025&lt;/a&gt;. As a developer of a GitOps tool (&lt;a href="https://pipecd.dev/" rel="noopener noreferrer"&gt;PipeCD&lt;/a&gt;), I was intrigued but found limited information available, so I decided to investigate.&lt;/p&gt;

&lt;p&gt;"&lt;em&gt;GitOps without Git? What do you mean?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;You can read the details in this report. Gitless is introduced as part of D2, Flux's reference architecture, so you don't need to read the entire document.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fluxcd.control-plane.io/guides/d2-architecture-reference/" rel="noopener noreferrer"&gt;https://fluxcd.control-plane.io/guides/d2-architecture-reference/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Points
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Gitless GitOps is a new GitOps architecture that &lt;strong&gt;centers on OCI Registry instead of Git&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;While it's "Gitless" because GitOps tools don't access Git, the fundamental principles remain largely unchanged&lt;/li&gt;
&lt;li&gt;The main benefit is &lt;strong&gt;enhanced security in the supply chain&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Review: Current GitOps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is GitOps?
&lt;/h3&gt;

&lt;p&gt;GitOps is a delivery method that "keeps the production environment in sync with Git configuration."&lt;br&gt;
It follows these &lt;a href="https://opengitops.dev/" rel="noopener noreferrer"&gt;4 principles&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Declarative&lt;/li&gt;
&lt;li&gt;Versioned and Immutable&lt;/li&gt;
&lt;li&gt;Pulled Automatically&lt;/li&gt;
&lt;li&gt;Continuously Reconciled&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Popular GitOps tools include &lt;a href="https://argo-cd.readthedocs.io/" rel="noopener noreferrer"&gt;ArgoCD&lt;/a&gt;, &lt;a href="https://fluxcd.io/" rel="noopener noreferrer"&gt;FluxCD&lt;/a&gt;, and &lt;a href="https://pipecd.dev/" rel="noopener noreferrer"&gt;PipeCD&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Simple GitOps Architecture
&lt;/h3&gt;

&lt;p&gt;Here's a simple GitOps architecture:&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%2Fhh62dq05jtx3bjknox9a.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%2Fhh62dq05jtx3bjknox9a.png" width="720" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The GitOps tool (like FluxCD) continuously monitors the Git repository and deploys changes to the production environment when detected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview of Gitless GitOps
&lt;/h2&gt;

&lt;p&gt;Gitless GitOps is a delivery method &lt;strong&gt;driven by OCI (Open Container Initiative) artifacts stored in container registries&lt;/strong&gt; instead of Git repositories.&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%2F1ybwoh5yiajmweucanph.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%2F1ybwoh5yiajmweucanph.png" width="720" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CI creates and pushes OCI artifacts, while the GitOps tool focuses solely on applying them.&lt;br&gt;
Continuous reconciliation is based on OCI artifacts rather than Git.&lt;/p&gt;

&lt;p&gt;Note that Git remains the Single Source of Truth in Gitless, but mechanisms to maintain consistency between Git and OCI registries through write control are necessary.&lt;/p&gt;

&lt;p&gt;This is unrelated to the tool called "Gitless": &lt;a href="https://gitless.com/" rel="noopener noreferrer"&gt;https://gitless.com/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Side Note: When Did It Emerge?
&lt;/h3&gt;

&lt;p&gt;As far as I researched, the concept and term "Gitless" appears to have been led by FluxCD developers within the last 3 years.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;2022: Flux added OCI support (&lt;code&gt;OCIRepository&lt;/code&gt; introduced)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fluxcd.io/blog/2022/10/cncf-talk-flux-oci/" rel="noopener noreferrer"&gt;https://fluxcd.io/blog/2022/10/cncf-talk-flux-oci/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;2024: The term "Gitless GitOps" was already introduced&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.heise.de/en/background/Gitless-GitOps-The-path-to-a-secure-app-environment-with-Flux-and-OCI-9811957.html" rel="noopener noreferrer"&gt;https://www.heise.de/en/background/Gitless-GitOps-The-path-to-a-secure-app-environment-with-Flux-and-OCI-9811957.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;April 2025: &lt;a href="https://control-plane.io/" rel="noopener noreferrer"&gt;ControlPlane&lt;/a&gt; released a reference architecture based on Gitless GitOps&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ControlPlane is a company providing enterprise solutions for FluxCD and other tools&lt;/li&gt;
&lt;li&gt;&lt;a href="https://control-plane.io/posts/d2-reference-architecture-guide/" rel="noopener noreferrer"&gt;https://control-plane.io/posts/d2-reference-architecture-guide/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;There seems to be variation in spelling between "Gitless" and "Git-less".&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Gitless
&lt;/h2&gt;

&lt;p&gt;The underlying context for these benefits seems to be that "Git itself wasn't designed for GitOps, and OCI registries are more suitable for cloud-native environments."&lt;/p&gt;

&lt;h3&gt;
  
  
  Software Supply Chain Security and Compliance
&lt;/h3&gt;

&lt;p&gt;This is the most emphasized benefit.&lt;br&gt;
The &lt;a href="https://sched.co/1tx8R" rel="noopener noreferrer"&gt;KubeCon session&lt;/a&gt; included the message "Configuration is Part of the Supply Chain".&lt;br&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%2Fjg8b1c4r1m462xyae10k.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.amazonaws.com%2Fuploads%2Farticles%2Fjg8b1c4r1m462xyae10k.jpg" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Gitless enables the following, with OCI ecosystem integration being a major advantage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manifest authenticity and integrity can be verified through OCI artifact signing/verification

&lt;ul&gt;
&lt;li&gt;Flux uses &lt;a href="https://github.com/sigstore/cosign" rel="noopener noreferrer"&gt;cosign&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Vulnerability scanning can be performed in OCI repositories&lt;/li&gt;

&lt;li&gt;SBOMs can handle manifests as well&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The increased focus on such measures is driven by regulations including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;US: &lt;a href="https://www.nist.gov/itl/executive-order-14028-improving-nations-cybersecurity" rel="noopener noreferrer"&gt;EO14028 "Executive Order on Improving the Nation's Cybersecurity"&lt;/a&gt; issued in 2021&lt;/li&gt;
&lt;li&gt;Europe: &lt;a href="https://digital-strategy.ec.europa.eu/en/policies/cyber-resilience-act" rel="noopener noreferrer"&gt;Cyber Resilience Act (CRA)&lt;/a&gt; enacted in 2024&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  No Git Access Required
&lt;/h3&gt;

&lt;p&gt;Eliminating git pull means network access, authentication, and permissions for Git are no longer needed by GitOps tools.&lt;br&gt;
As mentioned later, write permissions to Git also become unnecessary.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can authenticate to OCI registries using Workload Identity without PATs or SSH keys

&lt;ul&gt;
&lt;li&gt;No need for secret management or rotation&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Likely improves Git access permission management efficiency

&lt;ul&gt;
&lt;li&gt;Prevents scenarios like "Strict Git access control inadvertently restricted GitOps tool permissions, breaking Image Updater functionality"&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;Gitless focuses on pulling OCI artifacts instead of git pull, potentially leading to lighter and faster operations.&lt;/p&gt;

&lt;p&gt;Current GitOps can face performance challenges with large manifest repositories or frequent updates from trunk-based development. This is because GitOps tools frequently perform git pull and create local copies of pulled repositories.&lt;/p&gt;

&lt;p&gt;Various GitOps tools implement performance tuning for git operations, but some aspects remain challenging to optimize, such as identifying which manifests are linked to applications due to templating. Here's an example from PipeCD:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pipecd.dev/blog/2024/09/11/performance-improvement-in-git-operations-on-pipecd-v0.48.9/" rel="noopener noreferrer"&gt;https://pipecd.dev/blog/2024/09/11/performance-improvement-in-git-operations-on-pipecd-v0.48.9/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplification of GitOps Tools
&lt;/h3&gt;

&lt;p&gt;While CI's role expands, the GitOps tool's responsibilities are reduced and simplified. GitOps tools focus solely on "deploying OCI artifacts."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[1] Templating Processing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Since CI executes kustomize, jsonnet, etc., and uses the results as OCI artifacts, templating processing becomes unnecessary in CD. The final manifests to be applied can be fixed regardless of GitOps tool versions or dependencies.&lt;/p&gt;

&lt;p&gt;Flux's documentation mentions that &lt;a href="https://fluxcd.io/flux/cheatsheets/oci-artifacts/#how-does-flux-oci-work" rel="noopener noreferrer"&gt;OCI artifact-centric approaches are particularly convenient when final manifests aren't in Git due to templating&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[2] Automatic Image Updates&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Various GitOps tools have mechanisms to automatically deploy new application versions. All involve GitOps tools committing to manifest repositories themselves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FluxCD: &lt;a href="https://fluxcd.io/flux/guides/image-update/" rel="noopener noreferrer"&gt;Image Reflector Controller &amp;amp; Image Automation Controller&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;ArgoCD: &lt;a href="https://argocd-image-updater.readthedocs.io/en/stable/" rel="noopener noreferrer"&gt;Image Updater&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PipeCD: &lt;a href="https://pipecd.dev/docs/user-guide/event-watcher/" rel="noopener noreferrer"&gt;EventWatcher&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In Gitless, these responsibilities shift from GitOps tools to CI. This eliminates the need for Git write permissions for GitOps tools.&lt;/p&gt;

&lt;p&gt;Here's the Before/After of the overall CI/CD pipeline including image updates:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Current architecture:&lt;/em&gt;&lt;br&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%2Frwol3vn3sk72iwvxoe36.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%2Frwol3vn3sk72iwvxoe36.png" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gitless architecture:&lt;/em&gt;&lt;br&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%2F9gzowfzckssr24h95e1q.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%2F9gzowfzckssr24h95e1q.png" width="800" height="445"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Potentially Good for Edge Environments?
&lt;/h3&gt;

&lt;p&gt;While not mentioned in ControlPlane's report, some suggest that replicating OCI repositories across locations could enable fast, stable deployments in edge environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://itnext.io/advantages-of-storing-configuration-in-container-registries-rather-than-git-b4266dc0c79f" rel="noopener noreferrer"&gt;https://itnext.io/advantages-of-storing-configuration-in-container-registries-rather-than-git-b4266dc0c79f&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Needed to Migrate to Gitless?
&lt;/h2&gt;

&lt;p&gt;Here are some necessary tasks for migrating to Gitless. Both GitOps tool users and developers need to make adjustments.&lt;/p&gt;

&lt;h3&gt;
  
  
  User-side Tasks
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Reflect application image pushes in the manifest repository&lt;/li&gt;
&lt;li&gt;Create, sign, and push OCI artifacts from the manifest repository&lt;/li&gt;
&lt;li&gt;Modify GitOps tool configuration to monitor OCI artifacts instead of Git

&lt;ul&gt;
&lt;li&gt;Git access permissions and network access for GitOps tools can be removed&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Developer-side Tasks (Already Implemented in Flux)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Support OCI registry monitoring, retrieval, and signature verification

&lt;ul&gt;
&lt;li&gt;For Flux, the main task was adding &lt;a href="https://fluxcd.io/flux/components/source/ocirepositories/" rel="noopener noreferrer"&gt;&lt;code&gt;OCIRepository&lt;/code&gt;&lt;/a&gt; to &lt;a href="https://fluxcd.io/flux/components/source/" rel="noopener noreferrer"&gt;SourceController&lt;/a&gt;, which appears to be cleanly implemented&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Support OCI artifact deployment

&lt;ul&gt;
&lt;li&gt;Since manifest apply functionality should already exist, mainly needs artifact extraction processing&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;ArgoCD is currently &lt;a href="https://github.com/argoproj/argo-cd/issues/17564" rel="noopener noreferrer"&gt;working on implementation&lt;/a&gt;, while PipeCD hasn't started yet.&lt;/p&gt;

&lt;p&gt;For implementation, the OCI artifact manipulation client tool &lt;a href="https://oras.land/" rel="noopener noreferrer"&gt;ORAS&lt;/a&gt; (CNCF Sandbox project) seems useful. &lt;del&gt;&lt;a href="https://github.com/fluxcd/source-controller/blob/v1.5.0/internal/oci/notation/notation.go" rel="noopener noreferrer"&gt;Flux uses oras-go&lt;/a&gt;.&lt;/del&gt;&lt;/p&gt;

&lt;p&gt;[2025-04-17 edited] Flux implements their own OCI package here: &lt;a href="https://github.com/fluxcd/pkg/tree/main/oci" rel="noopener noreferrer"&gt;https://github.com/fluxcd/pkg/tree/main/oci&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;FluxCD's pioneering presence is impressive.&lt;/p&gt;

&lt;p&gt;Should everyone adopt Gitless? "Not everyone at this point" is my answer. While GitOps tools currently handle many tasks, Gitless requires additional CI setup.&lt;br&gt;
However, Gitless could be powerful in industries and countries requiring strict security and compliance.&lt;/p&gt;

&lt;p&gt;The momentum of Gitless likely depends on the strictness of software supply chain security regulations and the emergence of large-scale GitOps performance case studies.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;While writing this article, &lt;a href="https://www.thecvefoundation.org/" rel="noopener noreferrer"&gt;unsettling news about CVE program continuity&lt;/a&gt; emerged...&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gitops</category>
      <category>flux</category>
      <category>argocd</category>
      <category>pipecd</category>
    </item>
    <item>
      <title>ECS External Deployment &amp; TaskSet - Complete Guide</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Wed, 19 Mar 2025 11:35:00 +0000</pubDate>
      <link>https://dev.to/t-kikuc/ecs-external-deployment-taskset-complete-guide-21dl</link>
      <guid>https://dev.to/t-kikuc/ecs-external-deployment-taskset-complete-guide-21dl</guid>
      <description>&lt;p&gt;This guide explores "&lt;strong&gt;External Deployment&lt;/strong&gt;" and "&lt;strong&gt;TaskSet&lt;/strong&gt;" - two of the lesser-known yet powerful features in ECS. We'll cover their concepts and practical usage, including real-world examples with PipeCD. Mastering these features enables advanced deployment strategies in ECS.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This article is based on specifications as of December 14, 2024.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Key Takeaways
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TaskSet&lt;/strong&gt;: A layer between Service and Task that maintains revisions per TaskSet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External Deployment&lt;/strong&gt;: A deployment type that enables flexible deployments using TaskSets&lt;/li&gt;
&lt;li&gt;These features are essential for implementing advanced deployment strategies like Canary in ECS&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Understanding the Terminology
&lt;/h1&gt;

&lt;h2&gt;
  
  
  1. What is External Deployment?
&lt;/h2&gt;

&lt;p&gt;External Deployment is a deployment type in ECS that enables flexible deployments through third-party controllers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-external.html" rel="noopener noreferrer"&gt;https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-external.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: This is unrelated to &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-anywhere.html" rel="noopener noreferrer"&gt;&lt;code&gt;launchType: EXTERNAL&lt;/code&gt;&lt;/a&gt; used in ECS Anywhere.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Three Deployment Types
&lt;/h3&gt;

&lt;p&gt;ECS offers three &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeploymentController.html" rel="noopener noreferrer"&gt;deployment types&lt;/a&gt;, with External Deployment being one of them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-ecs.html" rel="noopener noreferrer"&gt;&lt;code&gt;ECS&lt;/code&gt;&lt;/a&gt;: Rolling update - the default and most conventional approach&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-bluegreen.html" rel="noopener noreferrer"&gt;&lt;code&gt;CODE_DEPLOY&lt;/code&gt;&lt;/a&gt;: Integrates with CodeDeploy for straightforward Canary and Blue/Green deployments&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-external.html" rel="noopener noreferrer"&gt;&lt;strong&gt;&lt;code&gt;EXTERNAL&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt;: Enables custom deployments through TaskSet manipulation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important: The deployment type cannot be changed after service creation.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Differences between &lt;code&gt;CODE_DEPLOY&lt;/code&gt; and &lt;code&gt;EXTERNAL&lt;/code&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Both manipulate TaskSets and follow similar operational flows[^1]&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CODE_DEPLOY&lt;/code&gt; is easier to implement as CodeDeploy handles most operations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EXTERNAL&lt;/code&gt; offers more flexibility despite its complexity

&lt;ul&gt;
&lt;li&gt;Examples: Custom deployment validation, rollback strategies&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. What is TaskSet?
&lt;/h2&gt;

&lt;p&gt;TaskSet is a concept that sits between ECS Service and Task, grouping Tasks together.&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%2Fcktwntzvsek245eiv9vf.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%2Fcktwntzvsek245eiv9vf.png" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TaskSets only appear when using CodeDeploy or External deployment types, handling Task scheduling and scaling instead of the Service.&lt;/p&gt;

&lt;p&gt;You won't encounter TaskSets when using rolling updates or running &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/standalone-tasks.html" rel="noopener noreferrer"&gt;Standalone Tasks&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examining TaskSets
&lt;/h3&gt;

&lt;p&gt;TaskSets aren't visible in the console. You can view them by using &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DescribeServices.html" rel="noopener noreferrer"&gt;&lt;code&gt;DescribeServices&lt;/code&gt;&lt;/a&gt; on a Service using CodeDeploy or External deployment. They have similar attributes to Services, including &lt;code&gt;runningCount&lt;/code&gt;, &lt;code&gt;launchType&lt;/code&gt;, and &lt;code&gt;networkConfiguration&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;aws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ecs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;describe-services&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--cluster&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;xxx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;--services&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;yyy-service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"services"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"serviceName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"yyy-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"taskSets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Here&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs-svc/4390851359570905103"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"taskSetArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:task-set/xxx/yyy-service/ecs-svc/4390851359570905103"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"serviceArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:service/xxx/yyy-service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"clusterArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:cluster/xxx"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ACTIVE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"taskDefinition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:task-definition/zzz-taskdef:1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"computedDesiredCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"pendingCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"runningCount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-12-13T20:00:24.064000+09:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"updatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-12-13T20:00:28.178000+09:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"launchType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FARGATE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"platformVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.4.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"platformFamily"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Linux"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"networkConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"awsvpcConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"subnets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                                &lt;/span&gt;&lt;span class="s2"&gt;"subnet-aaa"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                                &lt;/span&gt;&lt;span class="s2"&gt;"subnet-bbb"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"securityGroups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                                &lt;/span&gt;&lt;span class="s2"&gt;"sg-ccc"&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
                            &lt;/span&gt;&lt;span class="nl"&gt;"assignPublicIp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"DISABLED"&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"loadBalancers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"serviceRegistries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"scale"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                        &lt;/span&gt;&lt;span class="nl"&gt;"unit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PERCENT"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"stabilityStatus"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"STABILIZING"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"stabilityStatusAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-12-13T20:00:24.064000+09:00"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"deploymentController"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EXTERNAL"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;External&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;deployment&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  When to Use TaskSets
&lt;/h3&gt;

&lt;p&gt;TaskSets enable Canary releases and Blue/Green deployments because you can &lt;strong&gt;specify different TargetGroups and TaskDefinitions per TaskSet&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"TaskSet with v1 TaskDefinition points to TargetGroup A"&lt;/li&gt;
&lt;li&gt;"TaskSet with v2 TaskDefinition points to TargetGroup B"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Control traffic distribution between TargetGroups at the ALB level.&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%2Fajdrvsz53mevu33uhftq.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%2Fajdrvsz53mevu33uhftq.png" width="800" height="873"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Canary release and Blue/Green deployment using TaskSets&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  TaskSet Operations
&lt;/h3&gt;

&lt;p&gt;There are only five APIs for TaskSet operations. Most operations involve managing multiple TaskSets rather than modifying a single TaskSet's internals.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;CreateTaskSet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DescribeTaskSets.html" rel="noopener noreferrer"&gt;&lt;code&gt;DescribeTaskSets&lt;/code&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Requires TaskSet ID beforehand, making it cumbersome&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DescribeServices.html" rel="noopener noreferrer"&gt;&lt;code&gt;DescribeServices&lt;/code&gt;&lt;/a&gt; is recommended for easier TaskSet information retrieval&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeleteTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;DeleteTaskSet&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;UpdateTaskSet&lt;/code&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Can only update &lt;strong&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Scale.html" rel="noopener noreferrer"&gt;&lt;code&gt;scale&lt;/code&gt;&lt;/a&gt;&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;scale&lt;/code&gt;: Percentage of Tasks to run in this TaskSet relative to Service's &lt;code&gt;desiredCount&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Example: With &lt;code&gt;desiredCount&lt;/code&gt; 10 and &lt;code&gt;scale&lt;/code&gt; 30%, TaskSet maintains 3 Tasks&lt;/li&gt;
&lt;li&gt;Range: 0-100&lt;/li&gt;
&lt;li&gt;Task count automatically adjusts when Service autoscales (changes in &lt;code&gt;desiredCount&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Cannot update &lt;strong&gt;&lt;code&gt;taskDefinition&lt;/code&gt;&lt;/strong&gt;, ensuring all Tasks within a TaskSet use the same image with immutable tags&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateServicePrimaryTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;UpdateServicePrimaryTaskSet&lt;/code&gt;&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Changes a TaskSet's &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_TaskSet.html#ECS-Type-TaskSet-status" rel="noopener noreferrer"&gt;&lt;code&gt;status&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;PRIMARY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Optional but recommended as &lt;strong&gt;Primary TaskSet cannot be deleted with &lt;code&gt;DeleteTaskSet&lt;/code&gt;&lt;/strong&gt;&lt;sup id="fnref1"&gt;1&lt;/sup&gt;
&lt;/li&gt;
&lt;li&gt;Making a TaskSet Primary changes the previous Primary TaskSet to &lt;code&gt;ACTIVE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Some Primary TaskSet settings propagate to Service (&lt;code&gt;launchType&lt;/code&gt;, &lt;code&gt;taskDefinition&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - Before Primary TaskSet exists:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     ```json
     $ aws ecs describe-services --cluster xxx --services yyy-service
     {
         "services": [
             {
                 "serviceName": "yyy-service",
                 "launchType": "EC2", // Initial Service creation
                 "taskSets": [
                     {
                         "id": "ecs-svc/8721983045402263235",
                         "status": "ACTIVE", // Not PRIMARY yet
                         "taskDefinition": "arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:task-definition/zzz-taskdef:3",
                         "launchType": "FARGATE",
                         ...
     ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; - After `UpdateServicePrimaryTaskSet`:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;     ```json
     $ aws ecs describe-services --cluster xxx --services yyy-service
     {
         "services": [
             {
                 "serviceName": "yyy-service",
                 "launchType": "FARGATE", // Propagated from TaskSet
                 "taskDefinition": "arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:task-definition/zzz-taskdef:3", // Propagated from TaskSet
                 "taskSets": [
                     {
                         "id": "ecs-svc/8721983045402263235",
                         "status": "PRIMARY", // Now PRIMARY
                         "taskDefinition": "arn:aws:ecs:ap-northeast-1:&amp;lt;account&amp;gt;:task-definition/zzz-taskdef:3",
                         "launchType": "FARGATE",
                         ...
     ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h1&gt;
  
  
  Example: Canary Release with External Deployment
&lt;/h1&gt;

&lt;p&gt;There are multiple approaches to External Deployment, including rollback strategies.&lt;br&gt;
Here are two examples.&lt;br&gt;
For more details, refer to &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-external.html#deployment-type-external-workflow" rel="noopener noreferrer"&gt;this documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This article focuses on Services behind ALB.&lt;/p&gt;
&lt;h2&gt;
  
  
  Method A: Promoting Canary to Primary
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Assume ALB, ListenerRule, two TargetGroups, ECS Cluster, and TaskDefinitions (v1,v2) are ready&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1: Create Service
&lt;/h4&gt;

&lt;p&gt;Use &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html" rel="noopener noreferrer"&gt;&lt;code&gt;CreateService&lt;/code&gt;&lt;/a&gt; to create a Service.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;[Required] Set &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeploymentController.html#ECS-Type-DeploymentController-type" rel="noopener noreferrer"&gt;&lt;code&gt;deploymentController.type&lt;/code&gt;&lt;/a&gt; to &lt;code&gt;EXTERNAL&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fewer required parameters compared to &lt;code&gt;ECS&lt;/code&gt; deployment type&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No need for &lt;code&gt;taskDefinition&lt;/code&gt;, &lt;code&gt;launchType&lt;/code&gt;, &lt;code&gt;networkConfiguration&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Details &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-type-external.html#deployment-type-external-workflow" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws ecs create-service &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;cluster-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--service-name&lt;/span&gt; &amp;lt;service-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--desired-count&lt;/span&gt; 2 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--deployment-controller&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;EXTERNAL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;No TaskSets or Tasks are created at this point.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2: Create Initial TaskSet (v1)
&lt;/h4&gt;

&lt;p&gt;Use &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;CreateTaskSet&lt;/code&gt;&lt;/a&gt; to create the first TaskSet.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Specify parameters typically set at Service level (&lt;code&gt;launchType&lt;/code&gt;, &lt;code&gt;taskDefinition&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_LoadBalancer.html#ECS-Type-LoadBalancer-targetGroupArn" rel="noopener noreferrer"&gt;&lt;code&gt;loadBalancers[].targetGroupArn&lt;/code&gt;&lt;/a&gt;: Specify TargetGroup for ALB traffic&lt;/li&gt;
&lt;li&gt;Recommend 100% &lt;code&gt;scale&lt;/code&gt; for initial TaskSet
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws ecs create-task-set &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;cluster-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--service&lt;/span&gt; &amp;lt;service-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--task-definition&lt;/span&gt; &amp;lt;task-def-arn-v1&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--launch-type&lt;/span&gt; FARGATE &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--network-configuration&lt;/span&gt; &lt;span class="s2"&gt;"awsvpcConfiguration={subnets=[subnet-aaa,subnet-bbb],securityGroups=[sg-ccc],assignPublicIp=ENABLED}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--load-balancers&lt;/span&gt; &lt;span class="s2"&gt;"targetGroupArn=&amp;lt;tg-arn-1&amp;gt;,containerName=web,containerPort=80"&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="c"&gt;# Match TaskDefinition&lt;/span&gt;
&lt;span class="nt"&gt;--scale&lt;/span&gt; &lt;span class="nv"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PERCENT,value&lt;span class="o"&gt;=&lt;/span&gt;100
&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%2Fous79rpbq08kzubk1qe4.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%2Fous79rpbq08kzubk1qe4.png" width="800" height="977"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After prerequisites&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: &lt;code&gt;UpdateServicePrimaryTask&lt;/code&gt; is optional here&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Deployment Flow
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Create TaskSet (v2)
&lt;/h4&gt;

&lt;p&gt;Similar to Step 2 above, but with different &lt;code&gt;task-definition&lt;/code&gt;, &lt;code&gt;targetGroupArn&lt;/code&gt;, and &lt;code&gt;scale&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="nv"&gt;$ &lt;/span&gt;aws ecs create-task-set &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;cluster-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--service&lt;/span&gt; &amp;lt;service-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--task-definition&lt;/span&gt; &amp;lt;task-def-arn-v2&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--launch-type&lt;/span&gt; FARGATE &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--network-configuration&lt;/span&gt; &lt;span class="s2"&gt;"awsvpcConfiguration={subnets=[subnet-aaa,subnet-bbb],securityGroups=[sg-ccc],assignPublicIp=ENABLED}"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--load-balancers&lt;/span&gt; &lt;span class="s2"&gt;"targetGroupArn=&amp;lt;tg-arn-2&amp;gt;,containerName=web,containerPort=80"&lt;/span&gt; &lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="c"&gt;# Match TaskDefinition&lt;/span&gt;
&lt;span class="nt"&gt;--scale&lt;/span&gt; &lt;span class="nv"&gt;unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;PERCENT,value&lt;span class="o"&gt;=&lt;/span&gt;10
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No traffic flows to v2 TaskSet yet as its TargetGroup weight is 0.&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%2Faowp7ookpdksnj93i205.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%2Faowp7ookpdksnj93i205.png" width="800" height="977"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Creating Canary TaskSet&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. Route Traffic to Canary
&lt;/h4&gt;

&lt;p&gt;Use ELB's &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_ModifyRule.html" rel="noopener noreferrer"&gt;&lt;code&gt;ModifyRule&lt;/code&gt;&lt;/a&gt; to adjust TargetGroup weights.&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="nv"&gt;$ &lt;/span&gt;aws elbv2 modify-rule &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--rule-arn&lt;/span&gt; &amp;lt;listener-rule-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--actions&lt;/span&gt; &lt;span class="s1"&gt;'[{
    "Type": "forward", 
    "ForwardConfig": {
        "TargetGroups": [
            {
                "TargetGroupArn": "&amp;lt;tg-arn-1&amp;gt;", 
                "Weight": 90
            },
            {
                "TargetGroupArn": "&amp;lt;tg-arn-2&amp;gt;", 
                "Weight": 10
            }
        ]
    }
}]'&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%2F9raamvjx6riqcs0nx2l1.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%2F9raamvjx6riqcs0nx2l1.png" width="800" height="977"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Starting traffic flow to Canary&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_ModifyListener.html" rel="noopener noreferrer"&gt;&lt;code&gt;ModifyListener&lt;/code&gt;&lt;/a&gt; for default listener rules.&lt;br&gt;
For multiple ListenerRules, gather all target rules beforehand.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. If Successful, Route 100% Traffic to Canary
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Note: If Canary's &lt;code&gt;scale&lt;/code&gt; was less than 100, first use &lt;code&gt;UpdateTaskSet&lt;/code&gt; to set it to 100.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Use ELB's &lt;a href="https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_ModifyRule.html" rel="noopener noreferrer"&gt;&lt;code&gt;ModifyRule&lt;/code&gt;&lt;/a&gt; again to update TargetGroup weights.&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="nv"&gt;$ &lt;/span&gt;aws elbv2 modify-rule &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--rule-arn&lt;/span&gt; &amp;lt;listener-rule-arn&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--actions&lt;/span&gt; &lt;span class="s1"&gt;'[{
    "Type": "forward", 
    "ForwardConfig": {
        "TargetGroups": [
            {
                "TargetGroupArn": "&amp;lt;tg-arn-1&amp;gt;", 
                "Weight": 0
            },
            {
                "TargetGroupArn": "&amp;lt;tg-arn-2&amp;gt;", 
                "Weight": 100
            }
        ]
    }
}]'&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%2Fp5cfhdpfk3vrecdf3pqj.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%2Fp5cfhdpfk3vrecdf3pqj.png" width="800" height="977"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Routing 100% traffic to Canary&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  4. Promote Canary TaskSet to Primary
&lt;/h4&gt;
&lt;h4&gt;
  
  
  4.1. Get Canary TaskSet ID
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws ecs describe-services &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;cluster-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--services&lt;/span&gt; &amp;lt;service-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
| jq &lt;span class="s1"&gt;'.services[0].taskSets[]'&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Find Canary TaskSet ID in response, using &lt;code&gt;status&lt;/code&gt; (&lt;code&gt;PRIMARY&lt;/code&gt;/&lt;code&gt;ACTIVE&lt;/code&gt;) to identify it.&lt;/p&gt;
&lt;h4&gt;
  
  
  4.2. Use &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_UpdateServicePrimaryTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;UpdateServicePrimaryTaskSet&lt;/code&gt;&lt;/a&gt; to Make Canary TaskSet Primary
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;aws ecs update-service-primary-task-set &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;cluster-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--service&lt;/span&gt; &amp;lt;service-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--primary-task-set&lt;/span&gt; &amp;lt;ecs-svc/xxx&amp;gt; &lt;span class="c"&gt;# Canary TaskSet ID from 4.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  5. Delete Old TaskSet
&lt;/h4&gt;

&lt;p&gt;Use &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeleteTaskSet.html" rel="noopener noreferrer"&gt;&lt;code&gt;DeleteTaskSet&lt;/code&gt;&lt;/a&gt; to remove v1 TaskSet.&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="nv"&gt;$ &lt;/span&gt;aws ecs delete-task-set &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--cluster&lt;/span&gt; &amp;lt;cluster-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--service&lt;/span&gt; &amp;lt;service-name&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--task-set&lt;/span&gt; &amp;lt;ecs-svc/xxx&amp;gt; &lt;span class="c"&gt;# Old TaskSet ID from 4.1&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%2F8p41az0q9ki1a3tn1nx3.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%2F8p41az0q9ki1a3tn1nx3.png" width="800" height="977"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;After deployment completion&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Rollback Scenarios
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If failure occurs during steps 2 or 3:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Return 100% traffic to TargetGroup A&lt;/li&gt;
&lt;li&gt;Delete Canary TaskSet&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If failure occurs during step 5:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create new TaskSet using TaskDefinition v1 and TargetGroup A&lt;/li&gt;
&lt;li&gt;Update it to Primary&lt;/li&gt;
&lt;li&gt;Route 100% traffic to TargetGroup A&lt;/li&gt;
&lt;li&gt;Delete Canary TaskSet&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Method A Challenges
&lt;/h3&gt;

&lt;p&gt;TargetGroup assignments to old/new TaskSets aren't fixed, requiring tracking of current assignments.&lt;br&gt;
This complicates rollback especially.&lt;/p&gt;
&lt;h2&gt;
  
  
  Method B: Using Three TaskSets
&lt;/h2&gt;

&lt;p&gt;Here's an alternative approach that addresses Method A's challenges.&lt;br&gt;
It uses three TaskSets: "current", "canary", and "new".&lt;/p&gt;

&lt;p&gt;This is the approach PipeCD adopts.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deployment Flow
&lt;/h3&gt;
&lt;h4&gt;
  
  
  0. Initial State
&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%2Fjcol1cqqx6j5mf4r4357.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%2Fjcol1cqqx6j5mf4r4357.png" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  1. Create Canary
&lt;/h4&gt;

&lt;p&gt;Use &lt;code&gt;CreateTaskSet&lt;/code&gt; and &lt;code&gt;elbv2::ModifyRule&lt;/code&gt;.&lt;br&gt;
Canary TaskSet's &lt;code&gt;scale&lt;/code&gt; can be less than 100%.&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%2Fb0j5ifgefd5t2013a7sl.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%2Fb0j5ifgefd5t2013a7sl.png" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  2. If Successful, Create New TaskSet
&lt;/h4&gt;

&lt;p&gt;Use &lt;code&gt;CreateTaskSet&lt;/code&gt; with TargetGroup A and TaskDefinition v2.&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%2F60uxrc7w28p39alm381z.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%2F60uxrc7w28p39alm381z.png" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Traffic now flows to the third TaskSet.&lt;/p&gt;
&lt;h4&gt;
  
  
  3. Delete All Old TaskSets
&lt;/h4&gt;

&lt;p&gt;Use &lt;code&gt;UpdateServicePrimaryTaskSet&lt;/code&gt;, &lt;code&gt;elbv2::ModifyRule&lt;/code&gt;, and &lt;code&gt;DeleteTaskSet&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%2Ff86c8q9w0sa0xslhc8js.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%2Ff86c8q9w0sa0xslhc8js.png" width="800" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Back to initial state configuration.&lt;br&gt;
Next deployment starts with TargetGroup A pointing to latest version.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rollback Scenarios
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;For any failure phase, return to initial state:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Create new TaskSet with TaskDefinition v1 and TargetGroup A&lt;/li&gt;
&lt;li&gt;Update it to Primary&lt;/li&gt;
&lt;li&gt;Route 100% traffic to TargetGroup A&lt;/li&gt;
&lt;li&gt;Delete all other TaskSets&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;For failures before step 3, faster rollback:&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Route 100% traffic to TargetGroup A&lt;/li&gt;
&lt;li&gt;Delete all other TaskSets&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Pros/Cons
&lt;/h3&gt;

&lt;p&gt;Pros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed TargetGroup assignments simplify operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Longer deployment time due to two TaskSet creations&lt;/li&gt;
&lt;li&gt;Higher cost with three TaskSets&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Works on EC2 Too
&lt;/h3&gt;

&lt;p&gt;Method B works on EC2 as well as Fargate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initially concerned about &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_DeploymentConfiguration.html#ECS-Type-DeploymentConfiguration-maximumPercent" rel="noopener noreferrer"&gt;&lt;code&gt;deploymentConfiguration.maximumPercent&lt;/code&gt;&lt;/a&gt; limitations&lt;/li&gt;
&lt;li&gt;Worried about "Can't use Method B if limited to 2x &lt;code&gt;desiredCount&lt;/code&gt; Tasks", but &lt;code&gt;maximumPercent&lt;/code&gt; is ignored&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Note: Docs explicitly state that &lt;code&gt;maximumPercent&lt;/code&gt; is ignored for External Deployment on Fargate&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Using Method B with PipeCD
&lt;/h3&gt;

&lt;p&gt;External Deployment can be complex (especially with rollbacks).&lt;br&gt;
PipeCD implements Method B Canary releases with simple pipeline definitions.&lt;br&gt;
Handles rollbacks automatically.&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;pipeline&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# 1. Create Canary TaskSet&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;ECS_CANARY_ROLLOUT&lt;/span&gt; 
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
      &lt;span class="c1"&gt;# 2. Route 10% traffic to Canary&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;ECS_TRAFFIC_ROUTING&lt;/span&gt; 
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;canary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;
      &lt;span class="c1"&gt;# 3. Approval phase&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;WAIT_APPROVAL&lt;/span&gt;
      &lt;span class="c1"&gt;# 4. Create new Primary TaskSet&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;ECS_PRIMARY_ROLLOUT&lt;/span&gt; 
      &lt;span class="c1"&gt;# 5. Route 100% traffic to new Primary TaskSet&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;ECS_TRAFFIC_ROUTING&lt;/span&gt; 
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;
       &lt;span class="c1"&gt;# 6. Delete unnecessary TaskSets&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;ECS_CANARY_CLEAN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full configuration file &lt;a href="https://github.com/pipe-cd/examples/blob/master/ecs/canary/app.pipecd.yaml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Important Considerations for External Deployment
&lt;/h1&gt;

&lt;p&gt;Several important points to consider when using External Deployment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Many Service Features/Settings Unsupported
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Examples of unsupported features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect-concepts-deploy.html#service-connect-considerations" rel="noopener noreferrer"&gt;&lt;strong&gt;Service Connect&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-vpc-lattice.html#ecs-lattice-compatibility" rel="noopener noreferrer"&gt;&lt;strong&gt;VPC Lattice&lt;/strong&gt;&lt;/a&gt; (possible via Internal-ALB)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-circuit-breaker.html" rel="noopener noreferrer"&gt;Deployment Circuit Breaker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/deployment-alarm-failure.html" rel="noopener noreferrer"&gt;Deployment Alarms&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;No comprehensive list of unsupported features exists&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recommend searching docs for keywords like "Deployment"&lt;/li&gt;
&lt;li&gt;Service Connect example:
&amp;gt; Only services that use rolling deployments are supported with Service Connect.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;No known TaskDefinition-specific constraints for External Deployment&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  External Deployment Often Excluded from ECS Updates
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;November 2024's &lt;a href="https://aws.amazon.com/blogs/news/improving-deployment-visibility-for-amazon-ecs-services/" rel="noopener noreferrer"&gt;"Improved Deployment Visibility"&lt;/a&gt; enhanced ECS deployment history UI/API, but External Deployment remained unchanged&lt;/li&gt;
&lt;li&gt;November 2024's &lt;a href="https://aws.amazon.com/about-aws/whats-new/2024/11/amazon-vpc-lattice-elastic-container-service/" rel="noopener noreferrer"&gt;VPC Lattice-ECS native integration&lt;/a&gt; still requires Internal-ALB for External Deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Migration from Other Deployment Types is Challenging
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;As mentioned, deployment type can't be changed after Service creation &lt;strong&gt;(particularly painful)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Migrating to External Deployment requires creating new Service and gradually shifting traffic&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Many unsupported features mean &lt;strong&gt;reviewing Service settings&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Some settings move from &lt;code&gt;CreateService&lt;/code&gt; to &lt;code&gt;CreateTaskSet&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  Manual TaskSet Tagging Required
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;TaskSet doesn't support tag propagation (&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_CreateService.html#ECS-CreateService-request-propagateTags" rel="noopener noreferrer"&gt;&lt;code&gt;propagateTags&lt;/code&gt;&lt;/a&gt;) from Service/TaskDefinition &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-using-tags.html#tag-resources" rel="noopener noreferrer"&gt;reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_Service.html#ECS-Type-Service-enableECSManagedTags" rel="noopener noreferrer"&gt;&lt;code&gt;enableECSManagedTags&lt;/code&gt;&lt;/a&gt; doesn't apply Managed tags to TaskSets&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Limited Console Information
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;TaskSets not visible in ECS console, requiring CLI usage&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Deployment History" remains unchanged for External Deployment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Reference: PipeCD visualizes Service/TaskSet/Task states in UI &lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;br&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%2F396184rwpj61gm9adwjy.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%2F396184rwpj61gm9adwjy.png" width="800" height="373"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;PipeCD UI (during Canary deployment)&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Other Constraints
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/register-multiple-targetgroups.html#multiple-targetgroups-considerations" rel="noopener noreferrer"&gt;Can't link multiple TargetGroups to one TaskSet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maximum 5 TaskSets per Service&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows up to 5x &lt;code&gt;desiredCount&lt;/code&gt; Tasks per Service (scale100 x 5 TaskSets)&lt;/li&gt;
&lt;li&gt;Not documented&lt;/li&gt;
&lt;li&gt;Attempting to exceed limit results in:
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;An error occurred &lt;span class="o"&gt;(&lt;/span&gt;InvalidParameterException&lt;span class="o"&gt;)&lt;/span&gt; when calling the CreateTaskSet operation: 5 deployments exist on the service. Unable to create new TaskSet since this exceeds the maximum limit.
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;/ul&gt;

&lt;h1&gt;
  
  
  Additional Notes
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Note 1: Why Low Awareness?
&lt;/h3&gt;

&lt;p&gt;Two hypotheses for External Deployment and TaskSet's low recognition:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Minimal console presence&lt;br&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%2Ftcc858r42phhpu2fuj1n.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%2Ftcc858r42phhpu2fuj1n.png" width="800" height="155"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Service creation screen - "External Deployment" not visible&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Satisfaction with &lt;code&gt;ECS&lt;/code&gt;/&lt;code&gt;CODE_DEPLOY&lt;/code&gt; deployment types (&lt;em&gt;but are they truly sufficient?&lt;/em&gt;)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Note 2: Do TaskSets Exist in &lt;code&gt;ECS&lt;/code&gt; Deployment Type?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;A: Possibly used internally, but unclear&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two hints suggest TaskSet-like behavior:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Task's &lt;code&gt;StartedBy&lt;/code&gt; format matches External Deployment's &lt;code&gt;ecs-svc/xxx&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;TaskSet IDs use &lt;code&gt;ecs-svc/xxx&lt;/code&gt; format, and Tasks within TaskSets show this as &lt;code&gt;StartedBy&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;xxx&lt;/code&gt; in &lt;code&gt;ecs-svc/xxx&lt;/code&gt; matches &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-revision.html" rel="noopener noreferrer"&gt;service revision&lt;/a&gt; ID&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Service revision mechanism seems similar to TaskSets but has different ARN format.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;DescribeTaskSets&lt;/code&gt; on &lt;code&gt;ecs-svc/xxx&lt;/code&gt; fails:&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="nv"&gt;$ &lt;/span&gt;aws ecs describe-task-sets &lt;span class="nt"&gt;--cluster&lt;/span&gt; aaa &lt;span class="nt"&gt;--service&lt;/span&gt; bbb &lt;span class="nt"&gt;--task-sets&lt;/span&gt; ecs-svc/xxx

An error occurred &lt;span class="o"&gt;(&lt;/span&gt;InvalidParameterException&lt;span class="o"&gt;)&lt;/span&gt; when calling the DescribeTaskSets operation: Amazon ECS only supports task &lt;span class="nb"&gt;set &lt;/span&gt;management on services configured to use external deployment controllers.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;External Deployment, while sparsely documented and constrained, is powerful when mastered.&lt;br&gt;
Service Connect and VPC Lattice support would be welcome additions.&lt;/p&gt;

&lt;p&gt;While migrating to External Deployment is challenging, PipeCD will soon support other deployment types through "plugins".&lt;br&gt;
For plugin details, see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pipecd.dev/blog/2024/11/28/overview-of-the-plan-for-pluginnable-pipecd/" rel="noopener noreferrer"&gt;https://pipecd.dev/blog/2024/11/28/overview-of-the-plan-for-pluginnable-pipecd/&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;code&gt;DeleteTaskSet&lt;/code&gt; will return this error: &lt;code&gt;An error occurred (InvalidParameterException) when calling the DeleteTaskSet operation: Primary TaskSet cannot be deleted&lt;/code&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://pipecd.dev/docs/user-guide/managing-application/application-live-state/" rel="noopener noreferrer"&gt;https://pipecd.dev/docs/user-guide/managing-application/application-live-state/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>aws</category>
      <category>ecs</category>
      <category>pipecd</category>
    </item>
    <item>
      <title>ecstop: My CLI Tool to Stop ECS Resources Easily</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Sun, 05 Jan 2025 15:42:27 +0000</pubDate>
      <link>https://dev.to/t-kikuc/ecstop-my-cli-tool-to-stop-ecs-resources-easily-4cdf</link>
      <guid>https://dev.to/t-kikuc/ecstop-my-cli-tool-to-stop-ecs-resources-easily-4cdf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;On December 20, 2024, I developed and released a CLI tool called &lt;strong&gt;ecstop&lt;/strong&gt; that "quickly stops ECS resources in bulk".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/t-kikuc/ecstop" rel="noopener noreferrer"&gt;https://github.com/t-kikuc/ecstop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The name ecstop is a combination of &lt;strong&gt;ECS+Stop&lt;/strong&gt;. I pronounce it as "ee-c-stop".&lt;/p&gt;

&lt;p&gt;In this article, I'll introduce the overview, philosophy, and future prospects of ecstop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary in 3 Lines
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;ecstop can &lt;strong&gt;quickly stop ECS services, tasks, and container instances (EC2) in bulk&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;The main purpose is to easily reduce costs in dev environments.&lt;/li&gt;
&lt;li&gt;After &lt;code&gt;brew install t-kikuc/tap/ecstop&lt;/code&gt;, you're ready to use immediately without any configuration file.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Development Background
&lt;/h2&gt;

&lt;p&gt;I often created ECS resources when testing ECS itself or developing/testing &lt;a href="https://pipecd.dev" rel="noopener noreferrer"&gt;PipeCD&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since ECS charges for running tasks and container instances, I wanted to stop unused ones.&lt;/p&gt;

&lt;p&gt;As it's for testing, I didn't want to delete clusters or services. They're free.&lt;/p&gt;

&lt;p&gt;However, as I created many resources, it was troublesome to stop them one by one from the AWS console.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To stop a service from the console, you need to  go to the ECS console,  select the service and "update",  set the number of tasks to 0 and "confirm update" for each service.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;IaC and deployment tools are designed for production use and require careful configuration file changes, which isn't suitable for "quickly stopping multiple resources".&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had been using shell scripts/Go to stop them in bulk, but I often forgot how to call them.&lt;br&gt;
Therefore, I decided to make a proper CLI tool.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;You can install ecstop with the following command (Homebrew):&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="nv"&gt;$ &lt;/span&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;t-kikuc/tap/ecstop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enable auto-completion, please refer to &lt;a href="https://github.com/t-kikuc/ecstop?tab=readme-ov-file#auto-completion" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;For details on options, please refer to the &lt;a href="https://github.com/t-kikuc/ecstop" rel="noopener noreferrer"&gt;README&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Zero-scale Services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ecstop services &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets the &lt;code&gt;desiredCount&lt;/code&gt; of all services in the xxx cluster to 0. This also automatically stops tasks linked to the services.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Stop Tasks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ecstop tasks &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx &lt;span class="nt"&gt;--standalone&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;--standalone&lt;/code&gt; flag stops tasks that are not linked to services.&lt;/p&gt;

&lt;p&gt;This applies to tasks whose &lt;code&gt;group&lt;/code&gt; prefix is not &lt;code&gt;service:&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To stop tasks linked to services, use &lt;code&gt;ecstop services&lt;/code&gt; instead because services can start new tasks even after stopping by &lt;code&gt;ecstop tasks&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Stop Container Instances (EC2)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ecstop instances &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This stops (≠ Terminate) all container instances linked to the xxx cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Execute the Above Three in One Command
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;ecstop all &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command is equivalent to:&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="nv"&gt;$ &lt;/span&gt;ecstop services &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx
&lt;span class="nv"&gt;$ &lt;/span&gt;ecstop tasks &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx &lt;span class="nt"&gt;--standalone&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;ecstop instances &lt;span class="nt"&gt;--cluster&lt;/span&gt; xxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other Useful Flags
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--all-cluster&lt;/code&gt;: Instead of &lt;code&gt;--cluster xxx&lt;/code&gt;, this performs stop operations on all ECS clusters in the region.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--profile yyy&lt;/code&gt;: You can specify the AWS profile.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--region zzz&lt;/code&gt;: You can specify the AWS region.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Philosophy
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. No Deletion
&lt;/h3&gt;

&lt;p&gt;ecstop &lt;strong&gt;does not delete unnecessary ECR images or task definitions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;While tasks and container instances (EC2) have high operating costs, ECR images are relatively inexpensive, and task definitions are free, so I ignored them. Services and clusters themselves are also free, so they are not deleted.&lt;/p&gt;

&lt;p&gt;For this reason, I didn't include "clean" or "delete" in the tool name.&lt;/p&gt;

&lt;p&gt;In cases where "I want to delete it because it's not being used and is an eyesore", it's easier to select multiple items from the AWS console and delete them after human judgment.&lt;/p&gt;

&lt;p&gt;Also, for cleaning up ECR images, it's good to use a tool called &lt;strong&gt;ecrm&lt;/strong&gt; created by fujiwara-san.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/fujiwara/ecrm" rel="noopener noreferrer"&gt;https://github.com/fujiwara/ecrm&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Specialized for Bulk Operations
&lt;/h3&gt;

&lt;p&gt;I've minimized the selector options for "which resources to stop".&lt;/p&gt;

&lt;p&gt;The AWS console is sufficient for stopping individual resources, and in a testing environment (not staging, etc.), there shouldn't be any resources that "absolutely must not be stopped". Especially at night, let's stop them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Prospects
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I want to regularly execute ecstop as a scheduled process on AWS (e.g., daily at 24:00).

&lt;ul&gt;
&lt;li&gt;It's troublesome to call it every time + AWS authentication is cumbersome from local.&lt;/li&gt;
&lt;li&gt;I'm thinking of creating IaC for EventBridge+Lambda.&lt;/li&gt;
&lt;li&gt;As it's for testing environments, completion notifications seem unnecessary. I'm not sure about error notifications.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;At the moment, I don't have any "I want to add this option".

&lt;ul&gt;
&lt;li&gt;If there are any requests, I'll consider them.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Main Tools I Used
&lt;/h2&gt;

&lt;p&gt;ecstop is based on a typical Go CLI development stack.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Golang&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/spf13/cobra" rel="noopener noreferrer"&gt;cobra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://goreleaser.com/" rel="noopener noreferrer"&gt;GoReleaser&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.brew.sh/Taps" rel="noopener noreferrer"&gt;Homebrew Taps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This was my first time publishing a CLI tool, and I learned a lot, including how to define the philosophy.&lt;/p&gt;

&lt;p&gt;If you have any feedback or requests, please let me know at &lt;a href="https://github.com/t-kikuc/ecstop" rel="noopener noreferrer"&gt;https://github.com/t-kikuc/ecstop&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Actually, I'm developing another CLI tool related to ECS external deployment, which I plan to release soon.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ecs</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Copy changed files to another branch in Git</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Fri, 27 Dec 2024 17:40:00 +0000</pubDate>
      <link>https://dev.to/t-kikuc/copy-changed-files-to-another-branch-in-git-5dpc</link>
      <guid>https://dev.to/t-kikuc/copy-changed-files-to-another-branch-in-git-5dpc</guid>
      <description>&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &amp;lt;branch&amp;gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the above command, you can pickup files to copy to another branch.&lt;/p&gt;

&lt;p&gt;For example, &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You've been coding on branch-A for a long time.&lt;/li&gt;
&lt;li&gt;You wanna open a PR from some files of them.&lt;/li&gt;
&lt;li&gt;Then, execute:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Switch back to main&lt;/span&gt;
git checkout main 
&lt;span class="c"&gt;# Create and switch&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; branch-B 
&lt;span class="c"&gt;# Import subset files to branch-B&lt;/span&gt;
git checkout branch-A &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>git</category>
    </item>
    <item>
      <title>Hello, test post</title>
      <dc:creator>Tetsuya KIKUCHI</dc:creator>
      <pubDate>Fri, 27 Dec 2024 17:16:37 +0000</pubDate>
      <link>https://dev.to/t-kikuc/hello-test-post-2def</link>
      <guid>https://dev.to/t-kikuc/hello-test-post-2def</guid>
      <description>&lt;p&gt;This is my first post.&lt;/p&gt;

&lt;p&gt;How to write a blog post...&lt;/p&gt;

</description>
      <category>emptystring</category>
    </item>
  </channel>
</rss>
