Skip to content

EKS 集群创建 ​

最后更新:October 16, 2026

创建 Amazon EKS 集群有多种方法。本章将详细介绍如何使用各种工具和方法创建 EKS 集群。

本章中的创建方法是可选方案。为新的专用集群选择其中一种,不要同时使用多个工具管理相同的资源。请将示例名称、账户、角色、VPC、子网和 CIDR 替换为经批准的实际值。除非另有说明,Shell 示例使用 Bash;如果前置条件失败,请停止操作。本次审计未执行任何 AWS 资源预置或工作负载测量。

当前版本: EKS 1.37 于 October 1, 2026 开始提供。

示例基线: 以下示例保留了经过审核的 EKS 1.36 基线。选择其他版本时,请查阅当前 EKS 版本日历和组件兼容性文档。

目录 ​

  1. 先决条件
  2. 使用 eksctl 创建集群
  3. 使用 AWS 管理控制台创建集群
  4. 使用 AWS CLI 创建集群
  5. 使用 Terraform 创建集群
  6. 使用 AWS CDK 创建集群
  7. 配置集群访问权限
  8. 集群验证
  9. 集群升级
  10. 删除集群

先决条件 ​

创建 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,请按如下方式配置经批准的配置文件。否则请遵循其联合身份验证流程,不要假定使用长期访问密钥。

bash
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 安装需要管理员权限。下载或校验和验证失败时将停止安装。

