跳转至

EKS 两种创建模式:Auto Mode 与 Managed Node Group 实战方案

这篇文章解决什么问题

在 AWS 控制台创建 EKS 集群时,页面上通常会看到两类入口:

  • 快速配置,默认使用 EKS Auto Mode
  • 自定义配置,可以自己控制 VPC、节点、插件和访问方式

这两个选项背后真正影响架构的是:EKS 的计算资源由谁管理

常见模式有两种:

EKS Auto Mode:
  EKS 自动管理节点、容量、部分网络和存储基础设施

普通 EKS + Managed Node Group:
  你显式创建节点组,Pod 调度到这些 EC2 节点上

这篇文章给出两套创建方案,适合做生产上线前的验证集群,也能作为后续生产模板的起点。

两种模式怎么选

先给结论:

场景 推荐模式
快速验证应用能否跑在 EKS 上 EKS Auto Mode
团队刚开始使用 EKS,希望少管节点 EKS Auto Mode
想让 EKS 自动准备 EC2 节点承载 Pod EKS Auto Mode
生产计划使用 Auto Mode 验证环境也用 Auto Mode
需要验证节点组、实例规格、磁盘、DaemonSet Managed Node Group
生产计划使用固定节点池、Karpenter 或精细成本治理 Managed Node Group
需要强控制节点 AMI、启动参数、节点安全基线 Managed Node Group

一句话:

验证业务适配 EKS:优先 Auto Mode
验证生产节点架构:优先 Managed Node Group

共同前置条件

两种方案都需要本地具备:

terraform
aws
kubectl

这三个工具的作用分别是:

工具 作用
Terraform 创建 VPC、EKS、节点组、IAM 等 AWS 资源
AWS CLI 认证 AWS 账号、查询集群、生成 kubeconfig
kubectl 连接 EKS 集群并管理 Kubernetes 资源

Windows 安装

Windows 建议使用 winget 安装。如果你的系统没有 winget,也可以从 HashiCorp、AWS、Kubernetes 官方页面下载安装包。

安装 Terraform:

winget install Hashicorp.Terraform

安装 AWS CLI v2:

winget install Amazon.AWSCLI

安装 kubectl:

winget install Kubernetes.kubectl

安装后重新打开 PowerShell,验证:

terraform version
aws --version
kubectl version --client

macOS 安装

macOS 建议使用 Homebrew。

安装 Homebrew 后执行:

brew tap hashicorp/tap
brew install hashicorp/tap/terraform
brew install awscli
brew install kubectl

验证:

terraform version
aws --version
kubectl version --client

Linux 安装

Linux 发行版很多,下面给出通用思路。生产机器上建议优先使用官方仓库或公司内部软件源。

Ubuntu/Debian 可以使用 HashiCorp apt 仓库安装 Terraform:

wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(. /etc/os-release && echo "$VERSION_CODENAME") main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update
sudo apt install terraform

AWS CLI v2 可以这样安装:

curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install

kubectl 可以直接下载稳定版本:

curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl

验证:

terraform version
aws --version
kubectl version --client

如果是 ARM64 Linux,把 kubectl 下载地址里的 linux/amd64 改成 linux/arm64

配置 AWS 凭证

安装工具后,需要先让 AWS CLI 能访问你的 AWS 账号。

最简单的方式是:

aws configure

按提示输入:

AWS Access Key ID
AWS Secret Access Key
Default region name: us-east-1
Default output format: json

配置完成后会写入:

~/.aws/credentials
~/.aws/config

Windows 对应路径通常是:

C:\Users\<用户名>\.aws\credentials
C:\Users\<用户名>\.aws\config

如果公司使用 IAM Identity Center,也可以使用 SSO:

aws configure sso
aws sso login

验证当前身份:

aws sts get-caller-identity

能正常返回 AccountArnUserId,说明 AWS CLI 认证可用。

