terraform/website/intro/getting-started/build.html.md

289 lines
11 KiB
Markdown

---
layout: "intro"
page_title: "Build Infrastructure"
sidebar_current: "gettingstarted-build"
description: |-
With Terraform installed, let's dive right into it and start creating some infrastructure.
---
# Build Infrastructure
With Terraform installed, let's dive right into it and start creating
some infrastructure.
We'll build infrastructure on
[AWS](https://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](https://aws.amazon.com/free/).
For the getting started guide, we'll only be using resources
which qualify under the AWS
[free-tier](https://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.
~> **Warning!** If you're not using an account that qualifies under the AWS
[free-tier](https://aws.amazon.com/free/), 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.
## 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.
```hcl
provider "aws" {
access_key = "ACCESS_KEY_HERE"
secret_key = "SECRET_KEY_HERE"
region = "us-east-1"
}
resource "aws_instance" "example" {
ami = "ami-2757f631"
instance_type = "t2.micro"
}
```
~> **Note**: The above configuration is designed to work on most EC2 accounts,
with access to a default VPC. For EC2 Classic users, please use `t1.micro` for
`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.
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.
~> **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.
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 composed 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 "t2.micro" instance so we
qualify under the free tier.
## 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.
In particular, this command will install the plugins for the providers in
use within the configuration, which in this case is just the `aws` provider:
```
$ 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.
## 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-2757f631"
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>"
```
`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 displayed
is `<computed>`, it means that the value won't be known
until the resource is created.
## Apply
The plan looks good, our configuration appears valid, so it's time to
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-2757f631"
instance_type: "" => "t2.micro"
[...]
aws_instance.example: Still creating... (10s elapsed)
aws_instance.example: Creation complete
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 puts 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. It is generally recommended to
[setup remote state](https://www.terraform.io/docs/state/remote.html)
when working with Terraform. This will mean that any potential secrets
stored in the state file, will not be checked into version control
You can inspect the state using `terraform show`:
```
$ terraform show
aws_instance.example:
id = i-32cf65a8
ami = ami-2757f631
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
```
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](https://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).