I am using Terraform (and Terragrunt) to deploy Kubernetes manifests. I am dealing with the following situation: I am describing a Helm Chart for cert-manager
and a Kubernetes manifest for a cert-manager.io/v1/ClusterIssues
.
Here's the definition of the Helm Chart:
resource "helm_release" "cert_manager" {
name = "cert-manager"
namespace = kubernetes_namespace.cert_manager.metadata.0.name
chart = "cert-manager"
repository = "https://charts.jetstack.io"
wait = true
# ...
set {
name = "installCRDs"
value = "true"
}
}
Here's the ClusterIssuer
:
resource "kubernetes_manifest" "clusterissuer_letsencrypt" {
manifest = {
apiVersion = "cert-manager.io/v1"
kind = "ClusterIssuer"
metadata = {
name = "letsencrypt"
}
# ...
}
depends_on = [helm_release.cert_manager]
}
When creating a brand new Kubernetes cluster, the CRDs for the ClusterIssuer
don't exist, and Terraform fails to plan
the execution because:
│ Error: Failed to determine GroupVersionResource for manifest
| ...
│ 24: resource "kubernetes_manifest" "clusterissuer_letsencrypt" {
│
│ no matches for kind "ClusterIssuer" in group "cert-manager.io"
Now, I understand how depends_on
works and I understand that I can do a targeted deployment with Terraform and I can solve this in sort of a two-phased deployment, but I want to avoid manual actions as much as possible.
Are there any mechanisms in Terraform (or Terragrunt, just in case) that can make it ignore the presence of this ClusterIssuer
manifest altogether if the Helm Chart for cert-manager
is not deployed?
There is no way for both of these to be completed in a single plan-apply cycle, because kubernetes_manifest
relies on schema information from the cluster in order to produce its plan.
Instead, you will need to choose some strategy for splitting this across two runs. Here are some examples:
You can bootstrap by using -target
to ask Terraform to focus only on creating the cluster first. This is a common choice because it requires special actions only during the initial creation step, but you did already exclude this option in your question.
You can split your configuration into at least two parts. The first part would declare only the cluster itself. The second part might refer to the cluster using a data
block (declaring that it ought to already exist) and then do all of the cluster configuration using the hashicorp/kubernetes
provider.
This can be a good option if you expect that you'll rarely make changes to the cluster itself, and that your everyday work will be in changing manifests within the cluster. If you are frequently changing the cluster at the same time as its contents then this will be inconvenient, since you'll always need to run Terraform once for each configuration.
There are other variations of these two strategies with some different details but the above are the two main classes of solution here: either you have one configuration and ask Terraform to only plan and apply a part of it during initial creation, or you have two configurations so that you can use a normal Terraform workflow for both of them but it'll be more complicated to make changes to them both together.