kubernetes_manifest

Represents one Kubernetes resource by supplying a manifest attribute. The manifest value is the HCL representation of a Kubernetes YAML manifest. To convert an existing manifest from YAML to HCL, you can use the Terraform built-in function yamldecode() or tfk8s.

Once applied, the object attribute contains the state of the resource as returned by the Kubernetes API, including all default values.

Before you use this resource

Example: Create a Kubernetes ConfigMap

resource "kubernetes_manifest" "test-configmap" {
  manifest = {
    "apiVersion" = "v1"
    "kind"       = "ConfigMap"
    "metadata" = {
      "name"      = "test-config"
      "namespace" = "default"
    }
    "data" = {
      "foo" = "bar"
    }
  }
}

Example: Create a Kubernetes Custom Resource Definition

resource "kubernetes_manifest" "test-crd" {
  manifest = {
    apiVersion = "apiextensions.k8s.io/v1"
    kind       = "CustomResourceDefinition"

    metadata = {
      name = "testcrds.hashicorp.com"
    }

    spec = {
      group = "hashicorp.com"

      names = {
        kind   = "TestCrd"
        plural = "testcrds"
      }

      scope = "Namespaced"

      versions = [{
        name    = "v1"
        served  = true
        storage = true
        schema = {
          openAPIV3Schema = {
            type = "object"
            properties = {
              data = {
                type = "string"
              }
              refs = {
                type = "number"
              }
            }
          }
        }
      }]
    }
  }
}

Importing existing Kubernetes resources as kubernetes_manifest

Objects already present in a Kubernetes cluster can be imported into Terraform to be managed as kubernetes_manifest resources. Follow these steps to import a resource:

Extract the resource from Kubernetes and transform it into Terraform configuration

kubectl get secrets sample -o yaml | tfk8s --strip -o sample.tf

Import the resource state from the cluster

terraform import kubernetes_manifest.secret_sample "apiVersion=v1,kind=Secret,namespace=default,name=sample"

Note the import ID as the last argument to the import command. This ID points Terraform at which Kubernetes object to read when importing. It should be constructed with the following syntax: "apiVersion=<string>,kind=<string>,[namespace=<string>,]name=<string>". The namespace=<string> in the ID string is required only for Kubernetes namespaced objects and should be omitted for cluster-wide objects.

Using wait to block create and update calls

The kubernetes_manifest resource supports the ability to block create and update calls until a field is set or has a particular value by specifying the wait block. This is useful for when you create resources like Jobs and Services when you want to wait for something to happen after the resource is created by the API server before Terraform should consider the resource created.

wait supports supports a fields attribute which allows you specify a map of fields paths to regular expressions. You can also specify * if you just want to wait for a field to have any value.

resource "kubernetes_manifest" "test" {
  manifest = {
    // ...
  }

  wait {
    fields = {
      # Check the phase of a pod
      "status.phase" = "Running"

      # Check a container's status
      "status.containerStatuses[0].ready" = "true",

      # Check an ingress has an IP
      "status.loadBalancer.ingress[0].ip" = "^(\\d+(\\.|$)){4}"

      # Check the replica count of a Deployment
      "status.readyReplicas" = "2"
    }
  }

  timeouts {
    create = "10m"
    update = "10m"
    delete = "30s"
  }
}

The wait block also supports a rollout attribute which will wait for rollout to complete on Deployment, StatefulSet, and DaemonSet resources.

resource "kubernetes_manifest" "test" {
  manifest = {
    // ...
  }

  wait {
    rollout = true
  }
}

You can also wait for specified conditions to be met by specifying a condition block.

resource "kubernetes_manifest" "test" {
  manifest = {
    // ...
  }

  wait {
    condition {
      type   = "ContainersReady"
      status = "True"
    }
  }
}

Configuring field_manager

The kubernetes_manifest exposes configuration of the field manager through the optional field_manager block.

resource "kubernetes_manifest" "test" {
  provider = kubernetes-alpha

  manifest = {
    // ...
  }

  field_manager {
    # set the name of the field manager
    name = "myteam"

    # force field manager conflicts to be overridden
    force_conflicts = true
  }
}

Computed fields

When setting the value of an field in configuration, Terraform will check that the same value is returned after the apply operation. This ensures that the actual configuration requested by the user is successfully applied. In some cases, with the Kubernetes API this is not the desired behavior. Particularly when using mutating admission controllers, there is a chance that the values configured by the user will be modified by the API. This usually manifest as Error: Provider produced inconsistent result after apply and produced an unexpected new value: messages when applying.

To accommodate this, the kubernetes_manifest resources allows defining so-called "computed" fields. When an field is defined as "computed" Terraform will allow the final value stored in state after apply as returned by the API to be different than what the user requested.

The most common example of this is metadata.annotations. In some cases, the API will add extra annotations on top of the ones configured by the user. Unless the field is declared as "computed" Terraform will throw an error signaling that the state returned by the 'apply' operation is inconsistent with the value defined in the 'plan'.

To declare an field as "computed" add its full field path to the computed_fields field under the respective kubernetes_manifest resource. For example, to declare the "metadata.labels" field as "computed", add the following:

resource "kubernetes_manifest" "test-ns" {
  manifest = {
    ...
  }

  computed_fields = ["metadata.labels"]
 }

IMPORTANT: By default, metadata.labels and metadata.annotations are already included in the list. You don't have to set them explicitly in the computed_fields list. To turn off these defaults, set the value of computed_fields to an empty list or a concrete list of other fields. For example computed_fields = [].

The syntax for the field paths is the same as the one used in the wait block.

Argument Reference

The following arguments are supported:

wait

Arguments

A field path is a string that describes the fully qualified address of a field within the resource, including its parent fields all the way up to "object". The syntax of a path string follows the rules below:

wait_for (deprecated, use wait)

Arguments

field_manager

Arguments

timeouts

See Operation Timeouts