| subcategory | page_title | description |
|---|---|---|
manifest |
Kubernetes: kubernetes_manifest |
The resource provides a way to create and manage custom resources |
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.
~> A minimum Terraform version of 0.14.8 is required to use this resource.
manifest(Dynamic) A Kubernetes manifest describing the desired state of the resource in HCL format.
computed_fields(List of String) List of manifest fields whose values can be altered by the API server during 'apply'. Defaults to: ["metadata.annotations", "metadata.labels"]field_manager(Block List, Max: 1) Configure field manager options. (see below for nested schema)object(Dynamic) The resulting resource state, as returned by the API server after applying the desired state frommanifest.skip_validation(Boolean) When set totrue, skips validation of the manifest against the Kubernetes API server during the plan phase. This can be useful when the cluster is not available or when you want to defer validation until apply time. Defaults tofalse.timeouts(Block List, Max: 1) (see below for nested schema)wait(Block List, Max: 1) Configure waiter options. (see below for nested schema)wait_for(Object, Deprecated) A map of attribute paths and desired patterns to be matched. After each apply the provider will wait for all attributes listed here to reach a value that matches the desired pattern. (see below for nested schema)
Optional:
force_conflicts(Boolean) Force changes against conflicts.name(String) The name to use for the field manager when creating and updating the resource.
Optional:
create(String) Timeout for the create operation.delete(String) Timeout for the delete operation.update(String) Timeout for the update operation.
Optional:
condition(Block List) (see below for nested schema)fields(Map of String) A map of paths to fields to wait for a specific field value.rollout(Boolean) Wait for rollout to complete on resources that supportkubectl rollout status.
Optional:
status(String) The condition status.type(String) The type of condition.
Optional:
fields(Map of String)
-
This resource requires API access during planning time by default. This means the cluster has to be accessible at plan time and thus cannot be created in the same apply operation. However, you can use the
skip_validationattribute to defer validation until apply time, which allows creating the cluster and its resources in the same Terraform run. We recommend only using this resource for custom resources or resources not yet fully supported by the provider. -
This resource uses Server-side Apply to carry out apply operations. A minimum Kubernetes version of 1.16.x is required, but versions 1.17+ are strongly recommended as the SSA implementation in Kubernetes 1.16.x is incomplete and unstable.
resource "kubernetes_manifest" "test-configmap" {
manifest = {
"apiVersion" = "v1"
"kind" = "ConfigMap"
"metadata" = {
"name" = "test-config"
"namespace" = "default"
}
"data" = {
"foo" = "bar"
}
}
}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"
}
}
}
}
}]
}
}
}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:
kubectl get secrets sample -o yaml | tfk8s --strip -o sample.tf
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.
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"
}
}
}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
}
}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.
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:
-
Fields of objects are addressed with
. -
Keys of a map field are addressed with
["<key-string>"] -
Elements of a list or tuple field are addressed with
[<index-numeral>]The following example waits for Kubernetes to create a ServiceAccount token in a Secret, where the
datafield of the Secret is a map.wait { fields = { "data[\"token\"]" = ".+" } }
You can use the
type()Terraform function to determine the type of a field. With the resource created and present in state, runterraform consoleand then the following command:> type(kubernetes_manifest.my-secret.object.data) map(string)
By default, the kubernetes_manifest resource validates the manifest against the Kubernetes API server during the plan phase. This includes checking if the resource type exists, verifying CRD schemas, and validating namespace requirements. However, there are scenarios where you may want to skip this validation:
- When the cluster is not available during plan time (e.g., creating the cluster and its resources in the same Terraform run)
- When deploying CRDs and their custom resources in the same apply operation
- When you want to defer validation until apply time
To skip validation during plan phase, set the skip_validation attribute to true:
resource "kubernetes_manifest" "test" {
manifest = {
apiVersion = "apps/v1"
kind = "Deployment"
metadata = {
name = "test-deployment"
namespace = "default"
}
spec = {
replicas = 3
selector = {
matchLabels = {
app = "test"
}
}
template = {
metadata = {
labels = {
app = "test"
}
}
spec = {
containers = [
{
name = "nginx"
image = "nginx:1.21"
}
]
}
}
}
}
skip_validation = true
}Important notes:
-
When
skip_validationis enabled, the provider will not connect to the Kubernetes cluster during plan phase, which means:- CRD validation will be skipped
- Namespace validation will be skipped
- OpenAPI schema validation will be skipped
- The resource will be treated as requiring replacement on updates
-
Validation will still occur during the apply phase when the resource is actually created or updated in the cluster.
-
It is recommended to use this feature only when necessary, as it reduces the ability to catch configuration errors early during planning.