如何避免 ClusterIssuer 在 Terraform 计划和应用中依赖于 helm cert-manager CRD?(在组“cert-manager.io”中找不到“ClusterIssuer”)

eve*_*der 9 kubernetes terraform kubernetes-helm

我正在尝试在 Terraform 中创建一个模块,以在 Kubernetes 集群中创建基本资源,这意味着一个cert-manager, ingress-nginx(作为入口控制器)和一个ClusterIssuer用于证书。按照这个确切的顺序。

\n

前两个我使用helm_release资源和cluster_issuervia进行安装kubernetes_manifest

\n

我收到以下错误,经过一些 Google 搜索后,我发现这是因为cert-manager安装了所需的 CRD ,ClusterIssuer但在这个terraform plan阶段,由于它们尚未安装,清单无法检测到ClusterIssuer.

\n

然后,我想知道是否有一种方法可以绕过这个问题,但仍然可以在相同的配置中仅使用一个来创建所有内容terraform apply

\n

注意:我尝试使用 dependent_on 参数并包含一个time_sleep块,但它没有用,因为计划中没有安装任何内容,这就是它失败的地方

\n
| Error: Failed to determine GroupVersionResource for manifest\n\xe2\x94\x82 \n\xe2\x94\x82   with module.k8s_base.kubernetes_manifest.cluster_issuer,\n\xe2\x94\x82   on ../../modules/k8s_base/main.tf line 37, in resource "kubernetes_manifest" "cluster_issuer":\n\xe2\x94\x82   37: resource "kubernetes_manifest" "cluster_issuer" {\n\xe2\x94\x82 \n\xe2\x94\x82 no matches for kind "ClusterIssuer" in group "cert-manager.io"\n
Run Code Online (Sandbox Code Playgroud)\n
resource "helm_release" "cert_manager" {\n  chart      = "cert-manager"\n  repository = "https://charts.jetstack.io"\n  name       = "cert-manager"\n\n  create_namespace = var.cert_manager_create_namespace\n  namespace        = var.cert_manager_namespace\n\n  set {\n    name  = "installCRDs"\n    value = "true"\n  }\n}\n\nresource "helm_release" "ingress_nginx" {\n  name = "ingress-nginx"\n\n  repository = "https://kubernetes.github.io/ingress-nginx"\n  chart      = "ingress-nginx"\n\n  create_namespace = var.ingress_nginx_create_namespace\n  namespace        = var.ingress_nginx_namespace\n\n  wait = true\n\n  depends_on = [\n    helm_release.cert_manager\n  ]\n}\n\nresource "time_sleep" "wait" {\n  create_duration = "60s"\n\n  depends_on = [helm_release.ingress_nginx]\n}\n\nresource "kubernetes_manifest" "cluster_issuer" {\n  manifest = {\n    "apiVersion" = "cert-manager.io/v1"\n    "kind"       = "ClusterIssuer"\n    "metadata" = {\n      "name" = var.cluster_issuer_name\n    }\n    "spec" = {\n      "acme" = {\n        "email" = var.cluster_issuer_email\n        "privateKeySecretRef" = {\n          "name" = var.cluster_issuer_private_key_secret_name\n        }\n        "server" = var.cluster_issuer_server\n        "solvers" = [\n          {\n            "http01" = {\n              "ingress" = {\n                "class" = "nginx"\n              }\n            }\n          }\n        ]\n      }\n    }\n  }\n  depends_on = [helm_release.cert_manager, helm_release.ingress_nginx, time_sleep.wait]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

use*_*182 2

官方文档说在安装它之前使用kubectl apply舵图,使其成为一个两步过程。使用 Terraform,这将使其成为一个 3 步过程,因为您必须应用目标部分来创建集群,以便您可以访问 kubeconfig 凭据,然后运行 ​​kubectl apply 命令来安装 CRD,最后再次运行 terraform apply安装 Helm Chart 和 IaC 的其余部分。这更不理想。

我会kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml按照上面的评论建议使用 kubectl_manifest 资源,但这是不可能的,因为这不会链接到单个 yaml 文件,但其中很多文件将无法跟上更改。不幸的是,Helm Chart 没有“kubectl_apply”terraform 资源**来依赖于首先安装的 CRD。

尽管有这些古怪之处,还是有一个解决方案,那就是使用 helm_release 资源两次。它需要为证书颁发者创建一个模块并引用自定义 helm 图表。考虑到为满足自定义需求而创建它需要花费大量的精力,它并不理想,但一旦创建,它就是一个可重用的模块化解决方案。

#
# Cert-manager
# main.tf
#
resource "helm_release" "cert_manager" {
  name             = "cert-manager"
  repository       = "https://charts.jetstack.io"
  chart            = "cert-manager"
  version          = var.cert_manager_chart_version
  namespace        = var.cert_manager_namespace
  create_namespace = true

  set {
    name  = "installCRDs"
    value = true
  }

}
Run Code Online (Sandbox Code Playgroud)

自定义图表参考:

#
# cert-issuer.tf
#
# Cert Issuer using Helm
resource "helm_release" "cert_issuer" {
  name       = "cert-issuer"
  repository = path.module
  chart      = "cert-issuer"
  namespace  = var.namespace

  set {
    name  = "fullnameOverride"
    value = local.issuer_name
  }

  set {
    name  = "privateKeySecretRef"
    value = local.issuer_name
  }

  set {
    name  = "ingressClass"
    value = var.ingress_class
  }

  set {
    name  = "acmeEmail"
    value = var.cert_manager_email
  }

  set {
    name  = "acmeServer"
    value = var.acme_server
  }

  depends_on = [helm_release.cert_manager]
}
Run Code Online (Sandbox Code Playgroud)

你可以看到上面的用法helm_release是在本地引用自己作为存储库,这需要你有一个自定义的 Helm Chart,如下所示:

# ./cluster-issuer/cluster-issuer.yaml

apiVersion: cert-manager.io/v1alpha2
kind: ClusterIssuer
metadata:
 name: {{ include "cert-issuer.fullname" . }}
 namespace: {{ .Release.Namespace }}
spec:
 acme:
   # The ACME server URL
   server: {{ .Values.acmeServer }}
   email: {{ .Values.acmeEmail }}
   # Name of a secret used to store the ACME account private key
   privateKeySecretRef:
     name: {{ .Values.privateKeySecretRef }}
   # Enable the HTTP-01 challenge provider
   solvers:
   - http01:
       ingress:
         class: {{ .Values.ingressClass }}
Run Code Online (Sandbox Code Playgroud)

出于某种原因,这避免了 terraform 用来引发错误的依赖项检查,并且可以很好地将其安装在单个apply

通过创建纯图表而不使用values.yaml 值,可以进一步简化这一过程。

** 注意,我认为另一种解决方法是在创建集群后可以使用“local-exec”或“remote-exec”等配置程序直接运行 CRds 的 kubectl apply 命令,但我还没有测试过这一点然而。它还仍然需要您的配置环境安装了 kubectl 并正确配置了 .kubeconfig,从而创建依赖关系树。

另外,这当然不是完全有效的代码。有关要使用或分叉的模块的完整示例,请参阅此 github 存储库