# Aws Ecs Container Service

> 🐳 **Quick Start**: Highly scalable, high performance container orchestration service untuk Docker containers

## 📋 Table of Contents

* [🎯 ECS Overview](#-ecs-overview)
* [🐳 Container Concepts](#-container-concepts)
* [🏗️ ECS Launch Types](#️-ecs-launch-types)
* [🔧 Cluster Setup](#-cluster-setup)
* [📦 Task Definitions](#-task-definitions)
* [🚀 Services & Auto Scaling](#-services--auto-scaling)
* [🔒 Security & IAM](#-security--iam)
* [📊 Load Balancing](#-load-balancing)
* [🔄 Service Discovery](#-service-discovery)
* [📈 Monitoring & Logging](#-monitoring--logging)
* [⚡ Best Practices](https://github.com/mahbubzulkarnain/catatan-seekor-the-series/blob/master/cloud-computing/aws/%EF%B8%8F-best-practices/README.md)

## 🎯 ECS Overview

Amazon ECS adalah container orchestration service yang memungkinkan Anda:

* **🏗️ Container Orchestration**: Manage Docker containers secara otomatis
* **📈 Scalability**: Auto-scale containers berdasarkan demand
* **🔄 Service Discovery**: Automatic service registration dan discovery
* **🔒 Security**: IAM roles, security groups, dan VPC integration
* **💰 Cost Efficiency**: Pay for resources yang Anda gunakan
* **🛠️ Integration**: Seamless integration dengan AWS ecosystem

### ECS vs EKS vs Fargate

| Feature            | ECS             | EKS          | Fargate             |
| ------------------ | --------------- | ------------ | ------------------- |
| **Orchestrator**   | AWS Proprietary | Kubernetes   | Serverless          |
| **Learning Curve** | Low             | High         | Low                 |
| **Flexibility**    | Medium          | High         | Low                 |
| **Pricing**        | Pay per EC2     | Pay per node | Pay per vCPU/memory |
| **Portability**    | AWS only        | Portable     | AWS only            |

## 🐳 Container Concepts

### Docker Application Structure

```
my-app/
├── Dockerfile
├── docker-compose.yml
├── app/
│   ├── index.html
│   ├── app.js
│   └── package.json
└── nginx/
    └── nginx.conf
```

### Dockerfile Example

```dockerfile
# Multi-stage build
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

COPY . .
RUN npm run build

# Production image
FROM nginx:alpine

COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx/nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
```

### Docker Compose for Local Development

```yaml
# docker-compose.yml
version: '3.8'

services:
  webapp:
    build: .
    ports:
      - "8080:80"
    environment:
      - NODE_ENV=development
      - API_URL=http://api:3000
    depends_on:
      - api
      - redis

  api:
    build: ./api
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:pass@postgres:5432/myapp
      - REDIS_URL=redis://redis:6379
    depends_on:
      - postgres
      - redis

  postgres:
    image: postgres:15-alpine
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
    volumes:
      - postgres_data:/var/lib/postgresql/data

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

volumes:
  postgres_data:
```

## 🏗️ ECS Launch Types

### EC2 Launch Type

```bash
# Create ECS cluster with EC2 launch type
aws ecs create-cluster \
  --cluster-name my-ec2-cluster \
  --capacity-providers FARGATE,FARGATE_SPOT

# Create Auto Scaling Group for ECS instances
aws autoscaling create-auto-scaling-group \
  --auto-scaling-group-name ecs-asg \
  --launch-template LaunchTemplateId=lt-12345678,Version=1 \
  --vpc-zone-identifier subnet-12345678,subnet-87654321 \
  --min-size 1 \
  --max-size 10 \
  --desired-capacity 2 \
  --target-group-arns arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/ecs-targets/1234567890abcdef

# Register EC2 instances to cluster
aws ecs update-container-instances-state \
  --cluster my-ec2-cluster \
  --container-instances arn:aws:ecs:us-east-1:123456789012:container-instance/12345678-1234-1234-1234-123456789012 \
  --status DRAINING
```

### Fargate Launch Type

```bash
# Create ECS cluster with Fargate launch type
aws ecs create-cluster \
  --cluster-name my-fargate-cluster \
  --capacity-providers FARGATE,FARGATE_SPOT

# No need to manage EC2 instances with Fargate
# Fargate handles infrastructure automatically
```

### Terraform Cluster Configuration

```hcl
resource "aws_ecs_cluster" "main" {
  name = "${var.project_name}-cluster"

  setting {
    name  = "containerInsights"
    value = "enabled"
  }

  tags = merge(
    local.common_tags,
    {
      Name = "${var.project_name}-cluster"
    }
  )
}

resource "aws_ecs_cluster_capacity_providers" "main" {
  cluster_name = aws_ecs_cluster.main.name

  capacity_providers = ["FARGATE", "FARGATE_SPOT"]

  default_capacity_provider_strategy {
    base              = 1
    weight            = 100
    capacity_provider = "FARGATE"
  }
}
```

## 🔧 Cluster Setup

### Using AWS Management Console

```bash
1. Navigate to ECS Dashboard
2. Click "Create cluster"
3. Select cluster template:
   - Networking only (Fargate)
   - EC2 Linux + Networking
   - EC2 Windows + Networking
4. Configure cluster settings:
   - Cluster name
   - Infrastructure (Fargate or EC2)
   - Monitoring (CloudWatch Container Insights)
5. Configure networking:
   - VPC
   - Subnets
   - Security groups
6. Review and create
```

### Using AWS CLI

```bash
# Create VPC for ECS
VPC_ID=$(aws ec2 create-vpc \
  --cidr-block 10.0.0.0/16 \
  --tag-specifications 'ResourceType=vpc,Tags=[{Key=Name,Value=ecs-vpc}]' \
  --query 'Vpc.VpcId' \
  --output text)

# Create public subnets
PUBLIC_SUBNET_1=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.1.0/24 \
  --availability-zone us-east-1a \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ecs-public-1a}]' \
  --query 'Subnet.SubnetId' \
  --output text)

PUBLIC_SUBNET_2=$(aws ec2 create-subnet \
  --vpc-id $VPC_ID \
  --cidr-block 10.0.2.0/24 \
  --availability-zone us-east-1b \
  --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=ecs-public-1b}]' \
  --query 'Subnet.SubnetId' \
  --output text)

# Create internet gateway
IGW_ID=$(aws ec2 create-internet-gateway \
  --tag-specifications 'ResourceType=internet-gateway,Tags=[{Key=Name,Value=ecs-igw}]' \
  --query 'InternetGateway.InternetGatewayId' \
  --output text)

# Attach internet gateway to VPC
aws ec2 attach-internet-gateway \
  --vpc-id $VPC_ID \
  --internet-gateway-id $IGW_ID

# Create ECS cluster
aws ecs create-cluster \
  --cluster-name my-webapp-cluster \
  --capacity-providers FARGATE,FARGATE_SPOT

# Create task execution IAM role
cat > task-execution-role.json << EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF

ROLE_ARN=$(aws iam create-role \
  --role-name ecs-task-execution-role \
  --assume-role-policy-document file://task-execution-role.json \
  --query 'Role.Arn' \
  --output text)

aws iam attach-role-policy \
  --role-name ecs-task-execution-role \
  --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy

echo "Cluster created successfully!"
echo "Cluster ARN: $(aws ecs describe-clusters --clusters my-webapp-cluster --query 'clusters[0].clusterArn' --output text)"
```

## 📦 Task Definitions

### Task Definition JSON

```json
{
  "family": "webapp-task",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "256",
  "memory": "512",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecs-task-execution-role",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecs-task-role",
  "containerDefinitions": [
    {
      "name": "webapp",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/webapp:latest",
      "portMappings": [
        {
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:database-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/webapp",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3
      }
    }
  ]
}
```

### Multi-Container Task Definition

```json
{
  "family": "fullstack-app",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "1024",
  "memory": "2048",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecs-task-execution-role",
  "containerDefinitions": [
    {
      "name": "nginx",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/nginx:latest",
      "portMappings": [
        {
          "containerPort": 80,
          "protocol": "tcp"
        }
      ],
      "links": ["webapp"],
      "dependsOn": [
        {
          "containerName": "webapp",
          "condition": "START"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/fullstack-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "nginx"
        }
      }
    },
    {
      "name": "webapp",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/webapp:latest",
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        },
        {
          "name": "DATABASE_URL",
          "value": "postgresql://user:pass@rds-instance:5432/myapp"
        },
        {
          "name": "REDIS_URL",
          "value": "redis://redis-cluster:6379"
        }
      ],
      "secrets": [
        {
          "name": "JWT_SECRET",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:jwt-secret"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/fullstack-app",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "webapp"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3
      }
    }
  ]
}
```

### Terraform Task Definition

```hcl
resource "aws_ecs_task_definition" "webapp" {
  family                   = "${var.project_name}-webapp"
  network_mode             = "awsvpc"
  requires_compatibilities = ["FARGATE"]
  cpu                      = var.task_cpu
  memory                   = var.task_memory
  execution_role_arn       = aws_iam_role.ecs_task_execution.arn
  task_role_arn           = aws_iam_role.ecs_task.arn

  container_definitions = jsonencode([
    {
      name  = "webapp"
      image = "${aws_ecr_repository.webapp.repository_url}:latest"

      portMappings = [
        {
          containerPort = 3000
          protocol      = "tcp"
        }
      ]

      environment = [
        {
          name  = "NODE_ENV"
          value = "production"
        },
        {
          name  = "PORT"
          value = "3000"
        }
      ]

      secrets = [
        {
          name      = "DATABASE_URL"
          valueFrom = aws_secretsmanager_secret.database_url.arn
        },
        {
          name      = "JWT_SECRET"
          valueFrom = aws_secretsmanager_secret.jwt_secret.arn
        }
      ]

      logConfiguration = {
        logDriver = "awslogs"
        options = {
          "awslogs-group"         = aws_cloudwatch_log_group.webapp.name
          "awslogs-region"        = var.aws_region
          "awslogs-stream-prefix" = "ecs"
        }
      }

      healthCheck = {
        command     = ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
        interval    = 30
        timeout     = 5
        retries     = 3
        startPeriod = 60
      }

      dockerLabels = {
        "com.amazonaws.ecs.task-arn" = aws_ecs_task_definition.webapp.arn
      }
    }
  ])

  tags = local.common_tags
}

variable "task_cpu" {
  description = "CPU units for task"
  type        = number
  default     = 256
}

variable "task_memory" {
  description = "Memory for task (MiB)"
  type        = number
  default     = 512
}
```

## 🚀 Services & Auto Scaling

### Create ECS Service

```bash
# Create service with load balancer
aws ecs create-service \
  --cluster my-webapp-cluster \
  --service-name webapp-service \
  --task-definition webapp-task:1 \
  --desired-count 2 \
  --launch-type FARGATE \
  --platform-version LATEST \
  --network-configuration "awsvpcConfiguration={subnets=[$PUBLIC_SUBNET_1,$PUBLIC_SUBNET_2],securityGroups=[$SG_ID],assignPublicIp=ENABLED}" \
  --load-balancers "targetGroupArn=$TARGET_GROUP_ARN,containerName=webapp,containerPort=80" \
  --health-check-grace-period-seconds 30 \
  --deployment-controller type=ECS \
  --deployment-configuration maximumPercent=200,minimumHealthyPercent=100

# Update service
aws ecs update-service \
  --cluster my-webapp-cluster \
  --service webapp-service \
  --desired-count 4 \
  --force-new-deployment

# Enable service auto scaling
aws application-autoscaling register-scalable-target \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/my-webapp-cluster/webapp-service \
  --min-capacity 2 \
  --max-capacity 10

# CPU-based scaling policy
aws application-autoscaling put-scaling-policy \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/my-webapp-cluster/webapp-service \
  --policy-name ecs-cpu-scaling \
  --policy-type TargetTrackingScaling \
  --target-tracking-scaling-policy-configuration file://cpu-scaling-policy.json
```

### CPU Scaling Policy Configuration

```json
{
  "TargetValue": 70.0,
  "PredefinedMetricSpecification": {
    "PredefinedMetricType": "ECSServiceAverageCPUUtilization"
  },
  "ScaleInCooldown": 300,
  "ScaleOutCooldown": 300
}
```

### Terraform Service Configuration

```hcl
resource "aws_ecs_service" "webapp" {
  name            = "${var.project_name}-webapp"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.webapp.arn
  desired_count   = var.desired_count
  launch_type     = "FARGATE"

  network_configuration {
    subnets          = aws_subnet.public[*].id
    security_groups  = [aws_security_group.ecs.id]
    assign_public_ip = true
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.webapp.arn
    container_name   = "webapp"
    container_port   = 3000
  }

  health_check_grace_period_seconds = 30

  deployment_controller {
    type = "ECS"
  }

  deployment_configuration {
    maximum_percent         = 200
    minimum_healthy_percent = 100
  }

  depends_on = [aws_lb_listener.webapp]

  tags = local.common_tags
}

resource "aws_appautoscaling_target" "ecs_target" {
  max_capacity       = var.max_capacity
  min_capacity       = var.min_capacity
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.webapp.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_policy" "ecs_policy_cpu" {
  name               = "${var.project_name}-cpu-scaling"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs_target.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs_target.service_namespace

  target_tracking_scaling_policy_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }

    target_value       = 70
    scale_in_cooldown  = 300
    scale_out_cooldown = 300
  }
}

resource "aws_appautoscaling_policy" "ecs_policy_memory" {
  name               = "${var.project_name}-memory-scaling"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs_target.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs_target.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs_target.service_namespace

  target_tracking_scaling_policy_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageMemoryUtilization"
    }

    target_value       = 80
    scale_in_cooldown  = 300
    scale_out_cooldown = 300
  }
}

variable "desired_count" {
  description = "Desired number of tasks"
  type        = number
  default     = 2
}

variable "min_capacity" {
  description = "Minimum capacity for auto scaling"
  type        = number
  default     = 1
}

variable "max_capacity" {
  description = "Maximum capacity for auto scaling"
  type        = number
  default     = 10
}
```

## 🔒 Security & IAM

### Task Execution Role

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

### Task Role (for Application)

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ecs-tasks.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
```

### IAM Policies for Task Role

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "secretsmanager:GetSecretValue"
      ],
      "Resource": [
        "arn:aws:secretsmanager:us-east-1:123456789012:secret:database-url",
        "arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::my-app-bucket/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:Query",
        "dynamodb:Scan",
        "dynamodb:UpdateItem"
      ],
      "Resource": "arn:aws:dynamodb:us-east-1:123456789012:table/my-app-table"
    }
  ]
}
```

### Terraform IAM Configuration

```hcl
resource "aws_iam_role" "ecs_task_execution" {
  name = "${var.project_name}-ecs-task-execution"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
      }
    ]
  })

  tags = local.common_tags
}

resource "aws_iam_role_policy_attachment" "ecs_task_execution" {
  role       = aws_iam_role.ecs_task_execution.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy"
}

resource "aws_iam_role" "ecs_task" {
  name = "${var.project_name}-ecs-task"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ecs-tasks.amazonaws.com"
        }
      }
    ]
  })

  tags = local.common_tags
}

resource "aws_iam_role_policy" "ecs_task" {
  name = "${var.project_name}-ecs-task-policy"
  role = aws_iam_role.ecs_task.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Action = [
          "secretsmanager:GetSecretValue"
        ]
        Resource = [
          aws_secretsmanager_secret.database_url.arn,
          aws_secretsmanager_secret.jwt_secret.arn
        ]
      },
      {
        Effect = "Allow"
        Action = [
          "s3:GetObject",
          "s3:PutObject",
          "s3:DeleteObject"
        ]
        Resource = "${aws_s3_bucket.app_data.arn}/*"
      }
    ]
  })
}
```

## 📊 Load Balancing

### Application Load Balancer

```bash
# Create load balancer
aws elbv2 create-load-balancer \
  --name webapp-alb \
  --subnets $PUBLIC_SUBNET_1 $PUBLIC_SUBNET_2 \
  --security-groups $ALB_SG_ID \
  --scheme internet-facing \
  --type application \
  --ip-address-type ipv4

# Create target group
aws elbv2 create-target-group \
  --name webapp-targets \
  --protocol HTTP \
  --port 3000 \
  --target-type ip \
  --vpc-id $VPC_ID \
  --health-check-protocol HTTP \
  --health-check-path /health \
  --health-check-interval-seconds 30 \
  --health-check-timeout-seconds 5 \
  --healthy-threshold-count 2 \
  --unhealthy-threshold-count 3 \
  --matcher HttpCode=200

# Create listener
aws elbv2 create-listener \
  --load-balancer-arn $ALB_ARN \
  --protocol HTTP \
  --port 80 \
  --default-actions Type=forward,TargetGroupArn=$TARGET_GROUP_ARN
```

### Terraform Load Balancer

```hcl
resource "aws_lb" "webapp" {
  name               = "${var.project_name}-alb"
  internal           = false
  load_balancer_type = "application"
  security_groups    = [aws_security_group.alb.id]
  subnets            = aws_subnet.public[*].id

  enable_deletion_protection = false

  tags = merge(
    local.common_tags,
    {
      Name = "${var.project_name}-alb"
    }
  )
}

resource "aws_lb_target_group" "webapp" {
  name     = "${var.project_name}-targets"
  port     = 3000
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id
  target_type = "ip"

  health_check {
    enabled             = true
    healthy_threshold   = 2
    interval            = 30
    matcher             = "200"
    path                = "/health"
    port                = "traffic-port"
    protocol            = "HTTP"
    timeout             = 5
    unhealthy_threshold = 3
  }

  tags = merge(
    local.common_tags,
    {
      Name = "${var.project_name}-targets"
    }
  )
}

resource "aws_lb_listener" "webapp" {
  load_balancer_arn = aws_lb.webapp.arn
  port              = "80"
  protocol          = "HTTP"

  default_action {
    type             = "forward"
    target_group_arn = aws_lb_target_group.webapp.arn
  }
}

resource "aws_security_group" "alb" {
  name_prefix = "${var.project_name}-alb-"
  vpc_id      = aws_vpc.main.id

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

  ingress {
    description = "HTTPS from anywhere"
    from_port   = 443
    to_port     = 443
    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"]
  }

  tags = local.common_tags
}
```

## 🔄 Service Discovery

### Cloud Map Service Discovery

```bash
# Create private DNS namespace
aws servicediscovery create-private-dns-namespace \
  --name webapp.local \
  --vpc $VPC_ID \
  --description "Service discovery for webapp"

# Get namespace ID
NAMESPACE_ID=$(aws servicediscovery list-namespaces \
  --filters Name=NAME,Values=webapp.local \
  --query 'Namespaces[0].Id' \
  --output text)

# Create service
aws servicediscovery create-service \
  --name webapp \
  --namespace-id $NAMESPACE_ID \
  --dns-config '{
    "DnsRecords": [{
      "Type": "A",
      "TTL": 60
    }]
  }' \
  --health-check-custom-config '{ "FailureThreshold": 1 }'

# Update ECS service with service discovery
aws ecs create-service \
  --cluster my-webapp-cluster \
  --service-name webapp-service \
  --task-definition webapp-task:1 \
  --desired-count 2 \
  --launch-type FARGATE \
  --network-configuration "awsvpcConfiguration={subnets=[$PRIVATE_SUBNET_1,$PRIVATE_SUBNET_2],securityGroups=[$SG_ID],assignPublicIp=DISABLED}" \
  --service-registries registryArn=$SERVICE_REGISTRY_ARN
```

### Terraform Service Discovery

```hcl
resource "aws_service_discovery_private_dns_namespace" "main" {
  name        = "${var.project_name}.local"
  description = "Service discovery for ${var.project_name}"
  vpc         = aws_vpc.main.id

  tags = local.common_tags
}

resource "aws_service_discovery_service" "webapp" {
  name = "webapp"

  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.main.id

    dns_records {
      ttl  = 60
      type = "A"
    }
  }

  health_check_custom_config {
    failure_threshold = 1
  }

  tags = local.common_tags
}

# Update ECS service to use service discovery
resource "aws_ecs_service" "webapp_discovery" {
  name            = "${var.project_name}-webapp"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.webapp.arn
  desired_count   = var.desired_count
  launch_type     = "FARGATE"

  network_configuration {
    subnets          = aws_subnet.private[*].id
    security_groups  = [aws_security_group.ecs.id]
    assign_public_ip = false
  }

  service_registries {
    registry_arn = aws_service_discovery_service.webapp.arn
  }

  tags = local.common_tags
}
```

## 📈 Monitoring & Logging

### CloudWatch Container Insights

```bash
# Enable Container Insights
aws ecs update-cluster-settings \
  --cluster my-webapp-cluster \
  --settings name=containerInsights,value=enabled

# Create CloudWatch log group
aws logs create-log-group \
  --log-group-name /ecs/webapp \
  --retention-in-days 14

# Set log retention
aws logs put-retention-policy \
  --log-group-name /ecs/webapp \
  --retention-in-days 14
```

### CloudWatch Alarms

```bash
# CPU utilization alarm
aws cloudwatch put-metric-alarm \
  --alarm-name "ECS-Service-CPU-High" \
  --alarm-description "ECS service CPU utilization is high" \
  --metric-name CPUUtilization \
  --namespace AWS/ECS \
  --statistic Average \
  --period 300 \
  --threshold 80 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --dimensions Name=ServiceName,Value=webapp-service Name=ClusterName,Value=my-webapp-cluster \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:ecs-alerts

# Memory utilization alarm
aws cloudwatch put-metric-alarm \
  --alarm-name "ECS-Service-Memory-High" \
  --alarm-description "ECS service memory utilization is high" \
  --metric-name MemoryUtilization \
  --namespace AWS/ECS \
  --statistic Average \
  --period 300 \
  --threshold 85 \
  --comparison-operator GreaterThanThreshold \
  --evaluation-periods 2 \
  --dimensions Name=ServiceName,Value=webapp-service Name=ClusterName,Value=my-webapp-cluster \
  --alarm-actions arn:aws:sns:us-east-1:123456789012:ecs-alerts
```

### Terraform Monitoring

```hcl
resource "aws_cloudwatch_log_group" "webapp" {
  name              = "/ecs/${var.project_name}"
  retention_in_days = 14

  tags = local.common_tags
}

resource "aws_cloudwatch_metric_alarm" "ecs_cpu_high" {
  alarm_name          = "${var.project_name}-ecs-cpu-high"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name         = "CPUUtilization"
  namespace           = "AWS/ECS"
  period              = "300"
  statistic           = "Average"
  threshold           = "80"
  alarm_description   = "This metric monitors ECS service CPU utilization"
  alarm_actions       = [aws_sns_topic.alerts.arn]

  dimensions = {
    ServiceName = aws_ecs_service.webapp.name
    ClusterName = aws_ecs_cluster.main.name
  }

  tags = local.common_tags
}

resource "aws_cloudwatch_metric_alarm" "ecs_memory_high" {
  alarm_name          = "${var.project_name}-ecs-memory-high"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = "2"
  metric_name         = "MemoryUtilization"
  namespace           = "AWS/ECS"
  period              = "300"
  statistic           = "Average"
  threshold           = "85"
  alarm_description   = "This metric monitors ECS service memory utilization"
  alarm_actions       = [aws_sns_topic.alerts.arn]

  dimensions = {
    ServiceName = aws_ecs_service.webapp.name
    ClusterName = aws_ecs_cluster.main.name
  }

  tags = local.common_tags
}
```

## ⚡ Best Practices

### Task Definition Best Practices

```json
{
  "family": "production-webapp",
  "networkMode": "awsvpc",
  "requiresCompatibilities": ["FARGATE"],
  "cpu": "512",
  "memory": "1024",
  "executionRoleArn": "arn:aws:iam::123456789012:role/ecs-task-execution-role",
  "taskRoleArn": "arn:aws:iam::123456789012:role/ecs-task-role",
  "containerDefinitions": [
    {
      "name": "webapp",
      "image": "123456789012.dkr.ecr.us-east-1.amazonaws.com/webapp:1.0.0",
      "essential": true,
      "portMappings": [
        {
          "containerPort": 3000,
          "protocol": "tcp"
        }
      ],
      "environment": [
        {
          "name": "NODE_ENV",
          "value": "production"
        }
      ],
      "secrets": [
        {
          "name": "DATABASE_URL",
          "valueFrom": "arn:aws:secretsmanager:us-east-1:123456789012:secret:database-url"
        }
      ],
      "logConfiguration": {
        "logDriver": "awslogs",
        "options": {
          "awslogs-group": "/ecs/webapp",
          "awslogs-region": "us-east-1",
          "awslogs-stream-prefix": "ecs",
          "awslogs-create-group": "true"
        }
      },
      "healthCheck": {
        "command": ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"],
        "interval": 30,
        "timeout": 5,
        "retries": 3,
        "startPeriod": 60
      },
      "dockerLabels": {
        "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-east-1:123456789012:task-definition/production-webapp:1"
      },
      "ulimits": [
        {
          "name": "nofile",
          "softLimit": 1024,
          "hardLimit": 4096
        }
      ],
      "resourceRequirements": [
        {
          "type": "MEMORY",
          "value": "512"
        }
      ],
      "dependsOn": [],
      "stopTimeout": 30,
      "startTimeout": 30,
      "dockerSecurityOptions": ["no-new-privileges"]
    }
  ],
  "placementConstraints": [],
  "volumes": []
}
```

### Deployment Strategies

```bash
# Blue/Green deployment
aws ecs update-service \
  --cluster my-webapp-cluster \
  --service webapp-service \
  --task-definition webapp-task:2 \
  --deployment-controller type=CODE_DEPLOY \
  --deployment-configuration maximumPercent=200,minimumHealthyPercent=0

# Rolling update
aws ecs update-service \
  --cluster my-webapp-cluster \
  --service webapp-service \
  --task-definition webapp-task:2 \
  --deployment-controller type=ECS \
  --deployment-configuration maximumPercent=200,minimumHealthyPercent=100

# Canary deployment (with CodeDeploy)
aws deploy create-deployment \
  --application-name WebApp \
  --deployment-group-name WebApp-Canary \
  --deployment-config-name CodeDeployDefault.OneAtATime \
  --github-location repository=MyOrg/my-app,commitId=abc123
```

### Cost Optimization

```bash
# Use Fargate Spot for non-critical workloads
aws ecs create-service \
  --cluster my-webapp-cluster \
  --service-name background-worker \
  --task-definition worker-task:1 \
  --desired-count 2 \
  --launch-type FARGATE \
  --platform-version 1.4.0 \
  --capacity-provider-strategy capacityProvider=FARGATE_SPOT,weight=1

# Scale down during off-peak hours
aws application-autoscaling put-scheduled-action \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/my-webapp-cluster/webapp-service \
  --scheduled-action-name scale-down-night \
  --schedule "cron(0 2 * * ? *)" \
  --scalable-target-action MinCapacity=1,MaxCapacity=2

aws application-autoscaling put-scheduled-action \
  --service-namespace ecs \
  --scalable-dimension ecs:service:DesiredCount \
  --resource-id service/my-webapp-cluster/webapp-service \
  --scheduled-action-name scale-up-morning \
  --schedule "cron(0 8 * * ? *)" \
  --scalable-target-action MinCapacity=3,MaxCapacity=8
```

## 📚 References

* [ECS Documentation](https://docs.aws.amazon.com/ecs/)
* [ECS Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/)
* [ECS Best Practices](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/best-practices.html)
* [Fargate Documentation](https://docs.aws.amazon.com/AmazonECS/latest/userguide/what-is-fargate.html)

***

*🐳 Generated with ❤️ using Catatan Seekor Documentation Framework*
