[go: up one dir, main page]

0% found this document useful (0 votes)
19 views7 pages

Terraform Resources

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views7 pages

Terraform Resources

Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 7

Chapter 3 - Your First Terraform

Project
In this chapter we are going to create your first Terraform project. We are not
going to cover
everything in great detail as we will circle back and cover it in more detail in
later chapters. I want
the focus of this chapter to be about getting a feel for running Terraform and
actually creating some
infrastructure with it.
Code samples
All of the code samples given in this book will be on github in the repository:
https://github.com/kevholditch/terraformbeginner-
to-master-examples.
You can either type them in yourself from the book or feel free to clone the repo
or just copy and
paste them from github. The examples are grouped into folders at the top level of
the repository. I
will give the folder name of each sample as it is used.
Setting up your first project
1. Create a folder named MyFirstTerraformProject on your hard drive
2. Inside the folder create a file named main.tf
3. Inside the file main.tf paste the following text (replace <yourname> with your
name or
something unique):
1 provider "aws" {
2 region = "eu-west-1"
3 }
4
5 resource "aws_s3_bucket" "first_bucket" {
6 bucket = "<yourname>-first-bucket"
7 }
If you want to copy the code from the sample repository it is in the folder named
first_terraform_-
project
That’s all we need for our first Terraform project. The Terraform code we have just
written will
create an S3 bucket in AWS with the name <yourname>-first-bucket in the region eu-
west-1. I
Chapter 3 - Your First Terraform Project 11
reckon you could pretty much guess what it is going to even if you did not know
Terraform. That
is one of the strong parts of Terraform in that the code is very readable and
normally quite obvious
what is going to happen.
Lets take a second to explain each part of the code in a bit more detail. In the
first 3 lines we are
defining the provider that we want to use. Terraform itself is just an engine that
knows how to run
a provider that conforms to an interface. The Terraform engine is smart and knows
how to create
dependency trees and plans and it uses the provider to interface with the outside
world. As in this
book we are going to be using Terraform with AWS we need to configure the AWS
provider.
To configure the provider we use the keyword provider then follow it with the name
of the provider
in quotes in this case "aws". We start the provider block by opening a curly brace
{. We can now
specify any parameters we want to configure the provider. To pass a parameter you
simply put the
name of the parameter followed by an equals sign then the value you want to give
the parameter in
quotes, in our example we are setting the region this provider will use to be eu-
west-1. This is the
region where the AWS Terraform provider will create all of the infrastructure we
define. We then
end the provider block with a closing curly brace }.
The next block we have defined is a resource. A resource in Terraform represents a
thing in the
real world. In this case an S3 bucket. To define a resource you start a resource
block by using the
keyword resource. You then follow it with the resource you want to create in
quotes. We want to
create an S3 bucket so we are using the S3 resource "aws_s3_bucket". If you are
following along in
IntelliJ and typing in the code you might have noticed that IntelliJ gave you a
full list of possible
resources once you started typing. You can see the full list on the AWS provider
page if you are
interested: https://www.terraform.io/docs/providers/aws/index.html. After we have
specified the
type of resource we want to create we then put another space and then the
identifier you want
to give that resource in quotes, in our example "first_bucket". We then open the
block in the
same way that we did for the provider block with an opening curly brace {. Next we
can give any
parameters the resource takes values. We are only setting the name of the bucket.
You then end the
resource block with a closing }.
Creating your first infrastructure with Terraform
The first thing you have to do with a new Terraform project is initialise Terraform
for that project.
To do this go to your Terminal and cd into the folder where your project is, if you
followed this guide
exactly then cd into the folder named MyFirstTerraformProject. Now run the
following command:
1 terraform init
You will see some output on the screen as Terraform initialises, then you should
see the message
Terraform has been successfully initialized!. Once you have initialised Terraform
you are
now ready to create the infrastructure by running:
Chapter 3 - Your First Terraform Project 12
1 terraform apply
After you run the apply you will see quite a lot of output from Terraform. You will
notice that the
apply has paused and is awaiting a response from you.
Lets pause for a second and look at what is happening here. By default when you run
terraform
apply Terraform will look at the code you have written and then compare it to the
infrastructure
that you currently have (in this case in AWS). Once Terraform has done this it
calculates a plan.
The plan is what Terraform is going to do to get the real infrastructure from where
it is now to
how you have specified you want it to be in code. From looking at the plan we can
see Terraform
is saying if you do this it will create an S3 bucket. You have told Terraform you
want an S3 bucket
and Terraform went to AWS to check and realised that there is not an S3 bucket in
AWS with that
name, so it knows that the plan it needs to do is create the bucket. Plans will be
discussed in much
more detail later in this book.
The great thing about this plan is that Terraform presents it to us and then pauses
and lets us decide
whether we want to go ahead. You can imagine how useful this is if you accidentally
make a change
that is going to destroy your database! To get Terraform to make these changes and
create the S3
bucket type yes and press enter.
Once the apply has finished you should see the message Apply complete! Resources: 1
added,
0 changed, 0 destroyed.. This is Terraform telling you that it successfully created
the S3 bucket
for you. Log onto the aws console (website), go to the S3 section and you will see
the bucket that
Terraform created. Delete the bucket from the AWS console. Now go back to the
terminal and run
terraform apply again. You will notice that Terraform has worked out the S3 bucket
is not there
anymore so it needs to create it again. At no point did you tell Terraform the
bucket was gone,
Terraform worked it out. Confirm the apply (by typing yes) so the S3 bucket exists
again. Now run
terraform apply again when the bucket is there. You will see Terraform output Apply
complete!
Resources: 0 added, 0 changed, 0 destroyed.. Terraform realises that the state of
the world is
exactly how you want it to be, so Terraform is saying “nothing to do here!”.
To finish up lets destroy the infrastructure we created, don’t worry Terraform can
take care of that
for us. Simply run the command terraform destroy. Terraform will present a plan to
you of what it
is going to destroy and then pause so you can confirm. Type yes and press enter.
When the destroy
finishes you will see a message Destroy complete! Resources: 1 destroyed.. This is
telling you
Terraform has successfully destroyed everything. Log into the AWS console and go to
S3 and you
will see that the bucket is now gone.
That concludes our first experience with Terraform. I hope that you can start to
see the power that
Terraform provides and how simple it is to use. Feel free to play around with this
project and try
changing the properties like the name of the S3 bucket and see what happens. That
is a great way
to learn. Just remember to run terraform destroy when you are finished to ensure
that you are not
left with any infrastructure running in AWS.
Do not worry if you had more questions about any of the steps we have just been
through. We are
going to cover everything in much more detail. I wanted to give you a taster for
Terraform in action
so you could see how powerful it is!
Chapter 4 - Resources
Resources in detail
Resources in Terraform represent a thing in the real world. For example a resource
could be an AWS
Load Balancer, an alarm in PagerDuty, a policy in Vault, the list is pretty much
endless. The resource
is the bedrock of Terraform. It allows you to define how you want to create
something in the real
world. Remember you can create resources that represent things from multiple
vendors (for example
multiple clouds) in a single project.
Lets take a look in a bit more detail at the resource we defined in the previous
chapter:
1 resource "aws_s3_bucket" "first_bucket" {
2 bucket = "<yourname>-first-bucket"
3 }
The resource type aws_s3_bucket starts with the name of the provider followed by an
underscore
(aws_). This allows you to tell just from the first word of the resource which
vendor or component
this resource will be created in. Lets take a look at a few other examples:
1 resource "google_folder" "department" {
2 display_name = "Department"
3 parent = "organisation/1234567"
4 }
The department resource above will create a folder in Google Cloud (GCP). You can
see that it
starts with google_ which is the name of the Google Cloud (GCP) provider. Every
resource for this
provider will start with google_.
1 resource "postgresql_role" "my_role" {
2 name = "my_role"
3 login = true
4 password = "password123"
5 }
The my_role resource above will create a login on a Postgres database, with log in
name my_role
and password password123. The resource name starts postgresql_ as will every
resource for the
Postgres provider.
Chapter 4 - Resources 14
If we look back at our S3 bucket resource the last word on the line in quotes was
"first_bucket".
This is the identifier for that S3 bucket within your Terraform project. The
identifier is what we use
inside our project to refer to an instance of a resource. You can create multiple
instances of the same
resource for example you could create many S3 buckets. The identifier gives you a
way to reference
each one.
The key name value pairs that make up the body of the resource are the properties
for the resource.
Some properties on the resource are mandatory and some are optional. For an AWS S3
bucket the
only mandatory property is the name of the bucket. We could have set more
properties on the bucket
for example:
1 resource "aws_s3_bucket" "first_bucket" {
2 bucket = "kevholditch-first-bucket"
3 acl = "private"
4
5 versioning {
6 enabled = true
7 mfa_delete = false
8 }
9 }
In the above example (which you can find in the repository folder
resources_example_01 if you want
to copy the code across) we are setting the acl to private which is basically
saying that this bucket
will only allow private access. We are also setting two properties for versioning,
one to say we are
enabling versioning and another to say that you do not require MFA to delete an
item on this bucket.
With the properties for versioning you will notice that these are nested in another
object. This is a
design choice by the resource creator that groups all of the versioning properties
together. You may
also notice that the two properties in the versioning section are booleans
(true/false). These do not
require quotes around them like strings do as we have used for the other two
properties.
You can get a full list of all of the properties that are supported from the
Terraform provider documentation
page, for an S3 bucket it is:
https://www.terraform.io/docs/providers/aws/r/s3_bucket.html.
You can find the documentation quite easily on Google.
Lets take a look at another resource type so we can examine the other data types
that resources can
take in their properties:
Chapter 4 - Resources 15
1 resource "aws_security_group" "my_security_group" {
2 name = "allow_tls"
3 ingress {
4 protocol = "tcp"
5 from_port = 443
6 to_port = 443
7 cidr_blocks = ["10.0.0.0/16", "11.0.0.0/16"]
8 }
9 }
In the resource above we have the two other types of data resources can take
numbers and lists. The
port properties (from_port and to_port) are numbers, these are set by just
providing the value with
no quotes. cidr_blocks is a list type, it takes a list of CIDR blocks to restrict
for this security group
to. You can see that a list is given in the same way a JSON array of strings is
created where you
surround it in square braces.
Interpolation syntax
Once a resource is created it returns a bunch of attributes. The attributes a
resource returns can be
found in the Attributes Reference section on the documentation page for any
resource. This is
amazingly useful as it allows you to use the output from one resource as the
argument to another
resource.
Consider the following project (which can be found in same repository in the folder
resources_-
example_02). If you do not want to copy from the example repository then create a
new folder, create
a single file in the folder called main.tf and place the following code:
1 provider "aws" {
2 region = "eu-west-1"
3 }
4
5 resource "aws_vpc" "my_vpc" {
6 cidr_block = "10.0.0.0/16"
7 }
8
9 resource "aws_security_group" "my_security_group" {
10 vpc_id = aws_vpc.my_vpc.id
11 name = "Example security group"
12 }
13
14 resource "aws_security_group_rule" "tls_in" {
15 protocol = "tcp"
Chapter 4 - Resources 16
16 security_group_id = aws_security_group.my_security_group.id
17 from_port = 443
18 to_port = 443
19 type = "ingress"
20 cidr_blocks = ["0.0.0.0/0"]
21 }
This project creates an AWS VPC with CIDR block 10.0.0.0/16. Then it defines a
security group
(aws_security_group). In the definition of the security group notice that the value
of vpc_id is set
to aws_vpc.my_vpc.id. The value of aws_vpc.my_vpc.id is not known before we run the
project as
AWS will randomly assign it when we create the VPC. By referencing the VPC we
created it allows
us to use this value even though we do not know what it will be until we run the
project.
The format of using an output attribute from a resource is
<resource_type>.<resource_identifier>.<attribute_-
name>. In the VPC id example we are getting the output from an aws_vpc resource
type, with
the identifier name my_vpc and we want to get the id attribute value. So hence we
end up with
aws_vpc.my_vpc.id. It is worth noting here that this syntax was greatly simplified
in Terraform
version 0.12. Which is the syntax all of the examples in this book will be using.
Next in our project we define a security group rule (aws_security_group_rule) to
allow ingress
traffic on port 443. In the aws_security_group_rule we need to reference the id of
the security group
that we want to put this rule in. We can use the same technique as we did when we
referenced
the id of the VPC. Lets work through how to figure this out together. It will start
with the type
of the resource we want to reference aws_security_group. Next we use the identifier
to specify
which instance of the security group we want to use which is my_security_group.
Lastly we use the
attribute of that property we want to use, which is id. This leads use to build the
expression aws_-
security_group.my_security_group.id which we can use for the value of the property
security_-
group_id inside the aws_security_group_rule resource.
The neat thing about using interpolation syntax to reference the attribute of a
resource in another
resource is that it allows Terraform to work out the dependency order of the
resources. From our
HCL above Terraform can determine that first it needs to create the VPC because it
needs the id
that AWS assigns to the VPC in order to create the security group. It then knows
that it needs to
create the security group next as it needs the id of the security group in order to
create the security
group rule. Terraform uses this information to build up a dependency graph and then
tries to run in
parallel as much as possible.
To illustrate the way Terraform can create a project in parallel consider what
happens when we
add a new security group rule to our project above (folder resources_example_03 in
the example
repository).
Chapter 4 - Resources 17
1 resource "aws_security_group_rule" "http_in" {
2 protocol = "tcp"
3 security_group_id = aws_security_group.my_security_group.id
4 from_port = 80
5 to_port = 80
6 type = "ingress"
7 cidr_blocks = ["0.0.0.0/0"]
8 }
When you run the project now with Terraform, it will realise that it can create
both security group
rules in parallel. Once the security group they both depend on is created, it will
be able to create both
of the rules together. This feature of Terraform makes performance very good. It
may seem quite
obvious in this example but as a project grows it can be quite impressive at how
much Terraform
can run in parallel.

You might also like