并且当前 AWS 身份要有创建这些资源的权限:

  • VPC、Subnet、Route Table、NAT Gateway
  • EKS Cluster
  • EC2、Auto Scaling、Launch Template
  • IAM Role、Policy Attachment
  • CloudWatch Logs

配置 kubectl 访问 EKS

EKS 集群创建完成后,本地 kubectl 还不能直接访问集群,需要先生成 kubeconfig:

aws eks update-kubeconfig --region us-east-1 --name <cluster-name>

这条命令会把 EKS 访问配置写入:

~/.kube/config

Windows 对应路径通常是:

C:\Users\<用户名>\.kube\config

然后验证:

kubectl get nodes
kubectl get pods -A

方案一:EKS Auto Mode

适用场景

EKS Auto Mode 适合快速创建验证集群。它的重点是:

你提交 Pod
EKS 根据 Pod 资源需求自动准备合适的 EC2 节点

它不是 Lambda 那种纯 Serverless,底层仍然是 EC2。只是节点创建、替换、生命周期、部分网络和存储基础设施由 EKS 更自动化地管理。

适合验证:

  • 应用能否部署到 EKS
  • Service、Ingress、PVC 基本链路
  • 镜像拉取、Pod 启动、日志采集
  • 快速创建、快速销毁的临时集群

不适合重点验证:

  • 固定节点组规划
  • 自定义 AMI
  • 节点启动脚本
  • 复杂 DaemonSet 与节点安全基线
  • 精细 Spot/On-Demand 成本策略

Terraform 示例

下面示例使用 terraform-aws-modules/vpc/awsterraform-aws-modules/eks/aws 创建一个 Auto Mode 验证集群。

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

locals {
  cluster_name = "eks-prod-verify-135"

  # 复用 AWS 控制台“创建推荐的角色”生成的 EKS Auto Mode 角色。
  cluster_role_arn = "arn:aws:iam::788356290550:role/AmazonEKSAutoClusterRole"
  node_role_arn    = "arn:aws:iam::788356290550:role/AmazonEKSAutoNodeRole"

  # 可选:让 root 控制台身份也能查看和管理集群内资源。
  console_admin_principal_arn = "arn:aws:iam::788356290550:root"
}

