terraform-provider-aws EKS 入门指南:用 Terraform 一键搭建 Amazon EKS 集群的完整配置解析
【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws
本指南以terraform-provider-aws仓库中的 examples/eks-getting-started 示例为骨架,完整讲解如何使用 Terraform 与 AWS Provider 从零搭建一套可运行的 Amazon EKS 集群——包括 VPC 网络、EKS 控制平面、IAM 角色与节点组(Node Group)。读完本文,你将掌握该示例中每个配置文件的职责、核心资源参数的含义与默认值,以及如何一键应用、生成 kubeconfig 并接入 Kubernetes。
该示例源自 HashiCorp 官方 EKS 入门指南(Getting Started Guide),仓库中保留了全部可运行的配置:providers.tf、variables.tf、vpc.tf、eks-cluster.tf、eks-worker-nodes.tf、outputs.tf与workstation-external-ip.tf七个文件共同组成一个完整的端到端方案,本文将逐一剖析。
示例整体架构:七个文件各司其职
在动手之前,先建立对整体结构的认知。该示例的核心思想是:用最少的资源组合出一条可用的 EKS 集群最小链路——VPC 提供网络底座,IAM 角色授权 EKS 服务与节点运行,安全组放行工作站的 API 访问,最终由aws_eks_cluster与aws_eks_node_group完成集群与工作节点的创建。各文件职责如下:
| 文件 | 职责 |
|---|---|
| providers.tf | 声明 Terraform 版本约束、AWS Provider 与 HTTP Provider,并读取可用可用区 |
| variables.tf | 定义aws_region与cluster_name两个输入变量 |
| vpc.tf | 创建 VPC、两个子网、互联网网关、路由表与关联 |
| eks-cluster.tf | 创建集群 IAM 角色、安全组与aws_eks_cluster控制平面 |
| eks-worker-nodes.tf | 创建节点 IAM 角色与aws_eks_node_group工作节点 |
| outputs.tf | 生成aws-authConfigMap 与 kubeconfig 两个输出 |
| workstation-external-ip.tf | 通过 HTTP Provider 获取工作站公网 IP,用于安全组放行 |
前置准备:Provider 与输入变量
providers.tf 是 Terraform 的入口配置,内容如下:
terraform { required_version = ">= 0.12" } provider "aws" { region = var.aws_region } data "aws_availability_zones" "available" {} # Not required: currently used in conjunction with using # icanhazip.com to determine local workstation external IP # to open EC2 Security Group access to the Kubernetes cluster. # See workstation-external-ip.tf for additional information. provider "http" {}几个关键点:
required_version = ">= 0.12"声明了 Terraform 的最低版本要求,0.12 是 Terraform 引入 HCL2 语法与新表达式系统的里程碑版本,本示例使用的[*]展开、tomap等语法均依赖于此;provider "aws"通过var.aws_region指定目标区域(默认us-west-2);data "aws_availability_zones" "available" {}动态拉取当前区域可用的可用区列表,供后续子网分布使用——这正是 AWS Provider 数据源(Data Source)的典型用法;provider "http" {}并非 EKS 必需,仅为配合workstation-external-ip.tf获取工作站公网 IP,属于安全组放行的辅助手段。
对应的 variables.tf 只暴露两个可调参数,保持了示例的最小化:
variable "aws_region" { default = "us-west-2" } variable "cluster_name" { default = "terraform-eks-demo" type = string }cluster_name默认值为terraform-eks-demo,在整个示例中被反复引用——包括 VPC/子网的 Kubernetes 标签、安全组名称与 kubeconfig 生成。EKS 对集群名称有严格的约束(小写字母、数字、短横线,长度限制等),在 internal/service/eks/validate.go 中有对应的校验实现,改名时需符合命名规范。
网络底座:VPC、子网与路由
vpc.tf 构建了 EKS 运行所需的全部网络资源,这是集群能否对外提供服务的基础:
resource "aws_vpc" "demo" { cidr_block = "10.0.0.0/16" tags = tomap({ "Name" = "terraform-eks-demo-node", "kubernetes.io/cluster/${var.cluster_name}" = "shared", }) } resource "aws_subnet" "demo" { count = 2 availability_zone = data.aws_availability_zones.available.names[count.index] cidr_block = "10.0.${count.index}.0/24" map_public_ip_on_launch = true vpc_id = aws_vpc.demo.id tags = tomap({ "Name" = "terraform-eks-demo-node", "kubernetes.io/cluster/${var.cluster_name}" = "shared", }) } resource "aws_internet_gateway" "demo" { vpc_id = aws_vpc.demo.id tags = { Name = "terraform-eks-demo" } } resource "aws_route_table" "demo" { vpc_id = aws_vpc.demo.id route { cidr_block = "0.0.0.0/0" gateway_id = aws_internet_gateway.demo.id } } resource "aws_route_table_association" "demo" { count = 2 subnet_id = aws_subnet.demo[count.index].id route_table_id = aws_route_table.demo.id }设计要点:
- VPC 采用
10.0.0.0/16,两个子网分别位于10.0.0.0/24与10.0.1.0/24,通过count = 2与data.aws_availability_zones.available.names[count.index]自动分布到两个不同的可用区。EKS 要求控制平面至少跨两个可用区部署子网,这是集群高可用的基础; map_public_ip_on_launch = true让子网内实例自动获得公网 IP,配合互联网网关与默认路由,节点可以拉取镜像、上报状态;kubernetes.io/cluster/${var.cluster_name} = "shared"标签是 EKS 发现子网的关键:AWS 通过该标签识别哪些子网属于此集群;shared表示子网可被多个集群共享;- 路由表将
0.0.0.0/0指向互联网网关,实现子网的出网能力,这是节点能注册进集群、执行kubelet任务的前提。
控制平面:IAM 角色、安全组与 aws_eks_cluster
eks-cluster.tf 负责 EKS 集群控制平面的创建,包含三类资源。
集群 IAM 角色
EKS 控制平面需要代表你调用其他 AWS 服务(如 ELB、IAM、EC2),因此必须先建立信任关系与授权策略:
resource "aws_iam_role" "demo-cluster" { name = "terraform-eks-demo-cluster" assume_role_policy = <<POLICY { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "eks.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } POLICY } resource "aws_iam_role_policy_attachment" "demo-cluster-AmazonEKSClusterPolicy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" role = aws_iam_role.demo-cluster.name } resource "aws_iam_role_policy_attachment" "demo-cluster-AmazonEKSVPCResourceController" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSVPCResourceController" role = aws_iam_role.demo-cluster.name }assume_role_policy中的Principal.Service: eks.amazonaws.com允许 EKS 服务代入该角色;随后挂载两个 AWS 托管策略:
AmazonEKSClusterPolicy:授予 EKS 管理集群所需的基础权限(创建/管理 ENI、安全组、负载均衡器等);AmazonEKSVPCResourceController:授予 EKS 管理 VPC 资源的权限,用于支持 Security Group for Pods 等高级网络特性。
集群安全组与工作站放行规则
resource "aws_security_group" "demo-cluster" { name = "terraform-eks-demo-cluster" description = "Cluster communication with worker nodes" vpc_id = aws_vpc.demo.id egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "terraform-eks-demo" } } resource "aws_security_group_rule" "demo-cluster-ingress-workstation-https" { cidr_blocks = [local.workstation-external-cidr] description = "Allow workstation to communicate with the cluster API Server" from_port = 443 protocol = "tcp" security_group_id = aws_security_group.demo-cluster.id to_port = 443 type = "ingress" }安全组默认放行全部出站流量(-1协议、0.0.0.0/0);入站只开放一条规则——允许local.workstation-external-cidr(即你本机公网 IP)通过TCP 443访问集群 API Server。这正是workstation-external-ip.tf存在的意义:将kubectl所在工作站的 IP 动态写入规则,避免手动查询和写死 IP。
EKS 集群资源本体
resource "aws_eks_cluster" "demo" { name = var.cluster_name role_arn = aws_iam_role.demo-cluster.arn vpc_config { security_group_ids = [aws_security_group.demo-cluster.id] subnet_ids = aws_subnet.demo[*].id } depends_on = [ aws_iam_role_policy_attachment.demo-cluster-AmazonEKSClusterPolicy, aws_iam_role_policy_attachment.demo-cluster-AmazonEKSVPCResourceController, ] }核心参数:
name:集群名称,直接取自var.cluster_name;role_arn:指向上述集群 IAM 角色;vpc_config:指定集群控制平面运行的子网(aws_subnet.demo[*].id展开两个子网)与附加安全组;depends_on显式声明依赖策略挂载完成后再创建集群——如果策略未就绪就调用CreateCluster,会因权限不足而失败。
从源码实现看,aws_eks_cluster在 internal/service/eks/cluster.go 中实现。其中删除逻辑(cluster.go)值得注意:当集群正在扩容时删除请求会失败,因此 Provider 用tfresource.Retry在60 分钟超时内、以 30 秒轮询间隔对ResourceInUseException("in progress")进行重试,直到集群真正进入可删除状态。这解释了为什么实际使用中删除 EKS 集群往往需要等待较长时间——不是卡住,而是底层 API 的分布式一致性约束所致。
工作节点:Node Group 的创建
eks-worker-nodes.tf 创建承载业务 Pod 的节点组。
节点 IAM 角色
resource "aws_iam_role" "demo-node" { name = "terraform-eks-demo-node" assume_role_policy = <<POLICY { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } ] } POLICY } resource "aws_iam_role_policy_attachment" "demo-node-AmazonEKSWorkerNodePolicy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" role = aws_iam_role.demo-node.name } resource "aws_iam_role_policy_attachment" "demo-node-AmazonEKS_CNI_Policy" { policy_arn = "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" role = aws_iam_role.demo-node.name } resource "aws_iam_role_policy_attachment" "demo-node-AmazonEC2ContainerRegistryReadOnly" { policy_arn = "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" role = aws_iam_role.demo-node.name }与集群角色不同,节点角色信任的是EC2 服务(ec2.amazonaws.com),并挂载三个托管策略:
AmazonEKSWorkerNodePolicy:允许节点与 EKS 控制平面通信(注册、上报状态);AmazonEKS_CNI_Policy:允许 VPC CNI 插件为 Pod 分配弹性网卡与 IP;AmazonEC2ContainerRegistryReadOnly:允许节点从 ECR 拉取容器镜像。
Node Group 资源
resource "aws_eks_node_group" "demo" { cluster_name = aws_eks_cluster.demo.name node_group_name = "demo" node_role_arn = aws_iam_role.demo-node.arn subnet_ids = aws_subnet.demo[*].id scaling_config { desired_size = 1 max_size = 1 min_size = 1 } depends_on = [ aws_iam_role_policy_attachment.demo-node-AmazonEKSWorkerNodePolicy, aws_iam_role_policy_attachment.demo-node-AmazonEKS_CNI_Policy, aws_iam_role_policy_attachment.demo-node-AmazonEC2ContainerRegistryReadOnly, ] }关键点:
scaling_config将desired_size、max_size、min_size都设为1,即最小可运行的单节点集群,便于快速验证且节省成本;- 节点组同样通过
depends_on等待三个策略挂载完成; - 未显式指定的
ami_type与capacity_type在 internal/service/eks/node_group.go 中都有对应字段处理——ami_type默认使用与 Kubernetes 版本匹配的 EKS 优化 AMI,capacity_type默认ON_DEMAND按需实例,二者均可在实际项目中显式配置; - 从 node_group.go 可以看到,节点组的创建、删除与更新操作分别由
waitNodegroupCreated、waitNodegroupDeleted、waitNodegroupUpdateSuccessful三个等待函数轮询集群状态直至完成,这也是节点组apply需要数分钟的原因。
收尾输出:kubeconfig 与 aws-auth ConfigMap
outputs.tf 是示例的"交付层",通过两个locals模板动态拼接出接入集群所需的全部信息:
locals { config_map_aws_auth = <<CONFIGMAPAWSAUTH apiVersion: v1 kind: ConfigMap metadata: name: aws-auth namespace: kube-system data: mapRoles: | - rolearn: ${aws_iam_role.demo-node.arn} username: system:node:{{EC2PrivateDNSName}} groups: - system:bootstrappers - system:nodes CONFIGMAPAWSAUTH kubeconfig = <<KUBECONFIG apiVersion: v1 clusters: - cluster: server: ${aws_eks_cluster.demo.endpoint} certificate-authority-data: ${aws_eks_cluster.demo.certificate_authority[0].data} name: kubernetes contexts: - context: cluster: kubernetes user: aws name: aws current-context: aws kind: Config preferences: {} users: - name: aws user: exec: apiVersion: client.authentication.k8s.io/v1beta1 command: aws-iam-authenticator args: - "token" - "-i" - "${var.cluster_name}" KUBECONFIG } output "config_map_aws_auth" { value = local.config_map_aws_auth } output "kubeconfig" { value = local.kubeconfig }两个输出的用途:
kubeconfig:使用aws_eks_cluster.demo.endpoint(API Server 地址)与certificate_authority[0].data(CA 证书)动态生成,认证方式采用aws-iam-authenticator的token子命令,按集群名-i ${var.cluster_name}换取短期令牌。将该输出写入本地~/.kube/config即可用kubectl get nodes查看集群;config_map_aws_auth:这是节点接入集群控制平面的"准入名单"。由于本示例创建的是托管节点组(Managed Node Group),在较新的 EKS 版本中节点会自动注册;该 ConfigMap 输出保留了两方面的价值:一是作为理解 RBAC 映射机制的教学素材(system:bootstrappers与system:nodes两个组是 kubelet 注册的必备授权组),二是供使用自管节点或历史版本时手动kubectl apply使用。
工作站公网 IP 的自动获取
workstation-external-ip.tf 是一个可选但很实用的辅助模块:
data "http" "workstation-external-ip" { url = "http://ipv4.icanhazip.com" } # Override with variable or hardcoded value if necessary locals { workstation-external-cidr = "${chomp(data.http.workstation-external-ip.response_body)}/32" }其原理是借助 providers.tf 中声明的 HTTP Provider,向ipv4.icanhazip.com发起一次 GET 请求,把返回的公网 IP 字符串经chomp去掉尾随换行后拼接为/32的 CIDR 段,供集群安全组的入站规则使用。
这也解释了 README 中的提示:该配置不是 EKS 必需的,完全可以替换。例如在团队协作或 CI 场景下,可将其改为变量输入或硬编码固定的办公网出口 IP,避免每次执行terraform apply时对公网服务的依赖。注意此时需同步调整 providers.tf 中provider "http" {}的声明。
一键部署:从 apply 到 kubectl 可用
将上述七个文件置于同一目录后,完整的操作流程如下:
# 1. 初始化工作目录,下载 AWS Provider 与 HTTP Provider terraform init # 2. 查看将要创建的资源清单(建议每次都执行,确认变更范围) terraform plan # 3. 应用配置,创建 VPC、IAM、EKS 集群与节点组 # 集群创建通常需要 10~20 分钟 terraform apply等待apply完成后,利用输出接入集群:
# 查看两个输出值 terraform output kubeconfig terraform output config_map_aws_auth # 将 kubeconfig 写入本地并接入集群 terraform output -raw kubeconfig > ~/.kube/config # 验证节点状态(等待 Node 进入 Ready 状态) kubectl get nodes随后即可按需kubectl apply -f部署业务应用。若要回收整套环境,直接执行terraform destroy即可——需要注意的是,如前述源码分析所示,集群删除过程可能因底层资源清理而持续较长时间(Provider 内置 60 分钟重试窗口,cluster.go),属正常现象。
延伸阅读
该示例是理解 EKS 资源的最小闭环,进一步深入可关注仓库中的以下材料:
- 集群资源完整实现:internal/service/eks/cluster.go
- 节点组资源完整实现:internal/service/eks/node_group.go
- EKS 服务包入口与资源清单:internal/service/eks/README.md
- 仓库根目录的使用说明与贡献指南:README.md
若需要 Fargate 无服务器运行方式,仓库还提供了aws_eks_fargate_profile的实现(internal/service/eks/fargate_profile.go),可在本示例基础上扩展对比。
【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考