terraform-tofu-labs/2-simple-example/README.md

7.6 KiB

Introduction

Welcome to lab 2. You are going to find the code here very similar to lab 1, and thats by design, we'll build upon our experience and learn how to add variables and use environment files, so that you can reuse the code in say a deployment for dev, stage and prod. This is the power of IaC and prevents you having to rebuild everything from scratch.

Now I'll assume you have your AWS account and CloudShell setup already. If not please reffer to the lab 1 README.md. Remeber i use the command tofu but if you've installed terraform instead you can swap the commands easily enough.

In this example we are going to do the same and deploy a VPC with subnets and an instance with a security group attached. What's different is that this time we'll use the user_data feature of EC2 to run apache and show you a running web server. In the main.tf file it differs in the aws_resource block of code to include the command to start apache.

resource "aws_instance" "test_ami" {
  ami                    = "ami-029b91ed285a24a90"
  instance_type          = "t4g.nano"
  associate_public_ip_address = true
  subnet_id              = module.vpc.public_subnets[0]
  vpc_security_group_ids = [aws_security_group.web_server_sg_tf.id]

  user_data = <<-EOF
              #!/bin/bash
              sudo dnf install -y nginx
              sudo systemctl enable nginx
              sudo systemctl start nginx
              EOF
}

I've also updated outputs.tf to show the public IP address of the instance we've deployed by adding this code block:

# Public IP of instance
output "instance_public_ip" {
  description = "Show the public IP of the instance deployed"
  value = aws_instance.test_ami.public_ip
}

Create a Stack

Once again lets deploy the stack before editing it:

cd 2-simple-example/code
tofu init
tofu plan
tofu apply

Answer yes at the apply prompt and you should end up with a screen like this:

Tofu apply output

Embedded in there you'll see something liek this instance_public_ip thats out new output, copy the value and head to http://<YOUT_VALUE>/ and you should get a very similar looking default nginx page.

Default nginx page (I'm of course in dark mode, don't worry if yours is white with black text!)

Right we now have our basic stack to work with. Everything else we do will be to update this stack, so don't destroy it just yet

Introducing variables

Right this is great and all but what if we want to make it easy to change things, such as the ami_id we are deploying or the size of the instance we are running so we have more CPU and RAM. This is where variables make it easy, and as an added advantage we can create variable files for different environments with different values in them to override the defaults.

Note

For this next bit you can use your favourite command line editor to alter the files in CloudShell, vim and nano are installed by deafult, I use vim so if you copy the examples you'll need to press i after opening the files to go into insert mode and when you want to save and exit the file press ESC and type :wq to exit.

Right lets add new variables for both the ami_id and instance_size, start by opening variables.tf in the code directory from CloudShell:

vi variables.tf

Scroll to the bottom of the file and press i for insert then add the following:

variable "instance_size" {
  description = "Size of the instance to run"
  type        = string
  default     = "t4g.nano"
}

variable "ami_id" {
  description = "Instance Amazon Machine Image to run"
  type        = string
  default     = "ami-029b91ed285a24a90"
}

Save that file and exit press ESC and type :wq to exit (last tiem I'll remind you). Now you've set up terraform/tofu to understand the intsance_size and ami_id are variables and we've also given them default values. If you didn't use a dfault in this file when you run apply you'd get prompted to enter the details.

Right now terraform/tofu knows about the variables lets use them. Open up main.tf ready for editing:

vi main.tf

Scroll down to the code block called resource "aws_instance" "test_ami" and edit the following lines:

ami                    = "ami-029b91ed285a24a90"
instance_type          = "t4g.nano"

you want them to look like this:

ami                    = var.ami_id
instance_type          = var.instance_size

Now you're ready, it really was that easy. However, if you went and ran tofu plan right now you'd see that nothing has changed in the stack because our defaults we set on variables.tf have the same values as before.

No changes dialog

Using tfvars

So lets look how to override those settings. In this example we are going to alter both the ami_id and the instance_size to something more production ready. Let's use a Redhat AMI rather than Amazon Linux and a larger instance maybe a t4g.small rather than the t4g.nano. Create a new folder called env and a new file inside it called prod.tfvars

mkdir env
vi env/prod.tfvars

Lets populate it with some new values:

ami_id = "ami-01d28a73af0a85125"
instance_size = "t4g.small"

Save and quit the file and we are ready to use it! Let's start by running tofu plan but we are going to add the argument --var-file= and point it to our file we just created env/prod.tfvars

tofu plan --var-file=env/prod.tfvars

You'll see theres things to be changed now.

changes to the stack

So let's go ahead and apply that, once again adding our new argument:

tofu apply --var-file=env/prod.tfvars

Remeber to type yes at the prompt, you'll see terraform/tofu destroy the old instance and bring up a new one:

Destroying and instance

You'll finally land back at the command prompt. At this point I encourage you to go tot he AWS console and open EC2 > Instances you should see something liek this happening, which shows a terminated old instance and a new one either fully booted or initializing.

Instances swapped over in the console

There we have it a brand new instance this time running RedHat Linux, it'll also have a new public IP address to view in your web browser. You could go on and update again, adding in aditional arguments to any of the resources we've created. We could use a envirnment variable for instance to call the VPC a different name and label the instance according to what environment it's running in. You could go ahead and have a plan at this point and create another tfvars file such as env/stage.tfvars and have different values in there.

Clean up

Don't forget to terminate the resources running in this lab. Run the following:

tofu destroy

Recap

What we've done in this lab is learn how to:

  • create variables
  • use variables in out HCL code
  • create a tfvars file
  • specify the tvfars file onthe command line
  • update a running stack