Работа с AWS NLB и Terraform в Unix/Linux

Работа с AWS NLB и Terraform в Unix/Linux

Network Load Balancer (NLB) работает на уровне подключения (уровень 4), он маршрутизирует подключения к целевым объектам – инстансам Amazon EC2, контейнерам и IP-адресам – на основе данных IP-протокола. Network Load Balancer идеально подходит для балансировки нагрузки трафика TCP, он способен обрабатывать миллионы запросов в секунду при обеспечении сверхнизких задержек. Network Load Balancer оптимизирован для обработки резких и внезапных изменений трафика, при этом на каждую зону доступности используется один статический IP-адрес. Сервис интегрирован с другими востребованными сервисами AWS, такими как Auto Scaling, Amazon EC2 Container Service (ECS) и Amazon CloudFormation.

Балансировка нагрузки на основе подключений
Можно балансировать нагрузку трафика TCP путем маршрутизации подключений к целевым объектам – инстансам Amazon EC2, микросервисам и контейнерам, а также IP-адресам.

Высокая доступность
Network Load Balancer обеспечивает высокую доступность. Он принимает входящий трафик от клиентов и распределяет этот трафик по целевым объектам в пределах одной и той же зоны доступности. Балансировщик нагрузки также контролирует работоспособность своих зарегистрированных целевых объектов и гарантирует, что он направляет трафик только на работоспособные целевые объекты. Когда балансировщик нагрузки обнаруживает неработоспособный целевой объект, он прекращает маршрутизацию на этот целевой объект и перенаправляет трафик на оставшиеся работоспособные целевые объекты. Если в зоне доступности нет ни одного работоспособного целевого объекта, но при этом есть целевые объекты в других зонах доступности, Network Load Balancer выполнит автоматическую обработку отказа и перенаправит трафик на работоспособные целевые объекты в других зонах доступности.

Высокая пропускная способность
Network Load Balancer предназначен для обработки трафика по мере его роста и может балансировать нагрузку объемом в миллионы запросов в секунду. Он также способен обрабатывать резко и внезапно меняющийся трафик.

Низкая задержка
Network Load Balancer обеспечивает чрезвычайно низкую задержку и хорошо подходит для приложений, чувствительных к задержкам.

Сохранение IP-адреса источника
Network Load Balancer сохраняет IP-адрес источника на стороне клиента, позволяя серверу видеть IP-адрес клиента. Этот IP-адрес может затем использоваться приложениями для дальнейшей обработки.

Поддержка статического IP-адреса
Network Load Balancer автоматически предоставляет статический IP-адрес для зоны доступности (подсети), который может использоваться приложениями в качестве IP-адреса внешнего интерфейса балансировщика нагрузки.

Поддержка эластичных IP-адресов
Network Load Balancer также позволяет назначать эластичный IP-адрес для зоны доступности (подсети), тем самым предоставляя клиенту собственный фиксированный IP-адрес.

Проверки работоспособности
Network Load Balancer поддерживает проверку работоспособности целевых объектов как для сети, так и для приложений. Работоспособность на уровне сети определяется по общей реакции целевого объекта на обычный трафик. Если целевой объект не реагирует на новые соединения или реагирует слишком медленно, балансировщик нагрузки помечает целевой объект как недоступный. Проверки работоспособности на уровне приложений также могут использоваться для получения более подробной информации. Периодически опрашивая определенный URL-адрес данного целевого объекта, можно сделать обобщенный вывод о фактической работоспособности приложения. Быстрая диагностика и высокоэффективная отладка обеспечиваются полностью наглядным представлением проверок работоспособности. Причины выявленной в результате проверок неработоспособности также доступны как «коды причин» в API Network Load Balancer и через метрики Amazon CloudWatch, связанные с проверками работоспособности целевых объектов.

Обработка отказа DNS
Если в Network Load Balancer не зарегистрированы работоспособные целевые объекты или если узлы Network Load Balancer в данной зоне неработоспособны, Amazon Route 53 будет направлять трафик на узлы балансировки нагрузки в других зонах доступности.

Интеграция с Amazon Route 53
В случае отказа Network Load Balancer интеграция с Route 53 обеспечит удаление недоступных IP-адресов балансировщика нагрузки и перенаправит запросы на альтернативный балансировщик нагрузки в другом регионе.

Интеграция с сервисами AWS
Network Load Balancer интегрирован с другими сервисами AWS, такими как Auto Scaling, Amazon EC2 Container Service (ECS), AWS CloudFormation, AWS CodeDeploy и AWS Config.

Долговременные TCP-подключения
Network Load Balancer поддерживает долговременные TCP-подключения, которые идеально подходят для приложений типа WebSocket.

Централизованная поддержка API
Network Load Balancer использует тот же API, что и Application Load Balancer. Это позволяет работать с целевыми группами, проверками работоспособности и балансировать нагрузку между несколькими портами в одном инстансе Amazon EC2 для поддержки контейнерных приложений.

Надежный мониторинг и проверка
Amazon CloudWatch предоставляет метрики Network Load Balancer. CloudWatch предоставляет такие метрики, как Active Flow Count, Healthy Host Count, New Flow Count, Processed Bytes и многие другие. Network Load Balancer интегрирован с AWS CloudTrail. CloudTrail отслеживает вызовы API к Network Load Balancer.

Расширенное ведение журнала
Можно использовать возможность Flow Logs для записи всех запросов, отправленных на балансировщик нагрузки. Flow Logs регистрирует информацию об IP-трафике, поступающем на сетевые интерфейсы в VPC и из них. Данные журнала потока сохраняются с помощью Amazon CloudWatch Logs.

Изолирование по зонам
Network Load Balancer предназначен для приложений с архитектурой, размещенной в одной зоне. Если в зоне доступности что-то выходит из строя, происходит автоматическая обработка отказа и переход в другие работоспособные зоны доступности. Хотя мы рекомендуем клиентам для достижения высокой доступности настраивать балансировщик нагрузки и целевые объекты в нескольких зонах доступности, Network Load Balancer можно использовать в одной зоне доступности для поддержки архитектур, требующих изолированной работы в зоне.

Балансировка нагрузки с использованием IP-адресов как целевых объектов
Применять балансировку нагрузки можно для любого приложения, размещенного в AWS или локально, если использовать в качестве целей IP-адреса серверной части приложения. Это позволяет обеспечить балансировку нагрузки на сервер приложения, размещенный на любом IP-адресе и в любом интерфейсе инстанса. Каждое приложение, размещенное на том же инстансе, может относиться к своей группе безопасности и использовать один и тот же порт. Можно также использовать IP-адреса в качестве целей для балансировки нагрузки на приложения, размещенные локально (через подключение с помощью Direct Connect) и на инстансах EC2-Classic (с использованием ClassicLink). Возможность балансировки нагрузки между AWS и локальными ресурсами упрощает миграцию в облако, расширение ресурсов в облако или использование облака для обеспечения отказоустойчивости.

Установка terraform в Unix/Linux

Установка крайне примитивная и я описал как это можно сделать тут:

Установка terraform в Unix/Linux

Так же, в данной статье, я создал скрипт для автоматической установки данного ПО. Он был протестирован на CentOS 6/7, Debian 8 и на Mac OS X. Все работает должным образом!

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

$ terraform
Usage: terraform [--version] [--help] <command> [args]

The available commands for execution are listed below.
The most common, useful commands are shown first, followed by
less common or more advanced commands. If you're just getting
started with Terraform, stick with the common commands. For the
other commands, please read the help and docs before usage.

Common commands:
    apply              Builds or changes infrastructure
    console            Interactive console for Terraform interpolations
    destroy            Destroy Terraform-managed infrastructure
    env                Workspace management
    fmt                Rewrites config files to canonical format
    get                Download and install modules for the configuration
    graph              Create a visual graph of Terraform resources
    import             Import existing infrastructure into Terraform
    init               Initialize a Terraform working directory
    output             Read an output from a state file
    plan               Generate and show an execution plan
    providers          Prints a tree of the providers used in the configuration
    push               Upload this Terraform module to Atlas to run
    refresh            Update local state file against real resources
    show               Inspect Terraform state or plan
    taint              Manually mark a resource for recreation
    untaint            Manually unmark a resource as tainted
    validate           Validates the Terraform files
    version            Prints the Terraform version
    workspace          Workspace management

All other commands:
    debug              Debug output management (experimental)
    force-unlock       Manually unlock the terraform state
    state              Advanced state management

Приступим к использованию!

Работа с AWS NLB и Terraform в Unix/Linux

У меня есть папка terraform, в ней у меня будут лежать провайдеры с которыми я буду работать. Т.к в этом примере я буду использовать AWS, то создам данную папку и перейду в нее. Далее, в этой папке, стоит создать:

$ mkdir examples modules

В папке examples, я буду хранить так званые «плейбуки» для разварачивания различных служб, например — zabbix-server, grafana, web-серверы и так далее. В modules директории, я буду хранить все необходимые модули.

Начнем писать модуль, но для этой задачи, я создам папку:

$  mkdir modules/nlb

Переходим в нее:

$ cd modules/nlb

Открываем файл:

$ vim nlb.tf

В данный файл, вставляем:

#---------------------------------------------------
# Create AWS NLB
#---------------------------------------------------
resource "aws_lb" "lb" {
    #name_prefix        = "${var.name_prefix}-"
    name                = "${lower(var.name)}-nlb-${lower(var.environment)}"
    subnets             = ["${var.subnets}"]
    internal            = "${var.lb_internal}"

    enable_deletion_protection  = "${var.enable_deletion_protection}"
    load_balancer_type          = "${var.load_balancer_type}"
    idle_timeout                = "${var.idle_timeout}"
    ip_address_type             = "${var.ip_address_type}"

    timeouts {
        create  = "${var.timeouts_create}"
        update  = "${var.timeouts_update}"
        delete  = "${var.timeouts_delete}"
    }

    lifecycle {
        create_before_destroy = true
    }

    tags {
        Name            = "${lower(var.name)}-nlb-${lower(var.environment)}"
        Environment     = "${var.environment}"
        Orchestration   = "${var.orchestration}"
        Createdby       = "${var.createdby}"
    }
}
#---------------------------------------------------
# Create AWS LB target group
#---------------------------------------------------
resource "aws_lb_target_group" "lb_target_group" {
    name                 = "${lower(var.name)}-nlb-tg-${lower(var.environment)}"
    port                 = "${var.backend_port}"
    protocol             = "${upper(var.backend_protocol)}"
    vpc_id               = "${var.vpc_id}"
    target_type          = "${var.target_type}"
    deregistration_delay = "${var.deregistration_delay}"

    tags {
        Name            = "${lower(var.name)}-nlb-tg-${lower(var.environment)}"
        Environment     = "${var.environment}"
        Orchestration   = "${var.orchestration}"
        Createdby       = "${var.createdby}"
    }

    health_check {
        interval            = "${var.health_check_interval}"
        port                = "${var.health_check_port}"
        healthy_threshold   = "${var.health_check_healthy_threshold}"
        unhealthy_threshold = "${var.health_check_unhealthy_threshold}"
        protocol            = "${var.backend_protocol}"
    }
}
#---------------------------------------------------
# Create AWS LB listeners
#---------------------------------------------------
resource "aws_lb_listener" "frontend_tcp_80" {
    count               = "${trimspace(element(split(",", var.alb_protocols), 1)) == "TCP" ? 1 : 0}"

    load_balancer_arn   = "${aws_lb.lb.arn}"
    port                = "80"
    protocol            = "TCP"

    "default_action" {
        target_group_arn    = "${aws_lb_target_group.lb_target_group.arn}"
        type                = "forward"
    }

    depends_on = ["aws_lb.lb","aws_lb_target_group.lb_target_group"]
}
resource "aws_lb_listener" "frontend_tcp_443" {
    count               = "${trimspace(element(split(",", var.alb_protocols), 1)) == "TCP" ? 1 : 0}"

    load_balancer_arn   = "${aws_lb.lb.arn}"
    port                = "443"
    protocol            = "TCP"

    "default_action" {
        target_group_arn    = "${aws_lb_target_group.lb_target_group.arn}"
        type                = "forward"
    }

    depends_on = ["aws_lb.lb","aws_lb_target_group.lb_target_group"]
}
#---------------------------------------------------
# Create AWS LB target group attachment
#---------------------------------------------------
resource "aws_lb_target_group_attachment" "lb_target_group_attachment" {
    count               = "${length(var.target_ids) > 0 ? length(var.target_ids) : 0}"

    #availability_zone   = "all"
    target_id           = "${element(var.target_ids, count.index)}"
    port                = "${var.backend_port}"
    target_group_arn    = "${aws_lb_target_group.lb_target_group.arn}"

    depends_on = ["aws_lb_target_group.lb_target_group"]
}

