Q:

The tool to deploy per customer EC2 instance

I need to deploy one EC2 instance for each customer. I have hundreds of customer and increasing. 
So far, I found Terraform supports count property to provision exact number of instance I need. To do that, I maintain a list of customer, create number of instance to match the length of the list. For example:

customer_a
customer_b
customer_c

Terraform script looks like this:
resource aws_instance x {
  count = length(var.customers)

  #...
}

It works initially. However, unexpected behaviour happened when I tried to remove customer_b from the list, as a result, customer_c's instance was destroyed and customer_b's instance properties were replaced with customer_c's. What I need is to keep customer_c's instance untouched and destroy customer_b's instance with related resources.
I am not sure if there is better way to do that using Terraform or if there is any other more suitable tools for this use case. Please help.

A:

Using Terraform's for_each (available beginning in v0.12.x) can actually accomplish this.
This creates 3 AWS instances: 
variable "hosts" {
  default = {
    "one" = {
      "name"    = "one",
      "machine" = "t2.micro",
      "ami"     = "ami-009d6802948d06e52",
      "subnet"  = "subnet-002df68a36948517d"
    },
    "two" = {
      "name"    = "two",
      "machine" = "t3.micro",
      "ami"     = "ami-009d6802948d06e52",
      "subnet"  = "subnet-01c13b00a5531828e"
    },
    "three" = {
      "name"    = "three",
      "machine" = "t2.nano",
      "ami"     = "ami-009d6802948d06e52",
      "subnet"  = "subnet-0166523e6bd98ebd8"
    }
  }
}

resource "aws_instance" "instances" {
  for_each      = var.hosts
  ami           = each.value.ami
  instance_type = each.value.machine
  subnet_id     = each.value.subnet
  tags = {
    Name = each.value.name
  }
}

When I comment out two, I get the Terraform plan below
variable "hosts" {
  default = {
    "one" = {
      "name"    = "one",
      "machine" = "t2.micro",
      "ami"     = "ami-009d6802948d06e52",
      "subnet"  = "subnet-002df68a36948517d"
    },
    # "two" = {
    #   "name"    = "two",
    #   "machine" = "t3.micro",
    #   "ami"     = "ami-009d6802948d06e52",
    #   "subnet"  = "subnet-01c13b00a5531828e"
    # },
    "three" = {
      "name"    = "three",
      "machine" = "t2.nano",
      "ami"     = "ami-009d6802948d06e52",
      "subnet"  = "subnet-0166523e6bd98ebd8"
    }
  }
}

Terraform will perform the following actions:

  # aws_instance.instances["two"] will be destroyed
  - resource "aws_instance" "instances" {
      - ami                          = "ami-009d6802948d06e52" -> null
      - arn                          = "arn:aws:ec2:us-east-1:XXXXXXXX:instance/i-03a8285fc49f48a69" -> null
      - associate_public_ip_address  = true -> null
      - availability_zone            = "us-east-1b" -> null
      - cpu_core_count               = 1 -> null
      - cpu_threads_per_core         = 2 -> null
      - disable_api_termination      = false -> null
      - ebs_optimized                = false -> null
      - get_password_data            = false -> null
      - id                           = "i-03a8285fc49f48a69" -> null
      - instance_state               = "running" -> null
      - instance_type                = "t3.micro" -> null
      - ipv6_address_count           = 0 -> null
      - ipv6_addresses               = [] -> null
      - monitoring                   = false -> null
      - primary_network_interface_id = "eni-05f51ded8af0b5033" -> null
      - private_dns                  = "ip-172-31-36-204.ec2.internal" -> null
      - private_ip                   = "172.31.36.204" -> null
      - security_groups              = [
          - "default",
        ] -> null
      - source_dest_check            = true -> null
      - subnet_id                    = "subnet-01c13b00a5531828e" -> null
      - tags                         = {
          - "Name" = "two"
        } -> null
      - tenancy                      = "default" -> null
      - volume_tags                  = {} -> null
      - vpc_security_group_ids       = [
          - "sg-06aabe12f0a1b34fd",
        ] -> null

      - credit_specification {
          - cpu_credits = "unlimited" -> null
        }

      - root_block_device {
          - delete_on_termination = true -> null
          - encrypted             = false -> null
          - iops                  = 100 -> null
          - volume_id             = "vol-06ffd6ab6d4e8f671" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp2" -> null
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Ref: Terraform Resource For_Each

