Terraform EKS 标签化

7
我遇到了 Terraform EKS 标记的问题,似乎找不到可行的解决方案来标记创建新集群时的所有 VPC 子网。
一些背景信息:我们有一个 AWS VPC,在其中部署了几个 EKS 集群到子网中。我们不会在创建 EKS 集群时创建 VPC 或子网。因此,创建集群的 Terraform 代码无法标记现有的子网和 VPC。虽然 EKS 将添加所需的标记,但它们在下次运行 terraform apply 时会自动删除。
我的解决方法是在 VPC 中提供一个 terraform.tfvars 文件,如下所示:
eks_tags = 
 [
 "kubernetes.io/cluster/${var.cluster-1}", "shared", 
 "kubernetes.io/cluster/${var.cluster-2}", "shared",
 "kubernetes.io/cluster/${var.cluster-2}", "shared",
]    

然后在VPC和子网资源中,我们做了类似的事情

    resource "aws_vpc" "demo" {
      cidr_block = "10.0.0.0/16"

      tags = "${
        map(
         ${var.eks_tags}
        )
     }"
    }

然而,上述方法似乎不起作用。我尝试了来自https://www.terraform.io/docs/configuration-0-11/interpolation.html的各种Terraform 0.11函数,但它们都没有帮助。
有人能解决这个问题吗?
我们总是为每个EKS集群创建新的VPC和子网的想法是错误的。显然,必须有一种使用Terraform标记现有VPC和子网资源的方法?
3个回答

12
你现在可以使用AWS提供的ignore_tags属性,这样使用 aws_ec2_tag资源创建的标记不会在下一次应用VPC模块时被删除。
例如,提供程序变为:
provider "aws" {
  profile = "terraform"
  region  = "us-west-1"
  
  // This is necessary so that tags required for eks can be applied to the vpc without changes to the vpc wiping them out.
  // https://registry.terraform.io/providers/hashicorp/aws/latest/docs/guides/resource-tagging
  ignore_tags {
    key_prefixes = ["kubernetes.io/"]
  }
}

您可以在 EKS 模块中使用 aws_ec2_tag 资源,而不必担心下一次应用 VPC 模块时标签会被删除。

/**
  Start of resource tagging logic to update the provided vpc and its subnets with the necessary tags for eks to work
  The toset() function is actually multiplexing the resource block, one for every item in the set. It is what allows 
  for setting a tag on each of the subnets in the vpc.
*/
resource "aws_ec2_tag" "vpc_tag" {
  resource_id = data.terraform_remote_state.vpc.outputs.vpc_id
  key         = "kubernetes.io/cluster/${var.cluster_name}"
  value       = "shared"
}

resource "aws_ec2_tag" "private_subnet_cluster_tag" {
  for_each    = toset(data.terraform_remote_state.vpc.outputs.private_subnets)
  resource_id = each.value
  key         = "kubernetes.io/cluster/${var.cluster_name}"
  value       = "shared"
}

resource "aws_ec2_tag" "public_subnet_cluster_tag" {
  for_each    = toset(data.terraform_remote_state.vpc.outputs.public_subnets)
  resource_id = each.value
  key         = "kubernetes.io/cluster/${var.cluster_name}"
  value       = "shared"
}

/**
  These tags have been decoupled from the eks module and moved to the more appropirate vpc module.
*/
resource "aws_ec2_tag" "private_subnet_tag" {
  for_each    = toset(data.terraform_remote_state.vpc.outputs.private_subnets)
  resource_id = each.value
  key         = "kubernetes.io/role/internal-elb"
  value       = "1"
}

resource "aws_ec2_tag" "public_subnet_tag" {
  for_each    = toset(data.terraform_remote_state.vpc.outputs.public_subnets)
  resource_id = each.value
  key         = "kubernetes.io/role/elb"
  value       = "1"
}

1
确实非常有用。只能使用count,因为for_each总是抱怨“资源属性在应用之前无法确定”。 - Reginaldo Santos
1
非常感谢您提供的代码片段。 我认为私有子网应该被标记为“internal-elb”。 - cedric
此外,您应该忽略无法使用生命周期元参数完成的新前缀:provider "aws" { region = var.region ignore_tags { key_prefixes = ["kubernetes.io"] } }代码片段在此处找到:https://github.com/hashicorp/terraform/issues/5666#issuecomment-747746639 - cedric

2
在我们的情况下,我们有独立的脚本来配置VPC和网络资源,我们没有添加EKS特定的标签。
对于EKS集群配置,我们有单独的脚本,将自动更新/添加集群上的标签。
因此,在provider.tf文件中的VPC脚本中,我们添加以下条件,以便脚本不会删除这些标签,并且一切都可以正常运行。
provider "aws" {
region = "us-east-1"
 ignore_tags {
    key_prefixes = ["kubernetes.io/cluster/"]
  }
}

很好的提醒。我已经将我的标签从EKS模块移动到VPC模块,这样修改各种EKS集群就不会移除VPC子网的标签了。我也已经更新了我的答案以反映这一点。 - rsmets

1
这个问题在有两个具有不同状态文件的代码尝试在同一资源上执行操作时,将始终存在。
解决此问题的一种方法是每次应用EKS terraform代码时重新导入VPC资源到您的VPC状态文件中。这也会导入您的标记。子网也是如此,但从长远来看,这是一个手动而繁琐的过程。
terraform import aws_vpc.test_vpc vpc-a01106c2
参考: https://www.terraform.io/docs/providers/aws/r/vpc.html 干杯!

有一瞬间,我认为上述方法会奏效。然而,我的问题在于我的子网资源是在一个模块中创建的,而 Terraform 要求在根模块中定义(请参见下文): - Mimi
terraform import aws_subnet.public-cluster-c-subnet subnet-02ed*****1b6b Error: resource address "aws_subnet.public-cluster-c-subnet" does not exist in the configuration. - Mimi
`Before importing this resource, please create its configuration in the root module. For example: resource "aws_subnet" "public-cluster-c-subnet" { # (resource arguments) } ` - Mimi
如果资源在模块内部,您仍然可以导入它。尝试从状态文件中找到资源的绝对路径。类似于: terraform import module.some_module.module.some_other_module.aws_vpc.test_vpc vpc-12341234 - praveen.chandran
资源路径也应该在 terraform plan 的输出中可见。 - praveen.chandran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接