data "aws_availability_zones" "available" {
  state = "available"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "${local.cluster_name}-vpc"
  cidr = "10.20.0.0/16"

  azs             = slice(data.aws_availability_zones.available.names, 0, 2)
  public_subnets  = ["10.20.0.0/24", "10.20.1.0/24"]
  private_subnets = ["10.20.8.0/22", "10.20.12.0/22"]

  enable_dns_hostnames = true
  enable_nat_gateway   = true
  single_nat_gateway   = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"

  cluster_name    = local.cluster_name
  cluster_version = "1.35"

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  create_iam_role = false
  iam_role_arn    = local.cluster_role_arn

  create_node_iam_role = false

  cluster_endpoint_public_access       = true
  cluster_endpoint_public_access_cidrs = ["0.0.0.0/0"]
  cluster_endpoint_private_access      = true

  cluster_enabled_log_types = [
    "api",
    "audit",
    "authenticator",
  ]

  cluster_addons = {
    coredns = {
      most_recent = true
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
  }

  cluster_compute_config = {
    enabled       = true
    node_pools    = ["general-purpose", "system"]
    node_role_arn = local.node_role_arn
  }

  access_entries = {
    console_admin = {
      principal_arn = local.console_admin_principal_arn

      policy_associations = {
        cluster_admin = {
          policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
          access_scope = {
            type = "cluster"
          }
        }
      }
    }
  }

  enable_cluster_creator_admin_permissions = true
}

output "configure_kubectl" {
  value = "aws eks update-kubeconfig --region us-east-1 --name ${local.cluster_name}"
}

验证步骤

执行:

terraform init
terraform plan
terraform apply

配置 kubectl:

aws eks update-kubeconfig --region us-east-1 --name eks-prod-verify-135

查看节点:

kubectl get nodes -o wide

部署一个测试应用:

kubectl create deployment nginx --image=nginx:1.25
kubectl scale deployment nginx --replicas=3
kubectl get pod -o wide

如果集群当前没有足够容量,Auto Mode 会自动准备节点来运行 Pod。

控制台访问条目

这次实际创建时有一个很容易忽略的点:集群是 terraform IAM 用户创建的,不代表 root 用户登录控制台后就能查看集群内 Kubernetes 资源

这段配置:

enable_cluster_creator_admin_permissions = true

只会给执行 Terraform 的身份授权。例如本次创建者是:

arn:aws:iam::788356290550:user/terraform

所以这个用户可以执行:

kubectl get nodes
kubectl get pods -A

但如果你使用 root 用户登录 AWS 控制台,进入 EKS 页面查看工作负载、Pod、节点等集群内容,还需要额外添加一个 EKS 访问条目,并绑定:

AmazonEKSClusterAdminPolicy

Terraform 里可以这样声明:

access_entries = {
  console_admin = {
    principal_arn = "arn:aws:iam::788356290550:root"

    policy_associations = {
      cluster_admin = {
        policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
        access_scope = {
          type = "cluster"
        }
      }
    }
  }
}

控制台里对应路径是:

EKS 集群
  -> 访问
  -> IAM 访问条目
  -> 创建访问条目
  -> 选择 principal
  -> 绑定 AmazonEKSClusterAdminPolicy

生产环境不建议长期用 root 用户管理集群。更好的方式是给运维 IAM Role、SSO Role 或平台管理员组创建访问条目。这里给 root 加访问条目,是为了验证环境里方便从控制台查看集群内容。

如果集群已经创建完成,再补上这段 access_entries 后,先执行:

terraform plan

正常情况下应该只看到新增两个资源:

aws_eks_access_entry
aws_eks_access_policy_association

确认不会重建 EKS、VPC、NAT Gateway 等资源后,再执行:

terraform apply

Auto Mode 注意点

验证环境里,下面配置可以接受:

single_nat_gateway = true
cluster_endpoint_public_access_cidrs = ["0.0.0.0/0"]

但生产前置验证更建议改成:

cluster_endpoint_public_access_cidrs = ["你的办公出口IP/32"]

如果生产环境也准备用 Auto Mode,验证重点应该放在:

  • Pod requests/limits 是否合理
  • Auto Mode 是否能按预期创建节点
  • Ingress 和 LoadBalancer 是否符合预期
  • PVC 和 EBS 是否能正常挂载
  • Pod Identity 或 IRSA 是否能正常访问 AWS 资源
  • 成本是否符合预期

如果你没有提前在控制台创建 AmazonEKSAutoClusterRoleAmazonEKSAutoNodeRole,可以删除下面这些复用现有角色的配置,让 Terraform module 自己创建 Auto Mode 所需角色:

create_iam_role      = false
iam_role_arn         = local.cluster_role_arn
create_node_iam_role = false

cluster_compute_config = {
  enabled       = true
  node_pools    = ["general-purpose", "system"]
  node_role_arn = local.node_role_arn
}

然后保留一个不指定 node_role_arncluster_compute_config

cluster_compute_config = {
  enabled    = true
  node_pools = ["general-purpose", "system"]
}

方案二:普通 EKS + Managed Node Group

适用场景

Managed Node Group 是传统 EKS 最常见的方式。

它的模型是:

先创建节点组
再把 Pod 调度到这些 EC2 节点上

适合验证:

  • 固定节点组规划
  • 节点实例规格
  • 节点磁盘和加密
  • DaemonSet、安全 Agent、监控 Agent
  • 集群扩缩容策略
  • 生产环境相同的节点结构

如果生产集群计划使用 Managed Node Group 或 Karpenter,验证集群也建议采用这种模式。

Terraform 示例

下面示例创建一个普通 EKS 集群和一个 Managed Node Group。

terraform {
  required_version = ">= 1.6.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

locals {
  cluster_name = "eks-mng-verify"
}

data "aws_availability_zones" "available" {
  state = "available"
}

module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  version = "~> 5.0"

  name = "${local.cluster_name}-vpc"
  cidr = "10.30.0.0/16"

  azs             = slice(data.aws_availability_zones.available.names, 0, 2)
  public_subnets  = ["10.30.0.0/24", "10.30.1.0/24"]
  private_subnets = ["10.30.8.0/22", "10.30.12.0/22"]

  enable_dns_hostnames = true
  enable_nat_gateway   = true
  single_nat_gateway   = true

  public_subnet_tags = {
    "kubernetes.io/role/elb" = 1
  }

  private_subnet_tags = {
    "kubernetes.io/role/internal-elb" = 1
  }
}

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.0"

  cluster_name    = local.cluster_name
  cluster_version = "1.35"

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  cluster_endpoint_public_access       = true
  cluster_endpoint_public_access_cidrs = ["0.0.0.0/0"]
  cluster_endpoint_private_access      = true

  cluster_enabled_log_types = [
    "api",
    "audit",
    "authenticator",
  ]

  cluster_addons = {
    coredns = {
      most_recent = true
    }
    kube-proxy = {
      most_recent = true
    }
    vpc-cni = {
      most_recent = true
    }
  }

  eks_managed_node_groups = {
    main = {
      instance_types = ["t3.medium"]

      min_size     = 1
      max_size     = 3
      desired_size = 2

      capacity_type = "ON_DEMAND"

      block_device_mappings = {
        xvda = {
          device_name = "/dev/xvda"
          ebs = {
            volume_size           = 20
            volume_type           = "gp3"
            encrypted             = true
            delete_on_termination = true
          }
        }
      }

      labels = {
        role = "app"
      }
    }
  }

  enable_cluster_creator_admin_permissions = true
}

