terraform-aws-eks 实战 FAQ 全解析:启动模板、节点注册、安全组与 Add-on 配置排障指南
【免费下载链接】terraform-aws-eksTerraform module to create Amazon Elastic Kubernetes (EKS) resources 🇺🇦项目地址: https://gitcode.com/GitHub_Trending/te/terraform-aws-eks
本文基于 terraform-aws-eks 官方文档 docs/faq.md,结合仓库源码,系统解答使用该 Terraform 模块创建 Amazon EKS 集群时最高频的 7 类问题:为什么disk_size/remote_access不生效、安全组标签冲突报错、节点无法注册、desired_size修改无变化、如何读取计算资源输出属性,以及如何查询 EKS Add-on 的可用版本与配置 Schema。读完本文,你将掌握这些常见"坑"的根因,并能给出可直接落地的 Terraform 配置修复方案。
一、为什么设置了disk_size或remote_access却没有任何变化?
这是使用本模块创建 EKS 托管节点组(EKS Managed Node Group)时最常见的问题之一。根因在于:disk_size与remote_access只有在使用 EKS 托管节点组默认启动模板(default launch template)时才有效。
本模块默认会为节点组提供自定义启动模板(custom launch template),目的是支持自定义安全组、标签传播(tag propagation)、用户数据(user data)等高级能力。一旦使用自定义启动模板,EKS 服务端便不允许在节点组层面直接设置disk_size(磁盘大小)和remote_access(SSH 远程访问)——这两个值应当定义在启动模板本身。
这一约束在源码中有明确体现。在 modules/eks-managed-node-group/main.tf#L484 中:
disk_size = var.use_custom_launch_template ? null : var.disk_size # if using a custom LT, set disk size on custom LT or else it will error here也就是说,只要use_custom_launch_template = true(模块默认值),传入的disk_size会被直接置为null,自然"没有任何变化"。对应的变量声明同样强调了使用前提,见 modules/eks-managed-node-group/variables.tf#L517-L521(disk_size:Only valid whenuse_custom_launch_template=false)与 modules/eks-managed-node-group/variables.tf#L553-L560(remote_access:同样限定)。
解决方案
如果你确实需要放弃自定义启动模板,改由 EKS 使用默认启动模板,可以在节点组定义中显式关闭它:
module "eks" { source = "terraform-aws-modules/eks/aws" version = "~> 21.0" name = "my-cluster" kubernetes_version = "1.33" vpc_id = "vpc-1234556abcdef" subnet_ids = ["subnet-abcde012", "subnet-bcde012a", "subnet-fghi345a"] eks_managed_node_groups = { example = { use_custom_launch_template = false disk_size = 100 # 仅在 use_custom_launch_template = false 时生效 remote_access = { ec2_ssh_key = "my-key-pair" source_security_group_ids = ["sg-0123456789abcdef0"] } instance_types = ["m5.xlarge"] min_size = 2 max_size = 10 desired_size = 2 } } }需要权衡的是:关闭自定义启动模板后,你将失去模块提供的自定义安全组挂载、标签传播、cloudinit_pre_nodeadm/post_bootstrap_user_data等扩展能力。大多数生产场景建议保留自定义启动模板,并通过block_device_mappings配置磁盘大小、通过key_name配置 SSH 密钥,效果相同且能力更完整。
二、报错expect exactly one securityGroup tagged with kubernetes.io/cluster/<CLUSTER_NAME> ...如何解决?
⚠️ 提示:错误信息中的
<CLUSTER_NAME>即你的集群名称,例如my-cluster。
错误根因
默认情况下,EKS 服务会创建一个集群主安全组(cluster primary security group),它由 EKS 服务在模块之外创建,并被打上标签:
{ "kubernetes.io/cluster/<CLUSTER_NAME>" = "owned" }这个标签本身并不会引发冲突,直到用户决定同时挂载以下两个安全组到同一批节点上:
- 集群主安全组(cluster primary security group);
- 模块创建的共享节点安全组(shared node security group)——通过设置
attach_cluster_primary_security_group = true触发。
问题的关键不在于账号下存在多个带有该key:value标签组合的安全组,而在于同一集群的节点上同时挂载了多个带有该标签的安全组。像 AWS Load Balancer Controller 这类依赖该标签发现集群安全组的 Add-on,会因"期望恰好一个"而报错。
从源码可以看到,模块创建的共享节点安全组确实带上了这个标签,见 node_groups.tf#L187-L194:
tags = merge( var.tags, { "Name" = local.node_sg_name "kubernetes.io/cluster/${var.name}" = "owned" }, var.node_security_group_tags )同时,模块在 node_groups.tf#L70-L74 中默认创建该共享节点安全组:
create_node_sg = var.create && var.create_node_security_group解决方案
根据你的使用意图,有两种方式:
方案一:使用集群主安全组,禁用共享节点安全组的创建
module "eks" { source = "terraform-aws-modules/eks/aws" version = "~> 21.0" # ... 其他配置 create_node_security_group = false # 默认是 true eks_managed_node_groups = { example = { attach_cluster_primary_security_group = true # 默认是 false } } # 或者对于 self-managed 节点组: # self_managed_node_groups = { # example = { # attach_cluster_primary_security_group = true # 默认是 false # } # } }方案二:不挂载集群主安全组
集群主安全组的访问权限相当宽泛;模块转而提供了一个以最小权限启动空 EKS 集群的安全组,并鼓励用户按需放开访问以满足工作负载。这也是模块的默认行为:
eks_managed_node_groups = { example = { attach_cluster_primary_security_group = false # 默认是 false } } # 或者对于 self-managed # self_managed_node_groups = { # example = { # attach_cluster_primary_security_group = false # 默认是 false # } # }理论上,如果你选择挂载集群主安全组,就不应该再使用模块创建的共享节点安全组;反之亦然。具体取舍由你根据自身需求和用例决定。
附加提醒:Custom Networking
如果你使用了 EKS 的Custom Networking(自定义 CNI 网络,通过ENIConfig指定子网与安全组),请务必在ENIConfig资源中只挂载上面你选定方案对应的安全组,避免冗余标签再次引发同样的问题。
三、节点为什么无法注册到集群?
节点无法与 EKS 控制面完成注册(NotReady/ 未出现在kubectl get nodes中),绝大多数情况下是网络配置问题。请按以下顺序排查:
1. 至少启用一个集群端点
集群的公开端点(public endpoint)与私有端点(private endpoint)至少需要启用一个。
如果你需要使用公开端点,推荐同时启用公开与私有端点,并通过cluster_endpoint_public_access_cidrs限制公开端点的访问来源。关于与端点的通信方式,可参考 AWS EKS 官方文档中关于集群端点的说明。
2. 节点必须能够访问集群端点
模块默认只创建公开端点(variables.tf#L142-L146 中endpoint_public_access默认false,而 main.tf#L78-L85 中端点的启用与 CIDR 限制会原样传给aws_eks_cluster的vpc_config)。因此节点需要出站公网访问能力:
- 私有子网中的节点:需要 NAT 网关或 NAT 实例,并配置好对应的路由规则;
- 公有子网中的节点:确保节点以公网 IP 启动(通过模块配置或子网设置默认值)。
⚠️重要:如果你只启用公开端点,并通过
cluster_endpoint_public_access_cidrs限制访问来源,请务必注意——EKS 节点同样会走公开端点,你必须把节点的出网 IP(或所在子网的 CIDR)加入白名单。否则节点将无法正常工作。
3. 启用私有端点时的 VPC 前提
你也可以通过设置cluster_endpoint_private_access = true启用私有端点(该变量默认即为true,见 variables.tf 中endpoint_private_access的定义)。启用私有端点时,请确保 VPC 的DNS 解析(DNS resolution)和 DNS 主机名(DNS hostnames)都已开启。
4. 节点访问其他 AWS 服务的能力
节点还需要连接其他 AWS 服务才能正常工作(下载容器镜像、调用 API 完成角色代入等)。如果出于安全原因无法为节点开通公网访问,可以为相关服务添加VPC Endpoint:EC2 API、ECR API、ECR DKR 以及 S3。
模块侧的时序保障
另外,模块在集群创建与数据面(节点组、Fargate Profile)创建之间内置了一个等待期time_sleep,默认 30 秒(node_groups.tf#L10-L23,对应根模块变量dataplane_wait_duration,默认"30s")。它的作用是给需要先于数据面配置的 Add-on 留出创建与自配置的时间。如果集群刚创建完成节点就立即注册失败,也可以适当调大该值。
四、修改节点组的desired_size为什么没有任何变化?
这是模块的有意设计,不是 bug。模块通过lifecycle.ignore_changes显式忽略了desired_size的变更,见 modules/eks-managed-node-group/main.tf#L561-L566:
lifecycle { create_before_destroy = true ignore_changes = [ scaling_config[0].desired_size, ] }原因是:Terraform 的lifecycle块中不支持变量(无法写成ignore_changes = [scaling_config[0].desired_size]的条件式),因此模块选择无条件忽略该值,从而保证Cluster Autoscaler、Karpenter 等自动扩缩容控制器可以独立调整节点数量,而不会被 Terraform 的下一轮apply覆盖回去。
因此,节点组创建完成后,修改期望节点数必须绕过 Terraform,例如:
- 由 Cluster Autoscaler / Karpenter 自动扩缩容;
- 通过
aws eks update-nodegroup-config等 AWS API/CLI 手动调整; - 使用社区提供的
eks-desired-size-hack类方案绕开该限制(该方案利用 Terraform 的triggers/外部数据源技巧,在保留ignore_changes的同时仍能通过 Terraform 驱动desired_size,具体原理可参考该项目说明)。
注意:min_size与max_size不在忽略之列,仍然可以通过 Terraform 正常修改。
五、如何访问计算资源(节点组 / Fargate)的属性?
根模块通过module.eks_managed_node_group、module.self_managed_node_group、module.fargate_profile三个子模块管理计算资源,并把它们的完整属性以 Map 形式暴露为输出。以下示例假设你的集群模块定义命名为eks(即module "eks" { ... })。
EKS Managed Node Group 属性
eks_managed_role_arns = [for group in module.eks_managed_node_group : group.iam_role_arn]iam_role_arn是子模块输出之一,见 modules/eks-managed-node-group/outputs.tf#L73-L76。同一个子模块还输出了node_group_arn、node_group_autoscaling_group_names、launch_template_id、security_group_id等丰富属性,可组合使用。
Self Managed Node Group 属性
self_managed_role_arns = [for group in module.self_managed_node_group : group.iam_role_arn]对应子模块输出见 modules/self-managed-node-group/outputs.tf#L88-L96,此外还可取autoscaling_group_name、iam_instance_profile_arn、access_entry_arn等。
Fargate Profile 属性
fargate_profile_pod_execution_role_arns = [for group in module.fargate_profile : group.fargate_profile_pod_execution_role_arn]fargate_profile_pod_execution_role_arn在 modules/fargate-profile/outputs.tf#L39-L42 中定义。
根模块输出汇总
根模块在 outputs.tf#L259-L281 中同样暴露了这三类资源整体:
module.eks.eks_managed_node_groups—— 所有托管节点组属性 Map;module.eks.eks_managed_node_groups_autoscaling_group_names—— 托管节点组对应的 Auto Scaling Group 名称列表;module.eks.self_managed_node_groups/module.eks.self_managed_node_groups_autoscaling_group_names;module.eks.fargate_profiles—— 所有 Fargate Profile 属性 Map。
这样你可以在其他模块中直接消费这些属性,例如为节点组 IAM 角色配置额外的信任策略或附加策略。
六、有哪些 EKS Add-on 可以使用?
EKS Add-on 的可用清单由 AWS EKS 服务本身维护,会随区域和 Kubernetes 版本变化。官方可用列表见 AWS EKS 用户指南中的 Add-on 文档页;你也可以直接通过 AWS CLI 查询当前账号可用区域内的全部 Add-on 名称:
aws eks describe-addon-versions --query 'addons[*].addonName'常见的 EKS 官方 Add-on 包括:coredns、kube-proxy、vpc-cni(Amazon VPC CNI)、eks-pod-identity-agent、aws-ebs-csi-driver、aws-efs-csi-driver、aws-load-balancer-controller等。本模块在 main.tf#L769-L866 中通过aws_eks_addon与aws_eks_addon.before_compute两个资源实现 Add-on 管理,并支持before_compute标记——将vpc-cni、eks-pod-identity-agent等设为before_compute = true,可以保证它们在数据面计算资源创建之前完成部署(这也是 README.md 中 EKS Managed Node Group 示例的推荐写法)。
模块中一个典型的 Add-on 配置示例(来自 README.md):
addons = { coredns = {} eks-pod-identity-agent = { before_compute = true } kube-proxy = {} vpc-cni = { before_compute = true } }七、某个 Add-on 支持哪些配置值(configuration values)?
[!NOTE] 可用配置值会随 Add-on 版本变化——随着 EKS 为后续版本开放更多功能,通常会有更多配置项被加入。
查询配置 Schema 的命令
对于给定的 Add-on 名称与版本,可以通过以下命令获取其配置值的 JSON Schema:
aws eks describe-addon-configuration --addon-name <value> --addon-version <value> --query 'configurationSchema' --output text | jq例如,查询 CoreDNSv1.11.1-eksbuild.8的配置 Schema:
aws eks describe-addon-configuration --addon-name coredns --addon-version v1.11.1-eksbuild.8 --query 'configurationSchema' --output text | jq返回结果示例
(以下为撰写本文时该命令的返回结果,随版本演进可能不同)
{ "$ref": "#/definitions/Coredns", "$schema": "http://json-schema.org/draft-06/schema#", "definitions": { "Coredns": { "additionalProperties": false, "properties": { "affinity": { "default": { "affinity": { "nodeAffinity": { "requiredDuringSchedulingIgnoredDuringExecution": { "nodeSelectorTerms": [ { "matchExpressions": [ { "key": "kubernetes.io/os", "operator": "In", "values": ["linux"] }, { "key": "kubernetes.io/arch", "operator": "In", "values": ["amd64", "arm64"] } ] } ] } }, "podAntiAffinity": { "preferredDuringSchedulingIgnoredDuringExecution": [ { "podAffinityTerm": { "labelSelector": { "matchExpressions": [ { "key": "k8s-app", "operator": "In", "values": ["kube-dns"] } ] }, "topologyKey": "kubernetes.io/hostname" }, "weight": 100 } ] } } }, "description": "Affinity of the coredns pods", "type": ["object", "null"] }, "computeType": { "type": "string" }, "corefile": { "description": "Entire corefile contents to use with installation", "type": "string" }, "nodeSelector": { "additionalProperties": { "type": "string" }, "type": "object" }, "podAnnotations": { "properties": {}, "title": "The podAnnotations Schema", "type": "object" }, "podDisruptionBudget": { "description": "podDisruptionBudget configurations", "enabled": { "default": true, "description": "the option to enable managed PDB", "type": "boolean" }, "maxUnavailable": { "anyOf": [ { "pattern": ".*%$", "type": "string" }, { "type": "integer" } ], "default": 1, "description": "minAvailable value for managed PDB, can be either string or integer; if it's string, should end with %" }, "minAvailable": { "anyOf": [ { "pattern": ".*%$", "type": "string" }, { "type": "integer" } ], "description": "maxUnavailable value for managed PDB, can be either string or integer; if it's string, should end with %" }, "type": "object" }, "podLabels": { "properties": {}, "title": "The podLabels Schema", "type": "object" }, "replicaCount": { "type": "integer" }, "resources": { "$ref": "#/definitions/Resources" }, "tolerations": { "default": [ { "key": "CriticalAddonsOnly", "operator": "Exists" }, { "effect": "NoSchedule", "key": "node-role.kubernetes.io/control-plane" } ], "description": "Tolerations of the coredns pod", "items": { "type": "object" }, "type": "array" }, "topologySpreadConstraints": { "description": "The coredns pod topology spread constraints", "type": "array" } }, "title": "Coredns", "type": "object" }, "Limits": { "additionalProperties": false, "properties": { "cpu": { "type": "string" }, "memory": { "type": "string" } }, "title": "Limits", "type": "object" }, "Resources": { "additionalProperties": false, "properties": { "limits": { "$ref": "#/definitions/Limits" }, "requests": { "$ref": "#/definitions/Limits" } }, "title": "Resources", "type": "object" } } }如何理解并应用到模块中
这份 Schema 展示了该 Add-on 版本支持的所有可配置字段、类型、默认值与校验规则(如replicaCount为整数、tolerations为对象数组、resources.limits.cpu为字符串等)。拿到 Schema 后,你就可以在模块的addons配置中通过configuration_values传入自定义 JSON/YAML:
addons = { coredns = { addon_version = "v1.11.1-eksbuild.8" configuration_values = jsonencode({ replicaCount = 2 resources = { requests = { cpu = "100m" memory = "128Mi" } limits = { cpu = "200m" memory = "256Mi" } } }) } }模块会将configuration_values原样传递给aws_eks_addon资源(见 main.tf#L779 中configuration_values = each.value.configuration_values的透传逻辑)。注意additionalProperties: false意味着不能传入 Schema 未定义的字段,否则 EKS 会拒绝该配置,因此务必先通过上面的 CLI 命令确认当前版本支持的确切字段。
总结
本文覆盖的 7 个 FAQ 都来自模块维护者长期收集的真实使用场景:
| 问题 | 根因 | 关键配置/命令 |
|---|---|---|
disk_size/remote_access不生效 | 自定义启动模板接管了这些参数 | use_custom_launch_template = false |
| 安全组标签冲突报错 | 同一批节点挂了两个带kubernetes.io/cluster/<NAME>标签的安全组 | create_node_security_group/attach_cluster_primary_security_group |
| 节点无法注册 | 端点未启用或节点无法访问端点/AWS 服务 | endpoint_public_access、cluster_endpoint_public_access_cidrs、VPC Endpoint |
desired_size修改无变化 | 模块lifecycle.ignore_changes有意忽略 | 由 Autoscaler/Karpenter 或 AWS API 调整 |
| 读取计算资源属性 | 子模块输出为 Map | module.eks_managed_node_group/module.fargate_profile等输出 |
| 可用的 Add-on | 由 EKS 服务维护 | aws eks describe-addon-versions |
| Add-on 配置值 | 随版本变化的 JSON Schema | aws eks describe-addon-configuration |
建议在排障时先对照 docs/faq.md 定位问题类别,再结合 README.md 中的完整示例(EKS Managed Node Group、EKS Auto Mode、Karpenter、Hybrid Nodes 等场景)与 main.tf、node_groups.tf 等源码确认参数语义。如需进一步了解数据面细节,可继续阅读 docs/compute_resources.md 与 docs/network_connectivity.md。
【免费下载链接】terraform-aws-eksTerraform module to create Amazon Elastic Kubernetes (EKS) resources 🇺🇦项目地址: https://gitcode.com/GitHub_Trending/te/terraform-aws-eks
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考