Infrastruktúra

Konténerek prodban szerver nélkül: ECS Fargate + ALB + autoscaling, Terraformmal

A Fargate leveszi a válladról az EC2-hostok kezelését: csak a konténert adod meg, az AWS futtatja. Felépítünk egy teljes prod setupot ALB-vel, health checkkel, cél-alapú autoscalinggel és privát taskokkal — végig IaC-kal.

Röviden: A Fargate leveszi a válladról az EC2-hostok kezelését: csak a konténert adod meg, az AWS futtatja. Felépítünk egy teljes prod setupot ALB-vel, health checkkel, cél-alapú autoscalinggel és privát taskokkal — végig IaC-kal.

Ha van egy konténerbe csomagolt alkalmazásod, de nem akarsz Kubernetes-klasztert üzemeltetni, az ECS Fargate a legkevesebb súrlódással járó út prodba. A Fargate szerver nélküli: nem kell EC2-hostokat foglalni, patchelni, skálázni — csak megadod, mennyi CPU és memória kell a taskodnak, és az AWS futtatja. Ebben a cikkben egy teljes production setupot építünk: ALB a bejövő forgalomnak, ECS service Fargate-en, privát subnetben futó taskok, health check és terhelés-alapú autoscaling — mind Terraformmal.

A cél-architektúra

Az ALB a publikus subnetekben fogadja a HTTPS-t, és a privát subnetekben futó Fargate-taskokra osztja a forgalmat egy target groupon keresztül. Az ECS service tartja a kívánt példányszámot, az Application Auto Scaling pedig a CPU-terhelés alapján fel/le skálázza.

Fargate vagy EC2 launch type?

Az ECS kétféleképp futtathat taskot: Fargate-en (szerver nélkül) vagy saját EC2-hostokon. A Fargate egyszerűbb és operatívan olcsóbb; az EC2 akkor kerül képbe, ha nagyon nagy, állandó terhelésnél a compute egységára számít, vagy speciális (pl. GPU) hardver kell.

SzempontFargateEC2 launch type
Host-kezelésnincs (AWS)te patchelsz, skálázol
Számlázástask CPU/mem szerintEC2-instance szerint
Indulási időpár másodpercAMI/host függő
Nagy, állandó terhelésdrágább lehetolcsóbb lehet
Mikor?a legtöbb esetbenGPU, nagyon nagy skála

A cluster és a task definition, Terraformban

A task definition a szíve mindennek: megmondja, milyen konténer(ek), mennyi CPU/memória, milyen portok és környezeti változók. A awslogs driver a CloudWatchba küldi a logokat.

hcl
resource "aws_ecs_cluster" "main" {
  name = "${var.project}-cluster"
  setting {
    name  = "containerInsights"
    value = "enabled"
  }
  tags = local.tags
}

resource "aws_cloudwatch_log_group" "app" {
  name              = "/ecs/${var.project}"
  retention_in_days = 30
  tags              = local.tags
}

resource "aws_ecs_task_definition" "app" {
  family                   = "${var.project}-app"
  requires_compatibilities = ["FARGATE"]
  network_mode             = "awsvpc"
  cpu                      = 512
  memory                   = 1024
  execution_role_arn       = aws_iam_role.task_execution.arn
  task_role_arn            = aws_iam_role.task.arn

  container_definitions = jsonencode([{
    name      = "app"
    image     = "${var.ecr_repo_url}:${var.image_tag}"
    essential = true
    portMappings = [{ containerPort = 8080, protocol = "tcp" }]
    logConfiguration = {
      logDriver = "awslogs"
      options = {
        "awslogs-group"         = aws_cloudwatch_log_group.app.name
        "awslogs-region"        = var.region
        "awslogs-stream-prefix" = "app"
      }
    }
  }])

  tags = local.tags
}

Az ALB és a target group health checkkel

Az ALB egy target grouphoz irányítja a forgalmat, ami a taskok 8080-as portját célozza. A health check kritikus: az ALB csak egészséges taskokra oszt forgalmat, és a beteget kiveszi a rotációból.

