linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
Intro
Lessons
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Knowledge base
  • Cheat sheet
  • Capstone
  • Interview prep
Cluster

← все кластеры

Provider and resource: lifecycle, count/for_each

The provider block, alias, multi-region. Resource lifecycle (create_before_destroy, prevent_destroy, ignore_changes), count vs for_each, data vs resource, and depends_on when it is honestly needed. The grammar of everyday Terraform work.

6 вопросов · ~24 мин чтения

Questions

На этой странице

  1. 01What is the difference between `count` and `for_each`? Which do you pick in new code?
  2. 02How is a data source different from a resource? When do you use each?
  3. 03What does `alias` do in a provider block? Why do you need it?
  4. 04What does `create_before_destroy` do, and why do you need it?
  5. 05When is `ignore_changes` genuinely needed, and when is it a crutch?
  6. 06When is `depends_on` honestly needed, and when can you avoid it?

#count-vs-for-each

juniorчасто

What is the difference between `count` and `for_each`? Which do you pick in new code?

Что отвечать

`count = N` creates N identical resources at addresses `r[0]`, `r[1]`, `r[2]`. `for_each = set/map` creates one resource per element at addresses `r["alpha"]`, `r["beta"]`. The main difference is in state. Delete an element from the middle of a count list and everything after it shifts down one index and gets recreated. With for_each over a map, delete a key and only that one resource goes away. In new code it is almost always `for_each`. count stays for the "N of the same kind, no identity" case (letters of the alphabet, array indexes).

Что хотят услышать

The candidate should: - explain why for_each is safer on reindexing: stable keys instead of positional ones - note that for_each needs a set(string) or a map; a list has to be wrapped in `toset(list)` - say that for_each keys must be known at plan time, so `for_each = aws_subnet.x[*].id` is not allowed but `for_each = var.subnets` is - separate `each.key` and `each.value` for a map (key and value); for a set both equal the element - mention `for_each = { for k, v in var.users : k => v if v.enabled }` as the idiomatic filter

Подводные камни

  • ✗ Using count with a list whose length changes. Deleting an element from the middle recreates the tail
  • ✗ Passing a list to for_each with `for_each = var.list`. That is a type error, you need `toset(var.list)` or a map
  • ✗ Running for_each over a computed value (`aws_subnet.x[*].id`). The plan fails with 'cannot use unknown value'

Follow-up

  • ? What happens when you delete the 5th element from a list under `count`?
  • ? How do you build a map-based for_each over computed values?
  • ? When is `count` actually more sensible than `for_each`?

Глубина в базе знаний

  • count and for_each: many resources from one block
  • Resource block: the main building block of Terraform
  • References in HCL: how to read aws_s3_bucket.demo.bucket
tags: resources, count, for-each

#data-source-vs-resource

intermediateчасто

How is a data source different from a resource? When do you use each?

Что отвечать

`resource` creates and owns a resource, and Terraform handles its lifecycle (create, update, destroy). `data` only reads from the provider, changes nothing, and does not show up in state as owned. Use a data source to look up an existing resource (a VPC id by tag, the latest Ubuntu AMI) or to pull data through the provider's API. Use a resource when you intend to hold onto it. Mix them up and you either delete something that is not yours or lose control of something you were supposed to manage.

Что хотят услышать

A senior should: - name a data source as a read-only lookup that always runs at plan time (refresh) - say that a data source is a poor fit for secrets via AWS Secrets Manager: the value lands in the plan output and in state in plain text - separate your own resource (resource) from someone else's (data); change theirs by hand and it is fine, change yours and it is drift - mention that some providers offer write-data constructs (`ephemeral` in Terraform 1.10+) for cases where the value should not be saved in state

Подводные камни

  • ✗ Using a data source to read your own resource instead of a direct reference. You get a dependency through refresh rather than through the graph
  • ✗ Thinking a data source does not write to state. It does, refresh updates it on every plan/apply, and that eats time
  • ✗ Pointing a data source at a secret value and forgetting it. The value settles into state and into the plan logs

Follow-up

  • ? Can a data source reference your own resource in the same root?
  • ? What does `ephemeral` do in 1.10+, and why was it introduced?
  • ? How does a data source behave differently at plan versus apply?

Глубина в базе знаний

  • data block: reading what already exists in the cloud
  • Resource block: the main building block of Terraform
  • Secrets and Terraform state: where to store them and how to read them
tags: resources, data

#provider-alias-multi-region

intermediateиногда

What does `alias` do in a provider block? Why do you need it?

Что отвечать

A provider alias is a second (or third) provider of the same type with a different config. The canonical case is AWS multi-region. You write `provider "aws" { region = "us-east-1" }` and `provider "aws" { alias = "eu" ; region = "eu-west-1" }`. On a resource you set `provider = aws.eu` and it gets created in EU. Without an alias everything would go to the default provider. The same trick covers cross-account through `assume_role` or a provider per environment.

Что хотят услышать

The candidate should: - explain the semantics: `provider = aws.eu` is an explicit binding of a resource to a named provider - note that a module with multiple providers has to declare provider configuration aliases inside the module (`required_providers` with `configuration_aliases`) - say that the default provider (`aws` with no alias) is named too, just without a qualifier. If you do not need a default, do not declare one - mention that the provider alias binding is known at plan time, so you cannot pick a provider dynamically from a computed value

Подводные камни

  • ✗ Forgetting `provider = aws.eu` on a resource and creating it in the default region instead of EU
  • ✗ Passing an aliased provider into a child module without a `configuration_aliases` declaration inside. That is a plan error
  • ✗ Thinking `count` or `for_each` can pick a provider dynamically. They cannot, the provider is fixed at plan time

