Exposing a ECS Service to the net - amazon-web-services

I have created a ECS cluster and created a number of services. But I want one of the services be accessed to the outside world. That service will then interact with the other services.
Created an ECS cluster
Created services.
Created the apps loaded into a docker container.
I updated the security group to allow outside access
But under network interfaces on my console I cant find any reference to my security group I created. The security groups created are there.
resource "aws_ecs_service" "my_service" {
name = "my_service"
cluster = aws_ecs_cluster.fetcher_service.id
task_definition = "${aws_ecs_task_definition.my_service.family}:${max(aws_ecs_task_definition.my_service.revision, data.aws_ecs_task_definition.my_service.revision)}"
desired_count = 0
network_configuration {
subnets = var.vpc_subnet_ids
security_groups = var.zuul_my_group_ids
assign_public_ip = true
}
}
Am I missing any steps

If desired count is set to 0, probably no containers will be spun up in the first place and no network interfaces will be allocated. Maybe that's the issue.
Set the desires count to something larger than zero to test this.

Thank you tp LRuttens answer. I set desired count to 1. and under network instances I see a network associated with my securitygroup for that ECS service,

Related

My NEGs are not connecting to my cloud run functions

https://cloud.google.com/load-balancing/docs/https/setting-up-https-serverless#setting_up_regional_routing
I setup a GCE global load balancer and NEGs. What is unclear to me is how a NEG connects to a cloud run app. It looks like the Service name of a NEG just needs to match a corresponding cloud run app name.
I have done this but it appears it's not connected. I can't even find in the docs how to troubleshoot this linkage.
Created a neg via Terraform
resource "google_compute_region_network_endpoint_group" "neg" {
network_endpoint_type = "SERVERLESS"
region = us-east1
cloud_run {
service = "my-cloudrun-app"
}
}
Then deployed a cloud run app
gcloud run deploy my-cloudrun-app --region us-east1
My understanding is if the cloud run app name matches the service name it should connect to it. I can see the NEGs are connected to my GCE load balancer and the cloud run app was deployed successfully, but the NEG doesn't appear to be routing to my function.
I'm using this official GCP module to hook this up (it actually does make it pretty easy!) https://github.com/terraform-google-modules/terraform-google-lb-http/tree/v6.0.1/modules/serverless_negs
I found it does work the way I expected it to, the issue was just that I didn't have a cloud run app behind one of the regional NEGs I created (I thought I did). I actually created several regional NEGs, made kind of a mess, and the regional NEG the LB was routing my traffic to didn't have a corresponding cloud run app it pointed to.
How I was able to troubleshoot this:
Find the backend the load balancer was configured with
In GCP console I was able to view the backend and all the regional NEGs configured for it
Hit refresh/curl a bunch of times and saw in the gcp console on the backend's page one of the regional NEGs was actually receiving traffic- so I was at least able to see which NEG my traffic was being routed to
Realized I didn't deploy a cloud run app with a name that regional NEG was configured for
I still feel like visibility into how all these components play together could be better, but the traffic flow diagram for the Backend service details page was a life saver!
I don't know if you did that, but you need more to deploy your neg on a load balancer. Here the missing pieces
resource "google_compute_managed_ssl_certificate" "default" {
name = "cert"
managed {
domains = ["${var.domain}"]
}
}
resource "google_compute_backend_service" "default" {
name = "app-backend"
protocol = "HTTP"
port_name = "http"
timeout_sec = 30
backend {
group = google_compute_region_network_endpoint_group.neg.id
}
}
resource "google_compute_url_map" "default" {
name = "app-urlmap"
default_service = google_compute_backend_service.default.id
}
resource "google_compute_target_https_proxy" "default" {
name = "https-proxy"
url_map = google_compute_url_map.default.id
ssl_certificates = [
google_compute_managed_ssl_certificate.default.id
]
}
resource "google_compute_global_forwarding_rule" "default" {
name = "lb"
target = google_compute_target_https_proxy.default.id
port_range = "443"
ip_address = google_compute_global_address.default.address
}
resource "google_compute_global_address" "default" {
name = "address"
}
Easy?? Absolutely not. Let me know if you need more details, guidances or explanation.

Adding new AWS EBS Volume to ASG in same AZ

