Terraform Tutorial - terraform format(tf), interpolation(variables) & terraform console
Terraform uses text files to describe infrastructure and to set variables. These text files are called Terraform configurations. The format of the configuration files are able to be in two formats: Terraform format (.tf) and JSON (.tf.json). The Terraform format is more human-readable, supports comments, and is the generally recommended format for most Terraform files.
The configuration file should look like this in its simplest form, and it is designed to work with access to a default VPC in "us-east-1". The provider block is used to configure the named provider, in our case "aws".
ec2-instance.tf:
provider "aws" { region = "us-east-1" } resource "aws_instance" "my-instance" { ami = "ami-04169656fea786776" instance_type = "t2.nano" tags = { Name = "Terraform" Batch = "5AM" } }
The resource block creates a resource of the given TYPE (first parameter - "aws_instance") and NAME (second parameter - "my-instance"). The combination of the type and name must be unique. Within the block (the { }) is configuration for the resource, and the configuration is dependent on the TYPE.
For more about the aws_instance resource, please check Terraform: aws_instance .
Note also we added tags to the resource.
Now, we can run it:
$ terraform apply An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: + aws_instance.my-instance ... aws_instance.my-instance: Creating... ami: "" => "ami-04169656fea786776" ... instance_type: "" => "t2.nano" ... tags.%: "" => "2" tags.Batch: "" => "5AM" tags.Name: "" => "Terraform" ... aws_instance.my-instance: Creation complete after 17s (ID: i-085b8224321c186c9) Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
Actually, before we run the tf file, we need to get key pairs (credentials) for the provider. For aws, please check AWS Provider .
If we want an existing Key Pair for the instance, we can just add key_name to the tf file:
provider "aws" { region = "us-east-1" } resource "aws_instance" "my-instance" { ami = "ami-04169656fea786776" instance_type = "t2.nano" key_name = "einsteinish" tags = { Name = "Terraform" Batch = "5AM" } }
Run:
$ terraform apply aws_instance.my-instance: Refreshing state... (ID: i-085b8224321c186c9) An execution plan has been generated and is shown below. Resource actions are indicated with the following symbols: -/+ destroy and then create replacement Terraform will perform the following actions: -/+ aws_instance.my-instance (new resource required) ... key_name: "" => "einsteinish" (forces new resource) ... Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
Note that it destroys the old instance and created a new one since there is no way to attach a key after the instance has been created.
We need to generate public and private keys. Let's name it "terraform-demo":
$ ssh-keygen -f terraform-demo $ ls terraform-demo* terraform-demo terraform-demo.pub
To create a new key pair while launching an instance:
provider "aws" { region = "us-east-1" } resource "aws_key_pair" "terraform-demo" { key_name = "terraform-demo" public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+GmzMxZgBzis180Rz7tOi3w7JFNy1aVSOVgxRmV34R8ibCpcPWfgJ5ilO082dKgp2bh+ol8IxCBdSL4KpUFIQD/rGJ0Fw8xk9hd1n82iVDroF8y73w5m9AkRK9hAzA6eDR+U8sY8ckCbpx2fOs89PLap7xkZ+bPeOmWqMMr8nyd4z/COqg1NewYFdFjQWFANfOnwb8Lzo/wkm9gJ/ZNKQZfa2mJfwX3EgS9ioiaSlYQbPx0cCEp2oM+xjCgp0KFUjahC46tFxclHjWzQ3piByBm5cO/S121lerst/yRnibG3+Yvc/5c8EKW7Kp3RteKqeGC2363/PEViBpE4sqyEr k@laptop" } resource "aws_instance" "my-instance" { ami = "ami-04169656fea786776" instance_type = "t2.nano" key_name = "${aws_key_pair.terraform-demo.key_name}" tags = { Name = "Terraform" Batch = "5AM" } }
We're using Terraform's interpolation feature (variable) in the "aws_instance" resource where another resource is being referenced.
key_name = "${aws_key_pair.terraform-demo.key_name}"
Note that we use resource_type.logical_name.attribute
!
We can run the tf file again via "terraform apply:
$ terraform apply ... Apply complete! Resources: 2 added, 0 changed, 1 destroyed.
As we can see from the output, we added 2 resources (key and ec2-instance).
Let's see if we can ssh to the instance using private key we generated:
$ ssh -i terraform-demo ubuntu@34.227.10.12 The authenticity of host '34.227.10.12 (34.227.10.12)' can't be established. ECDSA key fingerprint is SHA256:zleRiY9GqTYG9aIRLgFSIvPW8yKB5qZ+HnwsV80wuyU. Are you sure you want to continue connecting (yes/no)? yes Warning: Permanently added '34.227.10.12' (ECDSA) to the list of known hosts. Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1065-aws x86_64) ... ubuntu@ip-172-31-39-47:~$
But we do not want to expose the public key, and instead keep it as a file.
As mentioned in the previous section, we want to get our key from a file. (Interpolation Syntax).
To read a file, we can use ${file("path.txt")}
:
public_key = "${file("path.txt")}"
Here, we're using "file" function with the "path.txt" arg. This function returns the contents of the "path.txt. We can check what it returns via terraform console
:
$ terraform console > "${file("terraform-demo.pub")}" ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC+GmzMxZgBzis180Rz7tOi3w7JFNy1aVSOVgxRmV34R8ibCpcPWfgJ5ilO082dKgp2bh+ol8IxCBdSL4KpUFIQD/rGJ0Fw8xk9hd1n82iVDroF8y73w5m9AkRK9hAzA6eDR+U8sY8ckCbpx2fOs89PLap7xkZ+bPeOmWqMMr8nyd4z/COqg1NewYFdFjQWFANfOnwb8Lzo/wkm9gJ/ZNKQZfa2mJfwX3EgS9ioiaSlYQbPx0cCEp2oM+xjCgp0KFUjahC46tFxclHjWzQ3piByBm5cO/S121lerst/yRnibG3+Yvc/5c8EKW7Kp3RteKqeGC2363/PEViBpE4sqyEr k@laptop > "${aws_key_pair.terraform-demo.key_name}" terraform-demo > exit $
Terraform is idempotent and convergent so only required changes are applied.
We modified the tf file in the previous section to use file for the key. However, the resources are not going to be changed. If we run terraform apply
, it does nothing to the resources. Terraform knows it by checking the local states of the resources. JUst refreshing the state of the resources via IDs:
$ terraform apply aws_key_pair.terraform-demo: Refreshing state... (ID: terraform-demo) aws_instance.my-instance: Refreshing state... (ID: i-086ffd758947c4d1c) Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Terraform
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization