EKS 集群创建
最后更新:October 16, 2026
创建 Amazon EKS 集群有多种方法。本章将详细介绍如何使用各种工具和方法创建 EKS 集群。
本章中的创建方法是可选方案。为新的专用集群选择其中一种,不要同时使用多个工具管理相同的资源。请将示例名称、账户、角色、VPC、子网和 CIDR 替换为经批准的实际值。除非另有说明,Shell 示例使用 Bash;如果前置条件失败,请停止操作。本次审计未执行任何 AWS 资源预置或工作负载测量。
当前版本: EKS 1.37 于 October 1, 2026 开始提供。
示例基线: 以下示例保留了经过审核的 EKS 1.36 基线。选择其他版本时,请查阅当前 EKS 版本日历和组件兼容性文档。
目录
- 先决条件
- 使用 eksctl 创建集群
- 使用 AWS 管理控制台创建集群
- 使用 AWS CLI 创建集群
- 使用 Terraform 创建集群
- 使用 AWS CDK 创建集群
- 配置集群访问权限
- 集群验证
- 集群升级
- 删除集群
先决条件
创建 EKS 集群前,需要满足以下先决条件:
1. AWS 账户
需要有效的 AWS 账户。如果您还没有 AWS 账户,可以在 AWS 网站注册。
2. IAM 权限
所需权限取决于所使用的工具及其管理的资源。授予 eks:*、ec2:*、iam:* 和 cloudformation:* 且适用于所有资源的策略,并不是必需的最小权限策略。
| 任务 | 需审查的权限范围 |
|---|---|
| EKS 集群/节点组管理 | 所需的 EKS 操作和目标资源 |
| 传递现有 IAM 角色 | 针对经批准角色 ARN 和服务条件的 iam:PassRole |
| 创建 IAM 角色/策略/OIDC 提供商 | 工具管理的 IAM 资源及名称/标签范围 |
| 创建网络 | 针对新 VPC、子网和安全组的 EC2 操作 |
| 使用 eksctl/CDK | 相关 CloudFormation 堆栈、执行角色和引导资源 |
预置身份、集群服务角色和节点角色彼此独立。SCP、权限边界和会话策略仍然适用。请根据合成模板/计划审查组织的预置权限。Auto Mode 的角色要求与传统节点组不同。
参考:EKS IAM 操作和资源、Auto Mode 角色。
3. 工具安装
AWS CLI
为您的操作系统/CPU 选择相应的软件包,并按照官方 AWS CLI v2 安装指南验证签名。如果已安装 v1/v2,请先查看其更新/迁移流程。
| 环境 | 官方软件包/安装方法 |
|---|---|
| macOS | 已签名的 AWSCLIV2.pkg |
| Linux x86_64 | 使用 PGP 签名验证的 awscli-exe-linux-x86_64.zip |
| Linux ARM64 | 使用 PGP 签名验证的 awscli-exe-linux-aarch64.zip |
| Windows | 适用于受支持 Windows 版本的 MSI 安装程序 |
不要在 ARM 上原样使用 Linux x86_64 软件包。使用 aws --version 检查当前 CLI。如果组织使用 IAM Identity Center,请按如下方式配置经批准的配置文件。否则请遵循其联合身份验证流程,不要假定使用长期访问密钥。
aws configure sso --profile eks-docs
aws sso login --profile eks-docs
aws sts get-caller-identity --profile eks-docs
export AWS_PROFILE=eks-docs请参阅 IAM Identity Center 身份验证。后续命令继续使用经批准的账户、角色和区域。
kubectl 和 eksctl(Linux/macOS)
本章的 EKS 1.36 示例以 kubectl 1.36.5 和 eksctl 0.231.0 为基线。最好使用与服务器相同的 kubectl 次要版本;支持的版本偏差为 ±1 个次要版本。对于较旧的 EKS 集群,不要盲目安装上游 stable.txt 中的最新次要版本。
此 Bash 示例会选择 AMD64/ARM64,并在安装前验证官方校验和。需要 curl、tar、awk 以及 sha256sum 或 shasum;在 /usr/local/bin 安装需要管理员权限。下载或校验和验证失败时将停止安装。
(
set -e
case "$(uname -s)" in
Linux) EKS_TOOL_OS=linux; EKS_ARCHIVE_OS=Linux ;;
Darwin) EKS_TOOL_OS=darwin; EKS_ARCHIVE_OS=Darwin ;;
*) printf 'Use the official installer for this operating system\n' >&2; exit 1 ;;
esac
case "$(uname -m)" in
x86_64) EKS_TOOL_ARCH=amd64 ;;
aarch64|arm64) EKS_TOOL_ARCH=arm64 ;;
*) printf 'Select a supported CPU architecture\n' >&2; exit 1 ;;
esac
EKS_TOOL_ARCHIVE="eksctl_${EKS_ARCHIVE_OS}_${EKS_TOOL_ARCH}.tar.gz"
EKS_TOOL_DIR=$(mktemp -d)
: "${EKS_TOOL_DIR:?}"
trap 'rm -f -- "$EKS_TOOL_DIR/kubectl" "$EKS_TOOL_DIR/kubectl.sha256" "$EKS_TOOL_DIR/eksctl" "$EKS_TOOL_DIR/eksctl_checksums.txt" "$EKS_TOOL_DIR/$EKS_TOOL_ARCHIVE" "$EKS_TOOL_DIR/selected.sha256"; rmdir -- "$EKS_TOOL_DIR"' EXIT
cd "$EKS_TOOL_DIR" || exit 1
verify_sha() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum --check "$1"
else
shasum -a 256 --check "$1"
fi
}
EKS_KUBECTL_VERSION=v1.36.5
curl -fL "https://dl.k8s.io/release/$EKS_KUBECTL_VERSION/bin/$EKS_TOOL_OS/$EKS_TOOL_ARCH/kubectl" -o kubectl || exit 1
curl -fL "https://dl.k8s.io/release/$EKS_KUBECTL_VERSION/bin/$EKS_TOOL_OS/$EKS_TOOL_ARCH/kubectl.sha256" -o kubectl.sha256 || exit 1
printf '%s kubectl\n' "$(tr -d '[:space:]' < kubectl.sha256)" > selected.sha256
verify_sha selected.sha256 || exit 1
EKSCTL_VERSION=0.231.0
curl -fL "https://github.com/eksctl-io/eksctl/releases/download/v$EKSCTL_VERSION/$EKS_TOOL_ARCHIVE" -o "$EKS_TOOL_ARCHIVE" || exit 1
curl -fL "https://github.com/eksctl-io/eksctl/releases/download/v$EKSCTL_VERSION/eksctl_checksums.txt" -o eksctl_checksums.txt || exit 1
awk -v name="$EKS_TOOL_ARCHIVE" '$2 == name {print; count++} END {if (count != 1) exit 1}' \
eksctl_checksums.txt > selected.sha256 || exit 1
verify_sha selected.sha256 || exit 1
tar -xzf "$EKS_TOOL_ARCHIVE" eksctl || exit 1
sudo install -m 0755 kubectl /usr/local/bin/kubectl || exit 1
sudo install -m 0755 eksctl /usr/local/bin/eksctl || exit 1
kubectl version --client
eksctl version
)官方流程:Linux kubectl、macOS kubectl、eksctl 安装。
Windows
按照 PowerShell 中的官方 kubectl 安装流程操作。本章的 AMD64 示例使用 kubectl 1.36.5 以及同一路径下的 .sha256 文件。请从 eksctl 0.231.0 发行版中选择与 CPU 匹配的 Windows ZIP 文件和 eksctl_checksums.txt。
将 Get-FileHash -Algorithm SHA256 的结果与官方哈希值比较,若不匹配则停止操作。验证后,解压 ZIP 文件,将可执行文件目录添加到 PATH,并检查 kubectl version --client 和 eksctl version。不要在 Bash 中运行 PowerShell 语法。
还需为 AWS CLI 示例中的 JSON 生成准备 jq。本次审计未实际下载/安装客户端或登录。
4. VPC 和子网
区域级 EKS 集群需要同一 VPC 中至少两个位于不同 AZ 的子网。每个集群子网至少需要六个可用 IP 地址才能供 EKS 使用;AWS 建议至少保留十六个。还需为节点、Pod、负载均衡器和升级规划额外地址。启用 VPC DNS 主机名和 DNS 解析。
并非所有 EKS 集群都必须具备互联网访问。节点和工作负载需要通过 NAT/互联网路径,或必要的 VPC 端点和镜像副本,访问 Kubernetes API、镜像和所需的 AWS 服务。通过适当的 DNS 和路由,可从 VPC 或已连接网络访问私有 Kubernetes 端点。
EKS 集群的 VPC 标签
kubernetes.io/cluster/<cluster-name> VPC 标签是一种旧机制,并非当前创建所有 EKS 集群的通用要求。对于负载均衡,请遵循所选控制器的子网发现规则:
- 公有负载均衡器的子网:
kubernetes.io/role/elb=1 - 内部负载均衡器的子网:
kubernetes.io/role/internal-elb=1
标签不会配置路由、安全组或可用 IP 容量。请参阅 VPC/子网要求和无互联网访问的集群。
使用 eksctl 创建集群
eksctl 是创建和管理 EKS 集群的最简单方法。eksctl 使用 CloudFormation 创建 EKS 集群和相关资源。
将 eksctl kubeconfig 存储在此 Shell 专用的路径中。
EKS_CLIENT_DIR=$(mktemp -d /tmp/eks-client.XXXXXX)
: "${EKS_CLIENT_DIR:?}"
EKS_KUBECONFIG="$EKS_CLIENT_DIR/kubeconfig"
export KUBECONFIG="$EKS_KUBECONFIG"创建基本集群
从经过审查的配置文件创建基本集群:
eksctl create cluster --config-file cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"运行此命令前,请阅读并编辑下面的 cluster.yaml。文件中明确选择了 EKS 1.36、AL2023、现有 VPC 子网和节点组容量。请将示例标识符和文档 CIDR 替换为实际的经批准值。这些是明确选择的设置,并不代表所有 eksctl 版本的默认值。
使用配置文件创建集群
对于更复杂的配置,可以使用 YAML 文件定义集群:
# cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: us-west-2
version: '1.36'
vpc:
id: vpc-12345678
subnets:
private:
us-west-2a:
id: subnet-12345678
us-west-2b:
id: subnet-87654321
public:
us-west-2a:
id: subnet-23456789
us-west-2b:
id: subnet-98765432
clusterEndpoints:
privateAccess: true
publicAccess: true
publicAccessCIDRs:
- 203.0.113.10/32
managedNodeGroups:
- name: ng-1
instanceType: m5.large
desiredCapacity: 2
minSize: 1
maxSize: 3
privateNetworking: true
volumeSize: 80
volumeType: gp3
amiFamily: AmazonLinux2023
disableIMDSv1: true
- name: ng-2
instanceType: c5.xlarge
desiredCapacity: 2
privateNetworking: true
spot: true
amiFamily: AmazonLinux2023
disableIMDSv1: true
cloudWatch:
clusterLogging:
enableTypes:
- api
- audit
- authenticator
- controllerManager
- scheduler
fargateProfiles:
- name: fp-default
selectors:
- namespace: default
labels:
env: fargate
iam:
withOIDC: true
accessConfig:
authenticationMode: API要使用此配置文件创建集群,请运行以下命令:
eksctl create cluster -f cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"上述配置展示了 EC2 节点和可选的应用 Fargate 配置文件。CoreDNS 保留在 EC2 上;若要将其迁移到 Fargate,除了配置文件外,还需审查 CoreDNS 计算设置。
创建托管节点组
要向现有集群添加托管节点组,请运行以下命令:
eksctl create nodegroup \
--cluster my-cluster \
--region us-west-2 \
--name my-nodegroup \
--node-type m5.large \
--nodes 3 \
--nodes-min 1 \
--nodes-max 5 \
--managed --node-ami-family AmazonLinux2023 --node-private-networking也可以使用配置文件:
# nodegroup.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: us-west-2
managedNodeGroups:
- name: my-nodegroup
instanceType: m5.large
desiredCapacity: 3
minSize: 1
maxSize: 5
volumeSize: 80
volumeType: gp3
amiFamily: AmazonLinux2023
privateNetworking: true
disableIMDSv1: trueeksctl create nodegroup -f nodegroup.yaml创建 EKS Auto Mode 集群
EKS Auto Mode 于 2024 年正式推出,可自动管理 Kubernetes 集群基础设施,降低运维开销。AWS 管理其计算、网络和存储功能。
EKS Auto Mode 的主要功能
- 自动节点管理:根据工作负载需求自动添加/移除节点
- 增强安全性:不可变 AMI、SELinux 强制模式、只读根文件系统
- 节点维护:节点会因到期和配置偏差而被替换。21 天不是控制平面次要版本升级周期
- 集成组件:默认提供 Pod 网络、DNS、存储和 GPU 支持
- 成本优化:自动终止未使用的实例并整合工作负载
创建基本 Auto Mode 集群
请先检查下面 auto-cluster.yaml 中的 CIDR 和网络配置。不要使用自行管理的附加组件重复配置 Auto Mode 的网络、DNS 和块存储。混合集群需要为每种计算类型明确指定放置位置和组件作用范围。
eksctl create cluster --config-file auto-cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"使用配置文件创建 Auto Mode 集群
# auto-cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-auto-cluster
region: us-west-2
version: '1.36'
autoModeConfig:
enabled: true
nodePools:
- system
- general-purpose
vpc:
cidr: 10.0.0.0/16
nat:
gateway: Single
clusterEndpoints:
privateAccess: true
publicAccess: true
publicAccessCIDRs:
- 203.0.113.10/32
cloudWatch:
clusterLogging:
enableTypes:
- api
- audit
- authenticator
- controllerManager
- scheduler
accessConfig:
authenticationMode: API创建集群:
eksctl create cluster -f auto-cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"Auto Mode 与传统方案对比
| 功能 | 传统 EKS | EKS Auto Mode |
|---|---|---|
| 节点管理 | 托管节点组或客户管理的节点 | AWS 管理节点生命周期 |
| 扩缩容 | 配置 Cluster Autoscaler、自行管理的 Karpenter 或其他策略 | 托管节点自动扩缩容 |
| 升级 | 规划控制平面、节点和附加组件更新 | AWS 管理节点/组件更新;按支持策略规划控制平面次要版本 |
| 安全性 | 用户配置 | 默认增强安全性 |
| 网络 | 设置 CNI 插件 | 自动配置网络 |
| 存储 | 需要安装 CSI 并配置权限 | 托管 EBS 预置程序 ebs.csi.eks.amazonaws.com |
| GPU 支持 | 选择兼容的加速 AMI 和所需设备插件 | 为受支持的实例提供托管驱动程序/插件 |
验证 Auto Mode 集群
集群创建完成后,可以使用以下命令检查其状态:
# Check cluster status
kubectl get nodes
# Check Auto Mode node pools
kubectl get nodepools
# Check Auto Mode node classes
kubectl get nodeclasses
# Check system pod status
kubectl get pods -n kube-system创建自定义节点池
在 Auto Mode 中,除了默认节点池,还可以创建自定义节点池:
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: gpu-nodepool
spec:
template:
metadata:
labels:
workload-type: gpu
spec:
requirements:
- key: karpenter.sh/capacity-type
operator: In
values:
- on-demand
- key: node.kubernetes.io/instance-type
operator: In
values:
- p3.2xlarge
- p3.8xlarge
nodeClassRef:
group: eks.amazonaws.com
kind: NodeClass
name: default
expireAfter: 336h
taints:
- key: nvidia.com/gpu
value: present
effect: NoSchedule
limits:
cpu: '1000'
disruption:
consolidationPolicy: WhenEmpty
consolidateAfter: 30s注意:在 Auto Mode 中,不能使用
EC2NodeClass、amiFamily或自定义userData(/etc/eks/bootstrap.sh)。AWS 管理节点 AMI 和引导过程;子网、安全组和临时存储则通过eks.amazonaws.com/v1NodeClass定义。
GPU 示例保留了 p3,该实例类型仍在当前官方支持列表中。请检查 AZ 容量、配额以及 GPU 显存/型号要求。GPU Pod 必须请求 nvidia.com/gpu 并容忍上述污点。此 YAML 已经过审查;未预置或基准测试任何 GPU 节点。
Auto Mode 限制
- 不支持通过 SSH 或 SSM 直接访问节点
- 默认到期时间为 336 小时(14 天),
expireAfter设置最多支持 21 天。请同时考虑排空、PDB/NodePool 阻塞因素和默认 24 小时的终止宽限期 - 无法修改默认节点池和节点类
- 可能存在某些实例类型限制
Auto Mode 监控
托管基础设施不会自动配置所有工作负载的 CloudWatch 指标。cluster_node_count 属于 ContainerInsights,而不是 AWS/EKS,并且需要配置 Container Insights 收集管道。请为您的环境配置收集,并查询包含实际数据的时间范围。
# Requires a configured Container Insights collection pipeline and metric data.
aws cloudwatch list-metrics --namespace ContainerInsights --metric-name cluster_node_count \
--dimensions Name=ClusterName,Value="${EKS_CLUSTER_NAME:?}" --region "${EKS_REGION:?}"
aws cloudwatch get-metric-statistics \
--namespace ContainerInsights --metric-name cluster_node_count \
--dimensions Name=ClusterName,Value="$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--start-time "${METRICS_START_TIME:?Set a reviewed ISO8601 start time}" \
--end-time "${METRICS_END_TIME:?Set a later ISO8601 end time}" \
--period 3600 --statistics Average结果为空并不能证明节点数为零或 Auto Mode 运行失败。请先检查数据收集、维度和时间范围。本次审计未运行 CloudWatch 查询或测量。请参阅官方 Container Insights 指标目录。
创建 Fargate 配置文件
要创建 Fargate 配置文件,请运行以下命令:
eksctl create fargateprofile \
--cluster my-cluster \
--region us-west-2 \
--name my-fargate-profile \
--namespace default \
--labels env=fargate也可以使用配置文件:
# fargate.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
name: my-cluster
region: us-west-2
fargateProfiles:
- name: my-fargate-profile
selectors:
- namespace: default
labels:
env: fargateeksctl create fargateprofile -f fargate.yaml更新集群
请先审查控制平面、节点和附加组件的兼容性,然后按照集群升级中的说明操作。
删除集群
请先审查工作负载、负载均衡器、数据保留要求和资源所属工具,然后按照删除集群中的说明操作。
使用 AWS 管理控制台创建集群
使用 AWS 管理控制台创建 EKS 集群的步骤如下:
- 登录 AWS 管理控制台。
- 搜索“EKS”,或从服务列表中选择“Elastic Kubernetes Service”。
- 在“Clusters”页面,单击“Create cluster”按钮。
创建 EKS Auto Mode 集群(快速配置)
EKS Auto Mode 可减少基础设施设置工作。工作负载身份、网络、容量、可用性和恢复仍需明确配置和验证。
1. 选择快速配置
- 确认已选择“Quick configuration”选项。
- 输入以下信息:
- 集群名称:输入集群的唯一名称。
- Kubernetes 版本:选择要使用的 Kubernetes 版本(建议使用最新版本)。
2. 配置 IAM 角色
选择集群 IAM 角色:
- 对于第一个 Auto Mode 集群,请使用“Create recommended role”选项。
- 如果已有角色,也可以重复使用。
- 建议的角色名称:
AmazonEKSAutoClusterRole
选择节点 IAM 角色:
- 对于第一个 Auto Mode 集群,请使用“Create recommended role”选项。
- 建议的角色名称:
AmazonEKSAutoNodeRole
3. 配置网络
选择 VPC:
- 创建新 VPC:选择“Create VPC”选项,为 EKS 创建新的 VPC。
- 使用现有 VPC:选择之前为 EKS 创建的 VPC。
子网配置(可选):
- EKS Auto Mode 会自动选择 VPC 中的私有子网。
- 可以根据需要添加或移除子网。
4. 检查配置并创建
- 选择 View quick configuration defaults,查看所有配置值。
- 单击 Create cluster。(集群创建大约需要 15 分钟)
使用自定义配置创建集群
如果需要更精细地控制,可以使用自定义配置。
集群配置
- 在“Configure cluster”页面,输入以下信息:
- 集群名称:输入集群的唯一名称。
- Kubernetes 版本:选择要使用的 Kubernetes 版本。
- 集群服务角色:创建新角色或选择现有角色。
- EKS Auto Mode:选中复选框以启用 Auto Mode。
- 标签:根据需要添加标签。
- 单击“Next”按钮。
指定网络
- 在“Specify networking”页面,输入以下信息:
- VPC:创建新 VPC 或选择现有 VPC。
- 子网:选择集群要使用的子网。至少需要两个位于不同可用区的子网。
- 安全组:选择集群要使用的安全组。
- 集群端点访问:配置对集群 API Server 端点的访问。
- 公有:可通过互联网访问 API Server。
- 私有:需要通过适当的 DNS 和路由从 VPC 或已连接网络访问。
- 公有和私有:可从互联网和 VPC 内部访问 API Server。
- 单击“Next”按钮。
配置日志记录
- 在“Configure logging”页面,输入以下信息:
- 控制平面日志记录:选择要启用的日志类型。
- API Server 日志
- 审计日志
- 身份验证器日志
- 控制器管理器日志
- 调度程序日志
- 单击“Next”按钮。
- 控制平面日志记录:选择要启用的日志类型。
选择附加组件
以下附加组件介绍传统计算方式。Auto Mode 管理重叠的网络、DNS 和块存储功能;请根据集群中的计算类型选择组件。
- 在“Select add-ons”页面,输入以下信息:
- Amazon VPC CNI:用于 Pod 网络的 CNI 插件。
- CoreDNS:集群内的 DNS 服务。
- kube-proxy:提供网络代理和负载均衡功能。
- 存储/网络附加组件:传统计算方式需要安装适当的组件并配置 IAM 权限。Auto Mode 提供托管 EBS/网络/DNS 功能;不要在 Auto Mode 节点上安装重复组件。
- 单击“Next”按钮。
检查并创建
- 在“Review and create”页面,检查配置并单击“Create”按钮。
为非 Auto Mode 集群添加节点组
对于传统 EC2 计算方式,请在集群创建后添加节点组。其他受支持的选项(如 Fargate 配置文件)有各自的设置流程;并非所有非 Auto Mode 集群都必须使用托管节点组。
添加节点组
在“Node group configuration”页面,输入以下信息:
- 节点组名称:输入节点组的唯一名称。
- 节点 IAM 角色:创建新角色或选择现有角色。
- 单击“Next”按钮。
在“Set compute and scaling configuration”页面,输入以下信息:
- AMI 类型:选择节点要使用的 AMI 类型。
- 实例类型:选择节点要使用的 EC2 实例类型。
- 磁盘大小:指定节点的磁盘大小。
- 节点数量:指定节点的最小数量、最大数量和期望数量。
- 单击“Next”按钮。
在“Specify networking”页面,输入以下信息:
- 子网:选择节点组要使用的子网。
- 远程访问配置:除非经批准的管理路径有需要,否则请禁用 SSH;在检查来源安全组之前,不要指定 SSH 密钥。
- 单击“Next”按钮。
在“Review and create”页面,检查配置并单击“Create”按钮。
使用 AWS CLI 创建集群
以下示例会创建一个新集群。请选择 Auto Mode 或传统 EKS;不要使用相同名称连续运行两条创建命令。使用 Bash、jq、当前版本的 AWS CLI v2 和获得授权的 AWS 角色。EKS 1.36 是经过验证的示例版本;选择其他版本前,请检查区域支持情况和兼容性。
两个子网必须位于同一 VPC 的不同 AZ。请单独准备 DNS、可用 IP、安全组以及节点访问镜像/服务所需的条件。实际 API 字段名称为 endpointPrivateAccess 和 endpointPublicAccess。此专用示例通过创建者管理员访问权限完成引导;后续访问应通过访问条目管理。
准备通用输入
为所选模式预先创建集群角色,并验证所需的 iam:PassRole 和创建服务相关角色的权限。执行创建命令前,请检查账户、区域、子网和经批准的 CIDR。
: "${EKS_CLUSTER_NAME:?Choose a unique new cluster name}"
: "${EKS_REGION:?Choose the intended AWS region}"
: "${EKS_CLUSTER_ROLE_ARN:?Pre-created cluster role for the chosen mode}"
: "${EKS_SUBNET_A:?Existing subnet in the intended VPC}"
: "${EKS_SUBNET_B:?Existing subnet in a different AZ of the same VPC}"
: "${EKS_PUBLIC_API_CIDR:?Approved client CIDR, normally /32}"
EKS_CREATION_DIR=$(mktemp -d /tmp/eks-create.XXXXXX)
: "${EKS_CREATION_DIR:?}"
EKS_KUBECONFIG="$EKS_CREATION_DIR/kubeconfig"
unset EKS_CREATED_CLUSTER_ARN
aws sts get-caller-identity创建 EKS Auto Mode 集群
集群角色需要对 eks.amazonaws.com 提供 sts:AssumeRole 和 sts:TagSession 信任,并附加 AmazonEKSClusterPolicy、AmazonEKSComputePolicy、AmazonEKSBlockStoragePolicyV2、AmazonEKSLoadBalancingPolicy 和 AmazonEKSNetworkingPolicy,或具备等效自定义权限。
节点角色信任 ec2.amazonaws.com,并使用 AmazonEKSWorkerNodeMinimalPolicy 和 AmazonEC2ContainerRegistryPullOnly。通过 Pod Identity/IRSA 单独授予工作负载 AWS 权限。请同时启用计算、负载均衡和块存储,并禁用默认自行管理附加组件的引导。
: "${EKS_AUTO_NODE_ROLE_ARN:?Pre-created Auto Mode node role}"
jq -n \
--arg name "${EKS_CLUSTER_NAME:?}" \
--arg role "${EKS_CLUSTER_ROLE_ARN:?}" \
--arg subnetA "${EKS_SUBNET_A:?}" --arg subnetB "${EKS_SUBNET_B:?}" \
--arg cidr "${EKS_PUBLIC_API_CIDR:?}" \
--arg nodeRole "$EKS_AUTO_NODE_ROLE_ARN" \
'{
name: $name,
version: "1.36",
roleArn: $role,
resourcesVpcConfig: {
subnetIds: [$subnetA, $subnetB],
endpointPrivateAccess: true,
endpointPublicAccess: true,
publicAccessCidrs: [$cidr]
},
accessConfig: {authenticationMode: "API", bootstrapClusterCreatorAdminPermissions: true},
logging: {clusterLogging: [{
types: ["api", "audit", "authenticator", "controllerManager", "scheduler"],
enabled: true
}]},
tags: {"docs-lab": $name}
} + {
bootstrapSelfManagedAddons: false,
computeConfig: {
enabled: true, nodePools: ["system", "general-purpose"], nodeRoleArn: $nodeRole
},
kubernetesNetworkConfig: {ipFamily: "ipv4", elasticLoadBalancing: {enabled: true}},
storageConfig: {blockStorage: {enabled: true}}
}' > "${EKS_CREATION_DIR:?}/create-auto.json"
cat "$EKS_CREATION_DIR/create-auto.json"
EKS_CREATED_CLUSTER_ARN=$(aws eks create-cluster --region "${EKS_REGION:?}" \
--cli-input-json "file://$EKS_CREATION_DIR/create-auto.json" \
--query cluster.arn --output text)
: "${EKS_CREATED_CLUSTER_ARN:?Creation failed; inspect the error before continuing}"验证创建结果和访问权限
: "${EKS_CREATED_CLUSTER_ARN:?Create and verify the new cluster first}"
aws eks wait cluster-active --name "${EKS_CLUSTER_NAME:?}" --region "${EKS_REGION:?}"
aws eks describe-cluster --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--query 'cluster.{arn:arn,status:status,version:version}' --output table
aws eks update-kubeconfig --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--kubeconfig "${EKS_KUBECONFIG:?}"
kubectl --kubeconfig "$EKS_KUBECONFIG" get nodes在工作负载需要容量之前,Auto Mode 可能没有节点。请检查 NodePool/NodeClass 状态以及后续 Pod 调度情况。集群状态为 ACTIVE 并不代表应用运行正常,也不保证固定的创建时长。
kubectl --kubeconfig "${EKS_KUBECONFIG:?}" get nodepools.karpenter.sh
kubectl --kubeconfig "$EKS_KUBECONFIG" get nodeclasses.eks.amazonaws.com创建传统集群
仅在未选择 Auto Mode 时使用此替代方案。集群角色需要传统 EKS 集群权限;EC2 节点角色以及 CNI/附加组件权限彼此独立。引导默认网络附加组件不会安装 EBS CSI 或 AWS LBC。
jq -n \
--arg name "${EKS_CLUSTER_NAME:?}" \
--arg role "${EKS_CLUSTER_ROLE_ARN:?}" \
--arg subnetA "${EKS_SUBNET_A:?}" --arg subnetB "${EKS_SUBNET_B:?}" \
--arg cidr "${EKS_PUBLIC_API_CIDR:?}" \
'{
name: $name,
version: "1.36",
roleArn: $role,
resourcesVpcConfig: {
subnetIds: [$subnetA, $subnetB],
endpointPrivateAccess: true,
endpointPublicAccess: true,
publicAccessCidrs: [$cidr]
},
accessConfig: {authenticationMode: "API", bootstrapClusterCreatorAdminPermissions: true},
logging: {clusterLogging: [{
types: ["api", "audit", "authenticator", "controllerManager", "scheduler"],
enabled: true
}]},
tags: {"docs-lab": $name}
} + {
bootstrapSelfManagedAddons: true,
kubernetesNetworkConfig: {ipFamily: "ipv4"}
}' > "${EKS_CREATION_DIR:?}/create-standard.json"
cat "$EKS_CREATION_DIR/create-standard.json"
EKS_CREATED_CLUSTER_ARN=$(aws eks create-cluster --region "${EKS_REGION:?}" \
--cli-input-json "file://$EKS_CREATION_DIR/create-standard.json" \
--query cluster.arn --output text)
: "${EKS_CREATED_CLUSTER_ARN:?Creation failed; inspect the error before continuing}"等待创建完成并配置 kubeconfig
: "${EKS_CREATED_CLUSTER_ARN:?Create and verify the new cluster first}"
aws eks wait cluster-active --name "${EKS_CLUSTER_NAME:?}" --region "${EKS_REGION:?}"
aws eks describe-cluster --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--query 'cluster.{arn:arn,status:status,version:version}' --output table
aws eks update-kubeconfig --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--kubeconfig "${EKS_KUBECONFIG:?}"
kubectl --kubeconfig "$EKS_KUBECONFIG" get nodes创建托管节点组
为 EC2 节点角色准备工作节点和 ECR 拉取权限,并准备单独的 CNI 角色或经过审查的节点角色 CNI 权限。不要原样重复使用 Auto Mode 最小节点角色。私有子网还需要 NAT 或必要的 VPC 端点。此 AL2023 示例默认不启用 SSH。
: "${EKS_MANAGED_NODE_ROLE_ARN:?Pre-created conventional EC2 node role}"
: "${EKS_NODEGROUP_NAME:?Unique managed node group name}"
aws eks create-nodegroup \
--cluster-name "${EKS_CLUSTER_NAME:?}" \
--nodegroup-name "$EKS_NODEGROUP_NAME" \
--subnets "${EKS_SUBNET_A:?}" "${EKS_SUBNET_B:?}" \
--instance-types m5.large --ami-type AL2023_x86_64_STANDARD \
--node-role "$EKS_MANAGED_NODE_ROLE_ARN" \
--scaling-config minSize=1,maxSize=3,desiredSize=2 \
--disk-size 20 --region "${EKS_REGION:?}"
aws eks wait nodegroup-active --cluster-name "$EKS_CLUSTER_NAME" \
--nodegroup-name "$EKS_NODEGROUP_NAME" --region "$EKS_REGION"
aws eks describe-nodegroup --cluster-name "$EKS_CLUSTER_NAME" \
--nodegroup-name "$EKS_NODEGROUP_NAME" --region "$EKS_REGION" \
--query 'nodegroup.{status:status,health:health,version:version}' --output json
kubectl --kubeconfig "${EKS_KUBECONFIG:?}" get nodes单独设置 minSize/maxSize 并不会根据 Pod 需求启用节点扩缩容。请检查状态和运行状况错误,然后根据需要配置自动扩缩容器。创建失败时,请检查记录的名称/ARN 和相关资源。本次审计未执行这些创建和等待命令。
参考:CreateCluster API、CreateNodegroup API、Auto Mode IAM 和创建。
使用 Terraform 创建集群
以下完整示例支持一个新集群,需在首次 apply 前选择 Auto Mode 或传统托管节点组。不要将另一种方案作为第二个集群资源附加,也不要在没有迁移计划的情况下切换现有集群。Terraform 状态及其提供商锁定文件属于此特定部署。
EKS Auto Mode 集群 Terraform 配置
保存为 main.tf。此示例固定使用 AWS provider 6.69.1 和 EKS 1.36。明确提供现有私有子网 ID;自定义 Type=Private 标签不能可靠地替代对路由和连通性的验证。前置条件会在规划期间检查 VPC/AZ 关系,但不会验证私有路由、服务端点、DNS、IP 容量或负载均衡器子网标签。
Auto Mode 需要同时启用计算、负载均衡和块存储,并将 bootstrap_self_managed_addons 设置为 false。集群角色包含 sts:TagSession 和所有五项必需策略。IAM 附加依赖关系可在 EKS 删除托管基础设施期间保留所需权限。
terraform {
required_version = ">= 1.5.0, < 2.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "= 6.69.1"
}
}
}
provider "aws" {
region = var.region
}
data "aws_partition" "current" {}
data "aws_subnet" "selected" {
for_each = toset(var.private_subnet_ids)
id = each.value
}
locals {
cluster_policies = var.enable_auto_mode ? toset([
"AmazonEKSClusterPolicy",
"AmazonEKSComputePolicy",
"AmazonEKSBlockStoragePolicyV2",
"AmazonEKSLoadBalancingPolicy",
"AmazonEKSNetworkingPolicy",
]) : toset(["AmazonEKSClusterPolicy"])
node_policies = var.enable_auto_mode ? toset([
"AmazonEKSWorkerNodeMinimalPolicy",
"AmazonEC2ContainerRegistryPullOnly",
]) : toset([
"AmazonEKSWorkerNodePolicy",
"AmazonEC2ContainerRegistryPullOnly",
# Conventional bootstrap baseline; see the CNI role caveat in the text.
"AmazonEKS_CNI_Policy",
])
}
resource "aws_iam_role" "cluster" {
name = "${var.cluster_name}-cluster"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = var.enable_auto_mode ? ["sts:AssumeRole", "sts:TagSession"] : ["sts:AssumeRole"]
Principal = {
Service = "eks.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "cluster" {
for_each = local.cluster_policies
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/${each.value}"
role = aws_iam_role.cluster.name
}
resource "aws_iam_role" "node" {
name = "${var.cluster_name}-node"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["sts:AssumeRole"]
Principal = {
Service = "ec2.amazonaws.com"
}
}]
})
}
resource "aws_iam_role_policy_attachment" "node" {
for_each = local.node_policies
policy_arn = "arn:${data.aws_partition.current.partition}:iam::aws:policy/${each.value}"
role = aws_iam_role.node.name
}
resource "aws_eks_cluster" "main" {
name = var.cluster_name
role_arn = aws_iam_role.cluster.arn
version = var.kubernetes_version
access_config {
authentication_mode = "API"
bootstrap_cluster_creator_admin_permissions = false
}
bootstrap_self_managed_addons = !var.enable_auto_mode
compute_config {
enabled = var.enable_auto_mode
node_pools = var.enable_auto_mode ? ["system", "general-purpose"] : null
node_role_arn = var.enable_auto_mode ? aws_iam_role.node.arn : null
}
kubernetes_network_config {
ip_family = "ipv4"
elastic_load_balancing {
enabled = var.enable_auto_mode
}
}
storage_config {
block_storage {
enabled = var.enable_auto_mode
}
}
vpc_config {
subnet_ids = var.private_subnet_ids
endpoint_private_access = true
endpoint_public_access = true
public_access_cidrs = var.public_api_cidrs
}
enabled_cluster_log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"]
# Keep policies attached until EKS finishes deleting managed infrastructure.
depends_on = [
aws_iam_role_policy_attachment.cluster,
aws_iam_role_policy_attachment.node,
]
lifecycle {
precondition {
condition = (
alltrue([for subnet in data.aws_subnet.selected : subnet.vpc_id == var.vpc_id]) &&
length(toset([for subnet in data.aws_subnet.selected : subnet.availability_zone])) >= 2
)
error_message = "Supply subnets in at least two AZs of the selected VPC."
}
}
tags = var.tags
}
resource "aws_eks_node_group" "standard" {
count = var.enable_auto_mode ? 0 : 1
cluster_name = aws_eks_cluster.main.name
node_group_name = "main-nodegroup"
node_role_arn = aws_iam_role.node.arn
subnet_ids = var.private_subnet_ids
version = aws_eks_cluster.main.version
ami_type = "AL2023_x86_64_STANDARD"
capacity_type = "ON_DEMAND"
instance_types = ["m5.large"]
scaling_config {
desired_size = 2
max_size = 3
min_size = 1
}
update_config {
max_unavailable = 1
}
depends_on = [aws_iam_role_policy_attachment.node]
tags = var.tags
}
resource "aws_eks_access_entry" "operator" {
cluster_name = aws_eks_cluster.main.name
principal_arn = var.operator_role_arn
type = "STANDARD"
}
resource "aws_eks_access_policy_association" "operator" {
cluster_name = aws_eks_cluster.main.name
principal_arn = aws_eks_access_entry.operator.principal_arn
policy_arn = "arn:${data.aws_partition.current.partition}:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy"
access_scope {
type = "cluster"
}
}
variable "enable_auto_mode" {
description = "Creation-time choice. Changing an existing cluster requires a separate migration plan."
type = bool
default = true
}
variable "cluster_name" {
description = "Unique name for this new cluster."
type = string
}
variable "kubernetes_version" {
description = "EKS-supported minor version; 1.36 is the reviewed example."
type = string
default = "1.36"
}
variable "region" {
type = string
}
variable "vpc_id" {
type = string
}
variable "private_subnet_ids" {
type = list(string)
validation {
condition = length(distinct(var.private_subnet_ids)) >= 2
error_message = "At least two distinct subnet IDs are required."
}
}
variable "public_api_cidrs" {
type = list(string)
validation {
condition = length(var.public_api_cidrs) > 0 && alltrue([
for cidr in var.public_api_cidrs :
can(cidrhost(cidr, 0)) && cidr != "0.0.0.0/0" && cidr != "::/0"
])
error_message = "Supply reviewed client CIDRs instead of unrestricted public API access."
}
}
variable "operator_role_arn" {
description = "Existing approved IAM role allowed to administer this cluster."
type = string
}
variable "tags" {
type = map(string)
default = {
Environment = "dev"
Project = "eks-creation-example"
}
}
output "cluster_name" {
value = aws_eks_cluster.main.name
}
output "cluster_endpoint" {
value = aws_eks_cluster.main.endpoint
}
output "cluster_security_group_id" {
value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
}
output "cluster_arn" {
value = aws_eks_cluster.main.arn
}操作员访问条目会向经批准的 IAM 角色授予集群管理权限;创建者不会自动获得 Kubernetes 管理员访问权限。该操作员角色必须预先存在,运行 kubectl 的人员必须能够代入该角色。
传统节点方案在节点角色中包含了 CNI 权限,作为初始引导基线。这是一个共享权限边界,并非经过加固的生产工作负载身份设计。投入生产前,请审查专用 CNI 角色,并限制 Pod 对 IMDS 的访问。应用的 AWS 权限应配置在特定工作负载身份上;不要向每个节点附加无关的附加组件权限。
运行 Terraform
使用全新的工作目录和通过身份验证的预置角色。请将示例 ID 和文档 CIDR 替换为目标账户中的资源和经批准的客户端 CIDR。默认选择 Auto Mode:
# terraform.tfvars: replace every example identifier before planning.
cluster_name = "eks-docs-unique-name"
region = "us-west-2"
vpc_id = "vpc-0123456789abcdef0"
private_subnet_ids = ["subnet-0123456789abcdef0", "subnet-1123456789abcdef0"]
public_api_cidrs = ["203.0.113.10/32"]
operator_role_arn = "arn:aws:iam::111122223333:role/ApprovedOperator"
enable_auto_mode = true# Run in a new directory containing main.tf and the reviewed terraform.tfvars.
terraform init
terraform fmt -check
terraform validate
terraform plan -out=reviewed.tfplan
# Apply only the plan you reviewed for the intended account/region/resources.
terraform apply reviewed.tfplan
: "${EKS_REGION:?Use the same region as terraform.tfvars}"
: "${EKS_OPERATOR_ROLE_ARN:?Use the same operator role as terraform.tfvars}"
aws eks update-kubeconfig --name "$(terraform output -raw cluster_name)" \
--region "$EKS_REGION" --role-arn "$EKS_OPERATOR_ROLE_ARN" --kubeconfig ./kubeconfig
kubectl --kubeconfig ./kubeconfig get nodesapply 前请审查状态/后端、拟议的 IAM 和网络更改以及所有计费资源。terraform validate 无法验证 AWS 账户权限、配额、路由或所选节点能否运行您的工作负载。节点组扩缩容范围不会安装基于 Pod 需求的自动扩缩容器。
传统 Terraform 配置
对于新的传统集群,使用同一份完整的 main.tf,并在首次 plan 前将 terraform.tfvars 中的值设置为:
enable_auto_mode = false这会禁用全部三项 Auto Mode 功能,启动传统网络附加组件,选择传统 EC2 节点权限并创建 AL2023 托管节点组。它不会安装 EBS CSI、AWS LBC、Metrics Server 或节点自动扩缩容器;请单独配置工作负载所需的组件。部署后更改此值会改变基础设施和 IAM,因此需要单独进行迁移审查。
验证:Terraform 1.16.6 使用已签名的 AWS provider 6.69.1 在本地通过 terraform validate,错误/警告均为零。未执行 plan、apply 或 AWS API 调用。 两种模式仍需进行部署验证;此示例不代表已达到生产就绪状态。
参考:AWS provider EKS 集群、托管节点组、Auto Mode 角色要求。
使用 AWS CDK 创建集群
此新堆栈示例使用 aws-cdk-lib/aws-eks-v2。它会创建原生 AWS::EKS::Cluster 和访问条目;启用 Auto Mode 不需要 Lambda 自定义资源。不要将用此示例替换现有已部署构造视为原地迁移。
此示例使用 CDK 库 2.273.0、CLI 2.1145.0 和 EKS 1.36。它通过属性导入现有私有子网,无需在合成时查找 VPC。部署前请验证所提供的子网/AZ 对应关系、VPC DNS、路由、服务访问和负载均衡器子网标签。导入的 VPC 定义不会验证这些条件。
使用 TypeScript 创建 EKS Auto Mode 集群
保存为 lib/eks-auto-mode-stack.ts。调用方提供现有且经批准的操作员角色;只有该角色会获得此集群的管理员访问权限。工作负载权限仍需单独配置。
import * as cdk from 'aws-cdk-lib';
import * as eks from 'aws-cdk-lib/aws-eks-v2';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
export interface EksAutoModeProps extends cdk.StackProps {
readonly clusterName: string;
readonly vpcId: string;
readonly privateSubnetIds: string[];
readonly availabilityZones: string[];
readonly publicApiCidrs: string[];
readonly operatorRoleArn: string;
}
export class EksAutoModeStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: EksAutoModeProps) {
super(scope, id, props);
if (props.privateSubnetIds.length < 2 ||
props.privateSubnetIds.length !== props.availabilityZones.length ||
new Set(props.availabilityZones).size < 2 ||
props.publicApiCidrs.length === 0) {
throw new Error('Supply corresponding private subnets/AZs in at least two AZs and approved API CIDRs');
}
const vpc = ec2.Vpc.fromVpcAttributes(this, 'Vpc', {
vpcId: props.vpcId,
availabilityZones: props.availabilityZones,
privateSubnetIds: props.privateSubnetIds,
});
const clusterRole = new iam.Role(this, 'ClusterRole', {
assumedBy: new iam.ServicePrincipal('eks.amazonaws.com'),
managedPolicies: [
'AmazonEKSClusterPolicy',
'AmazonEKSComputePolicy',
'AmazonEKSBlockStoragePolicyV2',
'AmazonEKSLoadBalancingPolicy',
'AmazonEKSNetworkingPolicy',
].map(name => iam.ManagedPolicy.fromAwsManagedPolicyName(name)),
});
clusterRole.assumeRolePolicy!.addStatements(new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
principals: [new iam.ServicePrincipal('eks.amazonaws.com')],
actions: ['sts:TagSession'],
}));
const nodeRole = new iam.Role(this, 'NodeRole', {
assumedBy: new iam.ServicePrincipal('ec2.amazonaws.com'),
managedPolicies: [
'AmazonEKSWorkerNodeMinimalPolicy',
'AmazonEC2ContainerRegistryPullOnly',
].map(name => iam.ManagedPolicy.fromAwsManagedPolicyName(name)),
});
const cluster = new eks.Cluster(this, 'Cluster', {
clusterName: props.clusterName,
version: eks.KubernetesVersion.V1_36,
vpc,
vpcSubnets: [{ subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }],
endpointAccess: eks.EndpointAccess.PUBLIC_AND_PRIVATE.onlyFrom(...props.publicApiCidrs),
defaultCapacityType: eks.DefaultCapacityType.AUTOMODE,
bootstrapSelfManagedAddons: false,
bootstrapClusterCreatorAdminPermissions: false,
// All required policies/trust are defined above. Avoid adding the older
// BlockStoragePolicy that CDK 2.273.0 otherwise attaches automatically.
role: clusterRole.withoutPolicyUpdates(),
compute: {
nodePools: ['system', 'general-purpose'],
nodeRole: nodeRole.withoutPolicyUpdates(),
},
clusterLogging: [
eks.ClusterLoggingTypes.API,
eks.ClusterLoggingTypes.AUDIT,
eks.ClusterLoggingTypes.AUTHENTICATOR,
eks.ClusterLoggingTypes.CONTROLLER_MANAGER,
eks.ClusterLoggingTypes.SCHEDULER,
],
removalPolicy: cdk.RemovalPolicy.DESTROY,
});
cluster.node.addDependency(clusterRole, nodeRole);
cluster.grantClusterAdmin('OperatorAccess', props.operatorRoleArn);
new cdk.CfnOutput(this, 'ClusterName', { value: cluster.clusterName });
new cdk.CfnOutput(this, 'ClusterEndpoint', { value: cluster.clusterEndpoint });
}
}集群角色明确包含 sts:TagSession 和五项 Auto Mode 策略,其中包括 AmazonEKSBlockStoragePolicyV2。withoutPolicyUpdates() 可防止 CDK 2.273.0 添加较旧的块存储策略;此示例负责提供所有必需权限。依赖关系会将这些角色保留到集群删除完成。节点角色仅附加了 Auto Mode 最小工作节点策略和 ECR 拉取策略。
bootstrapSelfManagedAddons: false 可避免添加重复的自行管理网络附加组件。Auto Mode 会一并管理计算、负载均衡和块存储。操作员访问条目独立于集群执行角色创建。
CDK 应用程序入口点
保存为 bin/eks-auto-mode.ts;请将 shebang 保留在第一行。环境变量为必填项,以避免意外使用示例账户、VPC 或角色值。
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { EksAutoModeStack } from '../lib/eks-auto-mode-stack';
function required(name: string): string {
const value = process.env[name];
if (!value) throw new Error(`Set ${name} before synthesis/deployment`);
return value;
}
function list(name: string): string[] {
return required(name).split(',').map(value => value.trim()).filter(Boolean);
}
const app = new cdk.App();
new EksAutoModeStack(app, 'EksAutoModeStack', {
env: {
account: required('CDK_DEFAULT_ACCOUNT'),
region: required('CDK_DEFAULT_REGION'),
},
clusterName: required('EKS_CLUSTER_NAME'),
vpcId: required('EKS_VPC_ID'),
privateSubnetIds: list('EKS_PRIVATE_SUBNET_IDS'),
availabilityZones: list('EKS_AVAILABILITY_ZONES'),
publicApiCidrs: list('EKS_PUBLIC_API_CIDRS'),
operatorRoleArn: required('EKS_OPERATOR_ROLE_ARN'),
});CDK 部署
创建一个全新的项目,初始化后保存上面的两个文件,并提供目标账户/区域的值。使用通过身份验证且已获授权的 AWS 角色。部署前请检查合成后的 IAM/网络配置和差异。CDK 库和 CLI 是不同的软件包,版本号并不相同。
mkdir eks-auto-mode
cd eks-auto-mode
npx --yes --package aws-cdk@2.1145.0 cdk init app --language typescript
npm install --save-exact aws-cdk-lib@2.273.0 constructs@10.5.0
npm install --save-dev --save-exact aws-cdk@2.1145.0 typescript@5.9.3
# Save the source files above, then set the required environment values.
: "${CDK_DEFAULT_ACCOUNT:?Set the intended AWS account ID}"
: "${CDK_DEFAULT_REGION:?Set the intended AWS region}"
: "${EKS_CLUSTER_NAME:?Use a unique name for this new cluster}"
: "${EKS_VPC_ID:?}"
: "${EKS_PRIVATE_SUBNET_IDS:?Comma-separated existing subnet IDs}"
: "${EKS_AVAILABILITY_ZONES:?Corresponding comma-separated AZs}"
: "${EKS_PUBLIC_API_CIDRS:?Approved client CIDRs, normally /32}"
: "${EKS_OPERATOR_ROLE_ARN:?Existing operator role you may assume}"
# Export the variables so the CDK application receives them.
export CDK_DEFAULT_ACCOUNT CDK_DEFAULT_REGION EKS_CLUSTER_NAME EKS_VPC_ID
export EKS_PRIVATE_SUBNET_IDS EKS_AVAILABILITY_ZONES EKS_PUBLIC_API_CIDRS EKS_OPERATOR_ROLE_ARN
npx tsc --noEmit
npx cdk synth
# Bootstrap creates AWS resources; review the account/region and execution policy.
npx cdk bootstrap "aws://$CDK_DEFAULT_ACCOUNT/$CDK_DEFAULT_REGION"
npx cdk diff
npx cdk deploy
aws eks update-kubeconfig --name "$EKS_CLUSTER_NAME" --region "$CDK_DEFAULT_REGION" \
--role-arn "$EKS_OPERATOR_ROLE_ARN" --kubeconfig ./kubeconfig
kubectl --kubeconfig ./kubeconfig get nodes审计在本地使用虚拟标识符编译了两个 TypeScript 文件并合成堆栈:已验证三项 Auto Mode 功能、限定范围的 API CIDR、所需角色和一个操作员访问条目。未生成 Lambda/自定义资源。缺少必需输入时会拒绝执行。未执行 bootstrap、查找、部署、集群创建或 AWS API 调用,因此账户配额、网络和工作负载可用性仍需在部署时检查。
参考:EKS V2 构造库、Auto Mode 集群角色、Auto Mode 创建。
配置集群访问权限
设置所选方法生成的集群名称、区域和专用 kubeconfig 路径。对于 Terraform/CDK 示例,请在 EKS_OPERATOR_ROLE_ARN 中设置经批准的操作员角色。使用 CLI 创建者访问权限时可以省略该变量。写入 kubeconfig 不会授予 Kubernetes 权限。
: "${EKS_CLUSTER_NAME:?Use the selected cluster name}"
: "${EKS_REGION:?Use the selected region}"
: "${EKS_KUBECONFIG:?Set the dedicated kubeconfig path for this method}"
aws sts get-caller-identity
if [[ -n ${EKS_OPERATOR_ROLE_ARN:-} ]]; then
aws eks update-kubeconfig --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--role-arn "$EKS_OPERATOR_ROLE_ARN" --kubeconfig "$EKS_KUBECONFIG"
else
aws eks update-kubeconfig --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--kubeconfig "$EKS_KUBECONFIG"
fi
eks_kubectl() {
kubectl --kubeconfig "${EKS_KUBECONFIG:?}" "$@"
}
eks_kubectl config current-context
aws eks describe-cluster --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--query cluster.accessConfig.authenticationModeRBAC 配置
对于新的 IAM 访问权限,请使用访问条目。此示例会向现有 dev 命名空间中的新角色授予读取权限;不要重复创建由集群创建工具管理的操作员条目。身份验证模式必须为 API 或 API_AND_CONFIG_MAP。旧版 aws-auth 方法已弃用;不要覆盖整个 ConfigMap。需要迁移时,请遵循官方迁移流程。
# A new reader identity, distinct from the operator already granted by IaC.
: "${EKS_READER_ROLE_ARN:?Existing approved IAM role without an access entry yet}"
if eks_kubectl get namespace dev &&
aws eks create-access-entry --cluster-name "${EKS_CLUSTER_NAME:?}" \
--region "${EKS_REGION:?}" --principal-arn "$EKS_READER_ROLE_ARN" \
--type STANDARD --kubernetes-groups eks-docs-readers; then
EKS_ACCESS_DIR=$(mktemp -d /tmp/eks-access.XXXXXX)
: "${EKS_ACCESS_DIR:?}"
cat > "$EKS_ACCESS_DIR/rbac.yaml" << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: eks-docs-reader
namespace: dev
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: eks-docs-readers
namespace: dev
subjects:
- kind: Group
name: eks-docs-readers
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: eks-docs-reader
apiGroup: rbac.authorization.k8s.io
EOF
eks_kubectl create -f "$EKS_ACCESS_DIR/rbac.yaml"
fi此读取角色既不授予 Secret API 访问权限,也不授予修改权限。请以该角色进行身份验证并检查 kubectl auth can-i;其他 RBAC/EKS 策略授权可能会增加权限。EKS 访问条目
集群验证
使用访问部分中的 eks_kubectl 和同一个专用 kubeconfig。仅能访问控制平面并不能证明节点或工作负载运行正常。
基本验证
eks_kubectl cluster-info
eks_kubectl get nodes
eks_kubectl get pods -n kube-system
eks_kubectl get events --sort-by='.lastTimestamp'Auto Mode 专项验证
AWS 管理 Auto Mode 预置控制器。不要期望在 karpenter 命名空间中看到自行管理的控制器 Pod。检查 NodePool/NodeClass 条件和事件,并检查需要容量的工作负载对应的 NodeClaims。
eks_kubectl get nodepools.karpenter.sh
eks_kubectl get nodeclasses.eks.amazonaws.com
eks_kubectl get nodeclaims.karpenter.sh部署示例应用
使用新命名空间检查镜像访问、调度、HTTP 就绪状态和 Service。仅使用 Fargate 的配置必须先创建匹配此命名空间的配置文件。
EKS_SAMPLE_DIR=$(mktemp -d /tmp/eks-validate.XXXXXX)
: "${EKS_SAMPLE_DIR:?}"
unset EKS_SAMPLE_NAMESPACE EKS_SAMPLE_UID
EKS_SAMPLE_CANDIDATE=$(basename "$EKS_SAMPLE_DIR" | tr '[:upper:].' '[:lower:]-')
if EKS_SAMPLE_UID=$(eks_kubectl create namespace "$EKS_SAMPLE_CANDIDATE" -o jsonpath='{.metadata.uid}'); then
EKS_SAMPLE_NAMESPACE=$EKS_SAMPLE_CANDIDATE
fi
: "${EKS_SAMPLE_NAMESPACE:?Namespace creation failed}"
: "${EKS_SAMPLE_UID:?Namespace UID missing}"
cat > "$EKS_SAMPLE_DIR/sample-app.yaml" << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-app
namespace: ${EKS_SAMPLE_NAMESPACE}
spec:
replicas: 2
selector:
matchLabels:
app: sample-app
template:
metadata:
labels:
app: sample-app
spec:
automountServiceAccountToken: false
containers:
- name: app
image: nginx:1.30.6-alpine
ports:
- name: http
containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
readinessProbe:
httpGet:
path: /
port: http
---
apiVersion: v1
kind: Service
metadata:
name: sample-app-service
namespace: ${EKS_SAMPLE_NAMESPACE}
spec:
type: ClusterIP
selector:
app: sample-app
ports:
- port: 80
targetPort: http
EOF
eks_kubectl apply -f "$EKS_SAMPLE_DIR/sample-app.yaml"
eks_kubectl -n "$EKS_SAMPLE_NAMESPACE" rollout status deployment/sample-app --timeout=180s
eks_kubectl -n "$EKS_SAMPLE_NAMESPACE" get pods,services
eks_kubectl -n "$EKS_SAMPLE_NAMESPACE" port-forward --address 127.0.0.1 service/sample-app-service 8080:80端口转发运行期间,打开 http://127.0.0.1:8080,然后按 Ctrl-C 停止。这会检查 ClusterIP 访问,而非外部负载均衡器。对于 NLB,请选择 Auto Mode 的 eks.amazonaws.com/nlb,或已安装且获得授权的 AWS LBC 的 service.k8s.aws/nlb,并单独检查网络/成本先决条件。本次审计未执行部署或端口转发。
集群升级
首先检查升级洞察、已移除的 API、Webhook/附加组件兼容性、节点版本、备用 IP 和恢复计划。先将滞后的节点升级到当前控制平面版本,然后每次推进一个受支持的次要版本。某些组件需要在控制平面升级前更新到兼容版本。
Auto Mode 不会每隔 21 天升级控制平面次要版本。操作员需规划次要版本升级,并考虑版本支持策略下的自动升级。
aws eks describe-cluster-versions --region "${EKS_REGION:?}" --output table
aws eks describe-cluster --name "${EKS_CLUSTER_NAME:?}" --region "$EKS_REGION" \
--query 'cluster.{version:version,status:status}' --output table
eks_kubectl get nodes
# After readiness/compatibility review, choose the next supported minor.
: "${NEXT_MINOR_VERSION:?Select one supported minor step, for example 1.35 to 1.36}"
EKS_UPDATE_ID=$(aws eks update-cluster-version --name "$EKS_CLUSTER_NAME" \
--region "$EKS_REGION" --kubernetes-version "$NEXT_MINOR_VERSION" \
--query update.id --output text)
: "${EKS_UPDATE_ID:?Update request failed}"
aws eks describe-update --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" \
--update-id "$EKS_UPDATE_ID" --query 'update.{status:status,errors:errors}'
# Alternative interface; do not execute both:
# eksctl upgrade cluster --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" --version "$NEXT_MINOR_VERSION" --approve只有在更新报告 Successful 后,才能继续升级数据平面。AWS 会逐步更新 Auto Mode 节点;传统托管节点组需要单独更新。
# Conventional managed node group only, after the control plane update is Successful.
aws eks update-nodegroup-version --cluster-name "${EKS_CLUSTER_NAME:?}" \
--region "${EKS_REGION:?}" --nodegroup-name "${EKS_NODEGROUP_NAME:?}" \
--kubernetes-version "${NEXT_MINOR_VERSION:?}"应分别根据相应机制规划自行管理/Hybrid Node 更新、Fargate Pod 替换、附加组件更新和 kubectl 更新。请检查 PDB 和备用容量,不要使用强制标志掩盖故障。符合条件的控制平面升级可在七天内回退一个次要版本,但需满足节点/附加组件/API 兼容性和支持策略限制;回退无法替代应用数据恢复。
删除集群
请在目标账户和区域中,通过原始所有者工具/状态删除集群。首先在相关控制器仍运行时移除工作负载和 Ingress/LoadBalancer Service,然后确认操作已完成。确定如何保留或恢复 PVC/PV、快照和日志。不要使用强制选项绕过超时或 finalizer。
清理示例命名空间
EKS_SAMPLE_CLEANUP_OK=true
if [[ -n ${EKS_SAMPLE_NAMESPACE:-} && -n ${EKS_SAMPLE_UID:-} ]]; then
current_uid=$(eks_kubectl get namespace "$EKS_SAMPLE_NAMESPACE" -o jsonpath='{.metadata.uid}') || current_uid=""
if [[ "$current_uid" = "$EKS_SAMPLE_UID" ]]; then
eks_kubectl delete namespace "$EKS_SAMPLE_NAMESPACE" --wait=true --timeout=180s || EKS_SAMPLE_CLEANUP_OK=false
else
EKS_SAMPLE_CLEANUP_OK=false
fi
elif [[ -n ${EKS_SAMPLE_NAMESPACE:-} || -n ${EKS_SAMPLE_UID:-} ]]; then
EKS_SAMPLE_CLEANUP_OK=false
fi
# Remove local files only after successful sample cleanup.
if [[ "$EKS_SAMPLE_CLEANUP_OK" = true ]]; then
if [[ -n ${EKS_SAMPLE_DIR:-} ]]; then
rm -f -- "$EKS_SAMPLE_DIR/sample-app.yaml"
rmdir -- "$EKS_SAMPLE_DIR"
fi
if [[ -n ${EKS_ACCESS_DIR:-} ]]; then
rm -f -- "$EKS_ACCESS_DIR/rbac.yaml"
rmdir -- "$EKS_ACCESS_DIR"
fi
else
printf 'Sample cleanup could not be verified; stop before deleting the cluster\n' >&2
fi如果清理失败,请停止并调查。将目标 ARN 与创建结果或所属 IaC 状态比较,不要仅依赖未经审查的当前查询结果。
: "${EKS_EXPECTED_CLUSTER_ARN:?Copy the ARN from the creation result or owning IaC state}"
: "${EKS_CLUSTER_NAME:?}"
: "${EKS_REGION:?}"
EKS_DELETE_TARGET_VERIFIED=false
if [[ ${EKS_SAMPLE_CLEANUP_OK:-false} != true ]]; then
printf 'Complete the sample cleanup check above first\n' >&2
else
current_arn=$(aws eks describe-cluster --name "$EKS_CLUSTER_NAME" \
--region "$EKS_REGION" --query cluster.arn --output text) || current_arn=""
if [[ "$current_arn" = "$EKS_EXPECTED_CLUSTER_ARN" ]]; then
EKS_DELETE_TARGET_VERIFIED=true
aws eks list-nodegroups --cluster-name "$EKS_CLUSTER_NAME" --region "$EKS_REGION"
aws eks list-fargate-profiles --cluster-name "$EKS_CLUSTER_NAME" --region "$EKS_REGION"
else
printf 'Target mismatch; stop and check the account, region and owning tool\n' >&2
fi
fi使用 eksctl 删除
对通过 eksctl 创建的集群使用此方法。
if [[ ${EKS_DELETE_TARGET_VERIFIED:-false} = true ]]; then
eksctl delete cluster --name "${EKS_CLUSTER_NAME:?}" --region "${EKS_REGION:?}" --wait
fi使用 AWS CLI 删除
对于直接通过 CLI 创建的集群,请设置上面列出的所属节点组/配置文件名称,并对每个资源重复操作。等待删除完成并确认资源均已清除后,再删除集群。
# For a cluster created directly with the AWS CLI, after workload/data cleanup.
if [[ ${EKS_DELETE_TARGET_VERIFIED:-false} = true ]]; then
if [[ -n ${EKS_NODEGROUP_NAME:-} ]]; then
aws eks delete-nodegroup --cluster-name "$EKS_CLUSTER_NAME" \
--nodegroup-name "$EKS_NODEGROUP_NAME" --region "$EKS_REGION" &&
aws eks wait nodegroup-deleted --cluster-name "$EKS_CLUSTER_NAME" \
--nodegroup-name "$EKS_NODEGROUP_NAME" --region "$EKS_REGION"
fi
if [[ -n ${EKS_FARGATE_PROFILE_NAME:-} ]]; then
aws eks delete-fargate-profile --cluster-name "$EKS_CLUSTER_NAME" \
--fargate-profile-name "$EKS_FARGATE_PROFILE_NAME" --region "$EKS_REGION" &&
aws eks wait fargate-profile-deleted --cluster-name "$EKS_CLUSTER_NAME" \
--fargate-profile-name "$EKS_FARGATE_PROFILE_NAME" --region "$EKS_REGION"
fi
remaining_nodes=$(aws eks list-nodegroups --cluster-name "$EKS_CLUSTER_NAME" \
--region "$EKS_REGION" --query 'length(nodegroups)' --output text) || remaining_nodes=unknown
remaining_profiles=$(aws eks list-fargate-profiles --cluster-name "$EKS_CLUSTER_NAME" \
--region "$EKS_REGION" --query 'length(fargateProfileNames)' --output text) || remaining_profiles=unknown
if [[ "$remaining_nodes" = 0 && "$remaining_profiles" = 0 ]]; then
aws eks delete-cluster --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION" &&
aws eks wait cluster-deleted --name "$EKS_CLUSTER_NAME" --region "$EKS_REGION"
else
printf 'Owned node groups/Fargate profiles remain, or their status could not be verified\n' >&2
fi
fi使用 Terraform 删除
使用原始配置、后端和工作区;仅针对目标资源/账户应用经过审查的销毁计划。
if [[ ${EKS_DELETE_TARGET_VERIFIED:-false} = true ]]; then
terraform plan -destroy -out=reviewed-destroy.tfplan &&
terraform apply reviewed-destroy.tfplan
fi使用 CDK 删除
使用原始应用、输入、账户和区域,并验证目标堆栈。
if [[ ${EKS_DELETE_TARGET_VERIFIED:-false} = true ]]; then
npx cdk list
npx cdk destroy EksAutoModeStack
fi完成后,请验证 EKS/CloudFormation 状态以及任何剩余的 ELB、磁盘、NAT、日志和 IAM 资源。在托管基础设施删除完成之前,请保留 Auto Mode 角色/策略。不要假定集群删除会清除其他地方拥有的 VPC、IAM 角色、日志或保留数据。本次审计未执行任何删除命令。
总结
创建 EKS 集群有多种方法,各有优缺点:
- EKS Auto Mode:自动化基础设施运维;仍需验证应用是否就绪
- eksctl:简单、快速地创建集群
- AWS 管理控制台:通过 GUI 直观地创建集群
- AWS CLI:适用于脚本自动化
- Terraform:以代码形式管理基础设施
- AWS CDK:使用编程语言定义基础设施
对于生产环境,请选择符合要求的计算模型和基础设施工具,并验证 IAM、连通性、容量、中断和恢复行为。模板成功合成或集群成功创建,并不能证明已达到生产就绪状态。
审计验证范围
已阅读两个完整语言版本,并根据官方文档和架构对其进行了检查。验证范围包括 Shell/JSON/YAML、CDK 编译/合成、Terraform validate 和模拟故障路径。未执行 AWS 资源预置、升级、删除、应用运行时/负载测试或成本测量。