ok, so I am trying to attach an EBS volume which I have created using Terraform to an ASG's instance using userdata, but now issue is both are in different AZ's, due to which, it failing to attach. Below is the steps I am trying and failing:
resource "aws_ebs_volume" "this" {
for_each = var.ebs_block_device
size = lookup(each.value,"volume_size", null)
type = lookup(each.value,"volume_type", null)
iops = lookup(each.value, "iops", null)
encrypted = lookup(each.value, "volume_encrypt", null)
kms_key_id = lookup(each.value, "kms_key_id", null)
availability_zone = join(",",random_shuffle.az.result)
}
In above resource, I am using random provider to get one AZ from list of AZs, and same list is provided to ASG resource below:
resource "aws_autoscaling_group" "this" {
desired_capacity = var.desired_capacity
launch_configuration = aws_launch_configuration.this.id
max_size = var.max_size
min_size = var.min_size
name = var.name
vpc_zone_identifier = var.subnet_ids // <------ HERE
health_check_grace_period = var.health_check_grace_period
load_balancers = var.load_balancer_names
target_group_arns = var.target_group_arns
tag {
key = "Name"
value = var.name
propagate_at_launch = true
}
}
And here is userdata which I am using:
TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
instanceId = curl -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id
aws ec2 attach-volume --volume-id ${ebs_volume_id} --instance-id $instanceId --device /dev/nvme1n1
Above will attach the newly created volume, as I am passing output ${ebs_volume_id} of above resource.
But, its failing because instance and volume are in different AZs.
Can anyone help me on this as a better solution than hardcoding AZ on both ASG and Volume?
I'd have to understand more about what you're trying to do to solve this with just the aws provider and terraform. And honestly, most ideas are going to be a bit complex.
You could have an ASG per AZ. Otherwise, the ASG is going to select some AZ at each launch. And you'll have more instances in an AZ than you have volumes and volumes in other AZs with no instances to attach to.
So you could create a number of volumes per az and an ASG per AZ. Then the userdata should list all the volumes in the AZ that are not attached to an instance. Then pick the id of the first volume that is unattached. Then attach it. If all are attached, you should trigger your alerting because you have more instances than you have volumes.
Any attempt to do this with a single ASG is really an attempt at writing your own ASG but doing it in a way that fights with your actual ASG.
But there is a company who offers managing this as a service. They also help you manage them as spot instances to save cost: https://spot.io/
The elastigroup resource is an ASG managed by them. So you won't have an aws asg anymore. But they have some interesting stateful configurations.
We support instance persistence via the following configurations. all values are boolean. For more information on instance persistence please see: Stateful configuration
persist_root_device - (Optional) Boolean, should the instance maintain its root device volumes.
persist_block_devices - (Optional) Boolean, should the instance maintain its Data volumes.
persist_private_ip - (Optional) Boolean, should the instance maintain its private IP.
block_devices_mode - (Optional) String, determine the way we attach the data volumes to the data devices, possible values: "reattach" and "onLaunch" (default is onLaunch).
private_ips - (Optional) List of Private IPs to associate to the group instances.(e.g. "172.1.1.0"). Please note: This setting will only apply if persistence.persist_private_ip is set to true
stateful_deallocation {
should_delete_images = false
should_delete_network_interfaces = false
should_delete_volumes = false
should_delete_snapshots = false
}
This allows you to have an autoscaler that preserves volumes and handles the complexities for you.

Terraform created EC2 Instances not associated with ECS Cluster

I'm new Terraform and I'm working on an infrastructure setup for deploying Docker Containers. I've based my ECS Cluster off Infrablocks/ECS-Cluster and my Base Networking on Infrablocks/Base-Network. I've opted to use these due to time constraints on the project.
The problem I'm having is that the two EC2 Container Instances that are created by Infrablocks/ECS-Cluster module are not associated with ECS Cluster that Infrablocks builds. I've had zero luck determining why. This is blocking my task definitions from being able to run containers in the ECS Cluster because there are no associated EC2 Instances. I've provided my two dependent module configurations below.
Thank you in advance for any help you can provide!
My Terraform thus far:
module "base_network" {
source = "infrablocks/base-networking/aws"
version = "2.3.0"
vpc_cidr = "10.0.0.0/16"
region = "us-east-1"
availability_zones = ["us-east-1a", "us-east-1b"]
component = "dev-base-network"
deployment_identifier = "development"
include_route53_zone_association = "true"
private_zone_id = module.route53.private_zone_id
include_nat_gateway = "true"}
module "ecs_cluster" {
source = "infrablocks/ecs-cluster/aws"
version = "2.2.0"
region = "us-east-1"
vpc_id = module.base_network.vpc_id
subnet_ids = module.base_network.public_subnet_ids
associate_public_ip_addresses = "yes"
component = "dev"
deployment_identifier = "devx"
cluster_name = "services"
cluster_instance_ssh_public_key_path = "~/.ssh/id_rsa.pub"
cluster_instance_type = "t2.small"
cluster_minimum_size = 2
cluster_maximum_size = 10
cluster_desired_capacity = 2 }
You'd have to troubleshoot the instance to see why it isn't joining the cluster. On your EC2 instances (which, I have not looked, but I would hope that the "infrablocks" ecs-cluster module uses an AMI with the ECS agent installed), you can look in /var/log/ecs/ecs-agent.log .
If the networking configuration is sound, my first guess would be to check the ECS configuration file. If your module is working properly, it should have populated the config with the cluster name. See here for more on that
(I would have commented instead of answered but this account doesn't have enough rep :shrug:)

How to block Terraform from deleting an imported resource?

I'm brand new to Terraform so I'm sure i'm missing something, but the answers i'm finding don't seem to be asking the same question I have.
I have an AWS VPC/Security Group that we need our EC2 instances to be created under and this VPC/SG is already created. To create an EC2 instance, Terraform requires that if I don't have a default VPC, I must import my own. But once I import and apply my plan, when I wish to destroy it, its trying to destroy my VPC as well. How do I encapsulate my resources so when I run "terraform apply", I can create an EC2 instance with my imported VPC, but when I run "terraform destroy" I only destroy my EC2 instance?
In case anyone wants to mention, I understand that:
lifecycle = {
prevent_destroy = true
}
is not what I'm looking for.
Here is my current practice code.
resource "aws_vpc" "my_vpc" {
cidr_block = "xx.xx.xx.xx/24"
}
provider "aws" {
region = "us-west-2"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
}
owners = ["099720109477"] # Canonical
}
resource "aws_instance" "web" {
ami = "${data.aws_ami.ubuntu.id}"
instance_type = "t3.nano"
vpc_security_group_ids = ["sg-0e27d851dxxxxxxxxxx"]
subnet_id = "subnet-0755c2exxxxxxxx"
tags = {
Name = "HelloWorld"
}
}
Terraform should not require you to deploy or import a VPC in order to deploy an EC2 instance into it. You should be able to reference the VPC, subnets and security groups by id so TF is aware of your existing network infrastructure just like you've already done for SGs and subnets. All you should need to deploy the EC2 instance "aws_instance" is give it an existing subnet id in the existing VPC like you already did. Why do you say deploying or importing a VPC is required by Terraform? What error or issue do you have deploying without the VPC and just using the existing one?
You can protect the VPC through AWS if you really wanted to, but I don't think you really want to import the VPC into your Terraform state and let Terraform manage it here. Sounds like you want the VPC to service other resources, maybe applications manually deployed or through other TF stacks, and the VPC to live independent of anyone application deployment.
To answer the original question, you can use a data source and match your VPC by id or tag name :
data "aws_vpc" "main" {
tags = {
Name = "main_vpc"
}
}
Or
data "aws_vpc" "main" {
id = "vpc-nnnnnnnn"
}
Then refer to it with : data.aws_vpc.main
Also, if you already included your VPC but would like not to destroy it while remove it from your state, you can manage to do it with the terraform state command : https://www.terraform.io/docs/commands/state/index.html

