'What happens if running "terraform apply" twice? (Terraform)

What happens if running "terraform apply" twice? Does it create all the resources twice?



Solution 1:[1]

I'm assuming that when you say "terraform deploy" here you mean running the terraform apply command.

The first time you run terraform apply against an entirely new configuration, Terraform will propose to create new objects corresponding with each of the resource instances you declared in the configuration. If you accept the plan and thus allow Terraform to really apply it, Terraform will create each of those objects and record information about them in the Terraform state.

If you then run terraform apply again, Terraform will compare your configuration with the state to see if there are any differences. This time, Terraform will propose changes only if the configuration doesn't match the existing objects that are recorded in the state. If you accept that plan then Terraform will take each of the actions it proposed, which can be a mixture of different action types: update, create, destroy.

This means that in order to use Terraform successfully you need to make sure to keep the state snapshots safe between Terraform runs. With no special configuration at all Terraform will by default save the state in a local file called terraform.tfstate, but when you are using Terraform in production you'll typically use remote state, which is a way to tell Terraform to store state snapshots in a remote data store separate from the computer where you are running Terraform. By storing the state in a location that all of your coworkers can access, you can collaborate together.

If you use Terraform Cloud, a complementary hosted service provided by HashiCorp, you can configure Terraform to store the state snapshots in Terraform Cloud itself. Terraform Cloud has various other capabilities too, such as running Terraform in a remote execution environment so that everyone who uses that environment can be sure to run Terraform with a consistent set of environment variables stored remotely.

Solution 2:[2]

If you run the terraform apply command first time, it will create the necessary resource which was in terraform plan.

If you run the terraform apply command second time, it will try to check if that resource already exist there or not. If found then will not create any duplicate resource.

Before running the terraform apply for the second time, if you run terraform plan you will get the list of change/create/delete list.

Solution 3:[3]

Apr, 2022 Update:

  • The first run of "terraform apply" creates(adds) resources.
  • The second or later run of "terraform apply" creates(adds), updates(changes) or deletes(destroys) existed resources if there are changes for them. Plus, basically when changing the mutable value of an existed resource, its existed resource is updated rather than deleted then created and basically when changing the immutable value of an existed resource, its existed resource is deleted then created rather than updated.

*A mutable value is the value which can change after creating a resource.

*An immutable values is the value which cannot change after creating a resource.

For example, I create(add) the Cloud Storage bucket "kai_bucket" with the Terraform code below:

resource "google_storage_bucket" "bucket" {
    name                        = "kai_bucket"
    location                    = "ASIA-NORTHEAST1"
    force_destroy               = true
    uniform_bucket_level_access = true
}

So, do the first run of the command below:

terraform apply -auto-approve

Then, one resource "kai_bucket" is created(added) as shown below:

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:

  # google_storage_bucket.bucket will be created
  + resource "google_storage_bucket" "bucket" {
      + force_destroy               = true
      + id                          = (known after apply)
      + location                    = "ASIA-NORTHEAST1"
      + name                        = "kai_bucket"
      + project                     = (known after apply)
      + self_link                   = (known after apply)
      + storage_class               = "STANDARD"
      + uniform_bucket_level_access = true
      + url                         = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.
google_storage_bucket.bucket: Creating...
google_storage_bucket.bucket: Creation complete after 1s [id=kai_bucket]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Now, I change the mutable value "uniform_bucket_level_access" from "true" to "false":

resource "google_storage_bucket" "bucket" {
    name                        = "kai_bucket"
    location                    = "ASIA-NORTHEAST1"
    force_destroy               = true
    uniform_bucket_level_access = false # Here
}

Then, do the second run of the command below:

terraform apply -auto-approve

Then, "uniform_bucket_level_access" is updated(changed) from "true" to "false" as shown below:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # google_storage_bucket.bucket will be updated in-place
  ~ resource "google_storage_bucket" "bucket" {
        id                          = "kai_bucket"
        name                        = "kai_bucket"
      ~ uniform_bucket_level_access = true -> false
        # (9 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
google_storage_bucket.bucket: Modifying... [id=kai_bucket]
google_storage_bucket.bucket: Modifications complete after 1s [id=kai_bucket]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Now, I change the immutable value "location" from "ASIA-NORTHEAST1" to "US-EAST1":

resource "google_storage_bucket" "bucket" {
    name                        = "kai_bucket"
    location                    = "US-EAST1" # Here
    force_destroy               = true
    uniform_bucket_level_access = false
}

Then, do the third run of the command below:

terraform apply -auto-approve

Then, one resource "kai_bucket" with "ASIA-NORTHEAST1" is deleted(destroyed) then one resource "kai_bucket" with "US-EAST1" is created(added) as shown below:

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:

  # google_storage_bucket.bucket must be replaced
-/+ resource "google_storage_bucket" "bucket" {
      - default_event_based_hold    = false -> null
      ~ id                          = "kai_bucket" -> (known after apply)
      - labels                      = {} -> null
      ~ location                    = "ASIA-NORTHEAST1" -> "US-EAST1" # forces replacement
        name                        = "kai_bucket"
      ~ project                     = "myproject-272234" -> (known after apply)
      - requester_pays              = false -> null
      ~ self_link                   = "https://www.googleapis.com/storage/v1/b/kai_bucket" -> (known after apply)
      ~ url                         = "gs://kai_bucket" -> (known after apply)
        # (3 unchanged attributes hidden)
    }

Plan: 1 to add, 0 to change, 1 to destroy.
google_storage_bucket.bucket: Destroying... [id=kai_bucket]
google_storage_bucket.bucket: Destruction complete after 1s
google_storage_bucket.bucket: Creating...
google_storage_bucket.bucket: Creation complete after 1s [id=kai_bucket]

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Martin Atkins
Solution 2 Soumik Das
Solution 3 Kai - Kazuya Ito