diff --git a/website/docs/provisioners/chef.html.markdown b/website/docs/provisioners/chef.html.markdown
index 67c34b59a..245db62a6 100644
--- a/website/docs/provisioners/chef.html.markdown
+++ b/website/docs/provisioners/chef.html.markdown
@@ -12,6 +12,10 @@ The `chef` provisioner installs, configures and runs the Chef Client on a remote
resource. The `chef` provisioner supports both `ssh` and `winrm` type
[connections](/docs/provisioners/connection.html).
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
## Requirements
The `chef` provisioner has some prerequisites for specific connection types:
diff --git a/website/docs/provisioners/connection.html.markdown b/website/docs/provisioners/connection.html.markdown
index 56dabe442..e2931d723 100644
--- a/website/docs/provisioners/connection.html.markdown
+++ b/website/docs/provisioners/connection.html.markdown
@@ -11,6 +11,10 @@ description: |-
Many provisioners require access to the remote resource. For example,
a provisioner may need to use SSH or WinRM to connect to the resource.
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
Terraform uses a number of defaults when connecting to a resource, but these can
be overridden using a `connection` block in either a `resource` or
`provisioner`. Any `connection` information provided in a `resource` will apply
@@ -62,7 +66,7 @@ provisioner "file" {
* `password` - The password we should use for the connection. In some cases this is
specified by the provider.
-* `host` - (Required) The address of the resource to connect to. This is usually specified by the provider.
+* `host` - (Required) The address of the resource to connect to.
* `port` - The port to connect to.
Defaults to `22` when using type `ssh` and defaults to `5985` when using type `winrm`.
diff --git a/website/docs/provisioners/file.html.markdown b/website/docs/provisioners/file.html.markdown
index c3b8602e8..5b3c80b0c 100644
--- a/website/docs/provisioners/file.html.markdown
+++ b/website/docs/provisioners/file.html.markdown
@@ -12,6 +12,10 @@ The `file` provisioner is used to copy files or directories from the machine
executing Terraform to the newly created resource. The `file` provisioner
supports both `ssh` and `winrm` type [connections](/docs/provisioners/connection.html).
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
## Example usage
```hcl
diff --git a/website/docs/provisioners/habitat.html.markdown b/website/docs/provisioners/habitat.html.markdown
index f96239b8e..8ed2edb2c 100644
--- a/website/docs/provisioners/habitat.html.markdown
+++ b/website/docs/provisioners/habitat.html.markdown
@@ -9,6 +9,11 @@ description: |-
# Habitat Provisioner
The `habitat` provisioner installs the [Habitat](https://habitat.sh) supervisor and loads configured services. This provisioner only supports Linux targets using the `ssh` connection type at this time.
+
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
## Requirements
The `habitat` provisioner has some prerequisites for specific connection types:
diff --git a/website/docs/provisioners/index.html.markdown b/website/docs/provisioners/index.html.markdown
index b2ab93911..c3a536ce1 100644
--- a/website/docs/provisioners/index.html.markdown
+++ b/website/docs/provisioners/index.html.markdown
@@ -8,25 +8,156 @@ description: |-
# Provisioners
+Provisioners can be used to model specific actions on the local machine or on
+a remote machine in order to prepare servers or other infrastructure objects
+for service.
+
+## Provisioners are a Last Resort
+
+Terraform includes the concept of provisioners as a measure of pragmatism,
+knowing that there will always be certain behaviors that can't be directly
+represented in Terraform's declarative model.
+
+However, they also add a considerable amount of complexity and uncertainty to
+Terraform usage. Firstly, Terraform cannot model the actions of provisioners
+as part of a plan because they can in principle take any action. Secondly,
+successful use of provisioners requires coordinating many more details than
+Terraform usage usually requires: direct network access to your servers,
+issuing Terraform credentials to log in, making sure that all of the necessary
+external software is installed, etc.
+
+The following sections describe some situations which can be solved with
+provisioners in principle, but where better solutions are also available. We do
+not recommend using provisioners for any of the use-cases described in the
+following sections.
+
+Even if your specific use-case is not described in the following sections, we
+still recommend attempting to solve it using other techniques first, and use
+provisioners only if there is no other option.
+
+### Passing data into virtual machines and other compute resources
+
+When deploying virtual machines or other similar compute resources, we often
+need to pass in data about other related infrastructure that the software on
+that server will need to do its job.
+
+The various provisioners that interact with remote servers over SSH or WinRM
+can potentially be used to pass such data by logging in to the server and
+providing it directly, but most cloud computing platforms provide mechanisms
+to pass data to instances at the time of their creation such that the data
+is immediately available on system boot. For example:
+
+* Alibaba Cloud: `user_data` on
+ [`alicloud_instance`](/docs/providers/alicloud/r/instance.html)
+ or [`alicloud_launch_template`](/docs/providers/alicloud/r/launch_template.html).
+* Amazon EC2: `user_data` or `user_data_base64` on
+ [`aws_instance`](/docs/providers/aws/r/instance.html),
+ [`aws_launch_template`](/docs/providers/aws/r/launch_template.html),
+ and [`aws_launch_configuration`](/docs/providers/aws/r/launch_configuration.html).
+* Amazon Lightsail: `user_data` on
+ [`aws_lightsail_instance`](/docs/providers/aws/r/lightsail_instance.html).
+* Microsoft Azure: `custom_data` on
+ [`azurerm_virtual_machine`](/docs/providers/azurerm/r/virtual_machine.html)
+ or [`azurerm_virtual_machine_scale_set`](/docs/providers/azurerm/r/virtual_machine_scale_set.html).
+* Google Cloud Platform: `metadata` on
+ [`google_compute_instance`](/docs/providers/google/r/compute_instance.html)
+ or [`google_compute_instance_group`](/docs/providers/google/r/compute_instance_group.html).
+* Oracle Cloud Infrastructure: `metadata` or `extended_metadata` on
+ [`oci_core_instance`](/docs/providers/oci/r/core_instance.html)
+ or [`oci_core_instance_configuration`](/docs/providers/oci/r/core_instance_configuration.html).
+* VMWare vSphere: Attach a virtual CDROM to
+ [`vsphere_virtual_machine`](/docs/providers/vsphere/r/virtual_machine.html)
+ using the `cdrom` block, containing a file called `user-data.txt`.
+
+Many official Linux distribution disk images include software called
+[cloud-init](https://cloudinit.readthedocs.io/en/latest/) that can automatically
+process in various ways data passed via the means described above, allowing
+you to run arbitrary scripts and do basic system configuration immediately
+during the boot process and without the need to access the machine over SSH.
+
+If you are building custom machine images, you can make use of the "user data"
+or "metadata" passed by the above means in whatever way makes sense to your
+application, by referring to your vendor's documentation on how to access the
+data at runtime.
+
+This approach is _required_ if you intend to use any mechanism in your cloud
+provider for automatically launching and destroying servers in a group,
+because in that case individual servers will launch unattended while Terraform
+is not around to provision them.
+
+Even if you're deploying individual servers directly with Terraform, passing
+data this way will allow faster boot times and simplify deployment by avoiding
+the need for direct network access from Terraform to the new server and for
+remote access credentials to be provided.
+
+### Running configuration management software
+
+As a convenience to users who are forced to use generic operating system
+distribution images, Terraform includes a number of specialized provisioners
+for launching specific configuration management products.
+
+We strongly recommend not using these, and instead running system configuration
+steps during a custom image build process. For example,
+[HashiCorp Packer](https://packer.io/) offers a similar complement of
+configuration management provisioners and can run their installation steps
+during a separate build process, before creating a system disk image that you
+can deploy many times.
+
+If you are using configuration management software that has a centralized server
+component, you will need to delay the _registration_ step until the final
+system is booted from your custom image. To achieve that, use one of the
+mechanisms described above to pass the necessary information into each instance
+so that it can register itself with the configuration management server
+immediately on boot, without the need to accept commands from Terraform over
+SSH or WinRM.
+
+### First-class Terraform provider functionality may be available
+
+It is technically possible to use the `local-exec` provisioner to run the CLI
+for your target system in order to create, update, or otherwise interact with
+remote objects in that system.
+
+If you are trying to use a new feature of the remote system that isn't yet
+supported in its Terraform provider, that might be the only option. However,
+if there _is_ provider support for the feature you intend to use, prefer to
+use that provider functionality rather than a provisioner so that Terraform
+can be fully aware of the object and properly manage ongoing changes to it.
+
+Even if the functionality you need is not available in a provider today, we
+suggest to consider `local-exec` usage a temporary workaround and to also
+open an issue in the relevant provider's repository to discuss adding
+first-class provider support. Provider development teams often prioritize
+features based on interest, so opening an issue is a way to record your
+interest in the feature.
+
Provisioners are used to execute scripts on a local or remote machine
as part of resource creation or destruction. Provisioners can be used to
bootstrap a resource, cleanup before destroy, run configuration management, etc.
-Provisioners are added directly to any resource:
+## How to use Provisioners
+
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+the sections above.
+
+If you are certain that provisioners are the best way to solve your problem
+after considering the advice in the sections above, you can add a
+`provisioner` block inside the `resource` block for your compute instance.
```hcl
resource "aws_instance" "web" {
# ...
provisioner "local-exec" {
- command = "echo ${self.private_ip} > file.txt"
+ command = "echo The server's IP address is ${self.private_ip}"
}
}
```
-For provisioners other than local execution, you must specify
-[connection settings](/docs/provisioners/connection.html) so Terraform knows
-how to communicate with the resource.
+The `local-exec` provisioner requires no other configuration, but most other
+provisioners must connect to the remote system using SSH or WinRM.
+You must write [a `connection` block](./connection.html) so that Terraform
+will know how to communicate with the server.
## Creation-Time Provisioners
@@ -127,7 +258,7 @@ resource "aws_instance" "web" {
# ...
provisioner "local-exec" {
- command = "echo ${self.private_ip} > file.txt"
+ command = "echo The server's IP address is ${self.private_ip}"
on_failure = "continue"
}
}
diff --git a/website/docs/provisioners/local-exec.html.markdown b/website/docs/provisioners/local-exec.html.markdown
index 8472d2312..2f8cf628f 100644
--- a/website/docs/provisioners/local-exec.html.markdown
+++ b/website/docs/provisioners/local-exec.html.markdown
@@ -18,6 +18,10 @@ Note that even though the resource will be fully created when the provisioner is
run, there is no guarantee that it will be in an operable state - for example
system services such as `sshd` may not be started yet on compute resources.
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
## Example usage
```hcl
diff --git a/website/docs/provisioners/puppet.html.markdown b/website/docs/provisioners/puppet.html.markdown
index f211a72ab..f4d598145 100644
--- a/website/docs/provisioners/puppet.html.markdown
+++ b/website/docs/provisioners/puppet.html.markdown
@@ -12,6 +12,10 @@ The `puppet` provisioner installs, configures and runs the Puppet agent on a
remote resource. The `puppet` provisioner supports both `ssh` and `winrm` type
[connections](/docs/provisioners/connection.html).
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
## Requirements
The `puppet` provisioner has some prerequisites for specific connection types:
diff --git a/website/docs/provisioners/remote-exec.html.markdown b/website/docs/provisioners/remote-exec.html.markdown
index 87b45ebe8..3085bb335 100644
--- a/website/docs/provisioners/remote-exec.html.markdown
+++ b/website/docs/provisioners/remote-exec.html.markdown
@@ -14,6 +14,9 @@ into a cluster, etc. To invoke a local process, see the `local-exec`
[provisioner](/docs/provisioners/local-exec.html) instead. The `remote-exec`
provisioner supports both `ssh` and `winrm` type [connections](/docs/provisioners/connection.html).
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
## Example usage
diff --git a/website/docs/provisioners/salt-masterless.html.md b/website/docs/provisioners/salt-masterless.html.md
index ad439918f..a50274906 100644
--- a/website/docs/provisioners/salt-masterless.html.md
+++ b/website/docs/provisioners/salt-masterless.html.md
@@ -13,6 +13,10 @@ Type: `salt-masterless`
The `salt-masterless` Terraform provisioner provisions machines built by Terraform
using [Salt](http://saltstack.com/) states, without connecting to a Salt master. The `salt-masterless` provisioner supports `ssh` [connections](/docs/provisioners/connection.html).
+-> **Note:** Provisioners should only be used as a last resort. For most
+common situations there are better alternatives. For more information, see
+[the main Provisioners page](./).
+
## Requirements
The `salt-masterless` provisioner has some prerequisites. `cURL` must be available on the remote host.