Открываем файл:

$ vim variables.tf

И прописываем:

#-----------------------------------------------------------
# Global or/and default variables
#-----------------------------------------------------------
variable "name" {
  description = "Name to be used on all resources as prefix"
  default     = "TEST-NLB"
}

variable "region" {
  description = "The region where to deploy this code (e.g. us-east-1)."
  default     = "us-east-1"
}

variable "environment" {
    description = "Environment for service"
    default     = "STAGE"
}

variable "orchestration" {
    description = "Type of orchestration"
    default     = "Terraform"
}

variable "createdby" {
    description = "Created by"
    default     = "Vitaliy Natarov"
}

variable "subnets" {
    description = "A list of subnet IDs to attach to the NLB"
    type        = "list"
    default     = []
}

variable "lb_internal" {
    description = "If true, NLB will be an internal NLB"
    default     = false
}

variable "name_prefix" {
    description = "Creates a unique name beginning with the specified prefix. Conflicts with name"
    default     = "nlb"
}

variable "enable_deletion_protection" {
    description = "If true, deletion of the load balancer will be disabled via the AWS API. This will prevent Terraform from deleting the load balancer. Defaults to false."
    default     = false
}

variable "load_balancer_type" {
    description = "The type of load balancer to create. Possible values are application or network. The default value is application."
    default     = "network"
}

variable "idle_timeout" {
    description = "The time in seconds that the connection is allowed to be idle. Default: 60."
    default     = "60"
}

variable "ip_address_type" {
    description = "The type of IP addresses used by the subnets for your load balancer. The possible values are ipv4 and dualstack"
    default     = "ipv4"
}

variable "timeouts_create" {
    description = "Used for Creating LB. Default = 10mins"
    default     = "10m"
}

variable "timeouts_update" {
    description = "Used for LB modifications. Default = 10mins"
    default     = "10m"
}

variable "timeouts_delete" {
    description = "Used for LB destroying LB. Default = 10mins"
    default     = "10m"
}

variable "vpc_id" {
    description = "Set VPC ID for ?LB"
}

variable "alb_protocols" {
    description = "A protocol the ALB accepts. (e.g.: TCP)"
    default     = "TCP"
}

variable "target_type" {
    description = "The type of target that you must specify when registering targets with this target group. The possible values are instance (targets are specified by instance ID) or ip (targets are specified by IP address). The default is instance. Note that you can't specify targets for a target group using both instance IDs and IP addresses. If the target type is ip, specify IP addresses from the subnets of the virtual private cloud (VPC) for the target group, the RFC 1918 range (10.0.0.0/8, 172.16.0.0/12, and 192.168.0.0/16), and the RFC 6598 range (100.64.0.0/10). You can't specify publicly routable IP addresses"
    default     = "instance"
}

variable "deregistration_delay" {
    description = "The amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused. The range is 0-3600 seconds. The default value is 300 seconds."
    default     = "300"
}

variable "backend_port" {
    description = "The port the service on the EC2 instances listen on."
    default     = 80
}

variable "backend_protocol" {
    description = "The protocol the backend service speaks. Options: HTTP, HTTPS, TCP, SSL (secure tcp)."
    default     = "HTTP"
}