output "configure_kubectl" {
  value = "aws eks update-kubeconfig --region us-east-1 --name ${local.cluster_name}"
}

验证步骤

执行:

terraform init
terraform plan
terraform apply

配置 kubectl:

aws eks update-kubeconfig --region us-east-1 --name eks-mng-verify

查看节点和系统组件:

kubectl get nodes -o wide
kubectl get pod -n kube-system -o wide

部署测试应用:

kubectl create deployment nginx --image=nginx:1.25
kubectl expose deployment nginx --port=80 --target-port=80 --type=ClusterIP
kubectl get pod,svc -o wide

如果要验证 NodePort:

kubectl expose deployment nginx --name=nginx-nodeport --port=80 --target-port=80 --type=NodePort
kubectl get svc nginx-nodeport

Managed Node Group 注意点

验证环境可以用:

instance_types = ["t3.medium"]
desired_size   = 2
single_nat_gateway = true

生产环境通常要调整:

  • 节点组跨 3 个可用区
  • 每个可用区一个 NAT Gateway
  • private subnet 留更大地址空间
  • system 和 app 节点组分开
  • 关键业务使用 On-Demand,弹性任务可以使用 Spot
  • 配合 Cluster Autoscaler 或 Karpenter 做自动扩缩容

复用现有 IAM Role 时要注意

如果你像控制台截图里那样已经有:

AmazonEKSAutoClusterRole
AmazonEKSAutoNodeRole

要先判断它们是给 Auto Mode 用,还是给普通 Managed Node Group 用。

不要混成:

Auto Mode IAM Role
  + Managed Node Group

这可能导致节点权限、信任关系或托管策略不匹配。

普通 Managed Node Group 的节点角色通常至少需要:

  • AmazonEKSWorkerNodePolicy
  • AmazonEC2ContainerRegistryPullOnly
  • VPC CNI 所需权限,常见做法是给 aws-node 使用 IRSA,验证环境也可以临时挂在节点角色上

