website: Warn against using provisioners
For a long time now we've been advising against the use of provisioners, but our documentation for them is pretty prominent on the website in comparision to the better alternatives, and so it's little surprise that many users end up making significant use of them. Although in the longer term a change to our information architecture would probably address this even better, this is an attempt to be explicit about the downsides of using provisioners and to prominently describe the alternatives that are available for common use-cases, along with some reasons why we consider them to be better. I took the unusual step here of directly linking to specific provider documentation pages about the alternatives, even though we normally try to keep the core documentation provider-agnostic, because otherwise that information tends to be rather buried in the provider documentation and thus the reader would be reasonable to use provisioners just because we're not giving specific enough alternative recommendations.
This commit is contained in:
parent
72f9385285
commit
e0d72930fa
|
@ -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:
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue