How to use Terraform to setup and configure Elastic Beanstalk

In the previous article, we talk about creating a foundation image, by using Packer and Ansible to provision and build a Docker image.

The next step is to create some infrastructure, so that we can deploy our app to it – for that, we’re going to use another tool from HashiCorp; Terraform@

Terraform has a simple command which will look for any files with the .tf extension. It will also look for .tf.json extension, but this is a more strict markup. It’s a bit more flexible to use the standard extension as it allows for more comments.

First, lets create our variables

# Request the Variables. Can be passed via ENV VARS.
variable "access_key" {}
variable "secret_key" {}
variable "aws_region" {
    default = "eu-west-1"
}

Now call:

terraform apply

Terraform will prompt you for your AWS access key and secret key. You can do this for any variables you’d like to prompt. If you then want to pass them in at runtime, rather than be prompted, you can do it like so:

TF_VAR_access_key=XXXXX \
TF_VAR_secret_key=YYYYY \
terraform apply

So far, we don’t have much, so lets use these variables to create a provider, and some simple VPC & ‘Networking stuff’:

# Specify the provider and access details
provider "aws" {
    access_key = "${var.access_key}"
    secret_key = "${var.secret_key}"
    region     = "${var.aws_region}"
}

# Create a VPC to launch our instances into
resource "aws_vpc" "default" {
  cidr_block = "10.0.0.0/16"
}

# Create an internet gateway to give our subnet access to the outside world
resource "aws_internet_gateway" "default" {
  vpc_id = "${aws_vpc.default.id}"
}

# Grant the VPC internet access on its main route table
resource "aws_route" "internet_access" {
  route_table_id         = "${aws_vpc.default.main_route_table_id}"
  destination_cidr_block = "0.0.0.0/0"
  gateway_id             = "${aws_internet_gateway.default.id}"
}

# Create a subnet for the ELB & EC2 intances
resource "aws_subnet" "default" {
  vpc_id                  = "${aws_vpc.default.id}"
  availability_zone       = "eu-west-1a"
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true

  tags {
        Name = "Subnet A"
  }
}

If you’re familiar with AWS, the above should be fairly simple to understand. We’ve created a VPC, an Internet Gateway, a Route and a Subnet. Feel free to apply these changes and watch the magic. The real show, and what I find amazing, is the ability to simply tear this down:

TF_VAR_access_key=XXXXX \
TF_VAR_secret_key=YYYYY \
terraform destroy

When it sinks in that your infrastructure can be ripped apart by such a simple command, it will open you up to a whole new world of how to design your application code.

Assuming you’ve had no issue so far, the next step is to create our Elastic Beanstalk application and environments. In this example, we’re just going to fire up a test environment, you could simply copy/paste for more.

# The elastic beanstalk application
resource "aws_elastic_beanstalk_application" "adapt-webapp" {
  name = "Test Application"
  description = "Test Application"
}

# The test environment
resource "aws_elastic_beanstalk_environment" "testenv" {
  name                  = "testenv"
  application           = "${aws_elastic_beanstalk_application.adapt-webapp.name}"
  solution_stack_name   = "64bit Amazon Linux 2016.03 v2.1.0 running Docker 1.9.1"
  tier                  = "WebServer"

  # This is the VPC that the instances will use.
  setting {
    namespace = "aws:ec2:vpc"
    name      = "VPCId"
    value     = "${aws_vpc.default.id}"
  }

  # This is the subnet of the ELB
  setting {
    namespace = "aws:ec2:vpc"
    name      = "ELBSubnets"
    value     = "${aws_subnet.default.id}"
  }

  # This is the subnets for the instances.
  setting {
    namespace = "aws:ec2:vpc"
    name      = "Subnets"
    value     = "${aws_subnet.default.id}"
  }

  # You can set the environment type, single or LoadBalanced
  setting {
    namespace = "aws:elasticbeanstalk:environment"
    name      = "EnvironmentType"
    value     = "LoadBalanced"
  }

  # Example of setting environment variables
  setting {
    namespace = "aws:elasticbeanstalk:application:environment"
    name      = "AWS_ENVIRONMENT"
    value     = "test"
  }

  # Are the load balancers multizone?
  setting {
    namespace = "aws:elb:loadbalancer"
    name      = "CrossZone"
    value     = "true"
  }

  # Enable connection draining.
  setting {
    namespace = "aws:elb:policies"
    name      = "ConnectionDrainingEnabled"
    value     = "true"
  }
}

