As your Terraform configuration grows in complexity, updating resources becomes more risky: an update to one resource may cause unintended changes to other parts of your infrastructure. One way to address this is to refactor your existing Terraform code into separate modules. In addition to limiting the scope of potential changes, modules help abstract your resources, making your configuration easier to understand.
When you create modules from existing infrastructure, your resource
IDs will change. Because of this, you must let Terraform know that you intend to
move resources rather than replace them, or Terraform will destroy and recreate
your resources with the new ID. In previous versions of Terraform, you would use
the terraform state mv
command to individually move your resources to their
new module address so Terraform can correctly track the infrastructure.
The moved
configuration block allows you to track your resource moves in the
configuration itself. With the moved
configuration block, you can plan,
preview, and validate resource moves, enabling you to safely refactor your
configuration.
In this tutorial, you will create several AWS resources in a single
configuration file and then divide them into compute and security group modules.
Then, you will use the moved
block to refactor your configuration and update
resource IDs, and review the corresponding state changes before you apply the
new configuration.
»Prerequisites
You can complete this tutorial using the same workflow with either Terraform OSS or Terraform Cloud. Terraform Cloud is a platform that you can use to manage and execute your Terraform projects. It includes features like remote state and execution, structured plan output, workspace resource summaries, and more.
Select the Terraform Cloud tab to complete this tutorial using Terraform Cloud.
This tutorial assumes that you are familiar with the Terraform workflow. If you are new to Terraform, complete Get Started collection first.
In order to complete this tutorial, you will need the following:
- Terraform v1.1+ installed locally.
- An AWS account with local credentials configured for use with Terraform.
»Clone the example configuration
Clone the example repository for this tutorial.
Change to the repository directory.
This configuration contains a VPC module, a security group that allows ingress
HTTP traffic on port 8080
, and an EC2 instance that uses the security group.
Later in this tutorial, you will move these resources into separate modules to
make your configuration more manageable.
»Initialize and apply the configuration
Initialize this configuration.
After Terraform initializes, apply the configuration and approve the run by
typing yes
at the prompt.
Test your instance availability with the curl
command.
In the next section, you will refactor your configuration into modules.
»Refactor your configuration
In this example, you have a small number of resources to manage. However, an operational environment may consist of many more resources and be difficult to manage in a single configuration file. By organizing these resources into modules, your configuration becomes flexible, reusable, and composable.
In your main.tf
file, remove the AMI data source, the instance resource, and
security group resource.
»Create compute module
Create a new modules
directory with a compute
subdirectory.
Create a new main.tf
file in the compute
directory and add the following
configuration.
Then, create a new variables.tf
file to capture your variables. You will
declare variables that you can use to configure the module.
Finally, create a new outputs.tf
file to capture your instance IP address. You
will use this output to pass as a variable into another module.
This is a modified version of the initial Terraform configuration for the EC2 instance.
»Create security group module
Next, create a new directory for your security_group
module.
Create a new main.tf
file in the security_group
directory and add the
following configuration.
Then, create a new variables.tf
file in the security_group
directory and add
the following configuration.
Next, create a new outputs.tf
file to capture your security group ID. You will
pass this output value as an input variable into another module.
»Update configuration with modules
Open the main.tf
file and add the new module
blocks to the end of your
configuration.
Save your changes.
Update the outputs.tf
file in the root directory.
»Review planned changes
Next, reinitialize your configuration to install the newly created modules.
Now that Terraform recognizes the module directory structure, generate a plan to observe the changes.
Your module changes would delete and recreate your resources, which could cause
service interruptions. In the next section, you will use
Terraform's moved
block to refactor your configuration to use modules without
destroying the existing resources.
»Move your resources with the moved
configuration block
In previous versions of Terraform, you had to refactor your existing
infrastructure manually, by using terraform state mv
to rename your resources
in your project's state to match the changes to your configuration.
With the moved
configuration block, you can inform Terraform about all
resource address changes in your configuration. Terraform also validates those
changes to provide you with clearer operational output and you can safely review
plans before applying.
In your root main.tf
file, add moved
configuration blocks for each of the
resources you moved into modules in the previous step.
Re-apply your configuration to move your resources into your new modules and update the resource IDs.
Confirm your changes with yes
after you verify that Terraform will move your
resources instead of replacing them.
Your instance and security group IDs changed but the resources themselves have not.
»Rename and move a resource
You can also use the moved
configuration block to rename existing resources.
In the root of your configuration, open the main.tf
file.
Rename your vpc
module, and update the references to it in the rest of your
configuration.
Add the moved
block for your VPC changes at the bottom of the file.
Run terraform init
to update your VPC module's name.
Apply your changes. Confirm your changes with yes
after you verify there are
no resource changes.
Note: We strongly recommend you retain all moved
blocks in your
configuration as a record of your changes. Removing a moved
block plans to
delete that existing resource instead of moving it.
»Clean up your resources
Remove the infrastructure you created in this tutorial. Respond to the
confirmation prompt with a yes
.
If you used Terraform Cloud for this tutorial, after destroying your resources, delete the learn-terraform-move
workspace from your Terraform Cloud organization.
»Next steps
In this tutorial, you created an EC2 instance and supporting networking
resources. Then, you refactored your Terraform configuration into modules.
Finally, you used the moved
configuration block to safely update the resource
IDs.
For more information on modules and state, review the following resources:
- Review the Terraform
Documentation
on the
moved
configuration block. Learn to use themoved
configuration block with resources containing thefor_each
orcount
functions. - Follow the Build and Use a Local Module tutorial to review how to create a module.
- Follow the Manage Resources in Terraform State tutorial to learn other methods for updating your state file.
- Follow the Manage Resource Lifecycle tutorial and use the different lifecycle management options available in Terraform to prevent resource deletion.