Terraform Apply
Introduction
terraform apply
is one of the most important commands in Terraform, an Infrastructure as Code (IaC) tool. This command is used to apply the changes required to reach the desired state of your infrastructure as defined in your Terraform configuration files. In simpler terms, it's the command that takes your infrastructure code and turns it into actual cloud resources.
In this tutorial, we'll explore the terraform apply
command in depth, understanding its purpose, how it works, and how to use it effectively in your infrastructure management workflows.
Prerequisites
Before diving into terraform apply
, make sure you:
- Have Terraform installed on your system
- Understand basic Terraform concepts like providers, resources, and state
- Have valid Terraform configuration files (.tf) prepared
How Terraform Apply Works
The terraform apply
command follows this general workflow:
Let's break down what happens step by step:
- Read Configuration: Terraform reads all
.tf
files in your directory - Create Execution Plan: Terraform compares your configuration against the current state
- Show Plan: The plan shows what changes will be made (create, update, destroy)
- User Approval: By default, Terraform asks for confirmation
- Apply Changes: Terraform makes API calls to create/modify/delete resources
- Update State: Terraform updates the state file with the new infrastructure state
Basic Usage
Simple Apply Command
The most basic form of the command is:
terraform apply
When you run this, Terraform will:
- Generate an execution plan
- Display the plan
- Ask for your approval
- Apply the changes after approval
Sample Output
Here's what the output might look like when running terraform apply
on a simple AWS EC2 instance configuration:
Terraform will perform the following actions:
# aws_instance.example will be created
+ resource "aws_instance" "example" {
+ ami = "ami-0c55b159cbfafe1f0"
+ arn = (known after apply)
+ associate_public_ip_address = (known after apply)
+ availability_zone = (known after apply)
+ cpu_core_count = (known after apply)
+ cpu_threads_per_core = (known after apply)
+ get_password_data = false
+ host_id = (known after apply)
+ id = (known after apply)
+ instance_state = (known after apply)
+ instance_type = "t2.micro"
+ ipv6_address_count = (known after apply)
+ ipv6_addresses = (known after apply)
+ key_name = (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
+ primary_network_interface_id = (known after apply)
+ private_dns = (known after apply)
+ private_ip = (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
+ security_groups = (known after apply)
+ source_dest_check = true
+ subnet_id = (known after apply)
+ tags = {
+ "Name" = "example-instance"
}
+ tenancy = (known after apply)
+ vpc_security_group_ids = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value:
Advanced Options
Auto-approve
If you want to skip the approval step (useful in automation scenarios), you can use:
terraform apply -auto-approve
This applies the changes immediately without asking for confirmation. Be careful with this in production environments!
Targeting Specific Resources
You can target specific resources to apply:
terraform apply -target=aws_instance.example
This is useful when you want to update only specific parts of your infrastructure.
Using Plan Files
You can create a plan file and apply it later:
terraform plan -out=tfplan
terraform apply tfplan
This approach is common in CI/CD pipelines where you might want to:
- Generate the plan during the build phase
- Have someone review it
- Apply it during the deployment phase if approved
Variables
You can provide variables during apply:
terraform apply -var="instance_count=5"
Or use var files:
terraform apply -var-file="prod.tfvars"
Practical Example
Let's walk through a complete example. We'll create a simple AWS infrastructure with a VPC, subnet, and EC2 instance.
Step 1: Create Configuration Files
Create a file named main.tf
with the following content:
provider "aws" {
region = "us-west-2"
}
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "main-vpc"
}
}
resource "aws_subnet" "main" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
tags = {
Name = "main-subnet"
}
}
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
subnet_id = aws_subnet.main.id
tags = {
Name = "web-server"
}
}
Step 2: Initialize Terraform
Before applying, you need to initialize your Terraform configuration:
terraform init
Output:
Initializing the backend...
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v4.15.0...
- Installed hashicorp/aws v4.15.0 (signed by HashiCorp)
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.
Terraform has been successfully initialized!
Step 3: Apply Configuration
Now, let's apply the configuration:
terraform apply
You'll see the execution plan showing the resources to be created:
Terraform used the selected providers to generate the following execution plan.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# aws_instance.web will be created
+ resource "aws_instance" "web" {
+ ami = "ami-0c55b159cbfafe1f0"
# ... (additional instance properties)
}
# aws_subnet.main will be created
+ resource "aws_subnet" "main" {
+ arn = (known after apply)
+ cidr_block = "10.0.1.0/24"
# ... (additional subnet properties)
}
# aws_vpc.main will be created
+ resource "aws_vpc" "main" {
+ arn = (known after apply)
+ cidr_block = "10.0.0.0/16"
# ... (additional vpc properties)
}
Plan: 3 to add, 0 to change, 0 to destroy.
Do you want to perform these actions?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
aws_vpc.main: Creating...
aws_vpc.main: Creation complete after 2s [id=vpc-0a1b2c3d4e5f6g7h8]
aws_subnet.main: Creating...
aws_subnet.main: Creation complete after 1s [id=subnet-0a1b2c3d4e5f6g7h8]
aws_instance.web: Creating...
aws_instance.web: Still creating... [10s elapsed]
aws_instance.web: Still creating... [20s elapsed]
aws_instance.web: Creation complete after 30s [id=i-0a1b2c3d4e5f6g7h8]
Apply complete! Resources: 3 added, 0 changed, 0 destroyed.
Step 4: Verify Created Resources
After applying, you can verify the resources were created by checking the AWS console or using the AWS CLI. You can also use terraform show
to display the current state:
terraform show
Common Issues and Troubleshooting
Error: Resource Already Exists
If you try to create a resource that already exists outside of Terraform's management:
Error: Error creating instance: InvalidParameterValue: Value (my-instance-name)
for parameter virtualMachineName is invalid.
Solution: Import the existing resource into Terraform state:
terraform import aws_instance.example i-1234567890abcdef0
Dependency Errors
When Terraform can't determine the correct order to create resources:
Error: Error creating instance: InvalidSubnetID: The subnet ID 'subnet-abcdef'
does not exist
Solution: Check your resource dependencies and make sure they're explicitly defined when needed:
resource "aws_instance" "web" {
# Explicitly define the dependency
depends_on = [aws_subnet.main]
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t2.micro"
subnet_id = aws_subnet.main.id
}
State Lock Errors
When someone else is modifying the same infrastructure:
Error: Error acquiring the state lock
Solution: If you're sure no one else is running Terraform, you can force unlock:
terraform force-unlock LOCK_ID
Best Practices
- Always review the plan: Never apply without reviewing what changes will be made
- Use version control: Keep your Terraform files in a version control system
- Use workspaces: Separate your environments (dev, staging, prod) using workspaces
- Modularize your code: Break down complex infrastructure into reusable modules
- Use remote state: Store your state file remotely for collaboration
- Lock your provider versions: Prevent unexpected changes due to provider updates
Terraform Apply in CI/CD Pipelines
Terraform apply works well in automated pipelines. Here's a common pattern:
- CI Build Stage: Run
terraform plan -out=tfplan
- Review Stage: Have someone review the plan
- CD Deploy Stage: Run
terraform apply tfplan
This ensures that what you review is exactly what gets applied.
Example GitLab CI/CD pipeline:
stages:
- validate
- plan
- apply
validate:
stage: validate
script:
- terraform init
- terraform validate
plan:
stage: plan
script:
- terraform init
- terraform plan -out=tfplan
artifacts:
paths:
- tfplan
apply:
stage: apply
script:
- terraform init
- terraform apply -auto-approve tfplan
when: manual
only:
- master
Summary
The terraform apply
command is central to the Infrastructure as Code approach, allowing you to create, update, and manage infrastructure in a declarative way. By understanding how it works and following best practices, you can safely and efficiently manage your infrastructure across multiple environments.
Key points to remember:
- Terraform apply transforms your code into real infrastructure
- Always review the plan before applying
- Use targeting and variables for more control
- Incorporate apply into your CI/CD pipelines for automation
- Follow best practices for safe and effective infrastructure management
Additional Resources
Exercises
- Create a Terraform configuration for a simple web server and apply it
- Make a change to your configuration and apply only that change using the target flag
- Create a plan file, examine it, and then apply it
- Set up a simple CI/CD pipeline that runs terraform apply
- Practice handling common errors like dependency issues and resource conflicts
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)