hcl
resource "aws_lb" "app" {
  name               = "${var.project}-alb"
  load_balancer_type = "application"
  subnets            = var.public_subnet_ids
  security_groups    = [var.alb_sg_id]
  tags               = local.tags
}

resource "aws_lb_target_group" "app" {
  name        = "${var.project}-tg"
  port        = 8080
  protocol    = "HTTP"
  vpc_id      = var.vpc_id
  target_type = "ip" # Fargate-nél kötelező az ip target type

  health_check {
    path                = "/healthz"
    healthy_threshold   = 2
    unhealthy_threshold = 3
    interval            = 15
    timeout             = 5
    matcher             = "200"
  }

  tags = local.tags
}

resource "aws_lb_listener" "https" {
  load_balancer_arn = aws_lb.app.arn
  port              = 443
  protocol          = "HTTPS"
  ssl_policy        = "ELBSecurityPolicy-TLS13-1-2-2021-06"
  certificate_arn   = var.certificate_arn

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

Az ECS service privát subnetben

A service tartja a kívánt taskszámot, privát subnetben (nincs publikus IP), és a taskokat az ALB target grouphoz köti. A depends_on a listenerre azért kell, hogy a service ne induljon a forgalmi útvonal kész léte előtt.

hcl
resource "aws_ecs_service" "app" {
  name            = "${var.project}-svc"
  cluster         = aws_ecs_cluster.main.id
  task_definition = aws_ecs_task_definition.app.arn
  desired_count   = 2
  launch_type     = "FARGATE"

  network_configuration {
    subnets          = var.private_subnet_ids
    security_groups  = [var.app_sg_id]
    assign_public_ip = false
  }

  load_balancer {
    target_group_arn = aws_lb_target_group.app.arn
    container_name   = "app"
    container_port   = 8080
  }

  depends_on = [aws_lb_listener.https]
  tags       = local.tags
}

Autoscaling: skálázz a valós terhelésre

A cél-alapú (target tracking) autoscaling a legkényelmesebb: megadsz egy célt (pl. 60% átlagos CPU), és az AWS annyi taskot tart fenn, hogy ezt tartani tudja. Nincs küszöb-hackelés, nincs kézi be/kikapcsolás.

hcl
resource "aws_appautoscaling_target" "ecs" {
  max_capacity       = 10
  min_capacity       = 2
  resource_id        = "service/${aws_ecs_cluster.main.name}/${aws_ecs_service.app.name}"
  scalable_dimension = "ecs:service:DesiredCount"
  service_namespace  = "ecs"
}

resource "aws_appautoscaling_policy" "cpu" {
  name               = "${var.project}-cpu-target"
  policy_type        = "TargetTrackingScaling"
  resource_id        = aws_appautoscaling_target.ecs.resource_id
  scalable_dimension = aws_appautoscaling_target.ecs.scalable_dimension
  service_namespace  = aws_appautoscaling_target.ecs.service_namespace

  target_tracking_scaling_policy_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ECSServiceAverageCPUUtilization"
    }
    target_value       = 60
    scale_in_cooldown  = 120
    scale_out_cooldown = 60
  }
}

A deploy-életciklus

Egy új verzió kigördülése így néz ki: új image az ECR-be, új task definition revízió, a service pedig fokozatosan cseréli a taskokat, miközben az ALB health check őrködik, hogy csak egészséges task kapjon forgalmat.

Mit jelent ez neked?

Ez a setup — cluster, task definition, ALB target grouppal és health checkkel, privát ECS service és cél-alapú autoscaling — egy teljes, önmagát skálázó és gyógyító konténer-platform, EC2-host nélkül. A Fargate elveszi a legfájdalmasabb operatív terhet (host-patch, cluster-skálázás), te pedig arra koncentrálhatsz, ami számít: az alkalmazásra. A kulcsdöntések itt is láthatók a kódban — ip target type, health check path, autoscaling cél, circuit breaker —, és pont ezek azok, amiket kézzel a legkönnyebb elrontani. Terraformmal viszont egyszer állítod be jól, és utána reprodukálható marad.