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 1 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
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)
ebs_block_device - (Optional) One or more configuration blocks with additional EBS block devices to attach to the instance. Block device configurations only apply on resource creation.
So, as per documentation, ebs_block_device can only be applied during creation of the resource. In your case it is an EC2 instance which needs to be re-created.
Related
I have the following Terraform configuration that is used to create a cluster with two instances:
resource "aws_rds_cluster" "aurora" {
storage_encrypted = true
cluster_identifier = var.cluster_identifier
engine = "aurora-postgresql"
engine_mode = "provisioned"
engine_version = "13.6"
database_name = var.database_name
master_username = "test"
master_password = var.database_password
availability_zones = ["ap-southeast-2a", "ap-southeast-2b"]
db_subnet_group_name = var.db_subnet_group_name
serverlessv2_scaling_configuration {
max_capacity = 1.0
min_capacity = 0.5
}
tags = {
Name = "${var.prefix}-${var.environment}-rds-cluster"
Environment = "${var.prefix}-${var.environment}"
}
vpc_security_group_ids = var.aurora_security_group_id
skip_final_snapshot = true
}
resource "aws_rds_cluster_instance" "aurora" {
count = 2
availability_zone = var.availability_zones[count.index]
cluster_identifier = aws_rds_cluster.aurora.id
instance_class = "db.serverless"
engine = aws_rds_cluster.aurora.engine
engine_version = aws_rds_cluster.aurora.engine_version
db_subnet_group_name = var.db_subnet_group_name
publicly_accessible = true
}
If I make literally no changes to my configuration, and run terraform plan, I receive the output below:
module.potentium_databases.module.potentium_rds_cluster.aws_rds_cluster_instance.aurora[1] must be replaced
-/+ resource "aws_rds_cluster_instance" "aurora" {
+ apply_immediately = (known after apply)
~ arn = "arn:aws:rds:ap-southeast-2:749732509682:db:tf-20220706042316120800000001" -> (known after apply)
~ ca_cert_identifier = "rds-ca-2019" -> (known after apply)
~ cluster_identifier = "potentium-cluster" -> (known after apply) # forces replacement
~ db_parameter_group_name = "default.aurora-postgresql13" -> (known after apply)
~ dbi_resource_id = "db-5AH6GR5KJNW4IXQ2BSGNPLL4FM" -> (known after apply)
~ endpoint = "tf-20220706042316120800000001.cv6x1exxvfdc.ap-southeast-2.rds.amazonaws.com" -> (known after apply)
~ engine_version_actual = "13.6" -> (known after apply)
~ id = "tf-20220706042316120800000001" -> (known after apply)
~ identifier = "tf-20220706042316120800000001" -> (known after apply)
+ identifier_prefix = (known after apply)
~ kms_key_id = "arn:aws:kms:ap-southeast-2:749732509682:key/a3f87bb9-f0b4-44a4-8677-bac5f0bb1546" -> (known after apply)
+ monitoring_role_arn = (known after apply)
~ performance_insights_enabled = false -> (known after apply)
+ performance_insights_kms_key_id = (known after apply)
~ performance_insights_retention_period = 0 -> (known after apply)
~ port = 5432 -> (known after apply)
~ preferred_backup_window = "13:51-14:21" -> (known after apply)
~ preferred_maintenance_window = "thu:15:39-thu:16:09" -> (known after apply)
~ storage_encrypted = true -> (known after apply)
- tags = {} -> null
~ tags_all = {} -> (known after apply)
~ writer = false -> (known after apply)
# (10 unchanged attributes hidden)
}
Can anyone explain why Terraform thinks this resource needs to be recreated even if nothing has changed? It is causing me grief due to how long it takes to actually re-create the instances.
It appears my issue is that I was only specifying 2 Availability Zones instead of 3. Im assuming because Terraform/AWS is left to decide the third AZ, it must perform a re-create as it does not know what to use.
As I know, the re-creating issue is usually caused by the changed attribute, which is shown with #forces replacement. In your case:
~ cluster_identifier = "potentium-cluster" -> (known after apply) # forces replacement
Please double-check it.
I'm using Terraform 1.1.3 with aws provider 3.75.2 to create TF code for the existing 2-node infra. The code snippet is like below:
module:
resource "aws_ebs_volume" "backend-logs" {
count = var.create_ebs_log_volumes ? var.backend_nodes_qty : 0
availability_zone = element(data.aws_subnet.backend.*.availability_zone, count.index)
size = var.volume_log_size
type = var.ebs_volume_type
encrypted = var.ebs_enable_encryption
kms_key_id = var.ebs_encryption_key_id
}
resource "aws_volume_attachment" "backend-logs" {
count = var.backend_nodes_qty
device_name = "/dev/sdf"
volume_id = element(module.xyz.backend_ebs_volume_log_ids, count.index)
instance_id = element(module.xyz.backend_instance_ids, count.index)
}
and I've imported the instance/volume/attachment resources successfully.
terraform import module.xyz.aws_ebs_volume.backend-logs[0] vol-0123456789abcedf0
terraform import module.xyz.aws_ebs_volume.backend-logs[1] vol-0123456789abcedf1
terraform import aws_volume_attachment.backend-logs[0] /dev/sdf:vol-0123456789abcedf0:i-0123456789abcedf0
terraform import aws_volume_attachment.backend-logs[1] /dev/sdf:vol-0123456789abcedf1:i-0123456789abcedf1
When I run terraform plan, the plan tells me that the volumes are going to be destroyed. How can we avoid that? thanks
# aws_volume_attachment.backend-logs[0] must be replaced
-/+ resource "aws_volume_attachment" "backend-logs" {
~ id = "vai-1993905001" -> (known after apply)
~ volume_id = "vol-0123456789abcedf0" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
# aws_volume_attachment.backend-logs[1] must be replaced
-/+ resource "aws_volume_attachment" "backend-logs" {
~ id = "vai-1955292002" -> (known after apply)
~ volume_id = "vol-0123456789abcedf1" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
# module.xyz.aws_ebs_volume.backend-logs[0] must be replaced
-/+ resource "aws_ebs_volume" "backend-logs" {
~ arn = "arn:aws:ec2:us-west-2:1234567890:volume/vol-0123456789abcedf0" -> (known after apply)
~ availability_zone = "us-west-2a" -> (known after apply) # forces replacement
~ id = "vol-0123456789abcedf0" -> (known after apply)
~ iops = 150 -> (known after apply)
+ kms_key_id = (known after apply)
- multi_attach_enabled = false -> null
+ snapshot_id = (known after apply)
~ throughput = 0 -> (known after apply)
# (3 unchanged attributes hidden)
}
# module.xyz.aws_ebs_volume.backend-logs[1] must be replaced
-/+ resource "aws_ebs_volume" "backend-logs" {
~ arn = "arn:aws:ec2:us-west-2:1234567890:volume/vol-0123456789abcedf1" -> (known after apply)
~ availability_zone = "us-west-2b" -> (known after apply) # forces replacement
~ id = "vol-0123456789abcedf1" -> (known after apply)
~ iops = 150 -> (known after apply)
+ kms_key_id = (known after apply)
- multi_attach_enabled = false -> null
+ snapshot_id = (known after apply)
~ throughput = 0 -> (known after apply)
# (3 unchanged attributes hidden)
}
It seems that the issue relates to AZ stuff. You can try the workaround by adding these lines in aws_instance block.
lifecycle {
ignore_changes = [ availability_zone ]
}
I created a documentdb cluster by terraform. When I run terraform plan, it tried to destroy the cluster and rebuild it, but I didn't change the value file.
below is the main content of terraform script,
resource "aws_docdb_subnet_group" "default" {
name = format("%s-subnet-group", var.env)
subnet_ids = [
data.terraform_remote_state.net.outputs.cicd-sub-priv1,
data.terraform_remote_state.net.outputs.cicd-sub-priv2,
data.terraform_remote_state.net.outputs.cicd-sub-pub2,
]
tags = {
Name = format("%s-subnet-group", var.env)
}
}
resource "aws_docdb_cluster_instance" "docdb" {
count = var.docdb_instance_count
identifier = "${var.env}-docdb-instance-${count.index}"
cluster_identifier = aws_docdb_cluster.docdb.id
instance_class = var.docdb_instance_class
tags = {
Name = format("%s-docdb-cluster-instance", var.env)
}
}
resource "aws_docdb_cluster" "docdb" {
cluster_identifier = format("%s-docdb-cluster", var.env)
availability_zones = var.docdb_az
db_subnet_group_name = aws_docdb_subnet_group.default.id
master_username = var.docdb_master_username
master_password = var.docdb_master_password
storage_encrypted = "true"
kms_key_id = data.aws_kms_alias.rds.arn
final_snapshot_identifier = format("%s-docdb-final-snapshot", var.env)
engine = "docdb"
engine_version = "4.0.0"
port = var.docdb_port
tags = {
Name = format("%s-docdb-cluster", var.env)
}
}
output "docdb_name" {
value = aws_docdb_cluster.docdb.id
description = "The name of docdb cluster"
}
output "docdb_arn" {
value = aws_docdb_cluster.docdb.arn
description = "The arn of docdb cluster"
}
output "docdb_endpoint" {
value = aws_docdb_cluster.docdb.endpoint
description = "The DNS address of the DocDB instance"
}
data_kms_alias_rds.tf
data "aws_kms_alias" "rds" {
name = "alias/aws/rds"
}
and these are terraform plan out reult
$ terraform plan -out tfplan -var-file test.tfvars
Acquiring state lock. This may take a few moments...
aws_docdb_subnet_group.default: Refreshing state... [id=test-subnet-group]
aws_docdb_cluster.docdb: Refreshing state... [id=test-docdb-cluster]
aws_docdb_cluster_instance.docdb[0]: Refreshing state... [id=test-docdb-instance-0]
aws_docdb_cluster_instance.docdb[1]: Refreshing state... [id=test-docdb-instance-1]
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
# aws_docdb_cluster.docdb has been changed
~ resource "aws_docdb_cluster" "docdb" {
~ cluster_members = [
+ "test-docdb-instance-0",
+ "test-docdb-instance-1",
]
+ enabled_cloudwatch_logs_exports = []
id = "test-docdb-cluster"
+ tags = {}
# (24 unchanged attributes hidden)
}
# aws_docdb_cluster_instance.docdb[0] has been changed
~ resource "aws_docdb_cluster_instance" "docdb" {
id = "test-docdb-instance-0"
+ tags = {}
# (21 unchanged attributes hidden)
}
# aws_docdb_cluster_instance.docdb[1] has been changed
~ resource "aws_docdb_cluster_instance" "docdb" {
id = "test-docdb-instance-1"
+ tags = {}
# (21 unchanged attributes hidden)
}
Unless you have made equivalent changes to your configuration, or ignored the relevant attributes using ignore_changes, the
following plan may include actions to undo or respond to these changes.
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
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_docdb_cluster.docdb must be replaced
-/+ resource "aws_docdb_cluster" "docdb" {
+ apply_immediately = (known after apply)
~ arn = "arn:aws:rds:us-east-1:<hidden>:cluster:test-docdb-cluster" -> (known after apply)
+ cluster_identifier_prefix = (known after apply)
~ cluster_members = [
- "test-docdb-instance-0",
- "test-docdb-instance-1",
] -> (known after apply)
~ cluster_resource_id = "cluster-<hidden>" -> (known after apply)
~ db_cluster_parameter_group_name = "default.docdb4.0" -> (known after apply)
- deletion_protection = false -> null
- enabled_cloudwatch_logs_exports = [] -> null
~ endpoint = "<hidden>" -> (known after apply)
~ hosted_zone_id = "ZNKXH85TT8WVW" -> (known after apply)
~ id = "test-docdb-cluster" -> (known after apply)
~ kms_key_id = "arn:aws:kms:us-east-1:<hidden>:key/<hidden>" -> "arn:aws:kms:us-east-1:<hidden>:alias/aws/rds" # forces replacement
~ preferred_backup_window = "07:55-08:25" -> (known after apply)
~ preferred_maintenance_window = "wed:10:07-wed:10:37" -> (known after apply)
~ reader_endpoint = "<hidden>" -> (known after apply)
- tags = {} -> null
~ tags_all = {} -> (known after apply)
~ vpc_security_group_ids = [
- "sg-066866c3e4988de42",
] -> (known after apply)
# (12 unchanged attributes hidden)
}
# aws_docdb_cluster_instance.docdb[0] must be replaced
-/+ resource "aws_docdb_cluster_instance" "docdb" {
+ apply_immediately = (known after apply)
~ arn = "arn:aws:rds:us-east-1:<hidden>:db:test-docdb-instance-0" -> (known after apply)
~ availability_zone = "us-east-1a" -> (known after apply)
~ ca_cert_identifier = "rds-ca-2019" -> (known after apply)
~ cluster_identifier = "test-docdb-cluster" -> (known after apply) # forces replacement
~ db_subnet_group_name = "test-subnet-group" -> (known after apply)
~ dbi_resource_id = "db-<hidden>" -> (known after apply)
~ endpoint = "<hidden>" -> (known after apply)
~ engine_version = "4.0.0" -> (known after apply)
~ id = "test-docdb-instance-0" -> (known after apply)
+ identifier_prefix = (known after apply)
~ kms_key_id = "arn:aws:kms:us-east-1:<hidden>:key/<hidden>" -> (known after apply)
~ port = 37018-> (known after apply)
~ preferred_backup_window = "07:55-08:25" -> (known after apply)
~ preferred_maintenance_window = "sat:07:23-sat:07:53" -> (known after apply)
~ publicly_accessible = false -> (known after apply)
~ storage_encrypted = true -> (known after apply)
- tags = {} -> null
~ tags_all = {} -> (known after apply)
~ writer = false -> (known after apply)
# (5 unchanged attributes hidden)
}
# aws_docdb_cluster_instance.docdb[1] must be replaced
-/+ resource "aws_docdb_cluster_instance" "docdb" {
+ apply_immediately = (known after apply)
~ arn = "arn:aws:rds:us-east-1:<hidden>:db:test-docdb-instance-1" -> (known after apply)
~ availability_zone = "us-east-1c" -> (known after apply)
~ ca_cert_identifier = "rds-ca-2019" -> (known after apply)
~ cluster_identifier = "test-docdb-cluster" -> (known after apply) # forces replacement
~ db_subnet_group_name = "test-subnet-group" -> (known after apply)
~ dbi_resource_id = "db-<hidden>" -> (known after apply)
~ endpoint = "<hidden>" -> (known after apply)
~ engine_version = "4.0.0" -> (known after apply)
~ id = "test-docdb-instance-1" -> (known after apply)
+ identifier_prefix = (known after apply)
~ kms_key_id = "arn:aws:kms:us-east-1:<hidden>:key/<hidden>" -> (known after apply)
~ port = 37018 -> (known after apply)
~ preferred_backup_window = "07:55-08:25" -> (known after apply)
~ preferred_maintenance_window = "sat:05:13-sat:05:43" -> (known after apply)
~ publicly_accessible = false -> (known after apply)
~ storage_encrypted = true -> (known after apply)
- tags = {} -> null
~ tags_all = {} -> (known after apply)
~ writer = true -> (known after apply)
# (5 unchanged attributes hidden)
}
Plan: 3 to add, 0 to change, 3 to destroy.
Changes to Outputs:
~ docdb_arn = "arn:aws:rds:us-east-1:<hidden>:cluster:test-docdb-cluster" -> (known after apply)
~ docdb_endpoint = "<hidden>" -> (known after apply)
~ docdb_name = "test-docdb-cluster" -> (known after apply)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Saved the plan to: tfplan
To perform exactly these actions, run the following command to apply:
terraform apply "tfplan"
Releasing state lock. This may take a few moments...
How can I keep update the documentdb cluster without rebuilding every time I run my script?
Changing kms key for your DocumentDB requires replacement. There is not much you can do about that.
You are correctly referring to default kms (kms_key_id = data.aws_kms_alias.rds.arn). But since you had different kms key before, a replacement is required. If so, make sure you backup your db before that.
It seems that AWS replaced the value for kms_key_id property during creation of the cluster.
Try to use target_key_arn property instead of arn of the alias in the cluster resource:
kms_key_id = data.aws_kms_alias.rds.target_key_arn
That’s the only property which forces replacement of the cluster resource. Cluster instances replacement is a consequence of the cluster replacement.
I am creating the EC2 instance and multiple EBS volumes with different sizes. Below Terraform script is given for creating the same.
resource "aws_ebs_volume" "ebs_volume" {
for_each = {
0 = var.influxdb_data_volume_size
1 = var.influxdb_wal_volume_size
2 = var.telegraf_volume_size
3 = var.grafana_volume_size
4 = var.data_volume_size
}
availability_zone = var.availability_zone
size = each.value
type = "gp2"
tags = {
name = "${var.tag}-ebs-volume"
billing = var.tag
}
}
# section for the EBS volume attachment
resource "aws_volume_attachment" "volume_attachement" {
count = var.ebs_volume_count
volume_id = aws_ebs_volume.ebs_volume[count.index].id
device_name = "${element(var.ec2_device_names, count.index)}"
instance_id = aws_instance.ec2_production.id
}
# section for the aws_key_pair
resource "aws_key_pair" "key_pair" {
key_name = "${var.tag}-key-pair"
public_key = var.key_pair
tags = {
name = "${var.tag}-key-pair"
billing = var.tag
}
}
resource "aws_instance" "ec2_production" {
# count = "${var.ec2_instance_count}"
ami = var.ami
availability_zone = var.availability_zone
instance_type = var.ec2_instance_type
subnet_id = aws_subnet.subnet.id
associate_public_ip_address = true
vpc_security_group_ids = [aws_security_group.security_group_access_internet.id]
# disable_api_termination = true
key_name = "${var.tag}-key-pair"
ebs_block_device {
device_name = "/dev/sda1"
volume_type = "gp2"
volume_size = var.root_volume_size
}
tags = {
name = "${var.tag}-ec2"
billing = var.tag
}
}
The volume defined in aws_instance resource is the root volume having size of 40GB and I am creating multiple volumes of different sizes in aws_ebs_volume resource.
Now I am trying to change the size of the root volume from 40GB to 60GB by updating the variable.tf file.
When I am using the command terraform plan it's creating 6 resources and destroying 6 resources which include the EBS volumes and EC2 instance.
Now, I want to increase the size of any volume which is root or any other which recreating or destroying anything.
Below I am giving output of terraform plan:
-/+ resource "aws_instance" "ec2_production" {
~ arn = "arn:aws:ec2:us-west-1:666268854852:instance/i-0ac516fab494df462" -> (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-0ac516fab494df462" -> (known after apply)
~ instance_initiated_shutdown_behavior = "stop" -> (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-0fd71c3a3e41237be" -> (known after apply)
~ private_dns = "ip-10-0-16-27.us-west-1.compute.internal" -> (known after apply)
~ private_ip = "10.0.16.27" -> (known after apply)
+ public_dns = (known after apply)
~ public_ip = "13.56.209.171" -> (known after apply)
~ secondary_private_ips = [] -> (known after apply)
~ security_groups = [] -> (known after apply)
tags = {
"billing" = "att"
"name" = "ec2"
}
~ tenancy = "default" -> (known after apply)
# (10 unchanged attributes hidden)
- credit_specification {
- cpu_credits = "standard" -> null
}
- ebs_block_device { # forces replacement
- delete_on_termination = false -> null
- device_name = "/dev/sdf" -> null
- encrypted = false -> null
- iops = 300 -> null
- tags = {
- "billing" = "att"
- "name" = "volume"
} -> null
- throughput = 0 -> null
- volume_id = "vol-08569e15ccd8f1aad" -> null
- volume_size = 100 -> null
- volume_type = "gp2" -> null
}
- ebs_block_device { # forces replacement
- delete_on_termination = false -> null
- device_name = "/dev/sdg" -> null
- encrypted = false -> null
- iops = 150 -> null
- tags = {
- "billing" = "att"
- "name" = "volume"
} -> null
- throughput = 0 -> null
- volume_id = "vol-0e8c7cd7830fa2e02" -> null
- volume_size = 50 -> null
- volume_type = "gp2" -> null
}
- ebs_block_device { # forces replacement
- delete_on_termination = false -> null
- device_name = "/dev/sdh" -> null
- encrypted = false -> null
- iops = 100 -> null
- tags = {
- "billing" = "att"
- "name" = "volume"
} -> null
- throughput = 0 -> null
- volume_id = "vol-0f989100daa275774" -> null
- volume_size = 20 -> null
- volume_type = "gp2" -> null
}
- ebs_block_device { # forces replacement
- delete_on_termination = false -> null
- device_name = "/dev/sdi" -> null
- encrypted = false -> null
- iops = 100 -> null
- tags = {
- "billing" = "att"
- "name" = "volume"
} -> null
- throughput = 0 -> null
- volume_id = "vol-03cd5be3fea05aa45" -> null
- volume_size = 20 -> null
- volume_type = "gp2" -> null
}
- ebs_block_device { # forces replacement
- delete_on_termination = false -> null
- device_name = "/dev/sdj" -> null
- encrypted = false -> null
- iops = 150 -> null
- tags = {
- "billing" = "att"
- "name" = "volume"
} -> null
- throughput = 0 -> null
- volume_id = "vol-023e380eebbf2c91f" -> null
- volume_size = 50 -> null
- volume_type = "gp2" -> 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 = 60
+ volume_type = "gp2"
}
~ 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 = 120 -> (known after apply)
+ kms_key_id = (known after apply)
~ tags = {} -> (known after apply)
~ throughput = 0 -> (known after apply)
~ volume_id = "vol-054112f2f104ff54e" -> (known after apply)
~ volume_size = 40 -> (known after apply)
~ volume_type = "gp2" -> (known after apply)
}
}
# aws_volume_attachment.volume_attachement[0] must be replaced
-/+ resource "aws_volume_attachment" "volume_attachement" {
~ id = "vai-1464807002" -> (known after apply)
~ instance_id = "i-0ac516fab494df462" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
# aws_volume_attachment.volume_attachement[1] must be replaced
-/+ resource "aws_volume_attachment" "volume_attachement" {
~ id = "vai-3274211254" -> (known after apply)
~ instance_id = "i-0ac516fab494df462" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
# aws_volume_attachment.volume_attachement[2] must be replaced
-/+ resource "aws_volume_attachment" "volume_attachement" {
~ id = "vai-1831356480" -> (known after apply)
~ instance_id = "i-0ac516fab494df462" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
# aws_volume_attachment.volume_attachement[3] must be replaced
-/+ resource "aws_volume_attachment" "volume_attachement" {
~ id = "vai-374757704" -> (known after apply)
~ instance_id = "i-0ac516fab494df462" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
# aws_volume_attachment.volume_attachement[4] must be replaced
-/+ resource "aws_volume_attachment" "volume_attachement" {
~ id = "vai-3725815030" -> (known after apply)
~ instance_id = "i-0ac516fab494df462" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
Plan: 6 to add, 0 to change, 6 to destroy.
Is there any way to achieve to update the volume size without destroying anything?
I am using Terraform to manage my infrastructure in AWS, I have used Terraform to launch one bastion instance.
My issue is that every time I do a terraform plan, Terraform tells me that it would be destroy and recreate that bastion instance and terraform apply does it.
Here is my code:
resource "aws_instance" "bastion" {
ami = var.ami_id
instance_type = "t2.micro"
key_name = var.key_name
monitoring = false
vpc_security_group_ids = [aws_security_group.`bastion_sg`.id]
subnet_id = var.subnet_id_private
iam_instance_profile = aws_iam_instance_profile.instance_profile.name
user_data = data.template_file.script.rendered
tags = merge(
{
"Name" = local.name_prefix
},
var.default_tags,
)
ebs_block_device {
device_name = "/dev/sda1"
volume_size = 8
volume_type = "gp2"
delete_on_termination = true
}
}
Here is terrafrom plan output:
# module.bastion.aws_instance.bastion must be replaced
-/+ resource "aws_instance" "bastion" {
~ arn = "arn:aws:ec2:xx-xxxx-x:xxxxx:instance/i-xxxxxxxxxxxxxx" -> (known after apply)
~ associate_public_ip_address = false -> (known after apply)
~ availability_zone = "xx-xxxx-xx" -> (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-xxxxxxxxxxxxxx" -> (known after apply)
~ instance_state = "running" -> (known after apply)
~ ipv6_address_count = 0 -> (known after apply)
~ ipv6_addresses = [] -> (known after apply)
+ outpost_arn = (known after apply)
+ password_data = (known after apply)
+ placement_group = (known after apply)
~ primary_network_interface_id = "eni-xxxxxxxxxxxxxx" -> (known after apply)
~ private_dns = "ip-xx-xxx-xxx-xxxxx.xx-xxxx-x.compute.internal" -> (known after apply)
~ private_ip = "xx.xxx.x.xx" -> (known after apply)
+ public_dns = (known after apply)
+ public_ip = (known after apply)
~ secondary_private_ips = [] -> (known after apply)
~ security_groups = [] -> (known after apply)
~ tenancy = "default" -> (known after apply)
# (10 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 = 8
+ volume_type = "gp2"
}
- ebs_block_device { # forces replacement
- delete_on_termination = true -> null
- device_name = "/dev/sda1" -> null
- encrypted = false -> null
- iops = 100 -> null
- snapshot_id = "snap-xxxxxxxxxxxxxx" -> null
- tags = {} -> null
- throughput = 0 -> null
- volume_id = "vol-xxxxxxxxxxxxxx" -> null
- volume_size = 8 -> 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-xxxxxxxxxxxxxx" -> (known after apply)
~ volume_size = 8 -> (known after apply)
~ volume_type = "gp2" -> (known after apply)
}
}
So it is the EBS volume that is causing the replacement.
The most likely cause is that it hasn't been able to attach to /dev/sda1 so when Terraform looks in the plan it sees its disk is not on sda1 and decides it needs to replace the instance.
You would need to confirm this when the instance is running to see where your volume has been attached to (this can be on the instance or in the console).
It is likely that the root volume has been attached to sda1 pushing yours elsewhere.
If this is the case then you would need to change the mount point of this volume OR if you intend this to be the root volume then use root_block_device