Terraform: инфраструктура на уровне кода — страница 16 из 65

Синтаксис использования источников данных очень похож на синтаксис ресурса:

data "_" "" {

   [CONFIG ...]

}

PROVIDER — имя провайдера (например, aws), TYPE — тип источника данных, который вы хотите использовать (скажем, vpc), NAME — идентификатор, с помощью которого можно ссылаться на этот источник данных в коде Terraform, а CONFIG состоит из одного или нескольких аргументов, предусмотренных специально для этого источника. Вот как можно воспользоваться источником данных aws_vpc, чтобы запросить информацию о вашем облаке VPC по умолчанию (справочную информацию ищите во врезке «Замечание о виртуальных частных облаках по умолчанию» на с. 63):

data "aws_vpc" "default" {

  default = true

}

Стоит отметить, что в случае с источниками данных в качестве аргументов обычно передаются фильтры, которые указывают на то, какую информацию вы ищете. Источнику данных aws_vpc нужно указать лишь один фильтр, default=true, который инициирует в вашей учетной записи AWS поиск VPC по умолчанию.

Чтобы получить данные из источника, нужно использовать следующий синтаксис доступа к атрибутам:

data._..

Например, чтобы получить идентификатор VPC из источника данных aws_vpc, надо написать следующее:

data.aws_vpc.default.id

Вы можете добавить к этому еще один источник данных, aws_subnet_ids, чтобы найти подсети внутри этого облака VPC:

data "aws_subnet_ids" "default" {

  vpc_id = data.aws_vpc.default.id

}

Вы можете извлечь идентификаторы подсетей из источника aws_subnet_ids и воспользоваться аргументом с довольно странным названием vpc_zone_identifier, чтобы ваша группа ASG использовала эти подсети:

resource "aws_autoscaling_group" "example" {

  launch_configuration = aws_launch_configuration.example.name

  vpc_zone_identifier  = data.aws_subnet_ids.default.ids

  min_size = 2

  max_size = 10

  tag {

    key                 = "Name"

    value               = "terraform-asg-example"

    propagate_at_launch = true

  }

}


Развертывание балансировщика нагрузки

Вы уже научились развертывать группу ASG, но при этом возникает небольшая проблема: у вас есть несколько серверов с отдельными IP-адресами, однако конечным пользователям обычно нужна единая точка входа. Одно из решений заключается в развертывании балансировщика нагрузки, который будет распределять трафик между вашими серверами и предоставлять всем вашим пользователям собственный IP-адрес (или, если быть точным, доменное имя). Создание балансировщика нагрузки с высокими доступностью и масштабируемостью требует много усилий. И опять вы можете положиться на AWS, воспользовавшись сервисом Elastic Load Balancer (ELB) от Amazon (рис. 2.10).

Рис. 2.10. Использование Amazon ELB для распределения трафика по группе автомасштабирования

AWS предлагает три типа балансировщиков нагрузки.

Application Load Balancer (ALB). Лучше всего подходит для балансировки трафика по протоколам HTTP и HTTPS. Работает на прикладном уровне (уровень 7) сетевой модели OSI.

• Network Load Balancer (NLB). Лучше всего подходит для балансировки трафика по протоколам TCP, UDP и TLS. Если сравнивать с ALB, может быстрее масштабироваться в обе стороны в зависимости от нагрузки (NLB рассчитан на масштабирование до десятков миллионов запросов в секунду). Работает на транспортном уровне (уровень 4) сетевой модели OSI.

Classic Load Balancer (CLB). Это «старый» балансировщик нагрузки, который появился раньше, чем ALB и NLB. Он способен работать с трафиком по протоколам HTTP, HTTPS, TCP и TLS, но ограничен в возможностях по сравнению со своими «преемниками». Работает как на прикладном, так и на транспортном уровне (L7 и L4) сетевой модели OSI.

Современные приложения должны использовать в основном ALB или NLB. Поскольку наш простой пример с веб-сервером является HTTP-приложением без серьезных требований к производительности, нам лучше всего подойдет ALB.

Как показано на рис. 2.11, ALB состоит из нескольких частей.

Прослушиватель (слушатель). Прослушивает определенные порты (например, 80) и протокол (скажем, HTTP).

• Правило прослушивателя. Берет запросы, направленные к прослушивателю, и передает те из них, которые соответствуют определенным путям (например, /foo или /bar) или сетевым именам (вроде foo.example.com или bar.example.com),  заданным целевым группам.

Целевые группы. Один или несколько серверов, которые принимают запросы от балансировщика нагрузки. Целевая группа также следит за работоспособностью этих серверов и шлет запросы только «здоровым» узлам.

Рис. 2.11. Обзор Application Load Balancer (ALB)

Первым делом нужно создать сам балансировщик ALB, используя ресурс aws_lb:

resource "aws_lb" "example" {

  name               = "terraform-asg-example"

  load_balancer_type = "application"

  subnets            = data.aws_subnet_ids.default.ids

}

