It is doable through the AWS Console or AWS CLI, but not through Terraform, based on a quick test.
Changing the volume_size parameter from 10 to 20 in an aws_instance definition such as the one below caused a destroy/re-create of the instance. Using terraform 0.15.0
If you need to keep managing the instance with Terraform, consider the option of (1) performing the modification outside of Terraform (aws console or CLI) and (2) importing the modified resource back into terraform.
In the second section of the answer I describe a simple example of re-importing into Terraform the state of the aws_instance modified through the console. Disclaimer: do this at your own risk and after suitable testing in a non-production environment. Read carefully the warnings in the documentation for the terraform import command
Testing EBS modification done in Terraform - requires instance replacement
resource "aws_instance" "testebs" {
availability_zone = local.aznames[0]
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
associate_public_ip_address = true
key_name = "zzzzzzzz"
ebs_block_device {
device_name = "/dev/sda1"
volume_size = 20
}
}
I paste below the full config and the output of terraform plan.
The ami is a recent ubuntu 20.04 for eu-west-1, not the one in the original question.
File ebstest.tf
terraform {
required_version = "~> 0.15.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 3.0"
}
}
}
provider "aws" {
region = "eu-west-1"
profile = "xxxxxxx"
}
data "aws_ami" "ubuntu" {
most_recent = true
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
filter {
name = "virtualization-type"
values = ["hvm"]
}
filter {
name = "root-device-type"
values = ["ebs"]
}
owners = ["099720109477"] # Canonical
}
data "aws_availability_zones" "available" {
state = "available"
}
locals {
aznames = data.aws_availability_zones.available.names
}
resource "aws_instance" "testebs" {
availability_zone = local.aznames[0]
ami = data.aws_ami.ubuntu.id
instance_type = "t2.micro"
associate_public_ip_address = true
key_name = "zzzzzzzz"
ebs_block_device {
device_name = "/dev/sda1"
volume_size = 20
}
tags = {
Name = "testebs-${local.aznames[0]}"
}
}
Output of terraform plan:
$ terraform plan
aws_instance.testebs: Refreshing state... [id=i-0e1fededb2e432a98]
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
# aws_instance.testebs must be replaced
-/+ resource "aws_instance" "testebs" {
~ arn = "arn:aws:ec2:eu-west-1:xxxxxxxxxxxxx:instance/i-0e1fededb2e432a98" -> (known after apply)
~ cpu_core_count = 1 -> (known after apply)
~ cpu_threads_per_core = 1 -> (known after apply)
- disable_api_termination = false -> null
- ebs_optimized = false -> null
- hibernation = false -> null
+ host_id = (known after apply)
~ id = "i-0e1fededb2e432a98" -> (known after apply)
~ instance_state = "running" -> (known after apply)
~ ipv6_address_count = 0 -> (known after apply)
~ ipv6_addresses = [] -> (known after apply)
- monitoring = false -> null
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
~ primary_network_interface_id = "eni-0a923724fec1e76ce" -> (known after apply)
~ private_dns = "ip-172-31-13-57.eu-west-1.compute.internal" -> (known after apply)
~ private_ip = "172.31.13.57" -> (known after apply)
~ public_dns = "ec2-3-250-102-86.eu-west-1.compute.amazonaws.com" -> (known after apply)
~ public_ip = "3.250.102.86" -> (known after apply)
~ secondary_private_ips = [] -> (known after apply)
~ security_groups = [
- "default",
] -> (known after apply)
~ subnet_id = "subnet-192e767f" -> (known after apply)
tags = {
"Name" = "testebs-eu-west-1a"
}
~ tenancy = "default" -> (known after apply)
~ vpc_security_group_ids = [
- "sg-d7dc5a9a",
] -> (known after apply)
# (7 unchanged attributes hidden)
- credit_specification {
- cpu_credits = "standard" -> null
}
+ ebs_block_device { # forces replacement
+ delete_on_termination = true
+ device_name = "/dev/sda1"
+ encrypted = (known after apply)
+ iops = (known after apply)
+ kms_key_id = (known after apply)
+ snapshot_id = (known after apply)
+ throughput = (known after apply)
+ volume_id = (known after apply)
+ volume_size = 20
+ volume_type = (known after apply)
}
- ebs_block_device { # forces replacement
- delete_on_termination = true -> null
- device_name = "/dev/sda1" -> null
- encrypted = false -> null
- iops = 100 -> null
- snapshot_id = "snap-0f4b18aebb4264157" -> null
- tags = {} -> null
- throughput = 0 -> null
- volume_id = "vol-01eade74ebeba666f" -> null
- volume_size = 10 -> null
- volume_type = "gp2" -> null
}
~ enclave_options {
~ enabled = false -> (known after apply)
}
+ ephemeral_block_device {
+ device_name = (known after apply)
+ no_device = (known after apply)
+ virtual_name = (known after apply)
}
~ metadata_options {
~ http_endpoint = "enabled" -> (known after apply)
~ http_put_response_hop_limit = 1 -> (known after apply)
~ http_tokens = "optional" -> (known after apply)
}
+ network_interface {
+ delete_on_termination = (known after apply)
+ device_index = (known after apply)
+ network_interface_id = (known after apply)
}
~ root_block_device {
~ delete_on_termination = true -> (known after apply)
~ device_name = "/dev/sda1" -> (known after apply)
~ encrypted = false -> (known after apply)
~ iops = 100 -> (known after apply)
+ kms_key_id = (known after apply)
~ tags = {} -> (known after apply)
~ throughput = 0 -> (known after apply)
~ volume_id = "vol-01eade74ebeba666f" -> (known after apply)
~ volume_size = 10 -> (known after apply)
~ volume_type = "gp2" -> (known after apply)
}
}
Plan: 1 to add, 0 to change, 1 to destroy.
Testing modification through AWS Console and importing resource from terraform (see disclaimer/warning above).
- Create instance with 10G volume as per the previous part of the answer.
- Modify EBS volume size to 20G in AWS Console.
(did not extend the volume at OS level -- exercise for the reader :D)
- List Terraform items in the state file and select aws_instance resource for which the state will be removed
$ terraform state list
data.aws_ami.ubuntu
data.aws_availability_zones.available
aws_instance.testebs
- Remove state (terraform state rm) for the aws_instance resource.
$ terraform state rm aws_instance.testebs
Removed aws_instance.testebs
Successfully removed 1 resource instance(s).
- Using terraform import, import the aws_resource using the instance-id of the modified ec2 instance
$ terraform import aws_instance.testebs i-xxxxxxxxxxxxxxxx
aws_instance.testebs: Importing from ID "i-xxxxxxxxxxxxxxxx"...
aws_instance.testebs: Import prepared!
Prepared aws_instance for import
aws_instance.testebs: Refreshing state... [id=i-xxxxxxxxxxxxxxxx]
Import successful!
The resources that were imported are shown above. These resources are now in your Terraform state and will henceforth be managed by Terraform.
- Verify that terraform can manage the imported instance properly (modify instance through terraform and verify behavior)