如果是 Auto Mode,则优先按 Auto Mode 文档创建推荐角色,并使用 Auto Mode 的创建方式。

两种模式的验证清单

创建完成后,不管哪种模式,都建议检查:

kubectl get nodes -o wide
kubectl get pod -A -o wide
kubectl get svc -A
kubectl get events -A --sort-by=.lastTimestamp

检查 EKS Add-ons:

aws eks list-addons --region us-east-1 --cluster-name <cluster-name>
aws eks describe-addon --region us-east-1 --cluster-name <cluster-name> --addon-name vpc-cni

检查节点是否能拉镜像:

kubectl create deployment image-test --image=public.ecr.aws/nginx/nginx:latest
kubectl get pod -l app=image-test -o wide

检查 DNS:

kubectl run dns-test --image=busybox:1.36 --restart=Never -- sleep 3600
kubectl exec dns-test -- nslookup kubernetes.default

检查出网:

kubectl exec dns-test -- wget -qO- https://aws.amazon.com

检查集群访问:

kubectl auth can-i get pods -A
kubectl auth can-i create deployment -n default

销毁验证环境

验证集群用完要及时销毁。不要先到控制台手工删除资源,优先让 Terraform 按 state 反向删除,否则容易出现 state 和真实资源不一致。

进入当初执行 terraform apply 的目录。以 Auto Mode 为例:

cd terraform/eks/auto-mode

先查看 Terraform 当前管理了哪些资源:

terraform state list

然后生成销毁计划:

terraform plan -destroy -out=tfplan.destroy

确认计划里只有销毁动作,例如:

Plan: 0 to add, 0 to change, 43 to destroy.

再按这个计划执行销毁:

terraform apply tfplan.destroy

本次 Auto Mode 验证集群实际销毁结果是:

Apply complete! Resources: 0 added, 0 changed, 43 destroyed.

如果只是临时验证,也可以直接执行:

terraform destroy

但更推荐先 plan -destroy,因为你能提前看到将要删除的 EKS、VPC、NAT Gateway、EIP、CloudWatch Log Group、KMS Key 等资源。

销毁后建议用 AWS CLI 或控制台检查是否还有残留:

aws eks describe-cluster \
  --region us-east-1 \
  --name eks-prod-verify-135

aws ec2 describe-nat-gateways \
  --region us-east-1 \
  --filter Name=vpc-id,Values=<vpc-id>

aws elbv2 describe-load-balancers \
  --region us-east-1

aws ec2 describe-vpcs \
  --region us-east-1 \
  --vpc-ids <vpc-id>

本次实测结果:

  • describe-cluster 返回 No cluster found
  • NAT Gateway 状态为 deleted
  • describe-load-balancers 返回空数组
  • describe-vpcs 返回 InvalidVpcID.NotFound

控制台里也建议重点看这些资源:

  • Load Balancer
  • Target Group
  • EBS Volume
  • EBS Snapshot
  • Elastic IP
  • NAT Gateway
  • CloudWatch Log Group

尤其是通过 Kubernetes Service/Ingress 创建的 ALB/NLB,有时会因为 finalizer 或控制器未清理干净而残留。验证环境里要养成销毁后复查账单资源的习惯。

还有一个正常现象:如果 EKS module 创建了 KMS Key,Terraform 销毁时会调用 KMS 的计划删除。KMS Key 不会立刻物理删除,而是进入 PendingDeletion,到删除窗口结束后才真正删除。本次销毁后,对应 KMS Key 的状态就是 PendingDeletion

我的建议

如果只是快速验证业务能否迁到 EKS:

用 EKS Auto Mode

如果你要模拟未来生产架构:

用 Managed Node Group

验证环境可以省钱,但不要让验证目标跑偏。最关键的是:

生产准备采用哪种资源管理模式,前置验证就尽量采用同一种模式。

参考资料