The core Terraform workflow consists of three main steps after you have written your Terraform configuration:
When you initialize a Terraform workspace, Terraform configures the backend, installs all providers and modules referred to in your configuration, and creates a version lock file if one doesn't already exist. In addition, you can use the terraform init
command to change your workspace's backend and upgrade your workspace's providers and modules.
In this tutorial, you will initialize a Terraform workspace that uses both local and remote modules, explore the .terraform
directory that Terraform uses to store your providers and modules, and update your provider and module versions. In the process, you will learn more about the terraform init
command's integral role in the Terraform workflow.
You can complete this tutorial using the same workflow with either Terraform Community Edition or HCP Terraform. HCP Terraform 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 HCP Terraform tab to complete this tutorial using HCP Terraform.
This tutorial assumes that you are familiar with the Terraform workflow. If you are new to Terraform, complete the Get Started tutorials first.
In order to complete this tutorial, you will need the following:
In your terminal, clone the learn-terraform-init
repository.
$ git clone https://github.com/hashicorp-education/learn-terraform-init
Navigate to the cloned repository.
$ cd learn-terraform-init
This directory contains Terraform configuration that uses multiple providers, a local module, and a remote module. You will use these resources to review how Terraform initializes the working directory.
$ tree
.
├── LICENSE
├── main.tf
├── modules
│ └── aws-ec2-instance
│ ├── main.tf
│ └── variables.tf
├── README.md
├── terraform.tf
└── variables.tf
The example repository includes the following:
LICENSE
includes the text of the Mozilla Public License under which HashiCorp distributes the example configuration.
main.tf
includes the resources and data sources used by the example configuration.
the modules/aws-ec2-instance
directory includes a Terraform module to provision an EC2 instance on AWS.
README.md
describes the example configuration.
terraform.tf
defines the terraform
block, which defines the providers, remote backend, and the Terraform version(s) to be used with this configuration.
variables.tf
defines the variables used in this configuration.
Initialize your Terraform workspace.
The output describes the steps Terraform executes when you initialize your workspace.
First, Terraform initializes the backend.
Since the terraform
block does not include a cloud
or backend
block, Terraform defaults to the local backend.
Initializing the backend...
Open your terraform.tf
file and uncomment the cloud
block. Replace the organization
name with your own HCP Terraform organization.
terraform.tf
terraform {
required_version = "~> 1.6"
required_providers {
### ...
}
cloud {
organization = "organization-name"
workspaces {
name = "learn-terraform-init"
}
}
}
The output describes the steps Terraform executes when you initialize your workspace.
First, Terraform initializes the backend.
Since the terraform
block includes a cloud
block, Terraform will use the HCP Terraform backend and create an HCP Terraform workspace in your organization with the name specified in the block.
Initializing HCP Terraform...
Next, Terraform downloads the modules required by your configuration.
Terraform recognizes that the module "ec2-instance"
block uses the local modules/aws-ec2-instance
module. Next, Terraform determines that the module "hello"
block references a remote module, so it downloads it from the public Terraform Registry.
Initializing modules...
- ec2-instance in modules/aws-ec2-instance
Downloading registry.terraform.io/joatmon08/hello/random 4.0.0 for hello...
- hello in .terraform/modules/hello
Note
When you change a module's source or version, you must either re-initialize your Terraform configuration or run terraform get
to download the new module.
Next, Terraform downloads the providers required by your configuration.
Since the configuration does not yet have a lock file, Terraform downloaded the aws
and random
providers specified in the required_providers
block found in terraform.tf
.
Initializing provider plugins...
- Finding hashicorp/random versions matching "3.6.0"...
- Finding hashicorp/aws versions matching "6.2.0"...
- Installing hashicorp/random v3.6.0...
- Installed hashicorp/random v3.6.0 (signed by HashiCorp)
- Installing hashicorp/aws v6.2.0...
- Installed hashicorp/aws v6.2.0 (signed by HashiCorp)
When you initialize a workspace, Terraform will attempt to download the provider versions specified by the workspace's lock file. If the lock file does not exist, Terraform will use the required_providers
block to determine the provider version and create a new lock file. If neither exists, Terraform will search for a matching provider and download the latest version.
Next, Terraform creates the lock file if it does not already exist, or updates it if necessary.
Terraform's lock file, .terraform.lock.hcl
, records the versions and hashes of the providers used in this run. This ensures consistent Terraform runs in different environments, since Terraform will download the versions recorded in the lock file for future runs by default.
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.
When you manage Terraform configuration in a source control repository, commit the .terraform.lock.hcl
file along with your configuration files.
Finally, Terraform prints out a success message and reminds you how to plan your configuration, and to re-run terraform init
if you change your modules or backend configuration.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
HCP Terraform has been successfully initialized!
You may now begin working with HCP Terraform. Try running "terraform plan" to
see any changes that are required for your infrastructure.
If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.
Now that you have initialized your workspace and downloaded the required modules and providers, Terraform can verify whether your configuration syntax is valid and internally consistent. This includes checking if your resources blocks have invalid or missing arguments. You must initialize your workspace before you can validate your configuration.
Validate your configuration.
$ terraform validate
Success! The configuration is valid.
When you initialize a new Terraform workspace, it creates a lock file named .terraform.lock.hcl
and the .terraform
directory.
The lock file ensures that Terraform uses the same provider versions across your team and in remote execution environments. During initialization, Terraform will download the provider versions specified by this file rather than the latest versions.
Open .terraform.lock.hcl
to review its structure and contents.
.terraform.lock.hcl
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "6.2.0"
constraints = "6.2.0"
hashes = [
"h1:ziUjk3KGwBa7bAwZaPuQklfcQ3Qlx2d0rlYFvdZn4g8=",
"zh:224b20371f7c7ce14d69a84e16ae94baa0a06c132474d4bc4d192d86936bc750",
"zh:2c079ad275c32b9abae7616d07c24901340207a85995ce0025ac38af16b317b7",
"zh:2d139c99d6e8e48cc5439c2945eee583bb3a2d7faf484639cdfd4590ebc294f2",
"zh:2f2dc72de43d845e5df5a1adeadd4a48f3cacfe413b89b95f50294a386a90124",
"zh:304d4e706ac34aba080a81867209c65cdd28f8e596c02b3565f6530ab697cf94",
"zh:40e69328ae11fe1711b34226d45aa4c685f73e8f958c76c49f4f6a6627a1a54f",
"zh:5c5c9faab6fe242b77f0d0ab6664313dd89409371123e2ec376c72e8f2cd97b3",
"zh:7824709f0226afec5e3ad41392233b4bd7d925bae0d35f4a2ac854b3516e955c",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:ab5417435121e8f9a6f539a6972f20c060ebc78624c1ce7c190671f163c423e4",
"zh:d6939385de4931f9fe07c87b744468fbfa96bd4b47861020d68e7ba1efb4185f",
"zh:e51434d1ba106c55d04fdc223aaf403b897ff96cba9bfce4c51854c805c36ed8",
"zh:e6d1012bafe338759ac42a59f566f8c4ad64a67faa3152c7fb758704d890cd75",
"zh:ee24b989ee3b6be79a7f24e97c144535bf7053471ae65343220db3ae78c7632a",
"zh:f61ec9482b9887c4901946407992874531b0c2eadab0c743fdfca4e6cd6dd889",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "3.6.0"
constraints = "3.6.0"
hashes = [
"h1:I8MBeauYA8J8yheLJ8oSMWqB0kovn16dF/wKZ1QTdkk=",
"zh:03360ed3ecd31e8c5dac9c95fe0858be50f3e9a0d0c654b5e504109c2159287d",
"zh:1c67ac51254ba2a2bb53a25e8ae7e4d076103483f55f39b426ec55e47d1fe211",
"zh:24a17bba7f6d679538ff51b3a2f378cedadede97af8a1db7dad4fd8d6d50f829",
"zh:30ffb297ffd1633175d6545d37c2217e2cef9545a6e03946e514c59c0859b77d",
"zh:454ce4b3dbc73e6775f2f6605d45cee6e16c3872a2e66a2c97993d6e5cbd7055",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:91df0a9fab329aff2ff4cf26797592eb7a3a90b4a0c04d64ce186654e0cc6e17",
"zh:aa57384b85622a9f7bfb5d4512ca88e61f22a9cea9f30febaa4c98c68ff0dc21",
"zh:c4a3e329ba786ffb6f2b694e1fd41d413a7010f3a53c20b432325a94fa71e839",
"zh:e2699bc9116447f96c53d55f2a00570f982e6f9935038c3810603572693712d0",
"zh:e747c0fd5d7684e5bfad8aa0ca441903f15ae7a98a737ff6aca24ba223207e2c",
"zh:f1ca75f417ce490368f047b63ec09fd003711ae48487fba90b4aba2ccf71920e",
]
}
If the versions defined in the lock file's provider
block do not match the versions defined in your configuration's required_providers
block, Terraform will prompt you to re-initialize your configuration using the -upgrade
flag. You will do this in the next section.
.terraform
directory
Terraform uses the .terraform
directory to store the project's providers and modules. Terraform will refer to these components when you run validate
, plan
, and apply
.
Note
Terraform automatically manages the .terraform
directory. Do not check it into version control, and do not directly modify this directory's contents. Exploring the .terraform
directory in this tutorial is meant to deepen your understanding of how Terraform works, but the contents and structure of this directory are subject to change between Terraform versions.
View the .terraform
directory structure.
$ tree .terraform -L 1
.terraform
├── modules
└── providers
Notice that the .terraform
directory contains two sub-directories: modules
and providers
. These two directories contain the modules and providers used by your Terraform workspace.
$ tree .terraform -L 1
.terraform
├── environment
├── modules
├── providers
└── terraform.tfstate
Notice that the .terraform
directory contains three sub-directories and a terraform.tfstate
file. The environment
file includes the name of your HCP Terraform workspace, and the terraform.tfstate
file contains a reference to your workspace's state in HCP Terraform.
The modules
and providers
directories contain the modules and providers used by your Terraform workspace.
The .terraform/modules
directory contains a modules.json
file, and a local copy of the remote module, "hello".
$ tree .terraform/modules
├── hello
│ ├── README.md
│ └── random.tf
└── modules.json
Open modules.json
. This file shows that the configuration uses three modules: the "root" module, referring to the configuration in the root directory of your workspace, the local aws-ec2-instance
module, and the remote hello
module.
modules.json
{
"Modules": [
{
"Key": "",
"Source": "",
"Dir": "."
},
{
"Key": "ec2-instance",
"Source": "./modules/aws-ec2-instance",
"Dir": "modules/aws-ec2-instance"
},
{
"Key": "hello",
"Source": "registry.terraform.io/joatmon08/hello/random",
"Version": "4.0.0",
"Dir": ".terraform/modules/hello"
}
]
}
The aws-ec2-instance
module refers to a local module, so Terraform refers directly to the module's configuration found within the modules/aws-ec2-instance
directory in the example repository. This means that if you make changes to a local module, Terraform will recognize them immediately.
Because the hello
module is remote, Terraform downloaded the module from its source and saved a local copy in the .terraform/modules/hello
directory when you initialized your workspace. Open the files in .terraform/modules/hello
to view the module's configuration. These files are intended to be read-only, like the other contents in .terraform
. Do not modify them. Terraform only updates a remote module when you run terraform init -upgrade
or terraform get
.
The .terraform/providers
directory stores cached versions of all the configuration's providers.
View the .terraform/providers
directory. When you ran terraform init
earlier, Terraform downloaded the providers defined in your configuration from the provider's source (defined by the required_providers
block) and saved them in their respective directories, defined as [hostname]/[namespace]/[name]/[version]/[os_arch]
.
$ tree .terraform/providers
.terraform/providers
└── registry.terraform.io
└── hashicorp
├── aws
│ └── 6.2.0
│ └── darwin_arm64
│ ├── LICENSE.txt
│ └── terraform-provider-aws_v6.2.0_x5
└── random
└── 3.6.0
└── darwin_arm64
└── terraform-provider-random_v3.6.0_x5
In terraform.tf
, update the random
provider's version to 3.6.1
.
terraform.tf
terraform {
required_providers {
## ..
random = {
source = "hashicorp/random"
version = "3.6.1"
}
}
## ..
required_version = "~> 1.6"
}
In main.tf
, update the hello
module's version to 6.0.0
.
main.tf
module "hello" {
source = "joatmon08/hello/random"
version = "6.0.0"
hello = "World"
second_hello = random_pet.instance.id
secret_key = "secret"
}
Because you updated the provider and module versions, you must re-initialize the configuration for Terraform to install the updated versions.
If you attempt to validate, plan, or apply your configuration before doing so, Terraform will prompt you to re-initialize.
$ terraform validate
╷
│ Error: Module version requirements have changed
│
│ on main.tf line 38, in module "hello":
│ 38: source = "joatmon08/hello/random"
│
│ The version requirements have changed since this module was installed and the installed version (4.0.0) is no longer acceptable. Run "terraform init" to
│ install all modules required by this configuration.
╵
Re-initialize your configuration to have Terraform upgrade the module to match the new version you configured in the previous step. Terraform will report an error for the provider, however.
$ terraform init
Initializing the backend...
Initializing modules...
Downloading registry.terraform.io/joatmon08/hello/random 6.0.0 for hello...
- hello in .terraform/modules/hello
Initializing provider plugins...
- Reusing previous version of hashicorp/random from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v6.2.0
╷
│ Error: Failed to query available provider packages
│
│ Could not retrieve the list of available versions for provider hashicorp/random: locked
│ provider registry.terraform.io/hashicorp/random 3.6.0 does not match configured version
│ constraint >= 3.0.1, 3.6.1; must use terraform init -upgrade to allow selection of new
│ versions
│
│ To see which modules are currently depending on hashicorp/random and what versions are
│ specified, run the following command:
│ terraform providers
╵
Notice that Terraform downloaded the updated module version and saved it in .terraform/modules/hello
. However, Terraform was unable to update the provider version since the new provider version conflicts with the version found in the lock file.
Re-initialize your configuration with the -upgrade
flag. This tells Terraform to upgrade the provider to the most recent version that matches the version
attribute in that provider's required_version
block.
$ terraform init -upgrade
Initializing the backend...
Upgrading modules...
- ec2-instance in modules/aws-ec2-instance
Downloading registry.terraform.io/joatmon08/hello/random 6.0.0 for hello...
- hello in .terraform/modules/hello
Initializing provider plugins...
- Finding hashicorp/aws versions matching "6.2.0"...
- Finding hashicorp/random versions matching ">= 3.0.1, 3.6.1"...
- Using previously-installed hashicorp/aws v6.2.0
- Installing hashicorp/random v3.6.1...
- Installed hashicorp/random v3.6.1 (signed by HashiCorp)
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
View the .terraform/providers
directory structure. Notice that Terraform installed the updated random
provider version.
$ tree .terraform/providers -L 4
.terraform/providers
└── registry.terraform.io
└── hashicorp
├── aws
│ └── 6.2.0
└── random
├── 3.6.0
└── 3.6.1
Open the lock file. Notice that the random
provider now uses version 3.6.1
. Even though there are two versions of the random
provider in .terraform/providers
, Terraform will always use the version recorded in the lock file.
.terraform.lock.hcl
## ...
provider "registry.terraform.io/hashicorp/random" {
version = "3.6.1"
constraints = ">= 3.0.1, 3.6.1"
hashes = [
"h1:a+Goawwh6Qtg4/bRWzfDtIdrEFfPlnVy0y4LdUQY3nI=",
## ...
"zh:e4aabf3184bbb556b89e4b195eab1514c86a2914dd01c23ad9813ec17e863a8a",
]
}
Update module arguments
Since you have updated your provider and module version, check whether your configuration is still valid.
$ terraform validate
╷
│ Error: Missing required argument
│
│ on main.tf line 37, in module "hello":
│ 37: module "hello" {
│
│ The argument "some_key" is required, but no definition was found.
╵
╷
│ Error: Missing required argument
│
│ on main.tf line 37, in module "hello":
│ 37: module "hello" {
│
│ The argument "hellos" is required, but no definition was found.
╵
╷
│ Error: Unsupported argument
│
│ on main.tf line 41, in module "hello":
│ 41: hello = "World"
│
│ An argument named "hello" is not expected here. Did you mean "hellos"?
╵
╷
│ Error: Unsupported argument
│
│ on main.tf line 42, in module "hello":
│ 42: second_hello = random_pet.instance.id
│
│ An argument named "second_hello" is not expected here.
╵
╷
│ Error: Unsupported argument
│
│ on main.tf line 44, in module "hello":
│ 44: secret_key = "secret"
│
│ An argument named "secret_key" is not expected here.
╵
The new version of the hello
module expects different arguments from the old version. Replace the entire module "hello"
block with the following:
main.tf
module "hello" {
source = "joatmon08/hello/random"
version = "6.0.0"
hellos = {
hello = random_pet.instance.id
second_hello = "World"
}
some_key = "secret"
}
Re-validate your configuration.
$ terraform validate
Success! The configuration is valid.
Now your Terraform workspace is initialized and ready to be applied.
Initialize your Terraform workspace with terraform init
when:
You create new Terraform configuration and are ready to use it to create a workspace and provision infrastructure.
You clone a version control repository containing Terraform configuration, and are ready to use it to create a workspace and provision infrastructure.
You add, remove, or change the version of a module or provider in an existing workspace.
You add, remove, or change the backend
or cloud
blocks within the terraform
block of an existing workspace.
Over the course of this tutorial, you initialized a Terraform configuration with both local and remote modules, explored the .terraform
directory, and updated your provider and module versions. These steps were integral to understanding the mechanisms underlying terraform init
.
For more information on topics covered in this tutorial, check out the following resources.
init
in the documentation.RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4