2014-07-28 19:43:00 +02:00
|
|
|
---
|
|
|
|
layout: "intro"
|
|
|
|
page_title: "Build Infrastructure"
|
2014-10-22 23:47:44 +02:00
|
|
|
sidebar_current: "gettingstarted-build"
|
2014-10-22 05:21:56 +02:00
|
|
|
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
|
2016-01-14 21:55:39 +01:00
|
|
|
[AWS](https://aws.amazon.com) for the getting started guide
|
2014-07-28 19:43:00 +02:00
|
|
|
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,
|
2016-01-14 21:55:39 +01:00
|
|
|
[create one now](https://aws.amazon.com/free/).
|
2014-07-28 19:43:00 +02:00
|
|
|
For the getting started guide, we'll only be using resources
|
|
|
|
which qualify under the AWS
|
2016-01-14 21:55:39 +01:00
|
|
|
[free-tier](https://aws.amazon.com/free/),
|
2014-07-28 19:43:00 +02:00
|
|
|
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.
|
|
|
|
|
2014-10-22 16:01:17 +02:00
|
|
|
~> **Warning!** If you're not using an account that qualifies under the AWS
|
2016-01-14 21:55:39 +01:00
|
|
|
[free-tier](https://aws.amazon.com/free/), you may be charged to run these
|
2014-10-22 16:01:17 +02:00
|
|
|
examples. The most you should be charged should only be a few dollars, but
|
|
|
|
we're not responsible for any charges that may incur.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
## 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.
|
|
|
|
|
2017-04-06 20:02:56 +02:00
|
|
|
```hcl
|
2014-07-28 19:43:00 +02:00
|
|
|
provider "aws" {
|
2016-05-20 23:19:01 +02:00
|
|
|
access_key = "ACCESS_KEY_HERE"
|
|
|
|
secret_key = "SECRET_KEY_HERE"
|
|
|
|
region = "us-east-1"
|
2014-07-28 19:43:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
resource "aws_instance" "example" {
|
2017-03-24 21:51:56 +01:00
|
|
|
ami = "ami-2757f631"
|
2016-05-20 23:19:01 +02:00
|
|
|
instance_type = "t2.micro"
|
2014-07-28 19:43:00 +02:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2016-09-01 12:30:55 +02:00
|
|
|
~> **Note**: The above configuration is designed to work on most EC2 accounts,
|
2016-05-20 23:19:01 +02:00
|
|
|
with access to a default VPC. For EC2 Classic users, please use `t1.micro` for
|
2017-06-16 09:18:29 +02:00
|
|
|
`instance_type`, and `ami-408c7f28` for the `ami`. If you use a region other than
|
|
|
|
`us-east-1` then you will need to choose an AMI in that region
|
|
|
|
as AMI IDs are region specific.
|
2016-05-20 23:19:01 +02:00
|
|
|
|
2014-07-28 19:43:00 +02:00
|
|
|
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.
|
|
|
|
|
2017-03-22 16:30:21 +01:00
|
|
|
~> **Note**: If you simply leave out AWS credentials, Terraform will
|
|
|
|
automatically search for saved API credentials (for example,
|
|
|
|
in `~/.aws/credentials`) or IAM instance profile credentials.
|
|
|
|
This option is much cleaner for situations where tf files are checked into
|
|
|
|
source control or where there is more than one admin user.
|
|
|
|
See details [here](https://aws.amazon.com/blogs/apn/terraform-beyond-the-basics-with-aws/).
|
|
|
|
Leaving IAM credentials out of the Terraform configs allows you to leave those
|
|
|
|
credentials out of source control, and also use different IAM credentials
|
|
|
|
for each user without having to modify the configuration files.
|
|
|
|
|
2014-07-28 19:43:00 +02:00
|
|
|
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
|
Fix the misuse of the word 'comprised' (#9603)
The proper use of "comprise" is "Array1 comprises item1, item2, and item3"
which is equivalent to saying "Array1 is composed of item1, item2, and item3."
That is, "comprises" is equivalent to "is composed of." Therefore, to say
"Array1 is comprised of item1, item2, and item3" is equivalent to saying
"Array1 IS IS COMPOSED OF OF item1, item2, and item3" which makes no
sense and is like "The La Trattoria" from Mickey Blue Eyes! This change fixes
the misuse of the word.
2016-10-25 19:22:15 +02:00
|
|
|
Terraform configuration is composed of multiple providers,
|
2014-07-28 19:43:00 +02:00
|
|
|
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
|
2016-05-20 23:19:01 +02:00
|
|
|
an AMI for Ubuntu, and request a "t2.micro" instance so we
|
2014-07-28 19:43:00 +02:00
|
|
|
qualify under the free tier.
|
|
|
|
|
2017-06-03 01:50:32 +02:00
|
|
|
## Initialization
|
|
|
|
|
|
|
|
The first command to run for a new configuration -- or after checking out
|
|
|
|
an existing configuration from version control -- is `terraform init`, which
|
|
|
|
initializes various local settings and data that will be used by subsequent
|
|
|
|
commands.
|
|
|
|
|
2017-08-21 22:44:27 +02:00
|
|
|
Terraform uses a plugin based architecture to support the numerous infrastructure
|
2017-09-01 20:42:06 +02:00
|
|
|
and service providers available. As of Terraform version 0.10.0, each "Provider" is its
|
2017-08-21 22:44:27 +02:00
|
|
|
own encapsulated binary distributed separately from Terraform itself. The
|
|
|
|
`terraform init` command will automatically download and install any Provider
|
|
|
|
binary for the providers in use within the configuration, which in this case is
|
|
|
|
just the `aws` provider:
|
|
|
|
|
2017-06-03 01:50:32 +02:00
|
|
|
|
|
|
|
```
|
|
|
|
$ terraform init
|
|
|
|
Initializing the backend...
|
|
|
|
Initializing provider plugins...
|
|
|
|
- downloading plugin for provider "aws"...
|
|
|
|
|
|
|
|
The following providers do not have any version constraints in configuration,
|
|
|
|
so the latest version was installed.
|
|
|
|
|
|
|
|
To prevent automatic upgrades to new major versions that may contain breaking
|
|
|
|
changes, it is recommended to add version = "..." constraints to the
|
|
|
|
corresponding provider blocks in configuration, with the constraint strings
|
|
|
|
suggested below.
|
|
|
|
|
|
|
|
* provider.aws: version = "~> 1.0"
|
|
|
|
|
|
|
|
Terraform has been successfully initialized!
|
|
|
|
|
|
|
|
You may now begin working with Terraform. Try running "terraform plan" to see
|
|
|
|
any changes that are required for your infrastructure. All Terraform commands
|
|
|
|
should now work.
|
|
|
|
|
|
|
|
If you ever set or change modules or backend configuration for Terraform,
|
|
|
|
rerun this command to reinitialize your environment. If you forget, other
|
|
|
|
commands will detect it and remind you to do so if necessary.
|
|
|
|
```
|
|
|
|
|
|
|
|
The `aws` provider plugin is downloaded and installed in a subdirectory of
|
|
|
|
the current working directory, along with various other book-keeping files.
|
|
|
|
|
|
|
|
The output specifies which version of the plugin was installed, and suggests
|
|
|
|
specifying that version in configuration to ensure that running
|
|
|
|
`terraform init` in future will install a compatible version. This step
|
|
|
|
is not necessary for following the getting started guide, since this
|
|
|
|
configuration will be discarded at the end.
|
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
## Apply Changes
|
2014-07-28 19:43:00 +02:00
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
~> **Note:** The commands shown in this guide apply to Terraform 0.11 and
|
|
|
|
above. Earlier versions require using the `terraform plan` command to
|
|
|
|
see the execution plan before applying it. Use `terraform version`
|
|
|
|
to confirm your running version.
|
|
|
|
|
|
|
|
In the same directory as the `example.tf` file you created, run
|
|
|
|
`terraform apply`. You should see output similar to below, though we've
|
|
|
|
truncated some of the output to save space:
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
```
|
2017-10-30 21:33:27 +01:00
|
|
|
$ terraform apply
|
2017-04-06 20:02:56 +02:00
|
|
|
# ...
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
+ aws_instance.example
|
2017-03-24 21:51:56 +01:00
|
|
|
ami: "ami-2757f631"
|
2016-05-20 23:19:01 +02:00
|
|
|
availability_zone: "<computed>"
|
|
|
|
ebs_block_device.#: "<computed>"
|
|
|
|
ephemeral_block_device.#: "<computed>"
|
|
|
|
instance_state: "<computed>"
|
|
|
|
instance_type: "t2.micro"
|
|
|
|
key_name: "<computed>"
|
|
|
|
placement_group: "<computed>"
|
|
|
|
private_dns: "<computed>"
|
|
|
|
private_ip: "<computed>"
|
|
|
|
public_dns: "<computed>"
|
|
|
|
public_ip: "<computed>"
|
|
|
|
root_block_device.#: "<computed>"
|
|
|
|
security_groups.#: "<computed>"
|
|
|
|
source_dest_check: "true"
|
|
|
|
subnet_id: "<computed>"
|
|
|
|
tenancy: "<computed>"
|
|
|
|
vpc_security_group_ids.#: "<computed>"
|
2014-07-28 19:43:00 +02:00
|
|
|
```
|
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
This output shows the _execution plan_, describing which actions Terraform
|
|
|
|
will take in order to change real infrastructure to match the configuration.
|
2014-07-28 19:43:00 +02:00
|
|
|
The output format is similar to the diff format generated by tools
|
2017-10-30 21:33:27 +01:00
|
|
|
such as Git. The output has a `+` next to `aws_instance.example`,
|
2014-07-28 19:43:00 +02:00
|
|
|
meaning that Terraform will create this resource. Beneath that,
|
2017-04-06 20:02:56 +02:00
|
|
|
it shows the attributes that will be set. When the value displayed
|
2016-03-25 15:34:47 +01:00
|
|
|
is `<computed>`, it means that the value won't be known
|
2014-07-28 19:43:00 +02:00
|
|
|
until the resource is created.
|
|
|
|
|
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
If `terraform apply` failed with an error, read the error message
|
|
|
|
and fix the error that occurred. At this stage, it is likely to be a
|
|
|
|
syntax error in the configuration.
|
|
|
|
|
|
|
|
If the plan was created successfully, Terraform will now pause and wait for
|
|
|
|
approval before proceeding. If anything in the plan seems incorrect or
|
|
|
|
dangerous, it is safe to abort here with no changes made to your infrastructure.
|
|
|
|
In this case the plan looks acceptable, so type `yes` at the confirmation
|
|
|
|
prompt to proceed.
|
|
|
|
|
|
|
|
Executing the plan will take a few minutes since Terraform waits for the EC2
|
|
|
|
instance to become available:
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
```
|
2017-10-30 21:33:27 +01:00
|
|
|
# ...
|
2014-07-28 19:43:00 +02:00
|
|
|
aws_instance.example: Creating...
|
2017-03-24 21:51:56 +01:00
|
|
|
ami: "" => "ami-2757f631"
|
2016-05-20 23:19:01 +02:00
|
|
|
instance_type: "" => "t2.micro"
|
|
|
|
[...]
|
|
|
|
|
|
|
|
aws_instance.example: Still creating... (10s elapsed)
|
|
|
|
aws_instance.example: Creation complete
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
|
|
|
|
|
2017-04-06 20:02:56 +02:00
|
|
|
# ...
|
2014-07-28 19:43:00 +02:00
|
|
|
```
|
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
After this, Terraform is all done! You can go to the EC2 console to see the
|
|
|
|
created EC2 instance. (Make sure you're looking at the same region that was
|
|
|
|
configured in the provider configuration!)
|
2014-07-28 19:43:00 +02:00
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
Terraform also wrote some data into the `terraform.tfstate` file. This state
|
|
|
|
file is extremely important; it keeps track of the IDs of created resources
|
|
|
|
so that Terraform knows what it is managing. This file must be saved and
|
|
|
|
distributed to anyone who might run Terraform. It is generally recommended to
|
2017-03-15 18:20:26 +01:00
|
|
|
[setup remote state](https://www.terraform.io/docs/state/remote.html)
|
2017-10-30 21:33:27 +01:00
|
|
|
when working with Terraform, to share the state automatically, but this is
|
|
|
|
not necessary for simple situations like this Getting Started guide.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
2017-10-30 21:33:27 +01:00
|
|
|
You can inspect the current 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:
|
2016-05-20 23:19:01 +02:00
|
|
|
id = i-32cf65a8
|
2017-03-24 21:51:56 +01:00
|
|
|
ami = ami-2757f631
|
2016-05-20 23:19:01 +02:00
|
|
|
availability_zone = us-east-1a
|
|
|
|
instance_state = running
|
|
|
|
instance_type = t2.micro
|
|
|
|
private_ip = 172.31.30.244
|
|
|
|
public_dns = ec2-52-90-212-55.compute-1.amazonaws.com
|
|
|
|
public_ip = 52.90.212.55
|
|
|
|
subnet_id = subnet-1497024d
|
|
|
|
vpc_security_group_ids.# = 1
|
|
|
|
vpc_security_group_ids.3348721628 = sg-67652003
|
2014-07-28 19:43:00 +02:00
|
|
|
```
|
|
|
|
|
|
|
|
You can see that by creating our resource, we've also gathered
|
2017-10-30 21:33:27 +01:00
|
|
|
a lot of information about it. These values can actually be referenced
|
|
|
|
to configure other resources or outputs, which will be covered later in
|
2014-07-28 19:43:00 +02:00
|
|
|
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
|
2015-01-03 19:31:53 +01:00
|
|
|
[Packer](https://www.packer.io)), then this is all you need.
|
2014-07-28 19:43:00 +02:00
|
|
|
|
|
|
|
However, many infrastructures still require some sort of initialization
|
2017-10-30 21:33:27 +01:00
|
|
|
or software provisioning step. Terraform supports provisioners,
|
2014-07-28 19:43:00 +02:00
|
|
|
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).
|