Redis Autoscaling Ec2

I need a help to Design a network that meets the following requirements:
Core network resources are duplicated in at least 2 regions
Network traffic is routed to the appropriate region, based on user location
Subnetworks are appropriately sized and secured
All devices exist such that networks can be connected to the internet and each other
Networks are tolerant of internet events, and are designed to be highly available
I will need to include in the design any device that will process information in this architecture, even if you do not have implicit control of it (routes, firewalls, NAT Gateways, Internet Gateways, etc.).
Need help in Automate the creation and deconstruction of this service. I need to use any tool like terraform/cloudformation or ansible / chef cookbooks to deploy, as long as it is expressed in code and/or configuration.
Assume the following:
The vpc and subnet already exists
Only local network access is required for all resources and need this architecture need to scale up and down using autoscaling launch configuration when it meets the threshold based on load and alert sent through cloudwatch/sns.
Does this yaml automation code help this is what I am going to try..Please let me know your input
Usage
resource "aws_sns_topic" "global" {
...
}
resource "aws_elasticache_subnet_group" "redis" {
...
}
resource "aws_elasticache_parameter_group" "redis" {
...
}
module "cache" {
source = "github.com/nazeerahamed79/terraform-aws-redis-elasticache"
vpc_id = "vpc-20f74844"
cache_identifier = "cache"
automatic_failover_enabled = "false"
desired_clusters = "1"
instance_type = "cache.t2.micro"
engine_version = "3.2.4"
parameter_group = "${aws_elasticache_parameter_group.redis.name}"
subnet_group = "${aws_elasticache_subnet_group.redis.name}"
maintenance_window = "sun:02:30-sun:03:30"
notification_topic_arn = "${aws_sns_topic.global.arn}"
alarm_cpu_threshold = "75"
alarm_memory_threshold = "10000000"
alarm_actions = ["${aws_sns_topic.global.arn}"]
project = "Redis_deployment"
environment = "Redis_deployment"
}
Variables
vpc_id - ID of VPC meant to house the cache
project - Name of the project making use of the cluster (default: Redis_deployment)
environment - Name of environment the cluster is targeted for (Redis_Multi_azdeployment: Unknown)
cache_identifier - Name used as ElastiCache cluster ID
automatic_failover_enabled - Flag to determine if automatic failover should be enabled
desired_clusters - Number of cache clusters in replication group
instance_type - Instance type for cache instance (default: cache.t2.micro)
engine_version - Cache engine version (default: 3.2.4)
parameter_group - Cache parameter group name (default: redis3.2)
subnet_group - Cache subnet group name
maintenance_window - Time window to reserve for maintenance
notification_topic_arn - ARN to notify when cache events occur
alarm_cpu_threshold - CPU alarm threshold as a percentage (default: 75)
alarm_memory_threshold - Free memory alarm threshold in bytes (default: 10000000)
alarm_actions - ARN to be notified via CloudWatch when alarm thresholds are triggered
Outputs
id - The replication group ID
cache_security_group_id - Security group ID of the cache cluster
port - Port of replication group leader
endpoint - Public DNS name of replication group leader