terraform/website/docs/configuration/modules.html.md

529 lines
20 KiB
Markdown
Raw Normal View History

2014-09-26 23:23:38 +02:00
---
layout: "docs"
page_title: "Modules - Configuration Language"
2014-09-26 23:23:38 +02:00
sidebar_current: "docs-config-modules"
2014-10-22 05:21:56 +02:00
description: |-
Modules allow multiple resources to be grouped together and encapsulated.
2014-09-26 23:23:38 +02:00
---
# Modules
2014-09-26 23:23:38 +02:00
-> **Note:** This page is about Terraform 0.12 and later. For Terraform 0.11 and
earlier, see
[0.11 Configuration Language: Modules](../configuration-0-11/modules.html).
A _module_ is a container for multiple resources that are used together.
Every Terraform configuration has at least one module, known as its
_root module_, which consists of the resources defined in the `.tf` files in
the main working directory.
2014-09-26 23:23:38 +02:00
A module can call other modules, which lets you include the child module's
resources into the configuration in a concise way. Modules
can also be called multiple times, either within the same configuration or
in separate configurations, allowing resource configurations to be packaged
and re-used.
2014-09-26 23:23:38 +02:00
This page describes how to call one module from another. Other pages in this
section of the documentation describe the different elements that make up
modules, and there is further information about how modules can be used,
created, and published in [the dedicated _Modules_
section](/docs/modules/index.html). You can also learn more about how to use and
create modules with our hands-on [modules track on
learn.hashicorp.com](https://learn.hashicorp.com/terraform/modules/modules-overview?utm_source=WEBSITE&utm_medium=WEB_IO&utm_offer=ARTICLE_PAGE&utm_content=DOCS).
## Calling a Child Module
To _call_ a module means to include the contents of that module into the
configuration with specific values for its
[input variables](./variables.html). Modules are called
from within other modules using `module` blocks:
2014-09-26 23:23:38 +02:00
```hcl
module "servers" {
source = "./app-cluster"
servers = 5
2014-09-26 23:23:38 +02:00
}
```
A module that includes a `module` block like this is the _calling module_ of the
child module.
The label immediately after the `module` keyword is a local name, which the
calling module can use to refer to this instance of the module.
Within the block body (between `{` and `}`) are the arguments for the module.
Most of the arguments correspond to [input variables](./variables.html)
defined by the module, including the `servers` argument in the above example.
Terraform also defines a few meta-arguments that are reserved by Terraform
and used for its own purposes; we will discuss those throughout the rest of
this section.
All modules require a `source` argument, which is a meta-argument defined by
Terraform CLI. Its value is either the path to a local directory of the
module's configuration files, or a remote module source that Terraform should
download and use. This value must be a literal string with no template
sequences; arbitrary expressions are not allowed. For more information on
possible values for this argument, see [Module Sources](/docs/modules/sources.html).
The same source address can be specified in multiple `module` blocks to create
multiple copies of the resources defined within, possibly with different
variable values.
After adding, removing, or modifying `module` blocks, you must re-run
`terraform init` to allow Terraform the opportunity to adjust the installed
modules. By default this command will not upgrade an already-installed module;
use the `-upgrade` option to instead upgrade to the newest available version.
## Accessing Module Output Values
2014-09-26 23:23:38 +02:00
The resources defined in a module are encapsulated, so the calling module
cannot access their attributes directly. However, the child module can
declare [output values](./outputs.html) to selectively
export certain values to be accessed by the calling module.
For example, if the `./app-cluster` module referenced in the example above
exported an output value named `instance_ids` then the calling module
can reference that result using the expression `module.servers.instance_ids`:
```hcl
resource "aws_elb" "example" {
# ...
instances = module.servers.instance_ids
}
```
For more information about referring to named values, see
[Expressions](./expressions.html).
## Module Versions
We recommend explicitly constraining the acceptable version numbers for
each external module to avoid unexpected or unwanted changes.
Use the `version` attribute in the `module` block to specify versions:
```shell
module "consul" {
source = "hashicorp/consul/aws"
version = "0.0.5"
servers = 3
}
```
The `version` attribute accepts a [version constraint string](./version-constraints.html).
Terraform will use the newest installed version of the module that meets the
constraint; if no acceptable versions are installed, it will download the newest
version that meets the constraint.
Version constraints are supported only for modules installed from a module
registry, such as the public [Terraform Registry](https://registry.terraform.io/)
or [Terraform Cloud's private module registry](/docs/cloud/registry/index.html).
Other module sources can provide their own versioning mechanisms within the
source string itself, or might not support versions at all. In particular,
modules sourced from local file paths do not support `version`; since
they're loaded from the same source repository, they always share the same
version as their caller.
## Other Meta-arguments
Along with the `source` meta-argument described above, module blocks have
some more meta-arguments that have special meaning across all modules,
described in more detail in other sections:
* `version` - (Optional) A [version constraint string](./version-constraints.html)
that specifies acceptable versions of the module. Described in detail above.
* `providers` - (Optional) A map whose keys are provider configuration names
that are expected by child module and whose values are corresponding
provider names in the calling module. This allows
[provider configurations to be passed explicitly to child modules](#passing-providers-explicitly).
If not specified, the child module inherits all of the default (un-aliased)
provider configurations from the calling module.
* `depends_on` - (Optional) Create explicit dependencies between the entire
module and the listed targets. This will delay the final evaluation of the
module, and any sub-modules, until after the dependencies have been applied.
Modules have the same dependency resolution behavior [as defined for managed resources](./resources.html#resource-dependencies).
In addition to the above, the `lifecycle` argument is not currently used by
Terraform but is reserved for planned future features.
Since modules are a complex feature in their own right, further detail
about how modules can be used, created, and published is included in
[the dedicated section on modules](/docs/modules/index.html).
## Providers within Modules
In a configuration with multiple modules, there are some special considerations
for how resources are associated with provider configurations.
While in principle `provider` blocks can appear in any module, it is recommended
that they be placed only in the _root_ module of a configuration, since this
approach allows users to configure providers just once and re-use them across
all descendent modules.
Each resource in the configuration must be associated with one provider
configuration, which may either be within the same module as the resource
or be passed from the parent module. Providers can be passed down to descendent
modules in two ways: either _implicitly_ through inheritance, or _explicitly_
via the `providers` argument within a `module` block. These two options are
discussed in more detail in the following sections.
In all cases it is recommended to keep explicit provider configurations only in
the root module and pass them (whether implicitly or explicitly) down to
descendent modules. This avoids the provider configurations from being "lost"
when descendent modules are removed from the configuration. It also allows
the user of a configuration to determine which providers require credentials
by inspecting only the root module.
Provider configurations are used for all operations on associated resources,
including destroying remote objects and refreshing state. Terraform retains, as
part of its state, a reference to the provider configuration that was most
recently used to apply changes to each resource. When a `resource` block is
removed from the configuration, this record in the state is used to locate the
appropriate configuration because the resource's `provider` argument (if any)
is no longer present in the configuration.
As a consequence, it is required that all resources created for a particular
provider configuration must be destroyed before that provider configuration is
removed, unless the related resources are re-configured to use a different
provider configuration first.
### Provider Version Constraints in Modules
To declare that a module requires particular versions of a specific provider,
use a [`required_providers`](terraform.html#specifying-required-provider-versions)
block inside a `terraform` block:
```hcl
terraform {
required_providers {
aws = ">= 2.7.0"
}
}
```
Shared modules should constrain only the minimum allowed version, using a `>=`
constraint. This specifies the minimum version the provider is compatible
with while allowing users to upgrade to newer provider versions without
altering the module source code.
### Implicit Provider Inheritance
For convenience in simple configurations, a child module automatically inherits
default (un-aliased) provider configurations from its parent. This means that
explicit `provider` blocks appear only in the root module, and downstream
modules can simply declare resources for that provider and have them
automatically associated with the root provider configurations.
For example, the root module might contain only a `provider` block and a
`module` block to instantiate a child module:
```hcl
provider "aws" {
region = "us-west-1"
}
module "child" {
source = "./child"
}
```
The child module can then use any resource from this provider with no further
provider configuration required:
```hcl
resource "aws_s3_bucket" "example" {
bucket = "provider-inherit-example"
}
```
This approach is recommended in the common case where only a single
configuration is needed for each provider across the entire configuration.
In more complex situations there may be [multiple provider instances](/docs/configuration/providers.html#multiple-provider-instances),
or a child module may need to use different provider settings than
its parent. For such situations, it's necessary to pass providers explicitly
as we will see in the next section.
### Passing Providers Explicitly
When child modules each need a different configuration of a particular
provider, or where the child module requires a different provider configuration
than its parent, the `providers` argument within a `module` block can be
used to define explicitly which provider configs are made available to the
child module. For example:
```hcl
# The default "aws" configuration is used for AWS resources in the root
# module where no explicit provider instance is selected.
provider "aws" {
region = "us-west-1"
}
# A non-default, or "aliased" configuration is also defined for a different
# region.
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
# An example child module is instantiated with the _aliased_ configuration,
# so any AWS resources it defines will use the us-west-2 region.
module "example" {
source = "./example"
providers = {
aws = "aws.usw2"
}
}
```
The `providers` argument within a `module` block is similar to
the `provider` argument within a resource as described for
[multiple provider instances](/docs/configuration/providers.html#multiple-provider-instances),
but is a map rather than a single string because a module may contain resources
from many different providers.
Once the `providers` argument is used in a `module` block, it overrides all of
the default inheritance behavior, so it is necessary to enumerate mappings
for _all_ of the required providers. This is to avoid confusion and surprises
that may result when mixing both implicit and explicit provider passing.
Additional provider configurations (those with the `alias` argument set) are
_never_ inherited automatically by child modules, and so must always be passed
explicitly using the `providers` map. For example, a module
that configures connectivity between networks in two AWS regions is likely
to need both a source and a destination region. In that case, the root module
may look something like this:
```hcl
provider "aws" {
alias = "usw1"
region = "us-west-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
module "tunnel" {
source = "./tunnel"
providers = {
aws.src = "aws.usw1"
aws.dst = "aws.usw2"
}
}
```
In the `providers` map, the keys are provider names as expected by the child
module, while the values are the names of corresponding configurations in
the _current_ module. The subdirectory `./tunnel` must then contain
_proxy configuration blocks_ like the following, to declare that it
requires configurations to be passed with these from the `providers` block in
the parent's `module` block:
```hcl
provider "aws" {
alias = "src"
}
provider "aws" {
alias = "dst"
}
```
Each resource should then have its own `provider` attribute set to either
`"aws.src"` or `"aws.dst"` to choose which of the two provider instances to use.
### Proxy Configuration Blocks
A proxy configuration block is one that is either completely empty or that
contains only the `alias` argument. It serves as a placeholder for
provider configurations passed between modules. Although an empty proxy
configuration block is valid, it is not necessary: proxy configuration blocks
are needed only to establish which _alias_ provider configurations a child
module is expecting.
A proxy configuration block must not include the `version` argument. To specify
version constraints for a particular child module without creating a local
module configuration, use the [`required_providers`](/docs/configuration/terraform.html#specifying-required-provider-versions)
setting inside a `terraform` block.
## Multiple Instances of a Module
Use the `count` or `for_each` arguments to create multiple instances of a module.
These arguments have the same syntax and type constraints as
[`count`](./resources.html#count-multiple-resource-instances-by-count) and
[`for_each`](./resources.html#for_each-multiple-resource-instances-defined-by-a-map-or-set-of-strings)
as defined for managed resources.
```hcl
# my_buckets.tf
module "bucket" {
for_each = toset(["assets", "media"])
2020-04-13 17:44:48 +02:00
source = "./publish_bucket"
name = "${each.key}_bucket"
}
```
```hcl
# publish_bucket/bucket-and-cloudfront.tf
variable "name" {} # this is the input parameter of the module
resource "aws_s3_bucket" "example" {
# ...
}
resource "aws_iam_user" "deploy_user" {
# ...
}
```
This example defines a local child module in the `./publish_bucket`
subdirectory. That module has configuration to create an S3 bucket. The module
wraps the bucket and all the other implementation details required to configure
a bucket.
We declare multiple module instances by using the `for_each` attribute,
which accepts a map (with string keys) or a set of strings as its value. Additionally,
we use the `each.key` in our module block, because the
[`each`](/docs/configuration/resources.html#the-each-object) object is available when
we have declared `for_each` on the module block. When using the `count` argument, the
[`count`](/docs/configuration/resources.html#the-count-object) object is available.
Resources from child modules are prefixed with `module.module_name[module index]`
when displayed in plan output and elsewhere in the UI. For a module with without
`count` or `for_each`, the address will not contain the module index as the module's
name suffices to reference the module.
In our example, the `./publish_bucket` module contains `aws_s3_bucket.example`, and so the two
instances of this module produce S3 bucket resources with [resource addresses](/docs/internals/resource-addressing.html) of `module.bucket["assets"].aws_s3_bucket.example`
and `module.bucket["media"].aws_s3_bucket.example` respectively. These full addresses
are used within the UI and on the command line, but only [outputs](docs/configuration/outputs.html)
from a module can be referenced from elsewhere in your configuration.
When refactoring an existing configuration to introduce modules, moving
resource blocks between modules causes Terraform to see the new location
as an entirely separate resource to the old. Always check the execution plan
after performing such actions to ensure that no resources are surprisingly
deleted.
2020-04-13 17:44:48 +02:00
### Limitations when using module expansion
Modules using `count` or `for_each` cannot include configured `provider` blocks within the module.
Only [proxy configuration blocks](#proxy-configuration-blocks) are allowed.
If a module contains proxy configuration blocks, the calling module block must be have the
corresponding providers passed to the `providers` argument. If you attempt to use `count` or
`for_each` with a module that does not satify this requirement, you will see an error:
```
Error: Module does not support count
on main.tf line 15, in module "child":
15: count = 2
Module "child" cannot be used with count because it contains a nested provider
configuration for "aws", at child/main.tf:2,10-15.
This module can be made compatible with count by changing it to receive all of
its provider configurations from the calling module, by using the "providers"
argument in the calling module block.
```
Assuming the child module only has proxy configuration blocks, the calling
module block could be adjusted like so to remove this error:
```
provider "aws" {
region = "us-east-1"
alias = "east"
}
module "child" {
count = 2
providers = {
aws = aws.east
}
}
```
Note how we are now [passing the providers](#passing-providers-explicitly) to the child module.
In addition, modules using `count` or `for_each` cannot pass different sets of providers
to different instances. For example, you cannot interpolate variables in the `providers`
block on a module.
2020-04-13 17:44:48 +02:00
This is because when a module instance is destroyed (such as a key-value being removed from the
`for_each` map), the appropriate provider must be available in order to perform the destroy.
You can pass different sets of providers to different module instances by using multiple `module` blocks:
2020-04-13 17:44:48 +02:00
```
# my_buckets.tf
provider "aws" {
alias = "usw1"
region = "us-west-1"
}
provider "aws" {
alias = "usw2"
region = "us-west-2"
}
provider "google" {
alias = "usw1"
credentials = "${file("account.json")}"
project = "my-project-id"
region = "us-west1"
zone = "us-west1-a"
}
provider "google" {
alias = "usw2"
credentials = "${file("account.json")}"
project = "my-project-id"
region = "us-west2"
zone = "us-west2-a"
}
module "bucket_w1" {
source = "./publish_bucket"
providers = {
aws.src = "aws.usw1"
google.src = "google.usw2"
}
}
module "bucket_w2" {
source = "./publish_bucket"
providers = {
aws.src = "aws.usw2"
google.src = "google.usw2"
}
}
```
Each module block may optionally have different providers passed to it
using the [`providers`](/docs/configuration/modules.html#passing-providers-explicitly)
2020-04-13 17:44:48 +02:00
argument. This can be useful in situations where, for example, a duplicated set of
resources must be created across several regions or datacenters.
## Tainting resources within a module
The [taint command](/docs/commands/taint.html) can be used to _taint_ specific
resources within a module:
```shell
$ terraform taint module.salt_master.aws_instance.salt_master
```
It is not possible to taint an entire module. Instead, each resource within
the module must be tainted separately.