2014-07-28 19:43:00 +02:00
|
|
|
---
|
|
|
|
layout: "intro"
|
|
|
|
page_title: "Build Infrastructure"
|
2014-10-22 05:21:56 +02:00
|
|
|
sidebar_current: "gettingstarted-build
|
|
|
|
description: |-
|
|
|
|
With Terraform installed, let's dive right into it and start creating some infrastructure.
|
2014-07-28 19:43:00 +02:00
|
|
|
---
|
|
|
|
|
|
|
|
# Build Infrastructure
|
|
|
|
|
|
|
|
With Terraform installed, let's dive right into it and start creating
|
|
|
|
some infrastructure.
|
|
|
|
|
|
|
|
We'll build infrastructure on
|
|
|
|
[AWS](http://aws.amazon.com) for the getting started guide
|
|
|
|
since it is popular and generally understood, but Terraform
|
|
|
|
can [manage many providers](/docs/providers/index.html),
|
|
|
|
including multiple providers in a single configuration.
|
|
|
|
Some examples of this are in the
|
|
|
|
[use cases section](/intro/use-cases.html).
|
|
|
|
|
|
|
|
If you don't have an AWS account,
|
|
|
|
[create one now](http://aws.amazon.com/free/).
|
|
|
|
For the getting started guide, we'll only be using resources
|
|
|
|
which qualify under the AWS
|
|
|
|
[free-tier](http://aws.amazon.com/free/),
|
|
|
|
meaning it will be free.
|
|
|
|
If you already have an AWS account, you may be charged some
|
|
|
|
amount of money, but it shouldn't be more than a few dollars
|
|
|
|
at most.
|
|
|
|
|
|
|
|
<div class="alert alert-block alert-warning">
|
|
|
|
<p>
|
|
|
|
<strong>Note:</strong> If you're not using an account that qualifies
|
|
|
|
under the AWS
|
|
|
|
<a href="http://aws.amazon.com/free/">free-tier</a>,
|
|
|
|
you may be charged to run these examples. The most you should
|
|
|
|
be charged should only be a few dollars, but we're not responsible
|
|
|
|
for any charges that may incur.
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
## Configuration
|
|
|
|
|
|
|
|
The set of files used to describe infrastructure in Terraform is simply
|
|
|
|
known as a Terraform _configuration_. We're going to write our first
|
|
|
|
configuration now to launch a single AWS EC2 instance.
|
|
|
|
|
|
|
|
The format of the configuration files is
|
|
|
|
[documented here](/docs/configuration/index.html).
|
|
|
|
Configuration files can
|
|
|
|
[also be JSON](/docs/configuration/syntax.html), but we recommend only using JSON when the
|
|
|
|
configuration is generated by a machine.
|
|
|
|
|
|
|
|
The entire configuration is shown below. We'll go over each part
|
|
|
|
after. Save the contents to a file named `example.tf`. Verify that
|
|
|
|
there are no other `*.tf` files in your directory, since Terraform
|
|
|
|
loads all of them.
|
|
|
|
|
|
|
|
```
|
|
|
|
provider "aws" {
|
|
|
|
access_key = "ACCESS_KEY_HERE"
|
|
|
|
secret_key = "SECRET_KEY_HERE"
|
|
|
|
region = "us-east-1"
|
|
|
|
}
|
|
|
|
|
|
|
|
resource "aws_instance" "example" {
|
|
|
|
ami = "ami-408c7f28"
|
|
|
|
instance_type = "t1.micro"
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Replace the `ACCESS_KEY_HERE` and `SECRET_KEY_HERE` with your
|
|
|
|
AWS access key and secret key, available from
|
|
|
|
[this page](https://console.aws.amazon.com/iam/home?#security_credential).
|
|
|
|
We're hardcoding them for now, but will extract these into
|
|
|
|
variables later in the getting started guide.
|
|
|
|
|
|
|
|
This is a complete configuration that Terraform is ready to apply.
|
|
|
|
The general structure should be intuitive and straightforward.
|
|
|
|
|
|
|
|
The `provider` block is used to configure the named provider, in
|
|
|
|
our case "aws." A provider is responsible for creating and
|
|
|
|
managing resources. Multiple provider blocks can exist if a
|
|
|
|
Terraform configuration is comprised of multiple providers,
|
|
|
|
which is a common situation.
|
|
|
|
|
|
|
|
The `resource` block defines a resource that exists within
|
|
|
|
the infrastructure. A resource might be a physical component such
|
|
|
|
as an EC2 instance, or it can be a logical resource such as
|
|
|
|
a Heroku application.
|
|
|
|
|
|
|
|
The resource block has two strings before opening the block:
|
|
|
|
the resource type and the resource name. In our example, the
|
|
|
|
resource type is "aws\_instance" and the name is "example."
|
|
|
|
The prefix of the type maps to the provider. In our case
|
|
|
|
"aws\_instance" automatically tells Terraform that it is
|
|
|
|
managed by the "aws" provider.
|
|
|
|
|
|
|
|
Within the resource block itself is configuration for that
|
|
|
|
resource. This is dependent on each resource provider and
|
|
|
|
is fully documented within our
|
|
|
|
[providers reference](/docs/providers/index.html). For our EC2 instance, we specify
|
|
|
|
an AMI for Ubuntu, and request a "t1.micro" instance so we
|
|
|
|
qualify under the free tier.
|
|
|
|
|
|
|
|
## Execution Plan
|
|
|
|
|
|
|
|
Next, let's see what Terraform would do if we asked it to
|
|
|
|
apply this configuration. In the same directory as the
|
|
|
|
`example.tf` file you created, run `terraform plan`. You
|
|
|
|
should see output similar to what is copied below. We've
|
|
|
|
truncated some of the output to save space.
|
|
|
|
|
|
|
|
```
|
|
|
|
$ terraform plan
|
|
|
|
...
|
|
|
|
|
|
|
|
+ aws_instance.example
|
|
|
|
ami: "" => "ami-408c7f28"
|
|
|
|
availability_zone: "" => "<computed>"
|
|
|
|
instance_type: "" => "t1.micro"
|
|
|
|
key_name: "" => "<computed>"
|
|
|
|
private_dns: "" => "<computed>"
|
|
|
|
private_ip: "" => "<computed>"
|
|
|
|
public_dns: "" => "<computed>"
|
|
|
|
public_ip: "" => "<computed>"
|
|
|
|
security_groups: "" => "<computed>"
|
|
|
|
subnet_id: "" => "<computed>"
|
|
|
|
```
|
|
|
|
|
|
|
|
`terraform plan` shows what changes Terraform will apply to
|
|
|
|
your infrastructure given the current state of your infrastructure
|
|
|
|
as well as the current contents of your configuration.
|
|
|
|
|
|
|
|
If `terraform plan` failed with an error, read the error message
|
|
|
|
and fix the error that occurred. At this stage, it is probably a
|
|
|
|
syntax error in the configuration.
|
|
|
|
|
|
|
|
The output format is similar to the diff format generated by tools
|
|
|
|
such as Git. The output has a "+" next to "aws\_instance.example",
|
|
|
|
meaning that Terraform will create this resource. Beneath that,
|
|
|
|
it shows the attributes that will be set. When the value it is
|
|
|
|
going to is `<computed>`, it means that the value won't be known
|
|
|
|
until the resource is created.
|
|
|
|
|
|
|
|
## Apply
|
|
|
|
|
2014-07-29 12:23:25 +02:00
|
|
|
The plan looks good, our configuration appears valid, so it's time to
|
2014-07-28 19:43:00 +02:00
|
|
|
create real resources. Run `terraform apply` in the same directory
|
|
|
|
as your `example.tf`, and watch it go! It will take a few minutes
|
|
|
|
since Terraform waits for the EC2 instance to become available.
|
|
|
|
|
|
|
|
```
|
|
|
|
$ terraform apply
|
|
|
|
aws_instance.example: Creating...
|
|
|
|
ami: "" => "ami-408c7f28"
|
|
|
|
instance_type: "" => "t1.micro"
|
|
|
|
|
|
|
|
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
|
|
|
|
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
Done! You can go to the AWS console to prove to yourself that the
|
|
|
|
EC2 instance has been created.
|
|
|
|
|
|
|
|
Terraform also put some state into the `terraform.tfstate` file
|
|
|
|
by default. This state file is extremely important; it maps various
|
|
|
|
resource metadata to actual resource IDs so that Terraform knows
|
|
|
|
what it is managing. This file must be saved and distributed
|
|
|
|
to anyone who might run Terraform. We recommend simply putting it
|
|
|
|
into version control, since it generally isn't too large.
|
|
|
|
|
2014-10-13 20:57:43 +02:00
|
|
|
You can inspect the state using `terraform show`:
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
```
|
2014-10-13 20:57:43 +02:00
|
|
|
$ terraform show
|
2014-07-28 19:43:00 +02:00
|
|
|
aws_instance.example:
|
|
|
|
id = i-e60900cd
|
|
|
|
ami = ami-408c7f28
|
|
|
|
availability_zone = us-east-1c
|
|
|
|
instance_type = t1.micro
|
|
|
|
key_name =
|
|
|
|
private_dns = domU-12-31-39-12-38-AB.compute-1.internal
|
|
|
|
private_ip = 10.200.59.89
|
|
|
|
public_dns = ec2-54-81-21-192.compute-1.amazonaws.com
|
|
|
|
public_ip = 54.81.21.192
|
|
|
|
security_groups.# = 1
|
|
|
|
security_groups.0 = default
|
|
|
|
subnet_id =
|
|
|
|
```
|
|
|
|
|
|
|
|
You can see that by creating our resource, we've also gathered
|
|
|
|
a lot more metadata about it. This metadata can actually be referenced
|
|
|
|
for other resources or outputs, which will be covered later in
|
|
|
|
the getting started guide.
|
|
|
|
|
|
|
|
## Provisioning
|
|
|
|
|
|
|
|
The EC2 instance we launched at this point is based on the AMI
|
|
|
|
given, but has no additional software installed. If you're running
|
|
|
|
an image-based infrastructure (perhaps creating images with
|
|
|
|
[Packer](http://www.packer.io)), then this is all you need.
|
|
|
|
|
|
|
|
However, many infrastructures still require some sort of initialization
|
|
|
|
or software provisioning step. Terraform supports
|
|
|
|
provisioners,
|
|
|
|
which we'll cover a little bit later in the getting started guide,
|
|
|
|
in order to do this.
|
|
|
|
|
|
|
|
## Next
|
|
|
|
|
|
|
|
Congratulations! You've built your first infrastructure with Terraform.
|
|
|
|
You've seen the configuration syntax, an example of a basic execution
|
|
|
|
plan, and understand the state file.
|
|
|
|
|
|
|
|
Next, we're going to move on to [changing and destroying infrastructure](/intro/getting-started/change.html).
|