Обратите внимание, что параметр subnets настраивает балансировщик нагрузки для использования всех подсетей в вашем облаке VPC по умолчанию с помощью источника данных aws_subnet_ids33. Балансировщики нагрузки в AWS состоят не из одного, а сразу из нескольких серверов, которые могут работать в разных подсетях (и, следовательно, в отдельных вычислительных центрах). AWS автоматически масштабирует количество балансировщиков в зависимости от трафика и отрабатывает отказ, если один из этих серверов выйдет из строя. Таким образом, вы получаете как масштабируемость, так и высокую доступность.

Следующим шагом будет определение прослушивателя для этого ALB с помощью ресурса aws_lb_listener:

resource "aws_lb_listener" "http" {

  load_balancer_arn = aws_lb.example.arn

  port              = 80

  protocol          = "HTTP"

  # По умолчанию возвращает простую страницу с кодом 404

  default_action {

    type = "fixed-response"

    fixed_response {

      content_type = "text/plain"

      message_body = "404: page not found"

      status_code  = 404

    }

  }

}

Этот прослушиватель настраивает ALB для прослушивания стандартного HTTP-порта (80), использования HTTP-протокола и возвращения простой страницы с кодом 404 в случае, если запрос не соответствует ни одному из правил прослушивания.

Стоит отметить, что по умолчанию для всех ресурсов AWS, включая ALB, закрыт входящий и исходящий трафик, поэтому нужно создать новую группу безопасности специально для балансировщика нагрузки. Эта группа должна разрешать входящие запросы на порт 80, чтобы вы могли обращаться к ALB по HTTP, а также исходящие запросы на всех портах, чтобы балансировщик мог проверять работоспособность:

resource "aws_security_group" "alb" {

  name = "terraform-example-alb"

  # Разрешаем все входящие HTTP-запросы

  ingress {

    from_port   = 80

    to_port     = 80

    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"]

  }

}

Нужно сделать так, чтобы ресурс aws_lb использовал указанную группу безопасности. Для этого установите аргумент security_groups:

resource "aws_lb" "example" {

  name               = "terraform-asg-example"

  load_balancer_type = "application"

  subnets            = data.aws_subnet_ids.default.ids

  security_groups    = [aws_security_group.alb.id]

}

Затем необходимо создать целевую группу для ASG, используя ресурс aws_lb_target_group:

resource "aws_lb_target_group" "asg" {

  name     = "terraform-asg-example"

  port     = var.server_port

  protocol = "HTTP"

  vpc_id   = data.aws_vpc.default.id

  health_check {

    path                = "/"

    protocol            = "HTTP"

    matcher             = "200"

    interval            = 15

    timeout             = 3

    healthy_threshold   = 2

    unhealthy_threshold = 2

  }

}

Обратите внимание на то, что данная целевая группа будет проверять работоспособность ваших серверов, отправляя им периодически HTTP-запросы; сервер считается работоспособным, только если его ответ совпадает с заданным сопоставителем (например, вы можете сделать так, чтобы сопоставитель ожидал ответа 200OK). Если сервер не отвечает (возможно, из-за перебоев в работе или перегрузки), он будет помечен как неработоспособный и целевая группа автоматически прекратит отправлять ему трафик, чтобы минимизировать нарушение обслуживания ваших пользователей.

Но откуда целевая группа знает, каким серверам EC2 следует отправлять запросы? Вы могли бы прописать в ней статический список серверов ресурсом aws_lb_target_group_attachment, однако при работе с ASG серверы могут запускаться и удаляться в любой момент, поэтому такой подход не годится. Вместо этого можно воспользоваться первоклассной интеграцией между ASG и ALB. Вернитесь к ресурсу aws_autoscaling_group и сделайте так, чтобы его аргумент target_group_arns указывал на новую целевую группу:

resource "aws_autoscaling_group" "example" {

  launch_configuration = aws_launch_configuration.example.name

  vpc_zone_identifier  = data.aws_subnet_ids.default.ids

  target_group_arns = [aws_lb_target_group.asg.arn]

  health_check_type = "ELB"

  min_size = 2

  max_size = 10

  tag {

    key                 = "Name"

    value               = "terraform-asg-example"

    propagate_at_launch = true

  }

}

Вы также должны поменять значение health_check_type на "ELB". Значение по умолчанию, "EC2", подразумевает минимальную проверку работоспособности, которая считает сервер неисправным, только если гипервизор AWS утверждает, что ВМ совсем не работает или является недоступной. Значение "ELB" более надежно, поскольку вынуждает ASG проверять работоспособность целевой группы. К тому же серверы автоматически заменяются, если целевая группа объявляет их неисправными. Таким образом, серверы подлежат замене не только в случае полного отказа, но и когда они, к примеру, перестают обслуживать запросы из-за нехватки памяти или остановки критически важного процесса.