bash
(
  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 专用的路径中。

bash
EKS_CLIENT_DIR=$(mktemp -d /tmp/eks-client.XXXXXX)
: "${EKS_CLIENT_DIR:?}"
EKS_KUBECONFIG="$EKS_CLIENT_DIR/kubeconfig"
export KUBECONFIG="$EKS_KUBECONFIG"

创建基本集群 ​

从经过审查的配置文件创建基本集群:

bash
eksctl create cluster --config-file cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"

运行此命令前,请阅读并编辑下面的 cluster.yaml。文件中明确选择了 EKS 1.36、AL2023、现有 VPC 子网和节点组容量。请将示例标识符和文档 CIDR 替换为实际的经批准值。这些是明确选择的设置,并不代表所有 eksctl 版本的默认值。

使用配置文件创建集群 ​

对于更复杂的配置,可以使用 YAML 文件定义集群:

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

要使用此配置文件创建集群,请运行以下命令:

bash
eksctl create cluster -f cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"

上述配置展示了 EC2 节点和可选的应用 Fargate 配置文件。CoreDNS 保留在 EC2 上;若要将其迁移到 Fargate,除了配置文件外,还需审查 CoreDNS 计算设置。

创建托管节点组 ​

要向现有集群添加托管节点组,请运行以下命令:

bash
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

也可以使用配置文件:

yaml
# 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: true
bash
eksctl 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 和块存储。混合集群需要为每种计算类型明确指定放置位置和组件作用范围。

bash
eksctl create cluster --config-file auto-cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"

使用配置文件创建 Auto Mode 集群 ​

yaml
# 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

创建集群:

bash
eksctl create cluster -f auto-cluster.yaml --kubeconfig "${EKS_KUBECONFIG:?}"

Auto Mode 与传统方案对比 ​

功能传统 EKSEKS Auto Mode
节点管理托管节点组或客户管理的节点AWS 管理节点生命周期
扩缩容配置 Cluster Autoscaler、自行管理的 Karpenter 或其他策略托管节点自动扩缩容
升级规划控制平面、节点和附加组件更新AWS 管理节点/组件更新;按支持策略规划控制平面次要版本
安全性用户配置默认增强安全性
网络设置 CNI 插件自动配置网络
存储需要安装 CSI 并配置权限托管 EBS 预置程序 ebs.csi.eks.amazonaws.com
GPU 支持选择兼容的加速 AMI 和所需设备插件为受支持的实例提供托管驱动程序/插件

验证 Auto Mode 集群 ​

集群创建完成后,可以使用以下命令检查其状态:

bash
# 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 中,除了默认节点池,还可以创建自定义节点池:

yaml
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/v1 NodeClass 定义。

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 收集管道。请为您的环境配置收集,并查询包含实际数据的时间范围。

bash
# 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 配置文件,请运行以下命令:

bash
eksctl create fargateprofile \
  --cluster my-cluster \
  --region us-west-2 \
  --name my-fargate-profile \
  --namespace default \
  --labels env=fargate

也可以使用配置文件:

yaml
# 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: fargate
bash
eksctl create fargateprofile -f fargate.yaml

更新集群 ​

请先审查控制平面、节点和附加组件的兼容性,然后按照集群升级中的说明操作。

删除集群 ​

请先审查工作负载、负载均衡器、数据保留要求和资源所属工具,然后按照删除集群中的说明操作。

使用 AWS 管理控制台创建集群 ​

使用 AWS 管理控制台创建 EKS 集群的步骤如下:

  1. 登录 AWS 管理控制台。
  2. 搜索“EKS”,或从服务列表中选择“Elastic Kubernetes Service”。
  3. 在“Clusters”页面,单击“Create cluster”按钮。

创建 EKS Auto Mode 集群(快速配置) ​

EKS Auto Mode 可减少基础设施设置工作。工作负载身份、网络、容量、可用性和恢复仍需明确配置和验证。

1. 选择快速配置 ​

  1. 确认已选择“Quick configuration”选项。
  2. 输入以下信息:
    • 集群名称:输入集群的唯一名称。
    • Kubernetes 版本:选择要使用的 Kubernetes 版本(建议使用最新版本)。

2. 配置 IAM 角色 ​

  1. 选择集群 IAM 角色:

    • 对于第一个 Auto Mode 集群,请使用“Create recommended role”选项。
    • 如果已有角色,也可以重复使用。
    • 建议的角色名称:AmazonEKSAutoClusterRole
  2. 选择节点 IAM 角色:

    • 对于第一个 Auto Mode 集群,请使用“Create recommended role”选项。
    • 建议的角色名称:AmazonEKSAutoNodeRole

3. 配置网络 ​

  1. 选择 VPC:

    • 创建新 VPC:选择“Create VPC”选项,为 EKS 创建新的 VPC。
    • 使用现有 VPC:选择之前为 EKS 创建的 VPC。
  2. 子网配置(可选):

    • EKS Auto Mode 会自动选择 VPC 中的私有子网。
    • 可以根据需要添加或移除子网。

4. 检查配置并创建 ​

  1. 选择 View quick configuration defaults,查看所有配置值。
  2. 单击 Create cluster。(集群创建大约需要 15 分钟)

使用自定义配置创建集群 ​

如果需要更精细地控制,可以使用自定义配置。

集群配置 ​

  1. 在“Configure cluster”页面,输入以下信息:
    • 集群名称:输入集群的唯一名称。
    • Kubernetes 版本:选择要使用的 Kubernetes 版本。
    • 集群服务角色:创建新角色或选择现有角色。
    • EKS Auto Mode:选中复选框以启用 Auto Mode。
    • 标签:根据需要添加标签。
    • 单击“Next”按钮。

指定网络 ​

  1. 在“Specify networking”页面,输入以下信息:
    • VPC:创建新 VPC 或选择现有 VPC。
    • 子网:选择集群要使用的子网。至少需要两个位于不同可用区的子网。
    • 安全组:选择集群要使用的安全组。
    • 集群端点访问:配置对集群 API Server 端点的访问。
      • 公有:可通过互联网访问 API Server。
      • 私有:需要通过适当的 DNS 和路由从 VPC 或已连接网络访问。
      • 公有和私有:可从互联网和 VPC 内部访问 API Server。
    • 单击“Next”按钮。

配置日志记录 ​

  1. 在“Configure logging”页面,输入以下信息:
    • 控制平面日志记录:选择要启用的日志类型。
      • API Server 日志
      • 审计日志
      • 身份验证器日志
      • 控制器管理器日志
      • 调度程序日志
    • 单击“Next”按钮。

选择附加组件 ​

以下附加组件介绍传统计算方式。Auto Mode 管理重叠的网络、DNS 和块存储功能;请根据集群中的计算类型选择组件。

  1. 在“Select add-ons”页面,输入以下信息:
    • Amazon VPC CNI:用于 Pod 网络的 CNI 插件。
    • CoreDNS:集群内的 DNS 服务。
    • kube-proxy:提供网络代理和负载均衡功能。
    • 存储/网络附加组件:传统计算方式需要安装适当的组件并配置 IAM 权限。Auto Mode 提供托管 EBS/网络/DNS 功能;不要在 Auto Mode 节点上安装重复组件。
    • 单击“Next”按钮。

检查并创建 ​

  1. 在“Review and create”页面,检查配置并单击“Create”按钮。

为非 Auto Mode 集群添加节点组 ​

对于传统 EC2 计算方式,请在集群创建后添加节点组。其他受支持的选项(如 Fargate 配置文件)有各自的设置流程;并非所有非 Auto Mode 集群都必须使用托管节点组。

添加节点组 ​

  1. 在“Node group configuration”页面,输入以下信息:

    • 节点组名称:输入节点组的唯一名称。
    • 节点 IAM 角色:创建新角色或选择现有角色。
    • 单击“Next”按钮。
  2. 在“Set compute and scaling configuration”页面,输入以下信息:

    • AMI 类型:选择节点要使用的 AMI 类型。
    • 实例类型:选择节点要使用的 EC2 实例类型。
    • 磁盘大小:指定节点的磁盘大小。
    • 节点数量:指定节点的最小数量、最大数量和期望数量。
    • 单击“Next”按钮。
  3. 在“Specify networking”页面,输入以下信息:

    • 子网:选择节点组要使用的子网。
    • 远程访问配置:除非经批准的管理路径有需要,否则请禁用 SSH;在检查来源安全组之前,不要指定 SSH 密钥。
    • 单击“Next”按钮。
  4. 在“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。

bash
: "${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 权限。请同时启用计算、负载均衡和块存储,并禁用默认自行管理附加组件的引导。

bash
: "${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}"

验证创建结果和访问权限 ​

bash
: "${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 并不代表应用运行正常,也不保证固定的创建时长。

bash
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。

bash
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 ​

bash
: "${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。

bash
: "${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 删除托管基础设施期间保留所需权限。

hcl
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:

hcl
# 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
bash
# 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 nodes

apply 前请审查状态/后端、拟议的 IAM 和网络更改以及所有计费资源。terraform validate 无法验证 AWS 账户权限、配额、路由或所选节点能否运行您的工作负载。节点组扩缩容范围不会安装基于 Pod 需求的自动扩缩容器。

传统 Terraform 配置 ​

对于新的传统集群,使用同一份完整的 main.tf,并在首次 plan 前将 terraform.tfvars 中的值设置为:

hcl
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。调用方提供现有且经批准的操作员角色;只有该角色会获得此集群的管理员访问权限。工作负载权限仍需单独配置。

typescript
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 或角色值。

typescript
#!/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 是不同的软件包,版本号并不相同。

bash
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 权限。

bash
: "${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.authenticationMode

RBAC 配置 ​

对于新的 IAM 访问权限,请使用访问条目。此示例会向现有 dev 命名空间中的新角色授予读取权限;不要重复创建由集群创建工具管理的操作员条目。身份验证模式必须为 API 或 API_AND_CONFIG_MAP。旧版 aws-auth 方法已弃用;不要覆盖整个 ConfigMap。需要迁移时,请遵循官方迁移流程。

bash
# 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。仅能访问控制平面并不能证明节点或工作负载运行正常。

基本验证 ​

bash
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。

bash
eks_kubectl get nodepools.karpenter.sh
eks_kubectl get nodeclasses.eks.amazonaws.com
eks_kubectl get nodeclaims.karpenter.sh

部署示例应用 ​

使用新命名空间检查镜像访问、调度、HTTP 就绪状态和 Service。仅使用 Fargate 的配置必须先创建匹配此命名空间的配置文件。

bash
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 天升级控制平面次要版本。操作员需规划次要版本升级,并考虑版本支持策略下的自动升级。

bash
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 节点;传统托管节点组需要单独更新。

bash
# 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。

清理示例命名空间 ​

bash
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 状态比较,不要仅依赖未经审查的当前查询结果。

bash
: "${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 创建的集群使用此方法。

bash
if [[ ${EKS_DELETE_TARGET_VERIFIED:-false} = true ]]; then
  eksctl delete cluster --name "${EKS_CLUSTER_NAME:?}" --region "${EKS_REGION:?}" --wait
fi

使用 AWS CLI 删除 ​

对于直接通过 CLI 创建的集群,请设置上面列出的所属节点组/配置文件名称,并对每个资源重复操作。等待删除完成并确认资源均已清除后,再删除集群。

bash
# 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 删除 ​

使用原始配置、后端和工作区;仅针对目标资源/账户应用经过审查的销毁计划。

bash
if [[ ${EKS_DELETE_TARGET_VERIFIED:-false} = true ]]; then
  terraform plan -destroy -out=reviewed-destroy.tfplan &&
    terraform apply reviewed-destroy.tfplan
fi

使用 CDK 删除 ​

使用原始应用、输入、账户和区域,并验证目标堆栈。

bash
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 资源预置、升级、删除、应用运行时/负载测试或成本测量。

向文档提问

按 Enter 发送,按 Shift+Enter 换行。