Skip to content

Instantly share code, notes, and snippets.

@okelet
Last active February 11, 2022 17:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save okelet/2b3364fa18ce74f39b43b6ce8f31cccc to your computer and use it in GitHub Desktop.
Save okelet/2b3364fa18ce74f39b43b6ce8f31cccc to your computer and use it in GitHub Desktop.

Testing aws ecs execute-command

Moved to the blog.

terraform {
required_providers {
aws = {
source = "hashicorp/aws"
}
}
}
data "aws_region" "current" {
}
data "aws_availability_zones" "available" {
state = "available"
}
variable "key_pair" {
type = string
default = null
}
variable "prefix" {
type = string
default = "ecs_fargate_exec_test"
}
locals {
ecs_service_name = "echo"
vpc_cidr = "192.168.22.0/24"
}
# https://registry.terraform.io/modules/terraform-aws-modules/vpc/aws/latest
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "${var.prefix}-vpc"
cidr = local.vpc_cidr
azs = slice(data.aws_availability_zones.available.names, 0, 2)
private_subnets = [cidrsubnet(local.vpc_cidr, 4, 0), cidrsubnet(local.vpc_cidr, 4, 1)]
public_subnets = [cidrsubnet(local.vpc_cidr, 4, 2), cidrsubnet(local.vpc_cidr, 4, 3)]
enable_nat_gateway = true
single_nat_gateway = true
enable_dns_hostnames = true
enable_dns_support = true
}
data "aws_ami" "amazon_linux_2" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-ebs"]
}
}
resource "aws_security_group" "allow_all" {
name = "${var.prefix}_allow_all"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 0
to_port = 0
protocol = "ALL"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "ALL"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "allow_ssh" {
name = "${var.prefix}_allow_ssh"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "ALL"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "allow_http_80" {
name = "${var.prefix}_allow_http_80"
vpc_id = module.vpc.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 = "ALL"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "allow_http_8080" {
name = "${var.prefix}_allow_http_8080"
vpc_id = module.vpc.vpc_id
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "ALL"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_instance" "bastion" {
ami = data.aws_ami.amazon_linux_2.id
instance_type = "t3.micro"
key_name = var.key_pair
user_data = <<-EOF
#!/bin/bash
amazon-linux-extras install nginx1 -y
systemctl enable nginx
cp /usr/share/nginx/html/index.html{,.old}
echo "Hello from $(hostname)" > /usr/share/nginx/html/index.html
systemctl start nginx
EOF
associate_public_ip_address = true
subnet_id = module.vpc.public_subnets[0]
vpc_security_group_ids = [aws_security_group.allow_ssh.id, aws_security_group.allow_http_80.id]
tags = {
Name = "${var.prefix}_bastion"
}
}
resource "aws_lb" "alb" {
name = replace(replace("${var.prefix}_alb", "_", "-"), "/[^a-zA-Z0-9-]/", "")
load_balancer_type = "application"
security_groups = [aws_security_group.allow_http_80.id]
subnets = module.vpc.public_subnets
}
resource "aws_lb_listener" "http" {
load_balancer_arn = aws_lb.alb.arn
port = "80"
protocol = "HTTP"
default_action {
type = "fixed-response"
fixed_response {
content_type = "text/html"
message_body = "<html><body><p>Nothing yet here; try <a href=\"/echo/\">here</a>.</p></body></html>\n"
status_code = "404"
}
}
}
resource "aws_lb_target_group" "tg" {
name = replace(replace("${var.prefix}_${local.ecs_service_name}", "_", "-"), "/[^a-zA-Z0-9-]/", "")
port = 80
protocol = "HTTP"
target_type = "ip"
vpc_id = module.vpc.vpc_id
deregistration_delay = 5
}
resource "aws_lb_listener_rule" "static" {
listener_arn = aws_lb_listener.http.arn
priority = 100
action {
type = "forward"
target_group_arn = aws_lb_target_group.tg.arn
}
condition {
path_pattern {
values = ["/${local.ecs_service_name}/*"]
}
}
}
resource "aws_ecs_cluster" "cluster" {
name = "${var.prefix}_ecs_cluster"
capacity_providers = ["FARGATE", "FARGATE_SPOT"]
default_capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
}
setting {
name = "containerInsights"
value = "enabled"
}
}
data "aws_iam_policy_document" "task_role_assume_role_policy" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["ecs-tasks.amazonaws.com"]
}
}
}
resource "aws_iam_role" "task_role" {
name = "${var.prefix}_task_role"
assume_role_policy = data.aws_iam_policy_document.task_role_assume_role_policy.json
}
resource "aws_iam_role_policy" "task_policy" {
name = "${var.prefix}_task_policy"
role = aws_iam_role.task_role.id
policy = jsonencode({
"Version" = "2012-10-17"
"Statement" = [
{
"Effect" = "Allow"
"Action" = [
"ssmmessages:CreateControlChannel",
"ssmmessages:CreateDataChannel",
"ssmmessages:OpenControlChannel",
"ssmmessages:OpenDataChannel"
]
"Resource" = "*"
}
]
})
}
resource "aws_iam_role" "task_execution_role" {
name = "${var.prefix}_task_execution_role"
assume_role_policy = jsonencode({
"Version" = "2012-10-17"
"Statement" = [
{
"Action" = "sts:AssumeRole"
"Principal" = {
"Service" = "ecs-tasks.amazonaws.com"
}
"Effect" = "Allow"
}
]
})
}
resource "aws_iam_role_policy_attachment" "task_execution_role" {
role = aws_iam_role.task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}
resource "aws_iam_role_policy_attachment" "task_execution_role_attachment_CloudWatchFullAccess" {
role = aws_iam_role.task_execution_role.name
policy_arn = "arn:aws:iam::aws:policy/CloudWatchFullAccess"
}
resource "aws_cloudwatch_log_group" "log_group" {
name = "/ecs/clusters/${aws_ecs_cluster.cluster.name}/services/${local.ecs_service_name}"
}
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition
resource "aws_ecs_task_definition" "task_def" {
family = "${var.prefix}_${local.ecs_service_name}"
network_mode = "awsvpc"
requires_compatibilities = ["EC2", "FARGATE"]
cpu = 256
memory = 512
execution_role_arn = aws_iam_role.task_execution_role.arn
task_role_arn = aws_iam_role.task_role.arn
container_definitions = jsonencode([
{
name = "echo"
image = "mendhak/http-https-echo:19"
essential = true
portMappings = [
{
containerPort = 8080
hostPort = 8080
}
],
"linuxParameters" : {
"initProcessEnabled" : true
},
"logConfiguration" = {
"logDriver" = "awslogs"
"options" = {
"awslogs-group" = aws_cloudwatch_log_group.log_group.name
"awslogs-region" = data.aws_region.current.name
"awslogs-stream-prefix" = "ecs"
}
}
}
])
}
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service
resource "aws_ecs_service" "service" {
name = "${var.prefix}_${local.ecs_service_name}"
cluster = aws_ecs_cluster.cluster.id
task_definition = aws_ecs_task_definition.task_def.arn
desired_count = 2
enable_execute_command = true
network_configuration {
subnets = module.vpc.private_subnets
security_groups = [aws_security_group.allow_http_8080.id]
}
load_balancer {
target_group_arn = aws_lb_target_group.tg.arn
container_name = "echo"
container_port = 8080
}
lifecycle {
ignore_changes = [desired_count]
}
capacity_provider_strategy {
capacity_provider = "FARGATE_SPOT"
weight = 1
}
}
resource "aws_appautoscaling_target" "target" {
max_capacity = 5
min_capacity = 1
resource_id = "service/${aws_ecs_cluster.cluster.name}/${aws_ecs_service.service.name}"
scalable_dimension = "ecs:service:DesiredCount"
service_namespace = "ecs"
}
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy
resource "aws_appautoscaling_policy" "memory" {
name = "${var.prefix}_memory"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.target.resource_id
scalable_dimension = aws_appautoscaling_target.target.scalable_dimension
service_namespace = aws_appautoscaling_target.target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageMemoryUtilization"
}
target_value = 80
}
}
# https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy
resource "aws_appautoscaling_policy" "cpu" {
name = "${var.prefix}_cpu"
policy_type = "TargetTrackingScaling"
resource_id = aws_appautoscaling_target.target.resource_id
scalable_dimension = aws_appautoscaling_target.target.scalable_dimension
service_namespace = aws_appautoscaling_target.target.service_namespace
target_tracking_scaling_policy_configuration {
predefined_metric_specification {
predefined_metric_type = "ECSServiceAverageCPUUtilization"
}
target_value = 60
}
}
output "cluster_name" {
value = aws_ecs_cluster.cluster.name
}
output "service_name" {
value = aws_ecs_service.service.name
}
output "lb_addr" {
value = aws_lb.alb.dns_name
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment