github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/examples/terraform-redeploy-example/main.tf (about)

     1  # ---------------------------------------------------------------------------------------------------------------------
     2  # PIN TERRAFORM VERSION TO >= 0.12
     3  # The examples have been upgraded to 0.12 syntax
     4  # ---------------------------------------------------------------------------------------------------------------------
     5  
     6  terraform {
     7    # This module is now only being tested with Terraform 0.13.x. However, to make upgrading easier, we are setting
     8    # 0.12.26 as the minimum version, as that version added support for required_providers with source URLs, making it
     9    # forwards compatible with 0.13.x code.
    10    required_version = ">= 0.12.26"
    11  }
    12  
    13  # ---------------------------------------------------------------------------------------------------------------------
    14  # DEPLOY AN AUTO SCALING GROUP (ASG) WITH AN APPLICATION LOAD BALANCER (ALB) IN FRONT OF IT
    15  # ---------------------------------------------------------------------------------------------------------------------
    16  
    17  provider "aws" {
    18    region = var.aws_region
    19  }
    20  
    21  # ---------------------------------------------------------------------------------------------------------------------
    22  # CREATE THE ASG
    23  # ---------------------------------------------------------------------------------------------------------------------
    24  
    25  resource "aws_autoscaling_group" "web_servers" {
    26    # Note that we intentionally depend on the Launch Configuration name so that creating a new Launch Configuration
    27    # (e.g. to deploy a new AMI) creates a new Auto Scaling Group. This will allow for rolling deployments.
    28    name = aws_launch_configuration.web_servers.name
    29  
    30    launch_configuration = aws_launch_configuration.web_servers.name
    31  
    32    min_size         = 3
    33    max_size         = 3
    34    desired_capacity = 3
    35    min_elb_capacity = 3
    36  
    37    # Deploy into all the subnets (and therefore AZs) available
    38    vpc_zone_identifier = data.aws_subnet_ids.default.ids
    39  
    40    # Automatically register this ASG's Instances in the ALB and use the ALB's health check to determine when an Instance
    41    # needs to be replaced
    42    health_check_type = "ELB"
    43  
    44    target_group_arns = [aws_alb_target_group.web_servers.arn]
    45  
    46    tag {
    47      key                 = "Name"
    48      value               = var.instance_name
    49      propagate_at_launch = true
    50    }
    51  
    52    # To support rolling deployments, we tell Terraform to create a new ASG before deleting the old one. Note: as
    53    # soon as you set create_before_destroy = true in one resource, you must also set it in every resource that it
    54    # depends on, or you'll get an error about cyclic dependencies (especially when removing resources).
    55    lifecycle {
    56      create_before_destroy = true
    57    }
    58  
    59    # This needs to be here to ensure the ALB has at least one listener rule before the ASG is created. Otherwise, on the
    60    # very first deployment, the ALB won't bother doing any health checks, which means min_elb_capacity will not be
    61    # achieved, and the whole deployment will fail.
    62    depends_on = [aws_alb_listener.http]
    63  }
    64  
    65  # ---------------------------------------------------------------------------------------------------------------------
    66  # CREATE THE LAUNCH CONFIGURATION
    67  # This is a "template" that defines the configuration for each EC2 Instance in the ASG
    68  # ---------------------------------------------------------------------------------------------------------------------
    69  
    70  resource "aws_launch_configuration" "web_servers" {
    71    image_id        = data.aws_ami.ubuntu.id
    72    instance_type   = var.instance_type
    73    security_groups = [aws_security_group.web_server.id]
    74    user_data       = data.template_file.user_data.rendered
    75    key_name        = var.key_pair_name
    76  
    77    # When used with an aws_autoscaling_group resource, the aws_launch_configuration must set create_before_destroy to
    78    # true. Note: as soon as you set create_before_destroy = true in one resource, you must also set it in every resource
    79    # that it depends on, or you'll get an error about cyclic dependencies (especially when removing resources).
    80    lifecycle {
    81      create_before_destroy = true
    82    }
    83  }
    84  
    85  # ---------------------------------------------------------------------------------------------------------------------
    86  # CREATE THE USER DATA SCRIPT THAT WILL RUN DURING BOOT ON THE EC2 INSTANCE
    87  # ---------------------------------------------------------------------------------------------------------------------
    88  
    89  data "template_file" "user_data" {
    90    template = file("${path.module}/user-data/user-data.sh")
    91  
    92    vars = {
    93      instance_text = var.instance_text
    94      instance_port = var.instance_port
    95    }
    96  }
    97  
    98  # ---------------------------------------------------------------------------------------------------------------------
    99  # FOR THIS EXAMPLE, WE JUST RUN A PLAIN UBUNTU 16.04 AMI
   100  # ---------------------------------------------------------------------------------------------------------------------
   101  
   102  data "aws_ami" "ubuntu" {
   103    most_recent = true
   104    owners      = ["099720109477"] # Canonical
   105  
   106    filter {
   107      name   = "virtualization-type"
   108      values = ["hvm"]
   109    }
   110  
   111    filter {
   112      name   = "architecture"
   113      values = ["x86_64"]
   114    }
   115  
   116    filter {
   117      name   = "image-type"
   118      values = ["machine"]
   119    }
   120  
   121    filter {
   122      name   = "name"
   123      values = ["ubuntu/images/hvm-ssd/ubuntu-xenial-16.04-amd64-server-*"]
   124    }
   125  }
   126  
   127  # ---------------------------------------------------------------------------------------------------------------------
   128  # CREATE A SECURITY GROUP TO CONTROL WHAT TRAFFIC CAN GO IN AND OUT OF THE EC2 INSTANCE
   129  # ---------------------------------------------------------------------------------------------------------------------
   130  
   131  resource "aws_security_group" "web_server" {
   132    name   = var.instance_name
   133    vpc_id = data.aws_vpc.default.id
   134  
   135    # This is here because aws_launch_configuration.web_servers sets create_before_destroy to true and depends on this
   136    # resource
   137    lifecycle {
   138      create_before_destroy = true
   139    }
   140  }
   141  
   142  resource "aws_security_group_rule" "web_server_allow_http_inbound" {
   143    type              = "ingress"
   144    from_port         = var.instance_port
   145    to_port           = var.instance_port
   146    protocol          = "tcp"
   147    security_group_id = aws_security_group.web_server.id
   148    cidr_blocks       = ["0.0.0.0/0"]
   149  }
   150  
   151  resource "aws_security_group_rule" "web_server_allow_ssh_inbound" {
   152    type              = "ingress"
   153    from_port         = var.ssh_port
   154    to_port           = var.ssh_port
   155    protocol          = "tcp"
   156    security_group_id = aws_security_group.web_server.id
   157    cidr_blocks       = ["0.0.0.0/0"]
   158  }
   159  
   160  resource "aws_security_group_rule" "web_server_allow_all_outbound" {
   161    type              = "egress"
   162    from_port         = 0
   163    to_port           = 0
   164    protocol          = "-1"
   165    security_group_id = aws_security_group.web_server.id
   166    cidr_blocks       = ["0.0.0.0/0"]
   167  }
   168  
   169  # ---------------------------------------------------------------------------------------------------------------------
   170  # CREATE AN ALB TO DISTRIBUTE TRAFFIC ACROSS THE ASG
   171  # ---------------------------------------------------------------------------------------------------------------------
   172  
   173  resource "aws_alb" "web_servers" {
   174    name            = var.instance_name
   175    security_groups = [aws_security_group.alb.id]
   176    subnets         = data.aws_subnet_ids.default.ids
   177  
   178    # This is here because aws_alb_listener.http depends on this resource and sets create_before_destroy to true
   179    lifecycle {
   180      create_before_destroy = true
   181    }
   182  }
   183  
   184  # ---------------------------------------------------------------------------------------------------------------------
   185  # CREATE AN ALB LISTENER FOR HTTP REQUESTS
   186  # ---------------------------------------------------------------------------------------------------------------------
   187  
   188  resource "aws_alb_listener" "http" {
   189    load_balancer_arn = aws_alb.web_servers.arn
   190    port              = var.alb_port
   191    protocol          = "HTTP"
   192  
   193    default_action {
   194      type             = "forward"
   195      target_group_arn = aws_alb_target_group.web_servers.arn
   196    }
   197  
   198    # This is here because aws_autoscaling_group.web_servers depends on this resource and sets create_before_destroy
   199    # to true
   200    lifecycle {
   201      create_before_destroy = true
   202    }
   203  }
   204  
   205  # ---------------------------------------------------------------------------------------------------------------------
   206  # CREATE AN ALB TARGET GROUP FOR THE ASG
   207  # This target group will perform health checks on the web servers in the ASG
   208  # ---------------------------------------------------------------------------------------------------------------------
   209  
   210  resource "aws_alb_target_group" "web_servers" {
   211    depends_on = [aws_alb.web_servers]
   212  
   213    name     = var.instance_name
   214    port     = var.instance_port
   215    protocol = "HTTP"
   216    vpc_id   = data.aws_vpc.default.id
   217  
   218    # Give existing connections 10 seconds to complete before deregistering an instance. The default delay is 300 seconds
   219    # (5 minutes), which significantly slows down redeploys. In theory, the ALB should deregister the instance as long as
   220    # there are no open connections; in practice, it waits the full five minutes every time. If your requests are
   221    # generally processed quickly, set this to something lower (such as 10 seconds) to keep redeploys fast.
   222    deregistration_delay = 10
   223  
   224    health_check {
   225      path                = "/"
   226      interval            = 15
   227      healthy_threshold   = 2
   228      unhealthy_threshold = 2
   229      timeout             = 5
   230    }
   231  
   232    # This is here because aws_autoscaling_group.web_servers depends on this resource and sets create_before_destroy
   233    # to true
   234    lifecycle {
   235      create_before_destroy = true
   236    }
   237  }
   238  
   239  # ---------------------------------------------------------------------------------------------------------------------
   240  # CREATE AN ALB LISTENER RULE TO SEND ALL REQUESTS TO THE ASG
   241  # ---------------------------------------------------------------------------------------------------------------------
   242  
   243  resource "aws_alb_listener_rule" "send_all_to_web_servers" {
   244    listener_arn = aws_alb_listener.http.arn
   245    priority     = 100
   246  
   247    action {
   248      type             = "forward"
   249      target_group_arn = aws_alb_target_group.web_servers.arn
   250    }
   251  
   252    condition {
   253      path_pattern {
   254        values = ["*"]
   255      }
   256    }
   257  }
   258  
   259  # ---------------------------------------------------------------------------------------------------------------------
   260  # CREATE A SECURITY GROUP TO CONTROL WHAT TRAFFIC CAN GO IN AND OUT OF THE ALB
   261  # ---------------------------------------------------------------------------------------------------------------------
   262  
   263  resource "aws_security_group" "alb" {
   264    name   = "${var.instance_name}-alb"
   265    vpc_id = data.aws_vpc.default.id
   266  }
   267  
   268  resource "aws_security_group_rule" "alb_allow_http_inbound" {
   269    type              = "ingress"
   270    from_port         = var.alb_port
   271    to_port           = var.alb_port
   272    protocol          = "tcp"
   273    security_group_id = aws_security_group.alb.id
   274    cidr_blocks       = ["0.0.0.0/0"]
   275  }
   276  
   277  # We need to allow outbound connections from the ALB so it can perform health checks
   278  resource "aws_security_group_rule" "allow_all_outbound" {
   279    type              = "egress"
   280    from_port         = 0
   281    to_port           = 0
   282    protocol          = "-1"
   283    security_group_id = aws_security_group.alb.id
   284    cidr_blocks       = ["0.0.0.0/0"]
   285  }
   286  
   287  # ---------------------------------------------------------------------------------------------------------------------
   288  # DEPLOY INTO THE DEFAULT VPC AND SUBNETS
   289  # To keep this example simple, we are deploying into the Default VPC and its subnets. In real-world usage, you should
   290  # deploy into a custom VPC and private subnets.
   291  # ---------------------------------------------------------------------------------------------------------------------
   292  
   293  data "aws_vpc" "default" {
   294    default = true
   295  }
   296  
   297  data "aws_subnet_ids" "default" {
   298    vpc_id = data.aws_vpc.default.id
   299  }
   300