Here is some information about this architecture.
Here are the steps you can follow to build this solution on your own.
In this project, you'll explore the integration of service discovery with AWS Fargate. You'll learn how to use Amazon ECS to manage containers and implement service discovery, enabling different microservices to find and communicate with each other seamlessly. This architecture is essential for building scalable and resilient containerized applications.
If you're using the Skillmix Labs feature, open the lab settings (the beaker icon) on the right side of the code editor. Then, click the Start Lab button to start hte lab environment.
Wait for the credentials to load. Then run this in the terminal.
Be sure to enter in your own access key and secret key and name your profile 'smx-lab'.
$ aws configure --profile smx-lab
AWS Access Key ID [None]:
AWS Secret Access Key [None]:
Default region name [None]: us-west-2
Default output format [None]:
Note: If you're using your own AWS account you'll need to ensure that you've created and configured a named AWS CLI profile named smx-lab.
First, we'll create the required_providers
config. This config is used to specify the providers that are required for the Terraform configuration. In this case, we are specifying that we require the AWS provider from HashiCorp with a version constraint of ~> 4.16
.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.16"
}
}
required_version = ">= 1.2.0"
}
Next, we'll create the aws config which is used to configure the AWS provider in Terraform. This config specifies the AWS profile to use (smx-lab) and the region (us-west-2) where the resources will be provisioned.
provider "aws" {
profile = "smx-lab"
region = "us-west-2"
}
Next, we'll create the aws_vpc config. This config is used to define the main VPC (Virtual Private Cloud) in AWS.
resource "aws_vpc" "main" {
cidr_block = "11.0.0.0/16"
tags = {
Name = "main_vpc"
}
}
Next, we'll create the aws_subnet
config. This config is used to define a subnet in the AWS VPC.
resource "aws_subnet" "pub_subnet_1" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "${cidrsubnet(aws_vpc.main.cidr_block, 4, 1)}"
availability_zone = "us-west-2a"
map_public_ip_on_launch = "true"
}
Next, we'll create the aws_internet_gateway
config. This config is used to create an internet gateway in AWS. An internet gateway is a horizontally scalable, redundant, and highly available VPC component that allows communication between instances in your VPC and the internet.
resource "aws_internet_gateway" "igw" {
vpc_id = "${aws_vpc.main.id}"
tags = {
Name = "demo_igw"
}
}
Next, we'll create the aws_route
config. This config is used to define a route in the route table that directs all traffic with a destination CIDR block of 0.0.0.0/0
to the internet gateway.
resource "aws_route" "internetgatewayroute" {
depends_on = ["${aws_internet_gateway.igw}"]
route_table_id = "${aws_route_table.pub_route_table.id}"
destination_cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.igw.id}"
}
Next, we'll create the aws_route_table config. This config is used to define a route table in AWS. In this example, we are creating a public route table associated with the main VPC.
resource "aws_route_table" "pub_route_table" {
vpc_id = "${aws_vpc.main.id}"
}
Next, we'll create the aws_route_table_association
config. This config is used to associate a subnet with a route table in AWS.
resource "aws_route_table_association" "pubsubnetroutetableassociation1" {
subnet_id = "${aws_subnet.pub_subnet_1.id}"
route_table_id = "${aws_route_table.pub_route_table.id}"
}
Next, we'll create the aws_default_security_group
config. This config is used to create a default security group in the AWS VPC specified by the aws_vpc.main.id
variable.
resource "aws_default_security_group" "default" {
vpc_id = "${aws_vpc.main.id}"
}
Next, we'll create the aws_security_group config. This config is used to define a security group in AWS that allows inbound HTTP traffic.
resource "aws_security_group" "allow_http" {
name = "allow_http"
description = "Allow http inbound traffic"
vpc_id = "${aws_vpc.main.id}"
ingress {
description = "TLS from VPC"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["${aws_vpc.main.cidr_block}"]
}
egress {
description = "Outbound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
Next, we'll create the aws_service_discovery_public_dns_namespace
config. This config is used to create a public DNS namespace in AWS Cloud Map.
resource "aws_service_discovery_public_dns_namespace" "cloud_map_dns" {
name = "serverless.terraform.com"
description = "cloud map"
}
Next, we'll create the aws_service_discovery_service
config. This config is used to create a service in AWS Cloud Map, which is a managed service discovery service.
resource "aws_service_discovery_service" "cloud_map_service" {
name = "cloudmapservice"
namespace_id = "${aws_service_discovery_public_dns_namespace.cloud_map_dns.id}"
dns_config {
namespace_id = "${aws_service_discovery_public_dns_namespace.cloud_map_dns.id}"
dns_records {
ttl = 10
type = "A"
}
}
}
Next, we'll create the aws_ecs_cluster config. This config is used to define an Amazon Elastic Container Service (ECS) cluster. In this example, we are creating a cluster named 'demo_ecs_cluster' with a setting for 'containerInsights' enabled.
resource "aws_ecs_cluster" "demo_cluster" {
name = "demo_ecs_cluster"
setting {
name = "containerInsights"
value = "enabled"
}
}
Next, we'll create the aws_ecs_cluster_capacity_providers
config. This config is used to define the capacity providers for an Amazon ECS cluster. Capacity providers are used to manage the allocation of tasks to the available resources in the cluster.
resource "aws_ecs_cluster_capacity_providers" "example" {
cluster_name = aws_ecs_cluster.demo_cluster.name
capacity_providers = ["FARGATE"]
default_capacity_provider_strategy = [
{
base = 1
weight = 100
capacity_provider = "FARGATE"
}
]
}
Next, we'll create the aws_ecs_task_definition
config. This config is used to define the task definition for an Amazon ECS task.
resource "aws_ecs_task_definition" "task_registration" {
family = "task_definition_demo"
requires_compatibilities = ["FARGATE"]
network_mode = "awsvpc"
cpu = ".5vCPU"
memory = "1024"
container_definitions = "${jsonencode([{
'name': 'dotnet',
'image': 'httpd:2.4',
'portMappings': [{'containerPort': 80, 'hostPort': 80}],
'essential': true
}])}"
runtime_platform = [{
'operating_system_family': 'LINUX',
'cpu_architecture': 'ARM64'
}]
}
Next, we'll create the aws_ecs_service
config. This config is used to define an ECS service in AWS.
resource "aws_ecs_service" "demo_service" {
name = "demo-fargate-service"
cluster = "${aws_ecs_cluster.demo_cluster.name}"
task_definition = "${aws_ecs_task_definition.task_registration.arn}"
desired_count = 2
deployment_maximum_percent = 200
deployment_minimum_healthy_percent = 100
enable_ecs_managed_tags = true
launch_type = "FARGATE"
network_configuration {
subnets = ["${aws_subnet.pub_subnet_1.id}"]
security_groups = ["${aws_security_group.allow_http.id}"]
assign_public_ip = true
}
service_registries {
registry_arn = "${aws_service_discovery_service.cloud_map_service.arn}"
}
}
This config creates an ECS service named demo-fargate-service
in the specified ECS cluster. It uses the specified task definition, sets the desired count to 2, and configures the deployment settings. The service is launched using the Fargate launch type and is associated with the specified subnets and security groups. Additionally, it enables ECS managed tags and registers the service with the specified service registry.
Deploy the Solution
Let's deploy this thing! If you haven't done so, start the Skillmix lab session and get the account credentials. Configure your Terraform environment to use those credentials.
Then, open a terminal or command prompt, navigate to the folder with your Terraform file, and execute these commands:
# initiatlize the project
$ terraform init
# show the plan
$ terraform plan
# apply the changes
$ terraform apply
Wait for the changes to be applied before proceeding.
Testing
Applications with VPC connectivity can now access the ECS tasks not only from the task IP but also from the Cloud Map namespace Domain name. You can do a "dig" from any EC2 instance/machine that has connectivity to the ECS tasks VPC to test access to Cloud Map Namespace. You can use either AWS Cloud Map API or DNS lookup to resolve a service's name to a current active endpoint.
Source: https://github.com/aws-samples/serverless-patterns/tree/main/cloudmap-fargate-terraform