Migration of Terraform state between various backends.
Sometimes the need to move existing Terraform state from your local machine to remote backend or between remote backends should popup. So how to deal with it easily without affecting existing resources? I'll try to show you how to do it from your command prompt easily.
Imagine the situation when you are developing locally and everything what you've already deployed needs to be moved to the remote state or you would like to switch between two types of remote backends. Sounds familiar? Yes? So in this article I'll guide you how to do it without deleting the resources and spinning them up again with different state configuration.
The example scenario
For this article let's assume simple scenario that we have to create Resource Group and Virtual Network in Azure via AzureRM provider. To achieve stated requirements we have to create following Terraform declaration and as first we will configure Terraform backend to work with the local state file.
Local state
Once we execute terraform init
command we can see the following output.
Once the Terraform is initialized you should see the confirmation message. The process also created .terraform
folder inside your project. Once we will execute the apply terraform.state
file with the actual deployment state will be created in root of the working directory.
TIP: If you need to work from different directory use
-chdir
flag as is documented here.
Let's execute terraform plan
command and verify if plan is contains resources we would like to create. As confirmed by the screenshot it will be exactly as we wanted.
Now we are ready to deploy resources by using terraform apply
command. This execution will create the resources via Azure Resource Manager provider and store its state inside local state file on your machine. The output should look similar to this:
We can simply check via Azure portal that resources were created. And terraform.state
file with actual deployment was stored on your local file system.
Transferring existing local state to remote backend provided by Azure Storage Account
So now once you are happy with your local deployment and you overcame all the bad ideas — how to manage state locally or via version control systems — It's time to choose one of the possibilities and share remote state properly with your teammates.
Let's extend our example declarations so that we can use remote backend and pick Azure Storage Account as the first option. For that purpose we have to extend our template in following way.
TIP: Each backend configuration key can be passed via CLI parameters as is documented here.
As you can see not much has changed
To make it work we also have to create Storage account and state container inside the Azure. So let's do it via following az cli
commands.
Once we have it, we can execute re-initialization of the backend viaterraform init
command.
Oops, we forgot to add the
-migrate-state
flag
This will tell the Terraform that our backend has be changed from local to remote and needs to be migrated first and we can modify our existing resources with state stored on the remote backend.
Let's add the flag and see if it works:
Terraform has asked if we want to copy existing state — to which we respond
yes
— to confirm state migration orno
— staring with with an empty state.
TIP: If you choose the
no
option Terraform will create empty state and all existing, ie. already deployed resources need to be imported to the state via import procedure as is described here.
If you choose yes
state will be copied into the remote location and can be used by your teammates as the source of truth. For verification we can check if the state file is visible trough the Azure portal inside defined container:
We can see the state was properly migrated into the Azure Blob Storage Container under defined Blob name and can be used without the need to redeploy or import the resources. Let's test it by changing CIDR of the virtual network to 10.100.0.0/16.
Once we have modified our declaration we can execute terraform plan
and terraform apply
with following result.
Terraform will do exactly what was planned and after the apply
we can once again verify virtual network was modified and state file was updated.
Pretty simple, huh? But what about the other use case — movement between two remote states?
Movement between Azure Storage Account and Terraform Cloud remote states
So let's pretend that we are not satisfied with the Azure Storage Account remote backend features and we'd like to use additional Terraform Cloud features for remote state management.
TIP: If you are not familiar with remote state management and its feautures have a look here.
So let's start with the fresh local directory where we have only the Terraform declaration template and start with the whole process from the scratch. So let's define following structure and main.tf
file content.
Now you have to execute the terraform init
command to get all the references to your working directory.
Now we’ll do the slight modification to use Terraform Cloud as the remote backend in main.tf
file.
To make it work and be able to migrate state we have to create the Terraform Cloud Workspace inside selected Organization (in my case it will be my private one marley-ma
). So let's do it.
TIP: For the authentication against the Terraform cloud several options could be used. I'm using the
.terraformrc
file inside my project folder with user token as is documented here but you can look for the option fitting you needs in the documentation.
Now we are prepared to execute terraform init -migrate-state
state to start the migration. Once again we’ll choose the yes
option, state will be migrated
and we can see it's the same flow as in the previous case but in different backend.
So as the last bit let's change the template one last time and rename virtual network to hope-you-like-it
string. To achieve it we have to modify main.tf
file in following way.
Now we can run terraform plan
and terraform apply
and verify if it works against remote state in the Terraform Cloud Workspace where we have migrated our state.
Conclusion
So as you have seen it was pretty simple. There are just few rules to follow when transgerring your existing state between local or remote state backends.
With this approach you can avoid affecting the existing resources by the movement itself and easily continue with the different backend provider on stuff which was already build with different state management.
There are few topics which I didn't touch in this article — such as Terraform workspaces, remote state prefixes, authentication and so on. But we will cover these separately in one of my future articles.
References
- https://www.terraform.io/cli/commands#switching-working-directory-with-chdir
- https://www.terraform.io/language/settings/backends/configuration#partial-configuration
- https://www.terraform.io/cli/import
- https://www.terraform.io/cloud-docs/overview
- https://www.terraform.io/cli/config/config-file#credentials-1