website: Remove extra copy of "Getting Started", update links
This guide now lives at: - https://learn.hashicorp.com/terraform#getting-started ...and terraform.io has been redirecting to there for quite a while. This commit removes the extra copy so that the text of the two versions doesn't drift, and updates existing links to point to the new location.
This commit is contained in:
parent
a797152648
commit
6494591ec1
|
@ -23,7 +23,7 @@ When you declare them in [child modules](./modules.html),
|
||||||
the calling module should pass values in the `module` block.
|
the calling module should pass values in the `module` block.
|
||||||
|
|
||||||
Input variable usage is introduced in the Getting Started guide section
|
Input variable usage is introduced in the Getting Started guide section
|
||||||
[_Input Variables_](/intro/getting-started/variables.html).
|
[_Input Variables_](https://learn.hashicorp.com/terraform/getting-started/variables).
|
||||||
|
|
||||||
-> **Note:** For brevity, input variables are often referred to as just
|
-> **Note:** For brevity, input variables are often referred to as just
|
||||||
"variables" or "Terraform variables" when it is clear from context what sort of
|
"variables" or "Terraform variables" when it is clear from context what sort of
|
||||||
|
|
|
@ -13,7 +13,7 @@ topic in Terraform, and is not required knowledge for day-to-day usage.
|
||||||
If you don't plan on writing any plugins, this section of the documentation is
|
If you don't plan on writing any plugins, this section of the documentation is
|
||||||
not necessary to read. For general use of Terraform, please see our
|
not necessary to read. For general use of Terraform, please see our
|
||||||
[Intro to Terraform](/intro/index.html) and [Getting
|
[Intro to Terraform](/intro/index.html) and [Getting
|
||||||
Started](/intro/getting-started/install.html) guides.
|
Started](https://learn.hashicorp.com/terraform/getting-started/install) guides.
|
||||||
|
|
||||||
This page documents the basics of how the plugin system in Terraform
|
This page documents the basics of how the plugin system in Terraform
|
||||||
works, and how to setup a basic development environment for plugin development
|
works, and how to setup a basic development environment for plugin development
|
||||||
|
|
|
@ -13,7 +13,7 @@ topic in Terraform, and is not required knowledge for day-to-day usage.
|
||||||
If you don't plan on writing any plugins, this section of the documentation is
|
If you don't plan on writing any plugins, this section of the documentation is
|
||||||
not necessary to read. For general use of Terraform, please see our
|
not necessary to read. For general use of Terraform, please see our
|
||||||
[Intro to Terraform](/intro/index.html) and [Getting
|
[Intro to Terraform](/intro/index.html) and [Getting
|
||||||
Started](/intro/getting-started/install.html) guides.
|
Started](https://learn.hashicorp.com/terraform/getting-started/install) guides.
|
||||||
|
|
||||||
A provider in Terraform is responsible for the lifecycle of a resource:
|
A provider in Terraform is responsible for the lifecycle of a resource:
|
||||||
create, read, update, delete. An example of a provider is AWS, which
|
create, read, update, delete. An example of a provider is AWS, which
|
||||||
|
|
|
@ -36,7 +36,7 @@ visiting the [Web UI](https://demo.consul.io/ui/dc1/kv/). We can see
|
||||||
that the `tf_test/id` and `tf_test/public_dns` values have been
|
that the `tf_test/id` and `tf_test/public_dns` values have been
|
||||||
set.
|
set.
|
||||||
|
|
||||||
You can now [tear down the infrastructure](/intro/getting-started/destroy.html)
|
You can now [tear down the infrastructure](https://learn.hashicorp.com/terraform/getting-started/destroy).
|
||||||
Because we set the `delete` property of two of the Consul keys, Terraform
|
Because we set the `delete` property of two of the Consul keys, Terraform
|
||||||
will clean up those keys on destroy. We can verify this by using
|
will clean up those keys on destroy. We can verify this by using
|
||||||
the Web UI.
|
the Web UI.
|
||||||
|
|
|
@ -25,7 +25,7 @@ Experimenting in this way can help you learn how the Terraform lifecycle
|
||||||
works, as well as how to repeatedly create and destroy infrastructure.
|
works, as well as how to repeatedly create and destroy infrastructure.
|
||||||
|
|
||||||
If you're completely new to Terraform, we recommend reading the
|
If you're completely new to Terraform, we recommend reading the
|
||||||
[getting started guide](/intro/getting-started/install.html) before diving into
|
[getting started guide](https://learn.hashicorp.com/terraform/getting-started/install) before diving into
|
||||||
the examples. However, due to the intuitive configuration Terraform
|
the examples. However, due to the intuitive configuration Terraform
|
||||||
uses it isn't required.
|
uses it isn't required.
|
||||||
|
|
||||||
|
|
|
@ -1,291 +0,0 @@
|
||||||
---
|
|
||||||
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 this 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.
|
|
||||||
|
|
||||||
~> **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 in a
|
|
||||||
Terraform configuration if the infrastructure needs them.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Terraform uses a plugin based architecture to support the numerous infrastructure
|
|
||||||
and service providers available. As of Terraform version 0.10.0, each "Provider" is its
|
|
||||||
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:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
$ 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.
|
|
||||||
|
|
||||||
## Apply Changes
|
|
||||||
|
|
||||||
~> **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:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply
|
|
||||||
# ...
|
|
||||||
|
|
||||||
+ 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>"
|
|
||||||
```
|
|
||||||
|
|
||||||
This output shows the _execution plan_, describing which actions Terraform
|
|
||||||
will take in order to change real infrastructure to match 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.
|
|
||||||
|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```
|
|
||||||
# ...
|
|
||||||
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.
|
|
||||||
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
After this, Terraform is all done! You can go to the EC2 console to see the newly
|
|
||||||
created EC2 instance. (Make sure you're looking at the same region that was
|
|
||||||
configured in the provider configuration!)
|
|
||||||
|
|
||||||
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
|
|
||||||
[setup remote state](https://www.terraform.io/docs/state/remote.html)
|
|
||||||
when working with Terraform, to share the state automatically, but this is
|
|
||||||
not necessary for simple situations like this Getting Started guide.
|
|
||||||
|
|
||||||
You can inspect the current 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 of information about it. These values can actually be referenced
|
|
||||||
to configure 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).
|
|
|
@ -1,123 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Change Infrastructure"
|
|
||||||
sidebar_current: "gettingstarted-change"
|
|
||||||
description: |-
|
|
||||||
In the previous page, you created your first infrastructure with Terraform: a single EC2 instance. In this page, we're going to modify that resource, and see how Terraform handles change.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Change Infrastructure
|
|
||||||
|
|
||||||
In the previous page, you created your first infrastructure with
|
|
||||||
Terraform: a single EC2 instance. In this page, we're going to
|
|
||||||
modify that resource, and see how Terraform handles change.
|
|
||||||
|
|
||||||
Infrastructure is continuously evolving, and Terraform was built
|
|
||||||
to help manage and enact that change. As you change Terraform
|
|
||||||
configurations, Terraform builds an execution plan that only
|
|
||||||
modifies what is necessary to reach your desired state.
|
|
||||||
|
|
||||||
By using Terraform to change infrastructure, you can version
|
|
||||||
control not only your configurations but also your state so you
|
|
||||||
can see how the infrastructure evolved over time.
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
Let's modify the `ami` of our instance. Edit the `aws_instance.example`
|
|
||||||
resource in your configuration and change it to the following:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
resource "aws_instance" "example" {
|
|
||||||
ami = "ami-b374d5a5"
|
|
||||||
instance_type = "t2.micro"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
~> **Note:** EC2 Classic users please use AMI `ami-656be372` and type `t1.micro`
|
|
||||||
|
|
||||||
We've changed the AMI from being an Ubuntu 16.04 LTS AMI to being
|
|
||||||
an Ubuntu 16.10 AMI. Terraform configurations are meant to be
|
|
||||||
changed like this. You can also completely remove resources
|
|
||||||
and Terraform will know to destroy the old one.
|
|
||||||
|
|
||||||
## Apply Changes
|
|
||||||
|
|
||||||
After changing the configuration, run `terraform apply` again to see how
|
|
||||||
Terraform will apply this change to the existing resources.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply
|
|
||||||
# ...
|
|
||||||
|
|
||||||
-/+ aws_instance.example
|
|
||||||
ami: "ami-2757f631" => "ami-b374d5a5" (forces new resource)
|
|
||||||
availability_zone: "us-east-1a" => "<computed>"
|
|
||||||
ebs_block_device.#: "0" => "<computed>"
|
|
||||||
ephemeral_block_device.#: "0" => "<computed>"
|
|
||||||
instance_state: "running" => "<computed>"
|
|
||||||
instance_type: "t2.micro" => "t2.micro"
|
|
||||||
private_dns: "ip-172-31-17-94.ec2.internal" => "<computed>"
|
|
||||||
private_ip: "172.31.17.94" => "<computed>"
|
|
||||||
public_dns: "ec2-54-82-183-4.compute-1.amazonaws.com" => "<computed>"
|
|
||||||
public_ip: "54.82.183.4" => "<computed>"
|
|
||||||
subnet_id: "subnet-1497024d" => "<computed>"
|
|
||||||
vpc_security_group_ids.#: "1" => "<computed>"
|
|
||||||
```
|
|
||||||
|
|
||||||
The prefix `-/+` means that Terraform will destroy and recreate
|
|
||||||
the resource, rather than updating it in-place. While some attributes
|
|
||||||
can be updated in-place (which are shown with the `~` prefix), changing the
|
|
||||||
AMI for an EC2 instance requires recreating it. Terraform handles these details
|
|
||||||
for you, and the execution plan makes it clear what Terraform will do.
|
|
||||||
|
|
||||||
Additionally, the execution plan shows that the AMI change is what
|
|
||||||
required the resource to be replaced. Using this information,
|
|
||||||
you can adjust your changes to possibly avoid destroy/create updates
|
|
||||||
if they are not acceptable in some situations.
|
|
||||||
|
|
||||||
Once again, Terraform prompts for approval of the execution plan before
|
|
||||||
proceeding. Answer `yes` to execute the planned steps:
|
|
||||||
|
|
||||||
|
|
||||||
```
|
|
||||||
# ...
|
|
||||||
aws_instance.example: Refreshing state... (ID: i-64c268fe)
|
|
||||||
aws_instance.example: Destroying...
|
|
||||||
aws_instance.example: Destruction complete
|
|
||||||
aws_instance.example: Creating...
|
|
||||||
ami: "" => "ami-b374d5a5"
|
|
||||||
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>"
|
|
||||||
aws_instance.example: Still creating... (10s elapsed)
|
|
||||||
aws_instance.example: Still creating... (20s elapsed)
|
|
||||||
aws_instance.example: Creation complete
|
|
||||||
|
|
||||||
Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
|
|
||||||
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
As indicated by the execution plan, Terraform first destroyed the existing
|
|
||||||
instance and then created a new one in its place. You can use `terraform show`
|
|
||||||
again to see the new values associated with this instance.
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
You've now seen how easy it is to modify infrastructure with
|
|
||||||
Terraform. Feel free to play around with this more before continuing.
|
|
||||||
In the next section we're going to [destroy our infrastructure](/intro/getting-started/destroy.html).
|
|
|
@ -1,201 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Resource Dependencies"
|
|
||||||
sidebar_current: "gettingstarted-deps"
|
|
||||||
description: |-
|
|
||||||
In this page, we're going to introduce resource dependencies, where we'll not only see a configuration with multiple resources for the first time, but also scenarios where resource parameters use information from other resources.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Resource Dependencies
|
|
||||||
|
|
||||||
In this page, we're going to introduce resource dependencies,
|
|
||||||
where we'll not only see a configuration with multiple resources
|
|
||||||
for the first time, but also scenarios where resource parameters
|
|
||||||
use information from other resources.
|
|
||||||
|
|
||||||
Up to this point, our example has only contained a single resource.
|
|
||||||
Real infrastructure has a diverse set of resources and resource
|
|
||||||
types. Terraform configurations can contain multiple resources,
|
|
||||||
multiple resource types, and these types can even span multiple
|
|
||||||
providers.
|
|
||||||
|
|
||||||
On this page, we'll show a basic example of multiple resources
|
|
||||||
and how to reference the attributes of other resources to configure
|
|
||||||
subsequent resources.
|
|
||||||
|
|
||||||
## Assigning an Elastic IP
|
|
||||||
|
|
||||||
We'll improve our configuration by assigning an elastic IP to
|
|
||||||
the EC2 instance we're managing. Modify your `example.tf` and
|
|
||||||
add the following:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
resource "aws_eip" "ip" {
|
|
||||||
instance = "${aws_instance.example.id}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This should look familiar from the earlier example of adding
|
|
||||||
an EC2 instance resource, except this time we're building
|
|
||||||
an "aws\_eip" resource type. This resource type allocates
|
|
||||||
and associates an
|
|
||||||
[elastic IP](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html)
|
|
||||||
to an EC2 instance.
|
|
||||||
|
|
||||||
The only parameter for
|
|
||||||
[aws\_eip](/docs/providers/aws/r/eip.html) is "instance" which
|
|
||||||
is the EC2 instance to assign the IP to. For this value, we
|
|
||||||
use an interpolation to use an attribute from the EC2 instance
|
|
||||||
we managed earlier.
|
|
||||||
|
|
||||||
The syntax for this interpolation should be straightforward:
|
|
||||||
it requests the "id" attribute from the "aws\_instance.example"
|
|
||||||
resource.
|
|
||||||
|
|
||||||
## Apply Changes
|
|
||||||
|
|
||||||
Run `terraform apply` to see how Terraform plans to apply this change.
|
|
||||||
The output will look similar to the following:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply
|
|
||||||
|
|
||||||
+ aws_eip.ip
|
|
||||||
allocation_id: "<computed>"
|
|
||||||
association_id: "<computed>"
|
|
||||||
domain: "<computed>"
|
|
||||||
instance: "${aws_instance.example.id}"
|
|
||||||
network_interface: "<computed>"
|
|
||||||
private_ip: "<computed>"
|
|
||||||
public_ip: "<computed>"
|
|
||||||
|
|
||||||
+ aws_instance.example
|
|
||||||
ami: "ami-b374d5a5"
|
|
||||||
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 will create two resources: the instance and the elastic
|
|
||||||
IP. In the "instance" value for the "aws\_eip", you can see the
|
|
||||||
raw interpolation is still present. This is because this variable
|
|
||||||
won't be known until the "aws\_instance" is created. It will be
|
|
||||||
replaced at apply-time.
|
|
||||||
|
|
||||||
As usual, Terraform prompts for confirmation before making any changes.
|
|
||||||
Answer `yes` to apply. The continued output will look similar to the
|
|
||||||
following:
|
|
||||||
|
|
||||||
```
|
|
||||||
# ...
|
|
||||||
aws_instance.example: Creating...
|
|
||||||
ami: "" => "ami-b374d5a5"
|
|
||||||
instance_type: "" => "t2.micro"
|
|
||||||
[..]
|
|
||||||
aws_instance.example: Still creating... (10s elapsed)
|
|
||||||
aws_instance.example: Creation complete
|
|
||||||
aws_eip.ip: Creating...
|
|
||||||
allocation_id: "" => "<computed>"
|
|
||||||
association_id: "" => "<computed>"
|
|
||||||
domain: "" => "<computed>"
|
|
||||||
instance: "" => "i-f3d77d69"
|
|
||||||
network_interface: "" => "<computed>"
|
|
||||||
private_ip: "" => "<computed>"
|
|
||||||
public_ip: "" => "<computed>"
|
|
||||||
aws_eip.ip: Creation complete
|
|
||||||
|
|
||||||
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
|
|
||||||
```
|
|
||||||
|
|
||||||
As shown above, Terraform created the EC2 instance before creating the Elastic
|
|
||||||
IP address. Due to the interpolation expression that passes the ID of the EC2
|
|
||||||
instance to the Elastic IP address, Terraform is able to infer a dependency,
|
|
||||||
and knows it must create the instance first.
|
|
||||||
|
|
||||||
## Implicit and Explicit Dependencies
|
|
||||||
|
|
||||||
By studying the resource attributes used in interpolation expressions,
|
|
||||||
Terraform can automatically infer when one resource depends on another.
|
|
||||||
In the example above, the expression `${aws_instance.example.id}` creates
|
|
||||||
an _implicit dependency_ on the `aws_instance` named `example`.
|
|
||||||
|
|
||||||
Terraform uses this dependency information to determine the correct order
|
|
||||||
in which to create the different resources. In the example above, Terraform
|
|
||||||
knows that the `aws_instance` must be created before the `aws_eip`.
|
|
||||||
|
|
||||||
Implicit dependencies via interpolation expressions are the primary way
|
|
||||||
to inform Terraform about these relationships, and should be used whenever
|
|
||||||
possible.
|
|
||||||
|
|
||||||
Sometimes there are dependencies between resources that are _not_ visible to
|
|
||||||
Terraform. The `depends_on` argument is accepted by any resource and accepts
|
|
||||||
a list of resources to create _explicit dependencies_ for.
|
|
||||||
|
|
||||||
For example, perhaps an application we will run on our EC2 instance expects
|
|
||||||
to use a specific Amazon S3 bucket, but that dependency is configured
|
|
||||||
inside the application code and thus not visible to Terraform. In
|
|
||||||
that case, we can use `depends_on` to explicitly declare the dependency:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
# New resource for the S3 bucket our application will use.
|
|
||||||
resource "aws_s3_bucket" "example" {
|
|
||||||
# NOTE: S3 bucket names must be unique across _all_ AWS accounts, so
|
|
||||||
# this name must be changed before applying this example to avoid naming
|
|
||||||
# conflicts.
|
|
||||||
bucket = "terraform-getting-started-guide"
|
|
||||||
acl = "private"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Change the aws_instance we declared earlier to now include "depends_on"
|
|
||||||
resource "aws_instance" "example" {
|
|
||||||
ami = "ami-2757f631"
|
|
||||||
instance_type = "t2.micro"
|
|
||||||
|
|
||||||
# Tells Terraform that this EC2 instance must be created only after the
|
|
||||||
# S3 bucket has been created.
|
|
||||||
depends_on = ["aws_s3_bucket.example"]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Non-Dependent Resources
|
|
||||||
|
|
||||||
We can continue to build this configuration by adding another EC2 instance:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
resource "aws_instance" "another" {
|
|
||||||
ami = "ami-b374d5a5"
|
|
||||||
instance_type = "t2.micro"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Because this new instance does not depend on any other resource, it can
|
|
||||||
be created in parallel with the other resources. Where possible, Terraform
|
|
||||||
will perform operations concurrently to reduce the total time taken to
|
|
||||||
apply changes.
|
|
||||||
|
|
||||||
Before moving on, remove this new resource from your configuration and
|
|
||||||
run `terraform apply` again to destroy it. We won't use this second instance
|
|
||||||
any further in the getting started guide.
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
In this page you were introduced to using multiple resources, interpolating
|
|
||||||
attributes from one resource into another, and declaring dependencies between
|
|
||||||
resources to define operation ordering.
|
|
||||||
|
|
||||||
In the next section, [we'll use provisioners](/intro/getting-started/provision.html)
|
|
||||||
to do some basic bootstrapping of our launched instance.
|
|
|
@ -1,62 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Destroy Infrastructure"
|
|
||||||
sidebar_current: "gettingstarted-destroy"
|
|
||||||
description: |-
|
|
||||||
We've now seen how to build and change infrastructure. Before we move on to creating multiple resources and showing resource dependencies, we're going to go over how to completely destroy the Terraform-managed infrastructure.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Destroy Infrastructure
|
|
||||||
|
|
||||||
We've now seen how to build and change infrastructure. Before we
|
|
||||||
move on to creating multiple resources and showing resource
|
|
||||||
dependencies, we're going to go over how to completely destroy
|
|
||||||
the Terraform-managed infrastructure.
|
|
||||||
|
|
||||||
Destroying your infrastructure is a rare event in production
|
|
||||||
environments. But if you're using Terraform to spin up multiple
|
|
||||||
environments such as development, test, QA environments, then
|
|
||||||
destroying is a useful action.
|
|
||||||
|
|
||||||
## Destroy
|
|
||||||
|
|
||||||
Resources can be destroyed using the `terraform destroy` command, which is
|
|
||||||
similar to `terraform apply` but it behaves as if all of the resources have
|
|
||||||
been removed from the configuration.
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform destroy
|
|
||||||
# ...
|
|
||||||
|
|
||||||
- aws_instance.example
|
|
||||||
```
|
|
||||||
|
|
||||||
The `-` prefix indicates that the instance will be destroyed. As with apply,
|
|
||||||
Terraform shows its execution plan and waits for approval before making any
|
|
||||||
changes.
|
|
||||||
|
|
||||||
Answer `yes` to execute this plan and destroy the infrastructure:
|
|
||||||
|
|
||||||
```
|
|
||||||
# ...
|
|
||||||
aws_instance.example: Destroying...
|
|
||||||
|
|
||||||
Destroy complete! Resources: 1 destroyed.
|
|
||||||
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Just like with `apply`, Terraform determines the order in which
|
|
||||||
things must be destroyed. In this case there was only one resource, so no
|
|
||||||
ordering was necessary. In more complicated cases with multiple resources,
|
|
||||||
Terraform will destroy them in a suitable order to respect dependencies,
|
|
||||||
as we'll see later in this guide.
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
You now know how to create, modify, and destroy infrastructure
|
|
||||||
from a local machine.
|
|
||||||
|
|
||||||
Next, we move on to features that make Terraform configurations
|
|
||||||
slightly more useful: [variables, resource dependencies, provisioning,
|
|
||||||
and more](/intro/getting-started/dependencies.html).
|
|
|
@ -1,64 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Installing Terraform"
|
|
||||||
sidebar_current: "gettingstarted-install"
|
|
||||||
description: |-
|
|
||||||
Terraform must first be installed on your machine. Terraform is distributed as
|
|
||||||
a binary package for all supported platforms and architecture. This page will
|
|
||||||
not cover how to compile Terraform from source.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Install Terraform
|
|
||||||
|
|
||||||
Terraform must first be installed on your machine. Terraform is distributed as a
|
|
||||||
[binary package](/downloads.html) for all supported platforms and architectures.
|
|
||||||
This page will not cover how to compile Terraform from source, but compiling
|
|
||||||
from source is covered in the [documentation](/docs/index.html) for those who
|
|
||||||
want to be sure they're compiling source they trust into the final binary.
|
|
||||||
|
|
||||||
## Installing Terraform
|
|
||||||
|
|
||||||
To install Terraform, find the [appropriate package](/downloads.html) for your
|
|
||||||
system and download it. Terraform is packaged as a zip archive.
|
|
||||||
|
|
||||||
After downloading Terraform, unzip the package. Terraform runs as a single
|
|
||||||
binary named `terraform`. Any other files in the package can be safely removed
|
|
||||||
and Terraform will still function.
|
|
||||||
|
|
||||||
The final step is to make sure that the `terraform` binary is available on the `PATH`.
|
|
||||||
See [this page](https://stackoverflow.com/questions/14637979/how-to-permanently-set-path-on-linux)
|
|
||||||
for instructions on setting the PATH on Linux and Mac.
|
|
||||||
[This page](https://stackoverflow.com/questions/1618280/where-can-i-set-path-to-make-exe-on-windows)
|
|
||||||
contains instructions for setting the PATH on Windows.
|
|
||||||
|
|
||||||
## Verifying the Installation
|
|
||||||
|
|
||||||
After installing Terraform, verify the installation worked by opening a new
|
|
||||||
terminal session and checking that `terraform` is available. By executing
|
|
||||||
`terraform` you should see help output similar to this:
|
|
||||||
|
|
||||||
```text
|
|
||||||
$ terraform
|
|
||||||
Usage: terraform [--version] [--help] <command> [args]
|
|
||||||
|
|
||||||
The available commands for execution are listed below.
|
|
||||||
The most common, useful commands are shown first, followed by
|
|
||||||
less common or more advanced commands. If you're just getting
|
|
||||||
started with Terraform, stick with the common commands. For the
|
|
||||||
other commands, please read the help and docs before usage.
|
|
||||||
|
|
||||||
Common commands:
|
|
||||||
apply Builds or changes infrastructure
|
|
||||||
console Interactive console for Terraform interpolations
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
If you get an error that `terraform` could not be found, your `PATH` environment
|
|
||||||
variable was not set up properly. Please go back and ensure that your `PATH`
|
|
||||||
variable contains the directory where Terraform was installed.
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
Time to [build infrastructure](/intro/getting-started/build.html) using a
|
|
||||||
minimal Terraform configuration file. You will be able to examine Terraform's
|
|
||||||
execution plan before you deploy it to AWS.
|
|
|
@ -1,269 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Modules"
|
|
||||||
sidebar_current: "gettingstarted-modules"
|
|
||||||
description: |-
|
|
||||||
Up to this point, we've been configuring Terraform by editing Terraform configurations directly. As our infrastructure grows, this practice has a few key problems: a lack of organization, a lack of reusability, and difficulties in management for teams.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Modules
|
|
||||||
|
|
||||||
Up to this point, we've been configuring Terraform by editing Terraform
|
|
||||||
configurations directly. As our infrastructure grows, this practice has a few
|
|
||||||
key problems: a lack of organization, a lack of reusability, and difficulties
|
|
||||||
in management for teams.
|
|
||||||
|
|
||||||
_Modules_ in Terraform are self-contained packages of Terraform configurations
|
|
||||||
that are managed as a group. Modules are used to create reusable components,
|
|
||||||
improve organization, and to treat pieces of infrastructure as a black box.
|
|
||||||
|
|
||||||
This section of the getting started will cover the basics of using modules.
|
|
||||||
Writing modules is covered in more detail in the
|
|
||||||
[modules documentation](/docs/modules/index.html).
|
|
||||||
|
|
||||||
~> **Warning!** The examples on this page are _**not** eligible_ for
|
|
||||||
[the AWS free tier](https://aws.amazon.com/free/). Do not try the examples
|
|
||||||
on this page unless you're willing to spend a small amount of money.
|
|
||||||
|
|
||||||
## Using Modules
|
|
||||||
|
|
||||||
If you have any instances running from prior steps in the getting
|
|
||||||
started guide, use `terraform destroy` to destroy them, and remove all
|
|
||||||
configuration files.
|
|
||||||
|
|
||||||
The [Terraform Registry](https://registry.terraform.io/) includes a directory
|
|
||||||
of ready-to-use modules for various common purposes, which can serve as
|
|
||||||
larger building-blocks for your infrastructure.
|
|
||||||
|
|
||||||
In this example, we're going to use
|
|
||||||
[the Consul Terraform module for AWS](https://registry.terraform.io/modules/hashicorp/consul/aws),
|
|
||||||
which will set up a complete [Consul](https://www.consul.io) cluster.
|
|
||||||
This and other modules can be found via the search feature on the Terraform
|
|
||||||
Registry site.
|
|
||||||
|
|
||||||
Create a configuration file with the following contents:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
provider "aws" {
|
|
||||||
access_key = "AWS ACCESS KEY"
|
|
||||||
secret_key = "AWS SECRET KEY"
|
|
||||||
region = "us-east-1"
|
|
||||||
}
|
|
||||||
|
|
||||||
module "consul" {
|
|
||||||
source = "hashicorp/consul/aws"
|
|
||||||
|
|
||||||
num_servers = "3"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The `module` block begins with the example given on the Terraform Registry
|
|
||||||
page for this module, telling Terraform to create and manage this module.
|
|
||||||
This is similar to a `resource` block: it has a name used within this
|
|
||||||
configuration -- in this case, `"consul"` -- and a set of input values
|
|
||||||
that are listed in
|
|
||||||
[the module's "Inputs" documentation](https://registry.terraform.io/modules/hashicorp/consul/aws?tab=inputs).
|
|
||||||
|
|
||||||
(Note that the `provider` block can be omitted in favor of environment
|
|
||||||
variables. See the [AWS Provider docs](/docs/providers/aws/index.html)
|
|
||||||
for details. This module requires that your AWS account has a default VPC.)
|
|
||||||
|
|
||||||
The `source` attribute is the only mandatory argument for modules. It tells
|
|
||||||
Terraform where the module can be retrieved. Terraform automatically
|
|
||||||
downloads and manages modules for you.
|
|
||||||
|
|
||||||
In this case, the module is retrieved from the official Terraform Registry.
|
|
||||||
Terraform can also retrieve modules from a variety of sources, including
|
|
||||||
private module registries or directly from Git, Mercurial, HTTP, and local
|
|
||||||
files.
|
|
||||||
|
|
||||||
The other attributes shown are inputs to our module. This module supports many
|
|
||||||
additional inputs, but all are optional and have reasonable values for
|
|
||||||
experimentation.
|
|
||||||
|
|
||||||
After adding a new module to configuration, it is necessary to run (or re-run)
|
|
||||||
`terraform init` to obtain and install the new module's source code:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform init
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
By default, this command does not check for new module versions that may be
|
|
||||||
available, so it is safe to run multiple times. The `-upgrade` option will
|
|
||||||
additionally check for any newer versions of existing modules and providers
|
|
||||||
that may be available.
|
|
||||||
|
|
||||||
## Apply Changes
|
|
||||||
|
|
||||||
With the Consul module (and its dependencies) installed, we can now apply
|
|
||||||
these changes to create the resources described within.
|
|
||||||
|
|
||||||
If you run `terraform apply`, you will see a large list of all of the
|
|
||||||
resources encapsulated in the module. The output is similar to what we
|
|
||||||
saw when using resources directly, but the resource names now have
|
|
||||||
module paths prefixed to their names, like in the following example:
|
|
||||||
|
|
||||||
```
|
|
||||||
+ module.consul.module.consul_clients.aws_autoscaling_group.autoscaling_group
|
|
||||||
id: <computed>
|
|
||||||
arn: <computed>
|
|
||||||
default_cooldown: <computed>
|
|
||||||
desired_capacity: "6"
|
|
||||||
force_delete: "false"
|
|
||||||
health_check_grace_period: "300"
|
|
||||||
health_check_type: "EC2"
|
|
||||||
launch_configuration: "${aws_launch_configuration.launch_configuration.name}"
|
|
||||||
max_size: "6"
|
|
||||||
metrics_granularity: "1Minute"
|
|
||||||
min_size: "6"
|
|
||||||
name: <computed>
|
|
||||||
protect_from_scale_in: "false"
|
|
||||||
tag.#: "2"
|
|
||||||
tag.2151078592.key: "consul-clients"
|
|
||||||
tag.2151078592.propagate_at_launch: "true"
|
|
||||||
tag.2151078592.value: "consul-example"
|
|
||||||
tag.462896764.key: "Name"
|
|
||||||
tag.462896764.propagate_at_launch: "true"
|
|
||||||
tag.462896764.value: "consul-example-client"
|
|
||||||
termination_policies.#: "1"
|
|
||||||
termination_policies.0: "Default"
|
|
||||||
vpc_zone_identifier.#: "6"
|
|
||||||
vpc_zone_identifier.1880739334: "subnet-5ce4282a"
|
|
||||||
vpc_zone_identifier.3458061785: "subnet-16600f73"
|
|
||||||
vpc_zone_identifier.4176925006: "subnet-485abd10"
|
|
||||||
vpc_zone_identifier.4226228233: "subnet-40a9b86b"
|
|
||||||
vpc_zone_identifier.595613151: "subnet-5131b95d"
|
|
||||||
vpc_zone_identifier.765942872: "subnet-595ae164"
|
|
||||||
wait_for_capacity_timeout: "10m"
|
|
||||||
```
|
|
||||||
|
|
||||||
The `module.consul.module.consul_clients` prefix shown above indicates
|
|
||||||
not only that the resource is from the `module "consul"` block we wrote,
|
|
||||||
but in fact that this module has its own `module "consul_clients"` block
|
|
||||||
within it. Modules can be nested to decompose complex systems into
|
|
||||||
manageable components.
|
|
||||||
|
|
||||||
The full set of resources created by this module includes an autoscaling group,
|
|
||||||
security groups, IAM roles and other individual resources that all support
|
|
||||||
the Consul cluster that will be created.
|
|
||||||
|
|
||||||
Note that as we warned above, the resources created by this module are
|
|
||||||
not eligible for the AWS free tier and so proceeding further will have some
|
|
||||||
cost associated. To proceed with the creation of the Consul cluster, type
|
|
||||||
`yes` at the confirmation prompt.
|
|
||||||
|
|
||||||
```
|
|
||||||
# ...
|
|
||||||
|
|
||||||
module.consul.module.consul_clients.aws_security_group.lc_security_group: Creating...
|
|
||||||
description: "" => "Security group for the consul-example-client launch configuration"
|
|
||||||
egress.#: "" => "<computed>"
|
|
||||||
ingress.#: "" => "<computed>"
|
|
||||||
name: "" => "<computed>"
|
|
||||||
name_prefix: "" => "consul-example-client"
|
|
||||||
owner_id: "" => "<computed>"
|
|
||||||
revoke_rules_on_delete: "" => "false"
|
|
||||||
vpc_id: "" => "vpc-22099946"
|
|
||||||
|
|
||||||
# ...
|
|
||||||
|
|
||||||
Apply complete! Resources: 34 added, 0 changed, 0 destroyed.
|
|
||||||
```
|
|
||||||
|
|
||||||
After several minutes and many log messages about all of the resources
|
|
||||||
being created, you'll have a three-server Consul cluster up and running.
|
|
||||||
Without needing any knowledge of how Consul works, how to install Consul,
|
|
||||||
or how to form a Consul cluster, you've created a working cluster in just
|
|
||||||
a few minutes.
|
|
||||||
|
|
||||||
## Module Outputs
|
|
||||||
|
|
||||||
Just as the module instance had input arguments such as `num_servers` above,
|
|
||||||
a module can also produce _output_ values, similar to resource attributes.
|
|
||||||
|
|
||||||
[The module's outputs reference](https://registry.terraform.io/modules/hashicorp/consul/aws?tab=outputs)
|
|
||||||
describes all of the different values it produces. Overall, it exposes the
|
|
||||||
id of each of the resources it creates, as well as echoing back some of the
|
|
||||||
input values.
|
|
||||||
|
|
||||||
One of the supported outputs is called `asg_name_servers`, and its value
|
|
||||||
is the name of the auto-scaling group that was created to manage the Consul
|
|
||||||
servers.
|
|
||||||
|
|
||||||
To reference this, we'll just put it into our _own_ output value. This
|
|
||||||
value could actually be used anywhere: in another resource, to configure
|
|
||||||
another provider, etc.
|
|
||||||
|
|
||||||
Add the following to the end of the existing configuration file created
|
|
||||||
above:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
output "consul_server_asg_name" {
|
|
||||||
value = "${module.consul.asg_name_servers}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The syntax for referencing module outputs is `${module.NAME.OUTPUT}`, where
|
|
||||||
`NAME` is the module name given in the header of the `module` configuration
|
|
||||||
block and `OUTPUT` is the name of the output to reference.
|
|
||||||
|
|
||||||
If you run `terraform apply` again, Terraform will make no changes to
|
|
||||||
infrastructure, but you'll now see the "consul\_server\_asg\_name" output with
|
|
||||||
the name of the created auto-scaling group:
|
|
||||||
|
|
||||||
```
|
|
||||||
# ...
|
|
||||||
|
|
||||||
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
|
|
||||||
|
|
||||||
Outputs:
|
|
||||||
|
|
||||||
consul_server_asg_name = tf-asg-2017103123350991200000000a
|
|
||||||
```
|
|
||||||
|
|
||||||
If you look in the Auto-scaling Groups section of the EC2 console you should
|
|
||||||
find an autoscaling group of this name, and from there find the three
|
|
||||||
Consul servers it is running. (If you can't find it, make sure you're looking
|
|
||||||
in the right region!)
|
|
||||||
|
|
||||||
## Destroy
|
|
||||||
|
|
||||||
Just as with top-level resources, we can destroy the resources created by
|
|
||||||
the Consul module to avoid ongoing costs:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform destroy
|
|
||||||
# ...
|
|
||||||
|
|
||||||
Terraform will perform the following actions:
|
|
||||||
|
|
||||||
- module.consul.module.consul_clients.aws_autoscaling_group.autoscaling_group
|
|
||||||
|
|
||||||
- module.consul.module.consul_clients.aws_iam_instance_profile.instance_profile
|
|
||||||
|
|
||||||
- module.consul.module.consul_clients.aws_iam_role.instance_role
|
|
||||||
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
As usual, Terraform describes all of the actions it will take. In this case,
|
|
||||||
it plans to destroy all of the resources that were created by the module.
|
|
||||||
Type `yes` to confirm and, after a few minutes and even more log output,
|
|
||||||
all of the resources should be destroyed:
|
|
||||||
|
|
||||||
```
|
|
||||||
Destroy complete! Resources: 34 destroyed.
|
|
||||||
```
|
|
||||||
|
|
||||||
With all of the resources destroyed, you can delete the configuration file
|
|
||||||
we created above. We will not make any further use of it, and so this avoids
|
|
||||||
the risk of accidentally re-creating the Consul cluster.
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
For more information on modules, the types of sources supported, how
|
|
||||||
to write modules, and more, read the in-depth
|
|
||||||
[module documentation](/docs/modules/index.html).
|
|
||||||
|
|
||||||
Next, we learn about [Terraform's remote collaboration features](/intro/getting-started/remote.html).
|
|
|
@ -1,30 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Next Steps"
|
|
||||||
sidebar_current: "gettingstarted-nextsteps"
|
|
||||||
description: |-
|
|
||||||
That concludes the getting started guide for Terraform. Hopefully you're now able to not only see what Terraform is useful for, but you're also able to put this knowledge to use to improve building your own infrastructure.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Next Steps
|
|
||||||
|
|
||||||
That concludes the getting started guide for Terraform. Hopefully
|
|
||||||
you're now able to not only see what Terraform is useful for, but
|
|
||||||
you're also able to put this knowledge to use to improve building
|
|
||||||
your own infrastructure.
|
|
||||||
|
|
||||||
We've covered the basics for all of these features in this guide.
|
|
||||||
|
|
||||||
As a next step, the following resources are available:
|
|
||||||
|
|
||||||
* [Documentation](/docs/index.html) - The documentation is an in-depth
|
|
||||||
reference guide to all the features of Terraform, including
|
|
||||||
technical details about the internals of how Terraform operates.
|
|
||||||
|
|
||||||
* [Examples](/intro/examples/index.html) - The examples have more full
|
|
||||||
featured configuration files, showing some of the possibilities
|
|
||||||
with Terraform.
|
|
||||||
|
|
||||||
* [Import](/docs/import/index.html) - The import section of the documentation
|
|
||||||
covers importing existing infrastructure into Terraform.
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Output Variables"
|
|
||||||
sidebar_current: "gettingstarted-outputs"
|
|
||||||
description: |-
|
|
||||||
In the previous section, we introduced input variables as a way to parameterize Terraform configurations. In this page, we introduce output variables as a way to organize data to be easily queried and shown back to the Terraform user.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Output Variables
|
|
||||||
|
|
||||||
In the previous section, we introduced input variables as a way
|
|
||||||
to parameterize Terraform configurations. In this page, we
|
|
||||||
introduce output variables as a way to organize data to be
|
|
||||||
easily queried and shown back to the Terraform user.
|
|
||||||
|
|
||||||
When building potentially complex infrastructure, Terraform
|
|
||||||
stores hundreds or thousands of attribute values for all your
|
|
||||||
resources. But as a user of Terraform, you may only be interested
|
|
||||||
in a few values of importance, such as a load balancer IP,
|
|
||||||
VPN address, etc.
|
|
||||||
|
|
||||||
Outputs are a way to tell Terraform what data is important.
|
|
||||||
This data is outputted when `apply` is called, and can be
|
|
||||||
queried using the `terraform output` command.
|
|
||||||
|
|
||||||
## Defining Outputs
|
|
||||||
|
|
||||||
Let's define an output to show us the public IP address of the
|
|
||||||
elastic IP address that we create. Add this to any of your
|
|
||||||
`*.tf` files:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
output "ip" {
|
|
||||||
value = "${aws_eip.ip.public_ip}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This defines an output variable named "ip". The name of the variable
|
|
||||||
must conform to Terraform variable naming conventions if it is
|
|
||||||
to be used as an input to other modules. The `value` field
|
|
||||||
specifies what the value will be, and almost always contains
|
|
||||||
one or more interpolations, since the output data is typically
|
|
||||||
dynamic. In this case, we're outputting the
|
|
||||||
`public_ip` attribute of the elastic IP address.
|
|
||||||
|
|
||||||
Multiple `output` blocks can be defined to specify multiple
|
|
||||||
output variables.
|
|
||||||
|
|
||||||
## Viewing Outputs
|
|
||||||
|
|
||||||
Run `terraform apply` to populate the output. This only needs
|
|
||||||
to be done once after the output is defined. The apply output
|
|
||||||
should change slightly. At the end you should see this:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply
|
|
||||||
...
|
|
||||||
|
|
||||||
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
|
|
||||||
|
|
||||||
Outputs:
|
|
||||||
|
|
||||||
ip = 50.17.232.209
|
|
||||||
```
|
|
||||||
|
|
||||||
`apply` highlights the outputs. You can also query the outputs
|
|
||||||
after apply-time using `terraform output`:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform output ip
|
|
||||||
50.17.232.209
|
|
||||||
```
|
|
||||||
|
|
||||||
This command is useful for scripts to extract outputs.
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
You now know how to parameterize configurations with input
|
|
||||||
variables, extract important data using output variables,
|
|
||||||
and bootstrap resources using provisioners.
|
|
||||||
|
|
||||||
Next, we're going to take a look at
|
|
||||||
[how to use modules](/intro/getting-started/modules.html), a useful
|
|
||||||
abstraction to organize and reuse Terraform configurations.
|
|
|
@ -1,128 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Provision"
|
|
||||||
sidebar_current: "gettingstarted-provision"
|
|
||||||
description: |-
|
|
||||||
Introduces provisioners that can initialize instances when they're created.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Provision
|
|
||||||
|
|
||||||
You're now able to create and modify infrastructure. Now let's see
|
|
||||||
how to use provisioners to initialize instances when they're created.
|
|
||||||
|
|
||||||
If you're using an image-based infrastructure (perhaps with images
|
|
||||||
created with [Packer](https://www.packer.io)), then what you've
|
|
||||||
learned so far is good enough. But if you need to do some initial
|
|
||||||
setup on your instances, then provisioners let you upload files,
|
|
||||||
run shell scripts, or install and trigger other software like
|
|
||||||
configuration management tools, etc.
|
|
||||||
|
|
||||||
## Defining a Provisioner
|
|
||||||
|
|
||||||
To define a provisioner, modify the resource block defining the
|
|
||||||
"example" EC2 instance to look like the following:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
resource "aws_instance" "example" {
|
|
||||||
ami = "ami-b374d5a5"
|
|
||||||
instance_type = "t2.micro"
|
|
||||||
|
|
||||||
provisioner "local-exec" {
|
|
||||||
command = "echo ${aws_instance.example.public_ip} > ip_address.txt"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This adds a `provisioner` block within the `resource` block. Multiple
|
|
||||||
`provisioner` blocks can be added to define multiple provisioning steps.
|
|
||||||
Terraform supports
|
|
||||||
[multiple provisioners](/docs/provisioners/index.html),
|
|
||||||
but for this example we are using the `local-exec` provisioner.
|
|
||||||
|
|
||||||
The `local-exec` provisioner executes a command locally on the machine
|
|
||||||
running Terraform. We're using this provisioner versus the others so
|
|
||||||
we don't have to worry about specifying any
|
|
||||||
[connection info](/docs/provisioners/connection.html) right now.
|
|
||||||
|
|
||||||
## Running Provisioners
|
|
||||||
|
|
||||||
Provisioners are only run when a resource is _created_. They
|
|
||||||
are not a replacement for configuration management and changing
|
|
||||||
the software of an already-running server, and are instead just
|
|
||||||
meant as a way to bootstrap a server. For configuration management,
|
|
||||||
you should use Terraform provisioning to invoke a real configuration
|
|
||||||
management solution.
|
|
||||||
|
|
||||||
Make sure that your infrastructure is
|
|
||||||
[destroyed](/intro/getting-started/destroy.html) if it isn't already,
|
|
||||||
then run `apply`:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply
|
|
||||||
# ...
|
|
||||||
|
|
||||||
aws_instance.example: Creating...
|
|
||||||
ami: "" => "ami-b374d5a5"
|
|
||||||
instance_type: "" => "t2.micro"
|
|
||||||
aws_eip.ip: Creating...
|
|
||||||
instance: "" => "i-213f350a"
|
|
||||||
|
|
||||||
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
|
|
||||||
```
|
|
||||||
|
|
||||||
Terraform will output anything from provisioners to the console,
|
|
||||||
but in this case there is no output. However, we can verify
|
|
||||||
everything worked by looking at the `ip_address.txt` file:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ cat ip_address.txt
|
|
||||||
54.192.26.128
|
|
||||||
```
|
|
||||||
|
|
||||||
It contains the IP, just as we asked!
|
|
||||||
|
|
||||||
## Failed Provisioners and Tainted Resources
|
|
||||||
|
|
||||||
If a resource successfully creates but fails during provisioning,
|
|
||||||
Terraform will error and mark the resource as "tainted". A
|
|
||||||
resource that is tainted has been physically created, but can't
|
|
||||||
be considered safe to use since provisioning failed.
|
|
||||||
|
|
||||||
When you generate your next execution plan, Terraform will not attempt to restart
|
|
||||||
provisioning on the same resource because it isn't guaranteed to be safe. Instead,
|
|
||||||
Terraform will remove any tainted resources and create new resources, attempting to
|
|
||||||
provision them again after creation.
|
|
||||||
|
|
||||||
Terraform also does not automatically roll back and destroy the resource
|
|
||||||
during the apply when the failure happens, because that would go
|
|
||||||
against the execution plan: the execution plan would've said a
|
|
||||||
resource will be created, but does not say it will ever be deleted.
|
|
||||||
If you create an execution plan with a tainted resource, however, the
|
|
||||||
plan will clearly state that the resource will be destroyed because
|
|
||||||
it is tainted.
|
|
||||||
|
|
||||||
## Destroy Provisioners
|
|
||||||
|
|
||||||
Provisioners can also be defined that run only during a destroy
|
|
||||||
operation. These are useful for performing system cleanup, extracting
|
|
||||||
data, etc.
|
|
||||||
|
|
||||||
For many resources, using built-in cleanup mechanisms is recommended
|
|
||||||
if possible (such as init scripts), but provisioners can be used if
|
|
||||||
necessary.
|
|
||||||
|
|
||||||
The getting started guide won't show any destroy provisioner examples.
|
|
||||||
If you need to use destroy provisioners, please
|
|
||||||
[see the provisioner documentation](/docs/provisioners).
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
Provisioning is important for being able to bootstrap instances.
|
|
||||||
As another reminder, it is not a replacement for configuration
|
|
||||||
management. It is meant to simply bootstrap machines. If you use
|
|
||||||
configuration management, you should use the provisioning as a way
|
|
||||||
to bootstrap the configuration management tool.
|
|
||||||
|
|
||||||
In the next section, we start looking at [variables as a way to
|
|
||||||
parameterize our configurations](/intro/getting-started/variables.html).
|
|
|
@ -1,113 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Terraform Remote"
|
|
||||||
sidebar_current: "gettingstarted-remote"
|
|
||||||
description: |-
|
|
||||||
We've now seen how to build, change, and destroy infrastructure from a local machine. However, you can use Atlas by HashiCorp to run Terraform remotely to version and audit the history of your infrastructure.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Remote Backends
|
|
||||||
|
|
||||||
We've now seen how to build, change, and destroy infrastructure
|
|
||||||
from a local machine. This is great for testing and development,
|
|
||||||
but in production environments it is more responsible to share responsibility
|
|
||||||
for infrastructure. The best way to do this is by running Terraform in a remote
|
|
||||||
environment with shared access to state.
|
|
||||||
|
|
||||||
Terraform supports team-based workflows with a feature known as [remote
|
|
||||||
backends](/docs/backends). Remote backends allow Terraform to use a shared
|
|
||||||
storage space for state data, so any member of your team can use Terraform to
|
|
||||||
manage the same infrastructure.
|
|
||||||
|
|
||||||
Depending on the features you wish to use, Terraform has multiple remote
|
|
||||||
backend options. You could use Consul for state storage, locking, and
|
|
||||||
environments. This is a free and open source option. You can use S3 which
|
|
||||||
only supports state storage, for a low cost and minimally featured solution.
|
|
||||||
|
|
||||||
[Terraform Cloud](https://www.hashicorp.com/products/terraform/?utm_source=oss&utm_medium=getting-started&utm_campaign=terraform)
|
|
||||||
is HashiCorp's commercial solution and also acts as a remote backend.
|
|
||||||
Terraform Cloud allows teams to easily version, audit, and collaborate
|
|
||||||
on infrastructure changes. Each proposed change generates
|
|
||||||
a Terraform plan which can be reviewed and collaborated on as a team.
|
|
||||||
When a proposed change is accepted, the Terraform logs are stored,
|
|
||||||
resulting in a linear history of infrastructure states to
|
|
||||||
help with auditing and policy enforcement. Additional benefits to
|
|
||||||
running Terraform remotely include moving access
|
|
||||||
credentials off of developer machines and freeing local machines
|
|
||||||
from long-running Terraform processes.
|
|
||||||
|
|
||||||
## How to Store State Remotely
|
|
||||||
|
|
||||||
First, we'll use [Consul](https://www.consul.io) as our backend. Consul
|
|
||||||
is a free and open source solution that provides state storage, locking, and
|
|
||||||
environments. It is a great way to get started with Terraform backends.
|
|
||||||
|
|
||||||
We'll use the [demo Consul server](https://demo.consul.io) for this guide.
|
|
||||||
This should not be used for real data. Additionally, the demo server doesn't
|
|
||||||
permit locking. If you want to play with [state locking](/docs/state/locking.html),
|
|
||||||
you'll have to run your own Consul server or use a backend that supports locking.
|
|
||||||
|
|
||||||
First, configure the backend in your configuration:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
terraform {
|
|
||||||
backend "consul" {
|
|
||||||
address = "demo.consul.io"
|
|
||||||
path = "getting-started-RANDOMSTRING"
|
|
||||||
lock = false
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Please replace "RANDOMSTRING" with some random text. The demo server is
|
|
||||||
public and we want to try to avoid overlapping with someone else running
|
|
||||||
through the getting started guide.
|
|
||||||
|
|
||||||
The `backend` section configures the backend you want to use. After
|
|
||||||
configuring a backend, run `terraform init` to setup Terraform. It should
|
|
||||||
ask if you want to migrate your state to Consul. Say "yes" and Terraform
|
|
||||||
will copy your state.
|
|
||||||
|
|
||||||
Now, if you run `terraform apply`, Terraform should state that there are
|
|
||||||
no changes:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply
|
|
||||||
# ...
|
|
||||||
|
|
||||||
No changes. Infrastructure is up-to-date.
|
|
||||||
|
|
||||||
This means that Terraform did not detect any differences between your
|
|
||||||
configuration and real physical resources that exist. As a result, Terraform
|
|
||||||
doesn't need to do anything.
|
|
||||||
```
|
|
||||||
|
|
||||||
Terraform is now storing your state remotely in Consul. Remote state
|
|
||||||
storage makes collaboration easier and keeps state and secret information
|
|
||||||
off your local disk. Remote state is loaded only in memory when it is used.
|
|
||||||
|
|
||||||
If you want to move back to local state, you can remove the backend configuration
|
|
||||||
block from your configuration and run `terraform init` again. Terraform will
|
|
||||||
once again ask if you want to migrate your state back to local.
|
|
||||||
|
|
||||||
## Terraform Cloud
|
|
||||||
|
|
||||||
[Terraform Cloud](https://www.hashicorp.com/products/terraform/?utm_source=oss&utm_medium=getting-started&utm_campaign=terraform) is a commercial solution which combines a predictable and reliable shared run environment with tools to help you work together on Terraform configurations and modules.
|
|
||||||
|
|
||||||
Although Terraform Cloud can act as a standard remote backend to support Terraform runs on local machines, it works even better as a remote run environment. It supports two main workflows for performing Terraform runs:
|
|
||||||
|
|
||||||
- A VCS-driven workflow, in which it automatically queues plans whenever changes are committed to your configuration's VCS repo.
|
|
||||||
- An API-driven workflow, in which a CI pipeline or other automated tool can upload configurations directly.
|
|
||||||
|
|
||||||
For a hands-on introduction to Terraform Cloud, [follow the Terraform Cloud getting started guide](/docs/cloud/getting-started/index.html).
|
|
||||||
|
|
||||||
|
|
||||||
## Next
|
|
||||||
You now know how to create, modify, destroy, version, and
|
|
||||||
collaborate on infrastructure. With these building blocks,
|
|
||||||
you can effectively experiment with any part of Terraform.
|
|
||||||
|
|
||||||
We've now concluded the getting started guide, however
|
|
||||||
there are a number of [next steps](/intro/getting-started/next-steps.html)
|
|
||||||
to get started with Terraform.
|
|
|
@ -1,259 +0,0 @@
|
||||||
---
|
|
||||||
layout: "intro"
|
|
||||||
page_title: "Input Variables"
|
|
||||||
sidebar_current: "gettingstarted-variables"
|
|
||||||
description: |-
|
|
||||||
You now have enough Terraform knowledge to create useful configurations, but we're still hardcoding access keys, AMIs, etc. To become truly shareable and committable to version control, we need to parameterize the configurations. This page introduces input variables as a way to do this.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Input Variables
|
|
||||||
|
|
||||||
You now have enough Terraform knowledge to create useful
|
|
||||||
configurations, but we're still hard-coding access keys,
|
|
||||||
AMIs, etc. To become truly shareable and version
|
|
||||||
controlled, we need to parameterize the configurations. This page
|
|
||||||
introduces input variables as a way to do this.
|
|
||||||
|
|
||||||
## Defining Variables
|
|
||||||
|
|
||||||
Let's first extract our access key, secret key, and region
|
|
||||||
into a few variables. Create another file `variables.tf` with
|
|
||||||
the following contents.
|
|
||||||
|
|
||||||
-> **Note**: that the file can be named anything, since Terraform loads all
|
|
||||||
files ending in `.tf` in a directory.
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
variable "access_key" {}
|
|
||||||
variable "secret_key" {}
|
|
||||||
variable "region" {
|
|
||||||
default = "us-east-1"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This defines three variables within your Terraform configuration. The first
|
|
||||||
two have empty blocks `{}`. The third sets a default. If a default value is
|
|
||||||
set, the variable is optional. Otherwise, the variable is required. If you run
|
|
||||||
`terraform plan` now, Terraform will prompt you for the values for unset string
|
|
||||||
variables.
|
|
||||||
|
|
||||||
## Using Variables in Configuration
|
|
||||||
|
|
||||||
Next, replace the AWS provider configuration with the following:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
provider "aws" {
|
|
||||||
access_key = "${var.access_key}"
|
|
||||||
secret_key = "${var.secret_key}"
|
|
||||||
region = "${var.region}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This uses more interpolations, this time prefixed with `var.`. This
|
|
||||||
tells Terraform that you're accessing variables. This configures
|
|
||||||
the AWS provider with the given variables.
|
|
||||||
|
|
||||||
## Assigning Variables
|
|
||||||
|
|
||||||
There are multiple ways to assign variables. Below is also the order
|
|
||||||
in which variable values are chosen. The following is the descending order
|
|
||||||
of precedence in which variables are considered.
|
|
||||||
|
|
||||||
#### Command-line flags
|
|
||||||
|
|
||||||
You can set variables directly on the command-line with the
|
|
||||||
`-var` flag. Any command in Terraform that inspects the configuration
|
|
||||||
accepts this flag, such as `apply`, `plan`, and `refresh`:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply \
|
|
||||||
-var 'access_key=foo' \
|
|
||||||
-var 'secret_key=bar'
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Once again, setting variables this way will not save them, and they'll
|
|
||||||
have to be input repeatedly as commands are executed.
|
|
||||||
|
|
||||||
#### From a file
|
|
||||||
|
|
||||||
To persist variable values, create a file and assign variables within
|
|
||||||
this file. Create a file named `terraform.tfvars` with the following
|
|
||||||
contents:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
access_key = "foo"
|
|
||||||
secret_key = "bar"
|
|
||||||
```
|
|
||||||
|
|
||||||
For all files which match `terraform.tfvars` or `*.auto.tfvars` present in the
|
|
||||||
current directory, Terraform automatically loads them to populate variables. If
|
|
||||||
the file is named something else, you can use the `-var-file` flag directly to
|
|
||||||
specify a file. These files are the same syntax as Terraform
|
|
||||||
configuration files. And like Terraform configuration files, these files
|
|
||||||
can also be JSON.
|
|
||||||
|
|
||||||
We don't recommend saving usernames and password to version control, but you
|
|
||||||
can create a local secret variables file and use `-var-file` to load it.
|
|
||||||
|
|
||||||
You can use multiple `-var-file` arguments in a single command, with some
|
|
||||||
checked in to version control and others not checked in. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply \
|
|
||||||
-var-file="secret.tfvars" \
|
|
||||||
-var-file="production.tfvars"
|
|
||||||
```
|
|
||||||
|
|
||||||
#### From environment variables
|
|
||||||
|
|
||||||
Terraform will read environment variables in the form of `TF_VAR_name`
|
|
||||||
to find the value for a variable. For example, the `TF_VAR_access_key`
|
|
||||||
variable can be set to set the `access_key` variable.
|
|
||||||
|
|
||||||
-> **Note**: Environment variables can only populate string-type variables.
|
|
||||||
List and map type variables must be populated via one of the other mechanisms.
|
|
||||||
|
|
||||||
#### UI Input
|
|
||||||
|
|
||||||
If you execute `terraform apply` with certain variables unspecified,
|
|
||||||
Terraform will ask you to input their values interactively. These
|
|
||||||
values are not saved, but this provides a convenient workflow when getting
|
|
||||||
started with Terraform. UI Input is not recommended for everyday use of
|
|
||||||
Terraform.
|
|
||||||
|
|
||||||
-> **Note**: In Terraform versions 0.11 and earlier, UI Input is only supported
|
|
||||||
for string variables. List and map variables must be populated via one of the
|
|
||||||
other mechanisms. Terraform 0.12 introduces the ability to populate complex
|
|
||||||
variable types from the UI prompt.
|
|
||||||
|
|
||||||
#### Variable Defaults
|
|
||||||
|
|
||||||
If no value is assigned to a variable via any of these methods and the
|
|
||||||
variable has a `default` key in its declaration, that value will be used
|
|
||||||
for the variable.
|
|
||||||
|
|
||||||
<a id="lists"></a>
|
|
||||||
## Lists
|
|
||||||
|
|
||||||
Lists are defined either explicitly or implicitly
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
# implicitly by using brackets [...]
|
|
||||||
variable "cidrs" { default = [] }
|
|
||||||
|
|
||||||
# explicitly
|
|
||||||
variable "cidrs" { type = "list" }
|
|
||||||
```
|
|
||||||
|
|
||||||
You can specify lists in a `terraform.tfvars` file:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
cidrs = [ "10.0.0.0/16", "10.1.0.0/16" ]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Maps
|
|
||||||
|
|
||||||
We've replaced our sensitive strings with variables, but we still
|
|
||||||
are hard-coding AMIs. Unfortunately, AMIs are specific to the region
|
|
||||||
that is in use. One option is to just ask the user to input the proper
|
|
||||||
AMI for the region, but Terraform can do better than that with
|
|
||||||
_maps_.
|
|
||||||
|
|
||||||
Maps are a way to create variables that are lookup tables. An example
|
|
||||||
will show this best. Let's extract our AMIs into a map and add
|
|
||||||
support for the `us-west-2` region as well:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
variable "amis" {
|
|
||||||
type = "map"
|
|
||||||
default = {
|
|
||||||
"us-east-1" = "ami-b374d5a5"
|
|
||||||
"us-west-2" = "ami-4b32be2b"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A variable can have a `map` type assigned explicitly, or it can be implicitly
|
|
||||||
declared as a map by specifying a default value that is a map. The above
|
|
||||||
demonstrates both.
|
|
||||||
|
|
||||||
Then, replace the `aws_instance` with the following:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
resource "aws_instance" "example" {
|
|
||||||
ami = "${lookup(var.amis, var.region)}"
|
|
||||||
instance_type = "t2.micro"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This introduces a new type of interpolation: a function call. The
|
|
||||||
`lookup` function does a dynamic lookup in a map for a key. The
|
|
||||||
key is `var.region`, which specifies that the value of the region
|
|
||||||
variables is the key.
|
|
||||||
|
|
||||||
While we don't use it in our example, it is worth noting that you
|
|
||||||
can also do a static lookup of a map directly with
|
|
||||||
`${var.amis["us-east-1"]}`.
|
|
||||||
|
|
||||||
## Assigning Maps
|
|
||||||
|
|
||||||
We set defaults above, but maps can also be set using the `-var` and
|
|
||||||
`-var-file` values. For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply -var 'amis={ us-east-1 = "foo", us-west-2 = "bar" }'
|
|
||||||
# ...
|
|
||||||
```
|
|
||||||
|
|
||||||
-> **Note**: Even if every key will be assigned as input, the variable must be
|
|
||||||
established as a map by setting its default to `{}`.
|
|
||||||
|
|
||||||
Here is an example of setting a map's keys from a file. Starting with these
|
|
||||||
variable definitions:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
variable "region" {}
|
|
||||||
variable "amis" {
|
|
||||||
type = "map"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can specify keys in a `terraform.tfvars` file:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
amis = {
|
|
||||||
"us-east-1" = "ami-abc123"
|
|
||||||
"us-west-2" = "ami-def456"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
And access them via `lookup()`:
|
|
||||||
|
|
||||||
```hcl
|
|
||||||
output "ami" {
|
|
||||||
value = "${lookup(var.amis, var.region)}"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Like so:
|
|
||||||
|
|
||||||
```
|
|
||||||
$ terraform apply -var region=us-west-2
|
|
||||||
|
|
||||||
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
|
|
||||||
|
|
||||||
Outputs:
|
|
||||||
|
|
||||||
ami = ami-def456
|
|
||||||
```
|
|
||||||
|
|
||||||
## Next
|
|
||||||
|
|
||||||
Terraform provides variables for parameterizing your configurations.
|
|
||||||
Maps let you build lookup tables in cases where that makes sense.
|
|
||||||
Setting and using variables is uniform throughout your configurations.
|
|
||||||
|
|
||||||
In the next section, we'll take a look at
|
|
||||||
[output variables](/intro/getting-started/outputs.html) as a mechanism
|
|
||||||
to expose certain values more prominently to the Terraform operator.
|
|
|
@ -75,5 +75,5 @@ See the page on [Terraform use cases](/intro/use-cases.html) to see the
|
||||||
multiple ways Terraform can be used. Then see
|
multiple ways Terraform can be used. Then see
|
||||||
[how Terraform compares to other software](/intro/vs/index.html)
|
[how Terraform compares to other software](/intro/vs/index.html)
|
||||||
to see how it fits into your existing infrastructure. Finally, continue onwards with
|
to see how it fits into your existing infrastructure. Finally, continue onwards with
|
||||||
the [getting started guide](/intro/getting-started/install.html) to use
|
the [getting started guide](https://learn.hashicorp.com/terraform/getting-started/install) to use
|
||||||
Terraform to manage real infrastructure and to see how it works.
|
Terraform to manage real infrastructure and to see how it works.
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
<ul class="nav docs-sidenav">
|
<ul class="nav docs-sidenav">
|
||||||
<li<%= sidebar_current("guides-getting-started") %>>
|
<li<%= sidebar_current("guides-getting-started") %>>
|
||||||
<a href="/intro/getting-started/install.html">Getting Started</a>
|
<a href="https://learn.hashicorp.com/terraform#getting-started">Getting Started</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("guides-core-workflow") %>>
|
<li<%= sidebar_current("guides-core-workflow") %>>
|
||||||
|
|
|
@ -34,45 +34,6 @@
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li<%= sidebar_current("gettingstarted") %>>
|
|
||||||
<a href="/intro/getting-started/install.html">Getting Started</a>
|
|
||||||
<ul class="nav">
|
|
||||||
<li<%= sidebar_current("gettingstarted-install") %>>
|
|
||||||
<a href="/intro/getting-started/install.html">Install Terraform</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-build") %>>
|
|
||||||
<a href="/intro/getting-started/build.html">Build Infrastructure</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-change") %>>
|
|
||||||
<a href="/intro/getting-started/change.html">Change Infrastructure</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-destroy") %>>
|
|
||||||
<a href="/intro/getting-started/destroy.html">Destroy Infrastructure</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-deps") %>>
|
|
||||||
<a href="/intro/getting-started/dependencies.html">Resource Dependencies</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-provision") %>>
|
|
||||||
<a href="/intro/getting-started/provision.html">Provision</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-variables") %>>
|
|
||||||
<a href="/intro/getting-started/variables.html">Input Variables</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-outputs") %>>
|
|
||||||
<a href="/intro/getting-started/outputs.html">Output Variables</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-modules") %>>
|
|
||||||
<a href="/intro/getting-started/modules.html">Modules</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-remote") %>>
|
|
||||||
<a href="/intro/getting-started/remote.html">Remote Backends</a>
|
|
||||||
</li>
|
|
||||||
<li<%= sidebar_current("gettingstarted-nextsteps") %>>
|
|
||||||
<a href="/intro/getting-started/next-steps.html">Next Steps</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li<%= sidebar_current("examples") %>>
|
<li<%= sidebar_current("examples") %>>
|
||||||
<a href="/intro/examples/index.html">Example Configurations</a>
|
<a href="/intro/examples/index.html">Example Configurations</a>
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
|
|
Loading…
Reference in New Issue