如何将来自 github 的 CRD 应用到具有 terraform 的集群?

How do I apply a CRD from github to a cluster with terraform?

我想用 terraform 安装 CRD,我希望这样做会很容易:

data "http" "crd" {
  url = "https://raw.githubusercontent.com/kubernetes-sigs/application/master/deploy/kube-app-manager-aio.yaml"
  request_headers = {
    Accept = "text/plain"
  }
}

resource "kubernetes_manifest" "install-crd" {
  manifest = data.http.crd.body
}

但是我得到这个错误:

can't unmarshal tftypes.String into *map[string]tftypes.Value, expected
map[string]tftypes.Value

尝试使用 yamldecode 将其转换为 yaml 也不起作用,因为 yamldecode 不支持多文档 yaml 文件。

我可以使用 exec,但我在等待 kubernetes_manifest 资源被释放时已经这样做了。 kubernetes_manifest 仅支持单个资源还是可以用于从原始文本清单文件创建多个资源?

kubernetes_manifest(强调我的)

Represents one Kubernetes resource by supplying a manifest attribute

在我看来,它不支持多资源/多文档 yaml 文件。

但是您可以手动拆分传入文档和yamldecode它的部分:

locals {
  yamls = [for data in split("---", data.http.crd.body): yamldecode(data)]
}

resource "kubernetes_manifest" "install-crd" {
  count = length(local.yamls)
  manifest = local.yamls[count.index]
}

不幸的是在我的机器上这然后抱怨

'status' attribute key is not allowed in manifest configuration

恰好是 11 个清单中的一个。

而且由于我对 kubernetes 一无所知,所以我不知道这意味着什么,也不知道它是否需要修复。

或者,您始终可以将 null_resource 与获取 yaml 文档的脚本一起使用,并使用 bash 工具或 python 或安装的任何工具来转换、拆分和过滤传入的内容yaml.

我使用 kubectl provider 让它工作。最终 kubernetes_manifest 应该也能正常工作,但它目前 (v2.5.0) 仍处于测试阶段并且有一些错误。此示例仅使用 kind+name,但为了完全唯一性,它还应包括 API 和命名空间参数。

resource "kubectl_manifest" "cdr" {
  # Create a map { "kind--name" => yaml_doc } from the multi-document yaml text.
  # Each element is a separate kubernetes resource.
  # Must use \n---\n to avoid splitting on strings and comments containing "---".
  # YAML allows "---" to be the first and last line of a file, so make sure
  # raw yaml begins and ends with a newline.
  # The "---" can be followed by spaces, so need to remove those too.
  # Skip blocks that are empty or comments-only in case yaml began with a comment before "---".
  for_each = {
    for pair in [
      for yaml in split(
        "\n---\n",
        "\n${replace(data.http.crd.body, "/(?m)^---[[:blank:]]*(#.*)?$/", "---")}\n"
      ) :
      [yamldecode(yaml), yaml]
      if trimspace(replace(yaml, "/(?m)(^[[:blank:]]*(#.*)?$)+/", "")) != ""
    ] : "${pair.0["kind"]}--${pair.0["metadata"]["name"]}" => pair.1
  }
  yaml_body = each.value
}

一旦 Hashicorp 修复 kubernetes_manifest,我建议使用相同的方法。不要使用 count+element(),因为如果元素的顺序发生变化,Terraform 将 delete/recreate 许多不需要的资源。

resource "kubernetes_manifest" "crd" {
  for_each = {
    for value in [
      for yaml in split(
        "\n---\n",
        "\n${replace(data.http.crd.body, "/(?m)^---[[:blank:]]*(#.*)?$/", "---")}\n"
      ) :
      yamldecode(yaml)
      if trimspace(replace(yaml, "/(?m)(^[[:blank:]]*(#.*)?$)+/", "")) != ""
    ] : "${value["kind"]}--${value["metadata"]["name"]}" => value
  }
  manifest = each.value
}

P.S。请为多文档 yamldecode 支持 Terraform feature request。将使事情比上面的正则表达式容易得多。