variable "target_ids" {
    description = "The ID of the target. This is the Instance ID for an instance, or the container ID for an ECS container. If the target type is ip, specify an IP address."
    type        = "list"
    #default     = ""
}

variable "certificate_arn" {
    description = "The ARN of the SSL Certificate. e.g. 'arn:aws:iam::XXXXXXXXXXX:server-certificate/ProdServerCert'"
    default     = ""
}

variable "health_check_healthy_threshold" {
    description = "Number of consecutive positive health checks before a backend instance is considered healthy."
    default     = 3
}

variable "health_check_interval" {
    description = "Interval in seconds on which the health check against backend hosts is tried."
    default     = 10
}

variable "health_check_port" {
    description = "The port used by the health check if different from the traffic-port."
    default     = "traffic-port"
}

variable "health_check_unhealthy_threshold" {
    description = "Number of consecutive positive health checks before a backend instance is considered unhealthy."
    default     = 3
}

Собственно в этом файле храняться все переменные. Спасибо кэп!

Открываем последний файл:

$ vim outputs.tf

И в него вставить нужно следующие строки:

output "lb_name" {
    description = ""
    value       = "${aws_lb.lb.name}"
}

output "lb_arn" {
    description = "ARN of the lb itself. Useful for debug output, for example when attaching a WAF."
    value       = "${aws_lb.lb.arn}"
}

output "lb_arn_suffix" {
    description = "ARN suffix of our lb - can be used with CloudWatch"
    value       = "${aws_lb.lb.arn_suffix}"
}

output "lb_dns_name" {
    description = "The DNS name of the lb presumably to be used with a friendlier CNAME."
    value       = "${aws_lb.lb.dns_name}"
}

output "lb_id" {
    description = "The ID of the lb we created."
    value       = "${aws_lb.lb.id}"
}

output "lb_zone_id" {
    description = "The zone_id of the lb to assist with creating DNS records."
    value       = "${aws_lb.lb.zone_id}"
}

output "lb_listener_frontend_tcp_80_arn" {
    description = "The ARN of the HTTPS lb Listener we created."
    value       = "${element(concat(aws_lb_listener.frontend_tcp_80.*.arn, list("")), 0)}"
}

output "lb_listener_frontend_tcp_443_arn" {
    description = "The ARN of the HTTP lb Listener we created."
    value       = "${element(concat(aws_lb_listener.frontend_tcp_443.*.arn, list("")), 0)}"
}

output "lb_listener_frontend_tcp_80_id" {
    description = "The ID of the lb Listener we created."
    value       = "${element(concat(aws_lb_listener.frontend_tcp_80.*.id, list("")), 0)}"
}

output "lb_listener_frontend_tcp_443_id" {
    description = "The ID of the lb Listener we created."
    value       = "${element(concat(aws_lb_listener.frontend_tcp_443.*.id, list("")), 0)}"
}

output "target_group_arn" {
    description = "ARN of the target group. Useful for passing to your Auto Scaling group module."
    value       = "${aws_lb_target_group.lb_target_group.arn}"
}

 

Переходим теперь в папку aws/examples и создадим еще одну папку для проверки написанного чуда:

$ mkdir nlb && cd $_

Внутри созданной папки открываем файл:

$ vim main.tf

И вставим в него следующий код:

# MAINTAINER Vitaliy Natarov "vitaliy.natarov@yahoo.com"
#
terraform {
  required_version = "> 0.9.0"
}
provider "aws" {
    region                  = "us-east-1"
    shared_credentials_file = "${pathexpand("~/.aws/credentials")}"
    profile                 = "default"
}
module "iam" {
    source                          = "../../modules/iam"
    name                            = "My-Security"
    region                          = "us-east-1"
    environment                     = "PROD"