Follow-up

  • ? How do you pass an aliased provider into a child module correctly?
  • ? Why do you need `configuration_aliases` in `required_providers`?
  • ? Can you use two providers of the same type in one root without an alias?

Глубина в базе знаний

  • The provider block: who Terraform will call
  • How terraform init pulls in modules
  • References in HCL: how to read aws_s3_bucket.demo.bucket
tags: provider, multi-region

#lifecycle-create-before-destroy

seniorиногда

What does `create_before_destroy` do, and why do you need it?

Что отвечать

By default, when Terraform replaces a resource it destroys the old one first, then creates the new one. `create_before_destroy = true` flips the order: create the new one first, then destroy the old. You use it when downtime is not acceptable: a load balancer, an ec2 in an autoscaling group, an RDS replica. The trap: names and ports have to allow two instances to exist at once. You cannot create a bucket with the same name, since the name is globally unique, so you either change the name or accept the downtime.

Что хотят услышать

A senior should: - note that create_before_destroy helps with a zero-downtime replace, but it needs the name or port to be unique or to change - say that the lifecycle block is one per resource, and you cannot make it conditional through for_each, so design for it up front - explain that dependent resources feel it too: if an LB target group references the resource, on replace it gets the new target first, then the old one disappears - mention `precondition` and `postcondition` in lifecycle for assertions on values, in 1.2+

Подводные камни

  • ✗ Turning on create_before_destroy for a resource with a unique name (an S3 bucket with no random suffix). The apply fails with a conflict
  • ✗ Thinking create_before_destroy solves downtime for any resource. It does not, an RDS major version bump, for one, forces destroy and create regardless of lifecycle
  • ✗ Using create_before_destroy 'just in case' on every resource. Some providers react oddly, so read the docs for each resource

Follow-up

  • ? What happens with `create_before_destroy = true` on an S3 bucket?
  • ? How does `precondition` differ from `validation` on a variable?
  • ? When is `prevent_destroy = true` a good idea in production?

Глубина в базе знаний

  • lifecycle: controlling resource behavior
  • [[tf-blue-green-migration]]
  • -replace and -target: targeted operations on a single resource
tags: resources, lifecycle, zero-downtimebook: mastering.terraform.epub:ch6

#ignore-changes-tradeoffs

intermediateиногда

When is `ignore_changes` genuinely needed, and when is it a crutch?

Что отвечать

`ignore_changes = [tags["LastModified"]]` tells Terraform not to react to a change in that attribute during drift. You need it when an outside system changes the attribute on its own (auto-scaling adjustments, cloud-managed tags, lambda code deployed through CI separately from Terraform). It is a crutch when the reasoning is "I have drift but I don't want to dig in." ignore_changes masks the problem instead of solving it. Once you set ignore_changes, Terraform no longer manages that attribute, and its drift goes unseen.

Что хотят услышать

A senior should: - name the legitimate use cases: auto-scaling capacity, lambda code, an ECS task definition revision, RDS engine_version on a minor auto-upgrade - say that ignore_changes takes a list of attributes, and `ignore_changes = all` means "do not touch anything," though that is already a sign the resource does not belong in Terraform - separate ignore_changes (drift on an attribute) from the lifecycle prevent_destroy (guard against accidental deletion) - mention `ignore_changes` with computed attributes: list indexes work too (`ignore_changes = [user_data]`), but a map key computed through interpolation does not

Подводные камни

  • ✗ Setting `ignore_changes = all` and forgetting it. The resource becomes 'bound to state but unmanaged,' and its drift is invisible
  • ✗ Using ignore_changes for secrets in state. They still sit there, ignore_changes is only a UI thing
  • ✗ Leaving no `description` next to ignore_changes. Six months later a colleague cannot tell why it is ignored

Follow-up

  • ? How does `ignore_changes = all` differ from just not managing the resource in Terraform at all?
  • ? How does ignore_changes react to nested attributes (`tags.Owner`)?
  • ? When is a data source better than ignore_changes on your own resource?

Глубина в базе знаний

  • lifecycle: controlling resource behavior
  • [[tf-drift-detection]]
tags: resources, lifecycle, drift

#depends-on-when-honestly-needed

intermediateиногда

When is `depends_on` honestly needed, and when can you avoid it?

Что отвечать

Terraform builds the graph from explicit references: write `aws_subnet.x.id` in HCL and you get an implicit dependency. `depends_on` is for when the dependency is real but the reference is not there: an IAM role with an inline policy that must be attached before an EC2 tries to use it, where the HCL may carry no link through the ARN. Most resources do not need depends_on, and writing it "just in case" adds extra edges to the graph and can cause a cycle.

Что хотят услышать

A senior should: - say that depends_on is an escape hatch, used when behavior is wrong without it - name the classic case: an IAM policy attachment has to come before the role is used; a lambda permission before the event source mapping - mention that you can declare a module-level dependency through `depends_on` at the `module "x" { depends_on = [...] }` level - warn that an unneeded depends_on makes the graph denser and can slow down plan on large infrastructure

Подводные камни

  • ✗ Adding `depends_on = [aws_iam_role.foo]` where an implicit dependency through `role = aws_iam_role.foo.name` already exists. It is unnecessary and sometimes harmful
  • ✗ Using depends_on instead of moving the dependency into a data source. A data source is cleaner when you do not own the resource
  • ✗ Putting depends_on on both ends of the chain. You get a cycle

Follow-up

  • ? How does `depends_on` at the `module` level differ from inside a resource?
  • ? Which providers need an explicit `depends_on` more often than others?
  • ? What does `terraform graph` show for an unnecessary `depends_on`?

Глубина в базе знаний

  • Resource dependencies: explicit and implicit
  • References in HCL: how to read aws_s3_bucket.demo.bucket
  • [[tf-dag-internals]]
tags: resources, dependencies
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies