Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terraform using both required_providers and provider blocks

Tags:

terraform

I am going through a terraform guide, where the author is spinning up a docker setup using the docker_image and docker_container resources.

In the sample code the main.tf file includes both the required_providers and the provider blocks, as follows:

terraform {
  required_providers {
    docker = {
      source = "kreuzwerker/docker"
    }
  }
}

provider "docker" {}

Why are they both needed?

Shouldn't terraform be able to understand the need for a docker provider, only by this line?

provider "docker" {}
like image 947
pkaramol Avatar asked Feb 06 '21 18:02

pkaramol


People also ask

Can multiple Terraform providers be used within a single Terraform configuration file?

The fact that Terraform is not tied to a specific infrastructure or cloud provider makes it a powerful tool in multi-provider deployments. You are able to manage all resources using the same set of configuration files, sharing variables or defining dependencies between resources across providers.

Is provider required in Terraform?

Terraform relies on plugins called "providers" to interact with remote systems. Terraform configurations must declare which providers they require, so that Terraform can install and use them.

Can you use multiple providers together in Terraform?

Terraform can deal with multiple providers and basically becomes an orchestrator.

Does Terraform allow third party plugins?

Third-party provider plugins — locally installed providers, not on the registry — need to be assigned an (arbitrary) source and placed in the appropriate subdirectory for Terraform to find and use them.


2 Answers

When considering Terraform providers there are two related notions to think about: the provider itself, and a configuration for the provider.

As an analogy, the provider kreuzwerker/docker here is a bit like a class you're importing from another library, giving it the local name docker. I'll use a pseudo-JavaScript syntax just to make this a bit more concrete:

var docker = require("kreuzwerker/docker");

However, all we have here so far is the class itself. In order to use it we need to create an instance of it, which in Terraform's vernacular is called a "configuration". Again, using pseudo-JavaScript syntax:

var dockerInstance = new docker({});

Terraform's syntax here is decidedly less explicit than this pseudo-JavaScript form, but we can make the distinction more visible by adding a second instance of the provider to the configuration, which in Terraform we do by assigning it a configuration "alias":

provider "docker" {
  alias = "example"

  host = "ssh://user@remote-host:22"
}

This is like creating a second instance of the provider "class" in our pseudo-JavaScript example:

var dockerInstance2 = new docker({
  host: 'ssh://user@remote-host:22'
});

Another variant that shows the distinction is when a module inherits a provider configuration from its calling module. In that case, it's as if the calling module were implicitly passing the provider configuration (instance) into the module, but the child module still needs to import the provider "class" so Terraform can see that we're talking about kreuzwerker/docker as opposed to any other provider that might have the name "docker".

Terraform has some automatic "magic" behaviors that try to make simpler cases implicit, but unfortunately that comes at the cost of making it harder to understand what's going on when things get more complicated. Providers and provider configurations are a particularly hard example of this, because providers have been in the Terraform language for a long time and the current incarnation of the language is trying to stay broadly backward-compatible with the simple uses while still allowing for the newer features like having third-party providers installable from multiple namespaces.

The particularly confusing assumption here is that if you don't declare a particular provider Terraform will create an implicit required_providers declaration assuming that you mean a provider in the hashicorp/ namespace, which makes it seem as though required_providers is only for third-party providers. In fact though, that is largely a backward-compatibility mechanism and so I'd suggest always writing out the required_providers entries, even for the providers in the hashicorp/ namespace, so that less-experienced readers don't need to know about this special backward-compatibility behavior. In your case though, the provider you're using is in a third-party namespace anyway and so the required_providers entry is mandatory.

like image 68
Martin Atkins Avatar answered Oct 13 '22 15:10

Martin Atkins


The source needs to be provided since this isn't one of the "official" HashiCorp providers. There could be multiple providers with the name "docker" in the provider registry, so providing the source is needed in order to tell Terraform exactly which provider to download.

like image 38
Mark B Avatar answered Oct 13 '22 16:10

Mark B