<?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: bardawilpeter</title>
    <description>The latest articles on DEV Community by bardawilpeter (@bardawilpeter).</description>
    <link>https://dev.to/bardawilpeter</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%2F582107%2Fde0399d3-7a14-435f-8ebb-00543fdd5fa3.png</url>
      <title>DEV Community: bardawilpeter</title>
      <link>https://dev.to/bardawilpeter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bardawilpeter"/>
    <language>en</language>
    <item>
      <title>Zero-Downtime Deployments with AWS and Terraform</title>
      <dc:creator>bardawilpeter</dc:creator>
      <pubDate>Tue, 30 Jan 2024 16:56:48 +0000</pubDate>
      <link>https://dev.to/bardawilpeter/zero-downtime-deployments-with-aws-and-terraform-182f</link>
      <guid>https://dev.to/bardawilpeter/zero-downtime-deployments-with-aws-and-terraform-182f</guid>
      <description>&lt;p&gt;Greetings, tech enthusiasts! I'm excited to share an approach to setting up blue/green deployments on AWS ECS using Terraform. This post isn't just about the 'how' but also the 'why' behind each step, making it different from what you might have read online.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Blue/Green Deployment?
&lt;/h2&gt;

&lt;p&gt;Before diving into the code, let's understand why blue/green deployment is a game-changer:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Minimized Downtime:&lt;/strong&gt; Seamless transition between versions.&lt;br&gt;
&lt;strong&gt;Risk Reduction:&lt;/strong&gt; Immediate rollback capabilities.&lt;br&gt;
&lt;strong&gt;Consistent Environment:&lt;/strong&gt; Identical production environments reduce surprises 😲 &lt;/p&gt;

&lt;p&gt;Have you ever wondered how to maintain your application’s availability even during updates? That's exactly what we'll uncover here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How It Works: The Mechanics of Zero-Downtime Deployment&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To appreciate the beauty of zero-downtime deployments, let's break down how the setup functions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ECS Cluster:&lt;/strong&gt; This is the core where our containerized applications run. When we deploy new versions, ECS ensures that the transition happens without interrupting the current services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task Definitions:&lt;/strong&gt; These are like blueprints for our applications. Each task definition specifies how to run a container, including which Docker image to use, CPU and memory allocations, and more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CodeDeploy Integration:&lt;/strong&gt; AWS CodeDeploy plays a pivotal role. It orchestrates the deployment process by gradually shifting traffic from the old version (blue) to the new version (green) of the application. This phased approach allows for monitoring the new version under load, ensuring stability before full traffic is shifted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Terraform's Role:&lt;/strong&gt; Terraform scripts are used to define and create the necessary AWS resources in a repeatable and consistent manner. This includes setting up the ECS cluster, task definitions, and CodeDeploy configurations.&lt;/p&gt;
&lt;h2&gt;
  
  
  Transitioning to Terraform: Building the Foundation
&lt;/h2&gt;

&lt;p&gt;Now that we've explored the key components and their roles in zero-downtime deployment, let's dive into the heart of the matter - the Terraform code that brings our setup to life. This is where the theory meets practice.&lt;/p&gt;
&lt;h3&gt;
  
  
  Terraform Code Breakdown
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;- Setting up the AWS Provider&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We start by configuring our Terraform provider for AWS. This step is crucial as it tells Terraform how to interact with our AWS resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider "aws" {
  region = "us-east-1"  # Feel free to choose the region that best fits your needs
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Creating the VPC and Subnets&lt;/strong&gt;&lt;br&gt;
A VPC provides network isolation for your resources. Private and public subnets are created for ECS tasks and the ALB.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a VPC
resource "aws_vpc" "my_vpc" {
  cidr_block = "10.0.0.0/16"
}

# Create a private subnet for ECS
resource "aws_subnet" "private_subnet" {
  vpc_id                  = aws_vpc.my_vpc.id
  cidr_block              = "10.0.1.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = false
}

# Create a public subnet in two different AZs for ALB
resource "aws_subnet" "public_subnet_1" {
  vpc_id                  = aws_vpc.my_vpc.id
  cidr_block              = "10.0.4.0/24"
  availability_zone       = "us-east-1a"
  map_public_ip_on_launch = true
}

resource "aws_subnet" "public_subnet_2" {
  vpc_id                  = aws_vpc.my_vpc.id
  cidr_block              = "10.0.5.0/24"
  availability_zone       = "us-east-1b"
  map_public_ip_on_launch = true
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Network Configuration and Routing&lt;/strong&gt;&lt;br&gt;
The next crucial part of our Terraform setup involves establishing a robust network infrastructure. This step is pivotal for maintaining secure and efficient communication within our AWS environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_eip" "nat_eip" {}

resource "aws_nat_gateway" "nat_gateway" {
  allocation_id = aws_eip.nat_eip.id
  subnet_id     = aws_subnet.public_subnet_1.id
  depends_on    = [aws_internet_gateway.my_gateway]
}


resource "aws_route_table" "private_route_table" {
  vpc_id = aws_vpc.my_vpc.id

  route {
    cidr_block     = "0.0.0.0/0"
    nat_gateway_id = aws_nat_gateway.nat_gateway.id
  }
}

resource "aws_route_table_association" "private_subnet_association" {
  subnet_id      = aws_subnet.private_subnet.id
  route_table_id = aws_route_table.private_route_table.id
}


resource "aws_internet_gateway" "my_gateway" {
  vpc_id = aws_vpc.my_vpc.id
}

resource "aws_route_table" "public_route_table" {
  vpc_id = aws_vpc.my_vpc.id

  route {
    cidr_block = "0.0.0.0/0"
    gateway_id = aws_internet_gateway.my_gateway.id
  }
}

resource "aws_route_table_association" "public_subnet_association_1" {
  subnet_id      = aws_subnet.public_subnet_1.id
  route_table_id = aws_route_table.public_route_table.id
}

resource "aws_route_table_association" "public_subnet_association_2" {
  subnet_id      = aws_subnet.public_subnet_2.id
  route_table_id = aws_route_table.public_route_table.id
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Security Groups for ECS and ALB&lt;/strong&gt;&lt;br&gt;
Security Groups act as a virtual firewall, defining the rules that control traffic to and from our ECS tasks and the Application Load Balancer (ALB). Here's how we set them up in Terraform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create a security group for ECS tasks
resource "aws_security_group" "ecs_sg" {
  name_prefix = "ecs-sg-"
  description = "Security group for ECS tasks"
  vpc_id      = aws_vpc.my_vpc.id

  # Allow inbound HTTP traffic from the ALB
  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.alb_sg.id]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1" # -1 means all protocols
    cidr_blocks = ["0.0.0.0/0"]
  }
}

# Create a security group for the Application Load Balancer (ALB)
resource "aws_security_group" "alb_sg" {
  name_prefix = "alb-sg-"
  description = "Security group for ALB"
  vpc_id      = aws_vpc.my_vpc.id

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Creating the ECS Cluster&lt;/strong&gt;&lt;br&gt;
The ECS cluster is where all our services and tasks will be managed. Here's how we define it in Terraform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_ecs_cluster" "ecs_cluster" {
  name = "zero-downtime-cluster"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Task Definitions and IAM Role&lt;/strong&gt;&lt;br&gt;
Now, let's dive into defining the ECS task that will run in our cluster. But before that, it's crucial to discuss the essential IAM role required for ECS task execution.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IAM Role for ECS Task Execution:&lt;/strong&gt;&lt;br&gt;
Before we proceed to define the ECS task, we need to ensure that our tasks have the necessary permissions to run seamlessly within our cluster. To achieve this, we create an IAM role specifically for ECS task execution.&lt;/p&gt;

&lt;p&gt;Here's how we define the IAM role in Terraform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_role" "ecs_execution_role" {
  name = "ecs_execution_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
      }
    ]
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Task Definition:&lt;/strong&gt;&lt;br&gt;
Now that we have the IAM role in place, we can proceed to define the ECS task that will run in our cluster. For simplicity and focus on the deployment strategy, we'll use a pre-built Docker image. In this example, we'll employ &lt;code&gt;nginx:latest&lt;/code&gt;, which is widely used for web servers.&lt;/p&gt;

