Search code examples
kubernetesterraformterraform-provider-kubernetes

How can we create same resource in multiple terraform providers?


I am using terraform to create Kubernetes namespace. Sample below

resource "kubernetes_namespace" "test1" {
  metadata {
    name = local.ns_name
  }

}

I am trying to create Blue/Green kind of deployment using terraform following this link. As part of it, I have created two kubernetes clusters now. One of blue and other for green side and there by now I have two kubernetes providers

provider "kubernetes" {
  alias                  = "kubernetes_blue"
}

provider "kubernetes" {
  alias                  = "kubernetes_green"
}

I want to understand if there is a way, I can have some conditional on the kubernetes_namespace such that, depending on the flags var.enable_green_side and var.enable_blue_side, I can create the same namespace in multiple kubernetes clusters without having to repeat the entire resource block as follows

resource "kubernetes_namespace" "test1" {
  metadata {
    name = local.ns_name
  }

  provider = kubernetes.kubernetes_blue  
}

resource "kubernetes_namespace" "test2" {
  metadata {
    name = local.ns_name
  }

  provider = kubernetes.kubernetes_green  
}

Thanks in advance.


Solution

  • Terraform's model requires that each resource block belong to exactly one provider configuration, so there is no way to avoid declaring the resource twice, but you can at least reduce the amount of duplication that causes by factoring it out into a module and calling that module twice, rather than by duplicating the resource block directly:

    provider "kubernetes" {
      alias = "blue"
    }
    
    provider "kubernetes" {
      alias = "green"
    }
    
    module "blue" {
      source = "../modules/bluegreen"
    
      # (any settings the module needs from the root)
    
      providers = {
        kubernetes = kubernetes.blue
      }
    }
    
    module "blue" {
      source = "../modules/bluegreen"
    
      # (any settings the module needs from the root)
    
      providers = {
        kubernetes = kubernetes.green
      }
    }
    

    The special providers argument in a module block allows you to give the child module a different "view" of the declared provider configurations than the caller has. In the module "blue" block above, the providers argument is saying: "Inside this module instance, any reference to the default kubernetes provider configuration means to use the kubernetes.blue configuration from the caller".

    Inside the module then you can just write normal resource "kubernetes_...." blocks without any special provider arguments, because that'll cause them to attach to the default provider from the perspective of that module instance, and each of the two module instances has a different configuration bound to that.

    Whether this factoring out into a module will be helpful will of course depend on how much context from the calling module the child module ends up needing. If your module block ends up with almost as many arguments inside it as the resource block(s) you're factoring out then it'd likely be better to just keep the resource blocks at the top level and avoid the indirection.