    aws_iam_role-principals         = [
        "ec2.amazonaws.com",
    ]
    aws_iam_policy-actions           = [
        "cloudwatch:GetMetricStatistics",
        "logs:DescribeLogStreams",
        "logs:GetLogEvents",
        "elasticache:Describe*",
        "rds:Describe*",
        "rds:ListTagsForResource",
        "ec2:DescribeAccountAttributes",
        "ec2:DescribeAvailabilityZones",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeVpcs",
        "ec2:Owner",
    ]
}
module "vpc" {
    source                              = "../../modules/vpc"
    name                                = "My"
    environment                         = "PROD"
    # VPC
    instance_tenancy                    = "default"
    enable_dns_support                  = "true"
    enable_dns_hostnames                = "true"
    assign_generated_ipv6_cidr_block    = "false"
    enable_classiclink                  = "false"
    vpc_cidr                            = "172.31.0.0/16"
    private_subnet_cidrs                = ["172.31.32.0/20"]
    public_subnet_cidrs                 = ["172.31.0.0/20"]
    availability_zones                  = ["us-east-1b"]
    enable_all_egress_ports             = "true"
    allowed_ports                       = ["8080", "3306", "443", "80"]

    map_public_ip_on_launch             = "true"

    #Internet-GateWay
    enable_internet_gateway             = "true"
    #NAT
    enable_nat_gateway                  = "false"
    single_nat_gateway                  = "true"
    #VPN
    enable_vpn_gateway                  = "false"
    #DHCP
    enable_dhcp_options                 = "false"
    # EIP
    enable_eip                          = "false"
}
module "ec2" {
    source                              = "../../modules/ec2"
    name                                = "TEST-Machine"
    region                              = "us-east-1"
    environment                         = "PROD"
    number_of_instances                 = 2
    ec2_instance_type                   = "t2.micro"
    enable_associate_public_ip_address  = "true"
    disk_size                           = "8"
    tenancy                             = "${module.vpc.instance_tenancy}"
    iam_instance_profile                = "${module.iam.instance_profile_id}"
    subnet_id                           = "${element(module.vpc.vpc-publicsubnet-ids, 0)}"
    #subnet_id                           = "${element(module.vpc.vpc-privatesubnet-ids, 0)}"
    #subnet_id                           = ["${element(module.vpc.vpc-privatesubnet-ids)}"]
    vpc_security_group_ids              = ["${module.vpc.security_group_id}"]

    monitoring                          = "true"
}
module "nlb" {
    source                  = "../../modules/nlb"
    name                    = "Load-Balancer"
    region                  = "us-east-1"
    environment             = "PROD"

    subnets                     = ["${module.vpc.vpc-privatesubnet-ids}"]
    vpc_id                      = "${module.vpc.vpc_id}"
    enable_deletion_protection  = false

    backend_protocol    = "TCP"
    alb_protocols       = "TCP"

    target_ids          = ["${module.ec2.instance_ids}"]
}

Еще полезности:

Работа с AWS IAM и Terraform в Unix/Linux

Работа с AWS VPC и Terraform в Unix/Linux

Работа с AWS S3 и Terraform в Unix/Linux

Работа с AWS EC2 и Terraform в Unix/Linux

Работа с AWS ASG(auto scaling group) и Terraform в Unix/Linux

Работа с AWS ELB и Terraform в Unix/Linux

Работа с AWS Route53 и Terraform в Unix/Linux

Работа с AWS RDS и Terraform в Unix/Linux

Работа с AWS SNS и Terraform в Unix/Linux

Работа с AWS SQS и Terraform в Unix/Linux

Работа с AWS KMS и Terraform в Unix/Linux

Все уже написано и готово к использованию. Ну что, начнем тестирование. В папке с вашим плейбуком, выполняем:

$ terraform init

Этим действием я инициализирую проект. Затем, подтягиваю модуль:

$ terraform get

PS: Для обновление изменений в самом модуле, можно выполнять:

$ terraform get -update

Проверим валидацию:

$ terraform validate

Запускем прогон:

$ terraform plan

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

$ terraform apply

Как видно с вывода, — все прошло гладко! Чтобы удалить созданное творение, можно выполнить:

$ terraform destroy

Весь материал аплоаджу в github аккаунт для удобства использования:

$ git clone https://github.com/SebastianUA/terraform.git

Вот и все на этом. Данная статья «Работа с AWS NLB и Terraform в Unix/Linux» завершена.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *