【问题标题】:How to avoid ClusterIssuer dependency on helm cert-manager CRDs in Terraform plan and apply? ("ClusterIssuer" not found in group "cert-manager.io")如何避免 ClusterIssuer 依赖于 Terraform 计划和应用中的 helm cert-manager CRD? (在组“cert-manager.io”中找不到“ClusterIssuer”)
【发布时间】:2022-05-05 00:33:41
【问题描述】:

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

前两个我通过helm_release 资源和cluster_issuer 通过kubernetes_manifest 安装。

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

然后,我想知道是否有办法绕过这个问题,但仍然在相同的配置中创建所有内容,只有一个 terraform apply

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

| Error: Failed to determine GroupVersionResource for manifest
│ 
│   with module.k8s_base.kubernetes_manifest.cluster_issuer,
│   on ../../modules/k8s_base/main.tf line 37, in resource "kubernetes_manifest" "cluster_issuer":
│   37: resource "kubernetes_manifest" "cluster_issuer" {
│ 
│ no matches for kind "ClusterIssuer" in group "cert-manager.io"
resource "helm_release" "cert_manager" {
  chart      = "cert-manager"
  repository = "https://charts.jetstack.io"
  name       = "cert-manager"

  create_namespace = var.cert_manager_create_namespace
  namespace        = var.cert_manager_namespace

  set {
    name  = "installCRDs"
    value = "true"
  }
}

resource "helm_release" "ingress_nginx" {
  name = "ingress-nginx"

  repository = "https://kubernetes.github.io/ingress-nginx"
  chart      = "ingress-nginx"

  create_namespace = var.ingress_nginx_create_namespace
  namespace        = var.ingress_nginx_namespace

  wait = true

  depends_on = [
    helm_release.cert_manager
  ]
}

resource "time_sleep" "wait" {
  create_duration = "60s"

  depends_on = [helm_release.ingress_nginx]
}

resource "kubernetes_manifest" "cluster_issuer" {
  manifest = {
    "apiVersion" = "cert-manager.io/v1"
    "kind"       = "ClusterIssuer"
    "metadata" = {
      "name" = var.cluster_issuer_name
    }
    "spec" = {
      "acme" = {
        "email" = var.cluster_issuer_email
        "privateKeySecretRef" = {
          "name" = var.cluster_issuer_private_key_secret_name
        }
        "server" = var.cluster_issuer_server
        "solvers" = [
          {
            "http01" = {
              "ingress" = {
                "class" = "nginx"
              }
            }
          }
        ]
      }
    }
  }
  depends_on = [helm_release.cert_manager, helm_release.ingress_nginx, time_sleep.wait]
}

【问题讨论】:

  • 您使用的是哪个版本的 Kubernetes,您是如何设置集群的?您是使用裸机安装还是某些云提供商?
  • @kkopczak 我使用的是 Kubernetes 2.6.0,我通过 Azure AKS 设置了集群
  • 能否请您告诉我您使用的是哪个版本的 cert-manager?
  • 我看到有人建议在 GitHub 问题中使用 kubectl_manifest,尝试使用它而不是 kubernetes_manifest,它成功了。
  • 我刚刚遇到了这个确切的问题。 @everspader 你找到解决方案了吗?

标签: kubernetes terraform kubernetes-helm


【解决方案1】:

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

我会在 kubectl_manifest 资源中使用kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.8.0/cert-manager.crds.yaml,正如上面的评论所暗示的那样,但这是不可能的,因为它没有链接到单个 yaml 文件,但其中很多人无法跟上这些变化。不幸的是,没有“kubectl_apply”terraform 资源** 供 helm chart 依赖于首先安装的 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
  }

}

参考自定义图表:

#
# 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]
}

你可以看到上面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 }}

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

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

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

另外,这当然不是完全可以工作的代码。有关要使用或 fork 的模块的完整示例,请参阅 this github repo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-21
    • 2021-10-01
    • 2022-10-05
    • 1970-01-01
    • 2022-08-06
    • 1970-01-01
    • 1970-01-01
    • 2020-04-12
    相关资源
    最近更新 更多