&lt;p&gt;Here's how the task definition looks in Terraform:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create an ECS task definition
resource "aws_ecs_task_definition" "ecs_task" {
  family                   = "my-ecs-task"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = "256"
  memory                   = "512"
  execution_role_arn       = aws_iam_role.ecs_execution_role.arn

  container_definitions = jsonencode([
    {
      name      = "my-container",
      image     = "nginx:latest", # Replace with your Docker image
      essential = true,
      portMappings = [
        {
          containerPort = 80,
          hostPort      = 80
        }
      ],
      memoryReservation = 128
    }
  ])
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Note on Docker Images:&lt;/strong&gt; This example uses &lt;code&gt;nginx:latest&lt;/code&gt; for its simplicity and ease of demonstration. However, in a real-world scenario, you might use a custom image that you've built and pushed to a container registry like Amazon ECR. You can replace &lt;code&gt;nginx:latest&lt;/code&gt; with the URI of your custom image.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;- Creating an ECS Service&lt;/strong&gt;&lt;br&gt;
Now, let's proceed to create an ECS service, a fundamental component for managing and ensuring the availability of our containers within our ECS cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create an ECS service
resource "aws_ecs_service" "ecs_service" {
  name            = "my-ecs-service"
  cluster         = aws_ecs_cluster.ecs_cluster.id
  task_definition = aws_ecs_task_definition.ecs_task.arn
  launch_type     = "FARGATE"
  desired_count   = 2

  network_configuration {
    subnets         = [aws_subnet.private_subnet.id]
    security_groups = [aws_security_group.ecs_sg.id]
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.blue_group.arn
    container_name   = "my-container"
    container_port   = 80
  }

  deployment_controller {
    type = "CODE_DEPLOY"
  }
  lifecycle {
    ignore_changes = [task_definition, desired_count, load_balancer]
  }
  depends_on = [aws_lb_target_group.blue_group, aws_lb_target_group.green_group]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Application Load Balancer and Target Groups&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now, let's set up our Application Load Balancer (ALB) and the target groups for blue/green deployment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ALB Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create an Application Load Balancer (ALB)
resource "aws_lb" "zero_downtime_alb" {
  name               = "my-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb_sg.id]
  subnets            = [aws_subnet.public_subnet_1.id, aws_subnet.public_subnet_2.id]
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Target Groups for Blue/Green Deployment:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create target groups for blue/green deployment (HTTP)
resource "aws_lb_target_group" "blue_group" {
  name        = "blue-target-group"
  port        = 80
  protocol    = "HTTP"
  vpc_id      = aws_vpc.my_vpc.id
  target_type = "ip"
  health_check {
    enabled             = true
    interval            = 30
    path                = "/"
    port                = "traffic-port"
    protocol            = "HTTP"
    healthy_threshold   = 3
    unhealthy_threshold = 3
    timeout             = 5
    matcher             = "200"
  }
}

resource "aws_lb_target_group" "green_group" {
  name        = "green-target-group"
  port        = 80
  protocol    = "HTTP"
  vpc_id      = aws_vpc.my_vpc.id
  target_type = "ip"
  health_check {
    enabled             = true
    interval            = 30
    path                = "/"
    port                = "traffic-port"
    protocol            = "HTTP"
    healthy_threshold   = 3
    unhealthy_threshold = 3
    timeout             = 5
    matcher             = "200"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Listener Configuration:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create an ALB listener for HTTP
resource "aws_lb_listener" "my_alb_listener" {
  load_balancer_arn = aws_lb.zero_downtime_alb.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.blue_group.arn
  }
  lifecycle {
    ignore_changes = [
      default_action # Ignore changes to the default action to prevent Terraform from reverting CodeDeploy changes
    ]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Integrating with CodeDeploy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IAM Role for CodeDeploy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_role" "codedeploy_role" {
  name = "codedeploy_role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Action = "sts:AssumeRole",
        Effect = "Allow",
        Principal = {
          Service = "codedeploy.amazonaws.com"
        }
      }
    ]
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IAM Policy for CodeDeploy:&lt;/strong&gt;&lt;br&gt;
This IAM policy defines the permissions required for CodeDeploy to interact with ECS and Elastic Load Balancing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_policy" "codedeploy_policy" {
  name        = "CodeDeployECSPolicy"
  description = "Policy for AWS CodeDeploy ECS Role"

  policy = jsonencode({
    Version = "2012-10-17",
    Statement = [
      {
        Effect = "Allow",
        Action = [
          "ecs:DescribeServices",
          "ecs:UpdateService",
          "ecs:CreateTaskSet",
          "ecs:UpdateServicePrimaryTaskSet",
          "ecs:DeleteTaskSet",
          "ecs:ListTaskSets",
        ],
        Resource = "*"
      },
      {
        Effect = "Allow",
        Action = [
          "elasticloadbalancing:Describe*",
          "elasticloadbalancing:DeregisterTargets",
          "elasticloadbalancing:RegisterTargets",
          "elasticloadbalancing:DeleteListener",
          "elasticloadbalancing:CreateListener",
          "elasticloadbalancing:ModifyListener"
        ],
        Resource = "*"
      },
      {
        Effect   = "Allow",
        Action   = "iam:PassRole",
        Resource = aws_iam_role.ecs_execution_role.arn
      }
    ]
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IAM Role Policy Attachment:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "aws_iam_role_policy_attachment" "codedeploy_attachment" {
  role       = aws_iam_role.codedeploy_role.name
  policy_arn = aws_iam_policy.codedeploy_policy.arn
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;CodeDeploy Application and Deployment Group:&lt;/strong&gt;&lt;br&gt;
The following resources create a CodeDeploy application and deployment group for ECS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create CodeDeploy application
resource "aws_codedeploy_app" "codedeploy_app" {
  name             = "my-codedeploy-app"
  compute_platform = "ECS"
}

# Create CodeDeploy deployment group
resource "aws_codedeploy_deployment_group" "codedeploy_group" {
  app_name               = aws_codedeploy_app.codedeploy_app.name
  deployment_config_name = "CodeDeployDefault.ECSAllAtOnce"
  deployment_group_name  = "my-codedeploy-group"
  service_role_arn       = aws_iam_role.codedeploy_role.arn

  ecs_service {
    cluster_name = aws_ecs_cluster.ecs_cluster.name
    service_name = aws_ecs_service.ecs_service.name
  }


  deployment_style {
    deployment_option = "WITH_TRAFFIC_CONTROL"
    deployment_type   = "BLUE_GREEN"
  }

  load_balancer_info {
    target_group_pair_info {
      prod_traffic_route {
        listener_arns = [aws_lb_listener.my_alb_listener.arn]
      }

      target_group {
        name = aws_lb_target_group.blue_group.name
      }

      target_group {
        name = aws_lb_target_group.green_group.name
      }
    }
  }

  blue_green_deployment_config {
    deployment_ready_option {
      action_on_timeout = "CONTINUE_DEPLOYMENT"
    }

    terminate_blue_instances_on_deployment_success {
      action                           = "TERMINATE"
      termination_wait_time_in_minutes = 1
    }
  }

  auto_rollback_configuration {
    enabled = true
    events  = ["DEPLOYMENT_FAILURE"]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;- Outputting the ALB DNS Name&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After deploying our ECS service with CodeDeploy, it's crucial to retrieve essential information for monitoring and accessing our application. Here, we define Terraform outputs to provide this information:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ALB DNS Name:&lt;/strong&gt;&lt;br&gt;
This output displays the DNS name of the Application Load Balancer (ALB), allowing easy access to your deployed application. You can use this DNS name in your browser to access the application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output "alb_dns_name" {
  description = "The DNS name of the ALB"
  value       = aws_lb.zero_downtime_alb.dns_name
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Latest Task Definition ARN:&lt;/strong&gt;&lt;br&gt;
This output provides the Amazon Resource Name (ARN) of the latest ECS task definition. It's useful for monitoring and tracking your task definitions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output "latest_task_definition_arn" {
  description = "The ARN of the latest task definition"
  value       = aws_ecs_task_definition.ecs_task.arn
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Container Name:&lt;/strong&gt;&lt;br&gt;
This output extracts the name of the container from the ECS task definition. Knowing the container name is essential for tasks like debugging and logging.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;output "container_name" {
  description = "The name of the container"
  value       = jsondecode(aws_ecs_task_definition.ecs_task.container_definitions)[0].name
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why This Code Matters
&lt;/h3&gt;

&lt;p&gt;In this setup, every line of Terraform code plays a critical role in ensuring a smooth and reliable deployment process. Here's a breakdown of why each component is significant:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AWS Provider Setup:&lt;/strong&gt; Starting with the AWS provider is foundational. The chosen region impacts latency, cost, and availability, making this a crucial first step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ECS Cluster Creation:&lt;/strong&gt; The ECS cluster is where our containerized applications are managed. It's the backbone of our deployment, providing the environment where our applications run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task Definition:&lt;/strong&gt; The task definition is essential for describing how our application runs in the containers. It includes specifications for the Docker image, CPU, memory, and more, ensuring our application behaves as expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ALB Configuration:&lt;/strong&gt; The Application Load Balancer is the traffic director of our setup. It handles incoming requests and routes them to the appropriate target groups. This is vital for managing traffic during the blue/green deployment process.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Target Groups for Blue/Green Deployment:&lt;/strong&gt; Setting up separate target groups for the blue and green environments allows us to control and monitor traffic flow to each version of the application. It's key for a seamless transition and rollback if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CodeDeploy Integration:&lt;/strong&gt; Integrating with CodeDeploy automates the deployment process. It manages the complex task of shifting traffic between the blue and green environments, ensuring a smooth transition with minimal user impact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing to Launch: Setting Up and Running Your Terraform Code
&lt;/h2&gt;

&lt;p&gt;Now that we've explored the significance of each component in our Terraform setup, let's move into the practical steps of initializing and applying our Terraform configuration. But first, we need to set up our AWS credentials to ensure Terraform can interact with our AWS resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up AWS Credentials for Terraform&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;AWS CLI Configuration:&lt;/strong&gt; If you haven't already, install the AWS CLI and configure it with your credentials. This can be done using the aws configure command, which will prompt you for your Access Key, Secret Key, and preferred AWS region.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Environment Variables:&lt;/strong&gt; Alternatively, you can set your AWS credentials as environment variables. This method is often preferred for temporary credentials or when working on multiple projects.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export AWS_ACCESS_KEY_ID="your-access-key-id"
export AWS_SECRET_ACCESS_KEY="your-secret-access-key"
export AWS_DEFAULT_REGION="us-east-1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Running the Terraform Code:&lt;/strong&gt; This command initializes your Terraform project, setting up the necessary plugins and modules.
&lt;/li&gt;
&lt;/ol&gt;

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

&lt;/div&gt;



&lt;p&gt;4.&lt;strong&gt;Apply Terraform Configuration:&lt;/strong&gt; Review the execution plan and confirm the changes if everything looks correct.&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing Your Deployment
&lt;/h2&gt;

&lt;p&gt;After applying your Terraform configurations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve the ALB DNS name from the Terraform output.&lt;/li&gt;
&lt;li&gt;Open a web browser and enter the ALB DNS name.&lt;/li&gt;
&lt;li&gt;You should see the NGINX welcome page or your application's specific content.&lt;/li&gt;
&lt;li&gt;This validates the successful deployment of your ECS service and proper configuration of your ALB.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Validating Blue/Green Deployment with a New Task Definition
&lt;/h2&gt;

&lt;p&gt;To test the blue/green deployment process, we'll introduce a new task definition using the &lt;code&gt;httpd&lt;/code&gt; image, and then deploy it using AWS CodeDeploy. This step is crucial to confirm that our setup properly handles the transition between two different application versions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Creating a New Task Definition with httpd Image&lt;/strong&gt;&lt;br&gt;
We'll create a new task definition, this time using the &lt;code&gt;httpd&lt;/code&gt; image. This represents a new version of your application. Here's the JSON for the new task definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "family": "my-ecs-task",
    "networkMode": "awsvpc",
    "containerDefinitions": [
        {
            "name": "my-container",
            "image": "httpd:latest",
            "cpu": 10,
            "memory": 512,
            "portMappings": [
                {
                    "containerPort": 80,
                    "hostPort": 80
                }
            ]
        }
    ],
    "requiresCompatibilities": [
        "FARGATE"
    ],
    "cpu": "256",
    "memory": "512"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Registering the Task Definition with AWS ECS&lt;/strong&gt;&lt;br&gt;
Once you have defined your new task, you need to register it with ECS. Use the AWS CLI to register the task definition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws ecs register-task-definition --cli-input-json file://path-to-your-task-definition.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Deploying with AWS CodeDeploy&lt;/strong&gt;&lt;br&gt;
Next, initiate a deployment using AWS CodeDeploy. We'll specify the new task definition in the &lt;code&gt;appspec.yaml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Example appspec.yaml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;applicationName: 'my-codedeploy-app'
deploymentGroupName: 'my-codedeploy-group'
revision:
  revisionType: AppSpecContent
  appSpecContent:
    content: |
      version: 0.0
      Resources:
        - TargetService:
            Type: AWS::ECS::Service
            Properties:
              TaskDefinition: "[YOUR_LATEST_TASK_DEFINITION]" # Replace with your new task definition ARN
              LoadBalancerInfo:
                ContainerName: "my-container"
                ContainerPort: 80

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

&lt;/div&gt;



&lt;p&gt;Be sure to replace the task definition ARN with the one for your new httpd based task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Running the Deployment&lt;/strong&gt;&lt;br&gt;
Deploy using the AWS CLI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws deploy create-deployment --cli-input-yaml file://appspec.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verifying the Deployment&lt;/strong&gt;&lt;br&gt;
Monitor the deployment in the AWS CodeDeploy console. Once it completes, visit the ALB DNS link again. You should now see the httpd welcome page, confirming the successful blue/green deployment with the new version of your application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqhe4z5krz4osj4efjil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvqhe4z5krz4osj4efjil.png" alt="Image description" width="800" height="413"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance and Cost Considerations
&lt;/h2&gt;

&lt;p&gt;When implementing blue/green deployments, it's crucial to consider the potential impact on performance and costs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Utilization:&lt;/strong&gt; Blue/green deployment requires running two environments simultaneously, which can increase resource usage and associated costs.&lt;br&gt;
&lt;strong&gt;Optimization Strategies:&lt;/strong&gt; Employ strategies like auto-scaling and choosing the right instance types to optimize resource utilization and control costs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-world Application Example
&lt;/h2&gt;

&lt;p&gt;Imagine a scenario where a fintech company uses this setup for their customer-facing application. By employing blue/green deployment, they can seamlessly update their application with zero downtime, ensuring continuous service for their users.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub Repository: Access the Code
&lt;/h2&gt;

&lt;p&gt;To help you better understand and implement the concepts discussed in this post, I've made the Terraform code available in a GitHub repository. This repository includes all the scripts and configurations you need to set up your own blue/green deployment on AWS ECS using Terraform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore the Code:&lt;/strong&gt;&lt;br&gt;
Visit &lt;a href="https://github.com/bardawilpeter/terraform-aws-blue-green-deployment"&gt;GitHub Repository Link&lt;/a&gt; to access the code and get started. Feel free to clone the repository, explore the code, and adapt it to your specific needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion and Recap&lt;/strong&gt;&lt;br&gt;
In this post, we explored the importance of blue/green deployments and walked through setting one up using AWS ECS and Terraform. This approach minimizes downtime, reduces risks, and ensures consistency in production environments.&lt;/p&gt;

&lt;p&gt;Happy coding! 😊 &lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>terraform</category>
    </item>
    <item>
      <title>Integrating SSM with serverless Applications</title>
      <dc:creator>bardawilpeter</dc:creator>
      <pubDate>Thu, 24 Nov 2022 14:55:28 +0000</pubDate>
      <link>https://dev.to/bardawilpeter/integrating-ssm-with-serverless-applications-5gln</link>
      <guid>https://dev.to/bardawilpeter/integrating-ssm-with-serverless-applications-5gln</guid>
      <description>&lt;p&gt;We always think about ways to include env vars for different environments where they can be used by various team members and stored in one place.&lt;br&gt;
Using AWS SSM will help you achieve that.&lt;/p&gt;

&lt;p&gt;In this article, I'll be taking you into the steps to create a serverless app that can use SSM for env vars on different environments. &lt;/p&gt;

&lt;p&gt;To create a serverless framework app, let's make sure that you have the package installed globally by running &lt;code&gt;serverless&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pick &lt;code&gt;AWS - Node.js - Starter&lt;/code&gt; to create a starter kit app
&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frzpnsafhh21cx6zcftw8.png" alt="Image description" width="800" height="466"&gt;
&lt;/li&gt;
&lt;li&gt;Choose a name for the project in "What do you want to call this project?"&lt;/li&gt;
&lt;li&gt;Put "no" as an answer for the next steps, as we don't need to log in or deploy.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After those steps, you should have a serverless starter app created for you.&lt;/p&gt;

&lt;p&gt;Let's use the AWS CLI to create an SSM param but first, ensure you have the &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html"&gt;CLI&lt;/a&gt; installed locally.&lt;/p&gt;

&lt;p&gt;Create two SSM params for dev and prod:&lt;br&gt;
Dev:&lt;/p&gt;

&lt;pre&gt;
aws ssm put-parameter \
    --name "/api/dev/url" \
    --value "http://prod.api.com" \
    --type String
&lt;/pre&gt;

&lt;p&gt;Prod:&lt;/p&gt;

&lt;pre&gt;
aws ssm put-parameter \
    --name "/api/prod/url" \
    --value "http://prod.api.com" \
    --type String
&lt;/pre&gt;

&lt;p&gt;`&lt;br&gt;
To confirm that the param is created, you can get one of the created params:&lt;/p&gt;

&lt;pre&gt;
aws ssm get-parameter --name "/api/prod/url"
&lt;/pre&gt;

&lt;p&gt;To use those params in our serverless app, let's create two files in the serverless app project having:&lt;br&gt;
&lt;code&gt;env.dev.yml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
API_URL: ${ssm:/api/dev/url}
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;env.prod.yml&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
API_URL: ${ssm:/api/dev/url}
&lt;/pre&gt;

&lt;p&gt;Edit your &lt;code&gt;serverless.yml&lt;/code&gt; to be:&lt;/p&gt;

&lt;pre&gt;
service: aws-demo-serverless-project

frameworkVersion: '3'

provider:
  stage: ${opt:stage, "dev"}
  name: aws
  runtime: nodejs14.x
  environment: ${file(./env.${self:provider.stage}.yml)}

custom:
  serverless-offline:
    httpPort: 4000

functions:
  hello:
    handler: handler.hello
    events:
      - http:
          path: hello
          method: get

plugins:
  - serverless-offline
&lt;/pre&gt;

&lt;p&gt;To run the app locally, install the &lt;code&gt;serveless-offline&lt;/code&gt; package. You can create this &lt;code&gt;package.json&lt;/code&gt; file in your demo project and run &lt;code&gt;npm install&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;
{
  "name": "serverless-ssm-demo",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "devDependencies": {
    "serverless-offline": "^11.1.3"
  },
  "scripts": {
    "serve": "serverless offline"
  },
  "author": "",
  "license": "ISC"
}
&lt;/pre&gt;

&lt;p&gt;As you can already see, we added a &lt;code&gt;serve&lt;/code&gt; script in the app, which will use the &lt;code&gt;serverless-offline&lt;/code&gt; package to run the application offline.&lt;/p&gt;

&lt;p&gt;Now we can start using the above-created env var &lt;code&gt;API_URL&lt;/code&gt; in our application. To do so, we can update the existing &lt;code&gt;handler.js&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;
'use strict';

module.exports.hello = async (event) =&amp;gt; {
  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: process.env.API_URL
      },
      null,
      2
    ),
  };
};
&lt;/pre&gt; 

&lt;p&gt;Let's test that printing the value of the &lt;code&gt;API_URL&lt;/code&gt; will work by running &lt;code&gt;yarn serve&lt;/code&gt;.&lt;br&gt;
After a successful run, you can check the output of the app by opening &lt;a href="http://localhost:4000/dev/hello"&gt;http://localhost:4000/dev/hello&lt;/a&gt; in your browser or running &lt;code&gt;curl http://localhost:4000/dev/hello&lt;/code&gt; using your terminal:&lt;/p&gt;

&lt;pre&gt;
{
  "message": "http://dev.api.com"
}
&lt;/pre&gt;

&lt;p&gt;Awesome! 👏 we are ready to deploy our app to different environments where each one has different env vars values&lt;br&gt;
Add some scripts to your existing &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;"deploy:env": "sls deploy --stage $NODE_ENV"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"deploy:dev": "NODE_ENV=stage yarn deploy:env"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"deploy:production": "NODE_ENV=production yarn deploy:env"&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Or replace this below ready &lt;code&gt;package.json&lt;/code&gt; with the existing one:&lt;/p&gt;

&lt;pre&gt;
{
  "name": "serverless-ssm-demo",
  "version": "1.0.0",
  "description": "",
  "main": "handler.js",
  "devDependencies": {
    "serverless-offline": "^11.1.3"
  },
  "scripts": {
    "serve": "serverless offline",
    "deploy:env": "sls deploy --stage $NODE_ENV",
    "deploy:dev": "NODE_ENV=dev yarn deploy:env",
    "deploy:production": "NODE_ENV=production yarn deploy:env"
  },
  "author": "",
  "license": "ISC"
}
&lt;/pre&gt;

&lt;p&gt;Let's start deploying to the dev environment by running &lt;code&gt;yarn deploy:dev&lt;/code&gt;&lt;br&gt;
After a success, serverless will return an endpoint for you in the terminal, copy it, and open it in your browser. You should see the value of the dev env var:&lt;/p&gt;

&lt;pre&gt;
{
  "message": "http://dev.api.com"
}
&lt;/pre&gt;

&lt;p&gt;Repeat the same by running &lt;code&gt;yarn deploy:production&lt;/code&gt; and opening the new prod endpoint in your browser. Now you should see the production env var instead:&lt;/p&gt;

&lt;pre&gt;
{
  "message": "http://prod.api.com"
}
&lt;/pre&gt;

&lt;p&gt;Congrats! 🥳 now you can use the same solution to add more env vars with the ability to be used in different environments.&lt;/p&gt;

&lt;p&gt;Link to the GitHub repo: &lt;a href="https://github.com/bardawilpeter/integrating-ssm-serverless-framework"&gt;https://github.com/bardawilpeter/integrating-ssm-serverless-framework&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
    </item>
  </channel>
</rss>