Most of the above, should again be fairly straight forward – but the comments should help if not. With another dash of the apply command, you’ll be up and running with a wonderful Elastic Beanstalk application. Elastic Beanstalk itself, will create the necessary Auto-Scaling groups, Security Groups & Elastic Load Balancers, so you don’t need to worry about setting this up in Terraform, although you could configure if you wish.

Truly amazing, right? It’s a far cry from the days of placing a custom build with Rackspace and waiting for them to send you all the details, right?

One last thing, should you decide you want to SSH into your instances, you need to specify the key/pair. This goes in as another environment setting:

# Optional, if you want to add a key pair to your instances
setting {
    namespace = "aws:autoscaling:launchconfiguration"
    name      = "EC2KeyName"
    value     = "${aws_key_pair.deployer.key_name}"
}

You’ll need to declare the key_pair as a resource to allow that to work:

  # Create the key/pair
resource "aws_key_pair" "deployer" {
  key_name   = "demo"
  public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCr9VLgck2nlRF4+VjekojDJA/O6q6qtBrIUM7c2hceF9SiuQQSTgrCKpQhsdV8Lhc4t/lmHyXD4CYeFoI0J+9OrkDlUgJCTXa3QnbYj8Oj4mrnAQ04euwxkhpqRyzYA/SPCxrEJjYz3iO8Mi/+QPJTVlgg5dNxRejngEYnveGN70ieabQZt4uOwwOa93ka8YqNVihr9e52i2QNTi6gDUALwZrc47++RR9Qo3vlbPZZ7yly9UUMZy0FfG9QcQbL2xQzV3JiYyjOfpVf/7lcEpqjdUHOp7CO9vGf6RnyMJz2cQCUcXLo4UA6/6epDXHUnIt/ZwsW/OQzGRYpy9FMl67EsNublVYbM4Ovcv9LMgpx8lXREP1N5a+Qw6SsYQQAlvjQQlvUZY1d/j4zWjh0SzcxRPhI/idk/QxJdiTMQDBXTdW+vhReSQg3P5FTi+h9Yc3qW4euipZK0GfyVu2pJtwxo7PeXaN1kqB/nEnHCqi4Dk3GblzF7/CCbugKbJiRAvd2edvvyHY3rlPKqkVRiPfVqOOvsk+UqrBiMpbwnkcoak6iYfun99N2ID4PfVgJM3WGjTcL9PQOIG98ppAGv4goaTBAUFiNj4gZGI/9ZjDp3/v9tgFgMDTE4vz4OfLrmH1GsrUC5kaOUmGaRu4vQQed8JcbxNaQgjRgqTthdLjtww=="
}

Don’t worry, that key is just for this article – it’s not in use anywhere.

There you have it, a simple a wonderful way to create automated infrastructure using Terraform & Elastic Beanstalk.

All the code used in this article can be found here

So what about deploying an application to said infrastructure? That blog post is coming soon, but you can see the source code for the application here

Be Sociable, Share!
Share

One thought on “How to use Terraform to setup and configure Elastic Beanstalk

  1. Pingback: How to Provision an AWS Elastic Beanstalk Instance Using Packer, Ansible, Docker & TerraformInternet Marketing - Bobby Jason | Internet Marketing - Bobby Jason

Leave a Reply

Your email address will not be published. Required fields are marked *