I am trying to increase size of my root volume for my ami ami-0d013c5896434b38a - I am using Terraform to provision this.
Just to clarify - I have only one instance. And I want to make sure that if I need to increase the disk space, I don't have to destroy the machine first. Elasticity (EC2) is my reason to believe that it's doable.
Does anyone know whether this is doable? Yes, I could simply do terraform plan and do a dry-run, but just double-checking.
I'm running Terraform 1.0.1 and would like to change my volume_size from 20gb to 30gb.
After run terraform apply
[...]
# aws_instance.typo3_staging_1 will be updated in-place
~ resource "aws_instance" "staging_1" {
id = "i-0eb2f8af6c8ac4125"
tags = {
"Name" = "Staging 1"
"Team" = "DevOps"
}
# (28 unchanged attributes hidden)
~ root_block_device {
tags = {}
~ volume_size = 20 -> 30
# (8 unchanged attributes hidden)
}
# (4 unchanged blocks hidden)
}
Plan: 0 to add, 1 to change, 0 to destroy.
[...]
I see that terraform will not destroy the system. Now a simple 'yes' change the volume. After ~33sec the root_block_device has been changed.
A login on the ec2 shows nothing has been changed. df shows the old 20gb size of the root partition. But a simple sudo reboot increased the disk space by 10gb without destoring the current system. All docker containers on that instance runs as expected. Perfect.
My Terraform resource config for such aws_instance is:
resource "aws_instance" "staging_1" {
instance_type = "t3.medium"
ebs_optimized = true
ami = "ami-001183208be54f75c"
key_name = aws_key_pair.master_key.key_name
subnet_id = aws_subnet.web_development_private_a.id
vpc_security_group_ids = [aws_security_group.ec2_staging.id]
root_block_device {
volume_size = 30 # in GB <<----- I increased this!
volume_type = "gp3"
encrypted = true
kms_key_id = data.aws_kms_key.customer_master_key.arn
}
# This is for T3 only (doesn't apply to M5/R5/...)
# standard: Baseline of 20% or 30% CPU. Short bursts of 100% CPU are possible, but under a budget. Throttled, if budget is 0.
# unlimited: Always 100% CPU possible, but costs are higher, if over burst budget.
credit_specification {
cpu_credits = "unlimited"
}
metadata_options {
http_endpoint = "enabled"
http_tokens = "required"
}
lifecycle {
prevent_destroy = true
}
tags = {
Name = "Staging 1"
Team = "DevOps"
}
volume_tags = {
Name = "Staging 1"
Team = "DevOps"
}
}
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
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.
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
terraform state rm) for the aws_instance resource.$ terraform state rm aws_instance.testebs
Removed aws_instance.testebs
Successfully removed 1 resource instance(s).
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With