
Sam Gabrail
President at TeKanAid
Terraform is a popular tool for managing infrastructure as code. It allows you to define and provision your resources in a declarative way, using a simple and human-readable language. But before you apply your configuration to create or update your infrastructure, you need to plan it. That's where Terraform Plan comes in and the topic of this blog post.
Let’s take a look at our setup.
TL;DR: You can find the repo here.
Before jumping into the code example, let's understand some of the concepts around the Terraform Plan command.
Terraform Plan is a command that shows you what Terraform will do before it actually does it. It compares your current state (the existing resources) with your desired state (the configuration file) and generates a plan of action to achieve it. The plan shows you which resources will be created, modified, or destroyed, and how their attributes will change.
Terraform Plan aims to help you review and verify your configuration before applying it. It gives you a chance to catch any errors or inconsistencies in your terraform code, and to make sure that you are not making any unwanted changes to your infrastructure. It also helps you communicate and collaborate with your team members, by showing them what you intend to do and getting their feedback.
Planning your infrastructure changes is very important. Let’s first talk about the challenges that you may encounter when you don’t plan then discuss the importance of running plans.
Without planning you may run into the following challenges:
Planning helps you:
To see how Terraform Plan works in action, let's look at a few use case examples based on pulling an NGINX docker image and creating a docker container with this image.
The process of creating a new resource is simple and we will take it one step at a time.
Then we have a variables.tf file that defines the following variables:
We then have a terraform.tfvars file to assign the variable values. There are many other ways to assign these variables such as using environment variables, but here we will define them in a file.
The output will look like this:
Here is the terraform plan output that shows the proposed changes:
When you run terraform apply, a terraform plan is created automatically with a prompt at the end to approve the plan and apply the configuration changes. Below is the output prompt to accept the plan along with the execution of the plan.
You can also view the newly created NGINX container by going to the ports tab and clicking the globe icon as shown below.
And you will get the famous NGINX welcome screen
Now let's say you want to modify the container's restart behavior from always restarting to restarting on-failure. Just modify the docker_container resource in the main.tf file as shown below.
Now run the terraform command again to see what resource will be modified and how its attribute will change. You review the plan and confirm that it matches your expectations. You run Terraform Apply to update the resource.
Notice how the output below shows that an update in-place will occur. This means that Terraform will not destroy any resources, it will update the resource in place. This behavior is dependent on the type of resource and provider being used along with which attribute we're changing. In our case, changing the restart behavior can be done with no destruction.
To demonstrate a modification that will cause the container to be destroyed and created, let's modify the external port number to use. Change the external port in the terraform.tfvars file from 8080 to 8081.
Now run terraform plan again and observe the output below:
You don't need to apply this change as we're just demonstrating what a destroy and then create replacement looks like. This is a very important change that you would need to pay attention to when running the terraform plan command.
Let's say we want to now delete our container but would like to keep our docker image. To do this, we can easily update our main.tf file and comment out our docker_container resource as shown below:
This is telling Terraform that we want to delete this resource. Now go ahead and run the plan again.
Here is the execution plan output showing that we will destroy the NGINX docker container:
We are going to go ahead and run a terraform apply to delete the container, but it's very important to pay attention to resources that are planned for destruction.
You can verify that the docker container is removed by running docker ps to see that there are no containers running.
Terraform Plan has two modes: normal mode and refresh-only mode.
Refresh-only mode is a special mode that only refreshes the state without generating a plan of action. It is useful when you want to update the state without making any changes to the infrastructure. It is also a faster operation since we're skipping the normal plan phase which could take some time in large configurations.Let's try this out. First we need to recreate our infrastructure. Run the following command and accept the prompt by typing ‘yes’
Now go ahead and delete our NGINX docker image using the following command:
Now run the following terraform command:
and the output looks like this:
This is showing you that changes occurred outside of Terraform. That is correct since we deleted the docker image outside of Terraform. Now since this is a terraform plan command, it will not refresh the state file. Take a look at your state file called terraform.tfstate. This is an example of what it would look like right now:
Notice how we still have our docker image. Now let's run the following command to refresh this state file and remove the docker image from it.
answer 'yes' to the prompt and observe the state file now:
We've successfully removed the docker image from our state file. Using the -refresh-only flag with the terraform plan and terraform apply commands is a much safer option than the older method of using the terraform refresh command.
Terraform Plan has several options that allow you to customize how it works. In this section, we will discuss the most popular ones, you can get a list of all the options using the terraform plan -h command.
Notice the output:
And now you run terraform apply while referencing this tfplan file as shown:
This will effectively replace our docker NGINX container. So it will destroy and create. Here is the summary output of this command:
To go ahead and apply the change, you will need to run:
Now if you run terraform plan, you will be prompted to supply values for both the image_name and the image_tag since they don't have default values specified in the variables.tf file as shown below:
To eliminate the need to answer these prompts, we can use the -var flag to provide the needed variables via the command line like this:
This should work fine and you should get a No changes to your infrastructure message.We could also use a variables file that perhaps is located in a different directory than our current one. Remember that Terraform looks for all its files in the current directory you're running Terraform from. Now check the folder called a_random_directory and the file called my_variables_file.txt. Notice how we gave this file the .txt extension to show you that we can include non-terraform-specific files to the terraform plan command. You'll see that we simply defined the two needed variables there:
Now let's run terraform plan again:
This should work fine and you should get a No changes to your infrastructure message.
To apply the changes, go ahead and run the following command:
Resource targeting in Terraform is a feature that allows you to apply changes to only a subset of your infrastructure, instead of applying the entire plan at once. This can be useful for troubleshooting errors, recovering from network failures, or testing out new configurations without affecting the rest of your resources.
We already mentioned how to target certain resources using the -target flag when you run terraform plan or terraform apply. You can provide one or more target options that contain references to resources, modules, or collections of resources in your configuration. For example:
This command will generate a plan that only includes the aws_instance.web resource and all the resources in the module.network module. Terraform will ignore any other resources or modules that are not explicitly targeted.
Resource targeting can be a powerful tool for managing your infrastructure, but it should not be part of your regular workflow. It can cause inconsistencies in your state file and lead to unexpected dependencies or conflicts between resources. It is recommended to use resource targeting only as a last resort when you need to fix a specific problem or test a specific change. For most cases, you should apply your entire plan as defined by your configuration files.
Let's give it a try with our docker example.
First, let's rebuild our infrastructure:
type 'yes' for the prompt.
Now let's change the image_tag from "1.23.3" to "1.23.1" in the terraform.tfvars file.
Run terraform plan again and notice that both the docker_container.nginx_container and the docker_image.nginx_image resources are planned to be destroyed and recreated.
To target only the docker image to be recreated let's use our -target flag:
Notice now that only the image will be updated. Also, notice the warning message about resource targeting being in effect.
You can go ahead and apply the changes with the following command:
Now notice the error message when we try to apply:
This shows the dependency that this container has on the current image tag. That's why the resource targeting capability needs to be used with care.
To make the most of Terraform Plan and Terraform in general, here are some best practices to follow:
Terraform Plan is a powerful and useful command that lets you preview the changes that Terraform will make to your infrastructure before applying them. It helps you validate your configuration, avoid errors and unwanted changes, and collaborate with your team. In this blog post, we learned about the purpose and importance of Terraform Plan, and how to use it in different scenarios. We also saw how to save and apply a plan file, and how to use some of the options and flags that Terraform Plan supports. By using Terraform Plan, you can make your infrastructure as code more reliable, predictable, and transparent.
Use custom workflows to model any process
Visualize all IaC changes pre and post-deployment
Gain code-to-cloud visibility and governance
Improve developer experience and collaboration
Use custom workflows to model any process
Visualize all changes pre and post-deployment
Gain code-to-cloud visibility and governance
Improve developer experience and collaboration
env0 is the best way to deploy, scale, and manage your Terraform and other Infrastructure as Code tools.