AWS EKS 配置及相关操作

EKS 集群特性总结

  • 节点的 IP 地址(EXTERNAL-IP 和 INTERNAL-IP)不固定,会变化。特别是在自治模式中,节点被视为 临时资源(Ephemeral) ,可能会频繁地进行节点池优化。

    如果集群需要固定的出口 IP,最推荐,最标准的做法是 使用 NAT 网关 ,将 EKS 节点部署在私有子网中,所有访问外部网络的流量都会经过 NAT 网关

通过 AWS 管理控制台部署 EKS 集群

  • Kubernetes 版本: v1.35

本示例中使用 EKS 自治模式(EKS Auto Mode)

EKS 自治模式 接管了原本需要手动管理的节点、存储和网络配置,因此它需要一组非常具体且强大的权限

EKS 自治模式 有额外的费用,大概比 EC2 价格高 12%

EKS 自治模式 在集群创建完成后可修改(编辑)为非自治模式

EKS 自治模式 中的 Worker Nodes 配置 不能在控制台修改参数、不能自定义 ,具体的配置可以通过 API 接口查看 nodepool 资源

# kubectl describe nodepool general-purpose
Name: general-purpose
Namespace:
Labels: app.kubernetes.io/managed-by=eks
Annotations: karpenter.sh/nodepool-hash: 4012513481623584108
karpenter.sh/nodepool-hash-version: v3
API Version: karpenter.sh/v1
Kind: NodePool
Metadata:
Creation Timestamp: 2026-02-06T09:38:18Z
Generation: 1
Resource Version: 784637
UID: e85261b9-3a4b-41b0-ac5...
Spec:
Disruption:
Budgets:
Nodes: 10% # 这是一个安全阀。在同一时间内,由于缩容或更新导致的节点离线比例不能超过 10%。这保证了你的集群不会因为自动优化而导致业务大面积中断。
Consolidate After: 30s # 节点达到上述状态 30 秒后,EKS 就会考虑将其关闭,并把上面的 Pod 迁移到更划算的节点上。
Consolidation Policy: WhenEmptyOrUnderutilized # 当节点变为空闲(没有 Pod)或者利用率较低(比如一个大节点只跑了一个小 Pod)时,EKS 会自动触发节点合并。
limits: # 资源限制
cpu: "1000"
memory: 1000Gi
Template:
Metadata:
Spec:
Expire After: 336h # 节点的最大“寿命”是 14 天(336 小时),强制节点定期更换,以确保所有节点都运行在最新的安全补丁和 Bottlerocket 镜像上,防止出现长期未重启的“僵尸节点”。
Node Class Ref: # nodeclass 信息,可通过 kubectl get nodeclass 查看
Group: eks.amazonaws.com
Kind: NodeClass
Name: default
Requirements: # 节点选择标准 (Requirements)
Key: karpenter.sh/capacity-type # 实例类型,on-demand 为 按需实例
Operator: In
Values:
on-demand
Key: eks.amazonaws.com/instance-category # 限定了实例系列 c: 计算优化型(适合高并发); m: 通用型(平衡 CPU 和内存); r: 内存优化型(适合数据库或缓存)。
Operator: In
Values:
c
m
r
Key: eks.amazonaws.com/instance-generation # 只使用 4 代以后的机型(如 c5, m6i 等)。这确保了节点拥有较新的硬件特性和性能。
Operator: Gt
Values:
4
Key: kubernetes.io/arch # CPU 架构。如果你想尝试性价比更高的 ARM 架构(Graviton),需要在这里添加 arm64
Operator: In
Values:
amd64
Key: kubernetes.io/os # 节点操作系统(OS)类型
Operator: In
Values:
linux
Termination Grace Period: 24h0m0s

EKS 自治模式限制资源上限 编辑 NodePool,修改 spec.limits.cpuspec.limits.memory 。这决定了该池子最多能“烧”掉多少 EC2 资源。

强制回收节点 : 如果你想让 EKS 重新平衡节点(例如你更改了实例限制),可以手动删除节点,Auto Mode 会自动根据 Pod 需求拉起符合新规的新节点

kubectl delete node <node-name>

同时要关注 nodeclass 资源,其中定义了 子网(Subnet)和安全组(Security Group)等信息

# kubectl get nodeclass
NAME ROLE READY AGE
default eksNodeRole True 44h


# kubectl describe nodeclass default
Name: default
Namespace:
Labels: app.kubernetes.io/managed-by=eks
Annotations: eks.amazonaws.com/nodeclass-hash: 13740036326424352917
eks.amazonaws.com/nodeclass-hash-version: v2
API Version: eks.amazonaws.com/v1
Kind: NodeClass
Metadata:
Creation Timestamp: 2026-02-06T09:38:18Z
Finalizers:
eks.amazonaws.com/termination
Generation: 2
Resource Version: 827607
UID: 5065b0f3-3795-4347-893a-338ae6fa882d
Spec:
Ephemeral Storage:
Iops: 3000
Size: 80Gi
Throughput: 125
Network Policy: DefaultAllow
Network Policy Event Logs: Disabled
Role: eksNodeRole
Security Group Selector Terms:
Id: sg-058bd1ef...
Snat Policy: Random
Subnet Selector Terms:
Id: subnet-07963d9b...
Id: subnet-0e359aac...
Id: subnet-0e76c601...
角色名称 关联策略示例 作用对象
集群 IAM 角色(Cluster Role) AmazonEKSClusterPolicy EKS 控制平面。用于管理网络、负载均衡等
节点 IAM 角色(Node Role) AmazonEKSWorkerNodePolicy EC2 节点。用于让节点加入集群、拉取镜像。
Pod 角色(IRSA) 自定义权限(如 S3 读写) 应用程序 (Pod)。用于业务代码访问 AWS 资源。
  1. 创建 EKS 集群 IAM 角色

    每个集群都需要一个 Amazon EKS 集群 IAM 角色。由 Amazon EKS 管理的 Kubernetes 集群会使用此角色来管理节点
    AWS 官方参考文档: https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/cluster-iam-role.html#create-service-role

    1. 进入 IAM 控制台 -> 角色 -> 创建角色。

    2. 选择 AWS 服务,找到 EKS。

    3. 选择 EKS - Cluster 用例。

    4. 确保关联了以下权限策略。

      • AmazonEKSClusterPolicy
      • AmazonEKSComputePolicy
      • AmazonEKSBlockStoragePolicy
      • AmazonEKSNetworkingPolicy
      • AmazonEKSLoadBalancingPolicy
    5. 修改角色 信任关系 (Trust relationships) ,在 Action 列表中添加 sts:TagSession

      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Principal": {
      "Service": "eks.amazonaws.com"
      },
      "Action": ["sts:AssumeRole",
      "sts:TagSession"
      ]}
      ]
      }
    6. 命名为 eksClusterRole 并保存。

  2. 创建 EKS 节点 IAM 角色

    Amazon EKS 节点 kubelet 守护进程代表您调用 AWS API。节点通过 IAM 实例配置文件和关联的策略获得这些 API 调用的权限。您必须先为节点创建 IAM 角色以在启动它们时使用,然后才能启动这些节点并在集群中注册它们。
    AWS 官方参考文档: https://docs.aws.amazon.com/zh_cn/eks/latest/userguide/create-node-role.html

    1. 通过 https://console.aws.amazon.com/iam/ 打开 IAM 控制台。

    2. 在左侧导航窗格中,选择 Roles(角色)

    3. 在 Roles(角色)页面上,选择 Create role(创建角色)

    4. Select trusted entity(选择受信任的实体) 页面上,请执行以下操作:

      1. 在可信实体类型部分中,选择 AWS 服务。
      2. 在 Use case(使用案例)下,选择 EC2。
      3. 选择下一步。
    5. 在添加权限页面上,附加自定义策略或执行以下操作:

      1. Filter policies (筛选器策略) 框中,输入 AmazonEKSWorkerNodePolicy
      2. 选中搜索结果中的 AmazonEKSWorkerNodePolicy 左侧的复选框。
      3. 请选择 Clear filters(清除筛选条件)
      4. Filter policies (筛选器策略) 框中,输入 AmazonEC2ContainerRegistryPullOnly
      5. 选中搜索结果中的 AmazonEC2ContainerRegistryPullOnly 左侧的复选框。
      6. 选择下一步。
    6. Name, review, and create(命名、查看和创建)页面中 ,对角色(Role)命名,本示例使用 eksNodeRole

    7. 选择 创建角色

  3. 可以根据需求为 EKS 集群中的工作节点(Nodes)新建 私有子网 (Private Subnet) 并配置 NAT Gateway 以使集群 Nodes 的出口 IP 固定。

    EKS 允许你动态更新集群关联的子网。这一步会告诉 EKS 控制平面以后在新的 Subnets 中工作。

    新建 私有子网 (Private Subnet) 并配置 NAT Gateway 操作参考文档

  4. 创建集群控制平面

    1. 进入 EKS 控制台 -> 集群 -> 添加集群 -> 创建。
    2. 配置集群:输入名称,选择 Kubernetes 版本,并选择已经创建的 集群 IAM 角色 eksClusterRole节点 IAM 角色 eksNodeRole
    3. 其他配置使用默认即可。
  5. 若要通过命令行来管理 Amazon EKS 集群,参考 官方文档安装 aws clikubectleksctl

AWS EKS 控制台基本不提供 Deployment / Pod 的创建、编辑、删除能力。只具备集群可视化、运维辅助的功能。对集群的变更操作主要通过 通过 API / kubectl ,集群管理可通过接入 Rancher ,它提供多集群管理、 RBAC 权限控制、审计等诸多方便 。

aws eks 常用命令

列出集群

# aws eks list-clusters
{
"clusters": [
"my_eks_cluster"
]
}

为集群创建或更新 kubeconfig 文件用于和集群通信

在配置了 aws cli 命令授权(如 ak/sk )的(EKS)外部系统上执行以下命令可配置 EKS 鉴权信息以和 EKS 集群进行通信。

# aws eks update-kubeconfig --region region-code --name my-cluster
Added new context arn:aws:eks:ap-east-1:252345564999:cluster/my-cluster to /root/.kube/config

更新 kubeconfig 文件成功后,会创建 ~/.kube/config 文件,里面包含集群的 API 信息和认证信息,凭此可以和 Kubernetes 集群进行通信

# kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
i-08430a2c906bc4c67 Ready <none> 16h v1.35.0-eks-ac2d5a0 172.31.45.250 18.166.67.169 Bottlerocket (EKS Auto, Standard) 2026.1.28 (aws-k8s-1.35-standard) 6.12.64 containerd://2.1.6+bottlerocket
i-0da674836789d8862 Ready <none> 16h v1.35.0-eks-ac2d5a0 172.31.29.11 43.198.109.233 Bottlerocket (EKS Auto, Standard) 2026.1.28 (aws-k8s-1.35-standard) 6.12.64 containerd://2.1.6+bottlerocket

在 EKS 集群内部创建 Bastion Pod 并管理 EKS 集群

如果只能在 EKS 内部授权的情况下,例如不能提供 ak/sk 或其他鉴权信息给外部系统,此时可以参考以下步骤在 EKS 内部部署 Bastion Pod、给 Bastion Pod 授予 Kubernetes API 权限并开放 SSH 连接到 Bastion Pod 以管理 EKS 集群

方案架构

  • 镜像 : 推荐使用包含 kubectl、helm、aws-cli 的基础镜像(如 bitnami/kubectl 或自定义 Alpine Linux 镜像)
  • 数据持久化 : 使用 EBS CSI Driver 挂载一个 PVC 到 /root/home/user ,确保你的脚本、 kubeconfig 和工具配置在 Pod 重启后不会丢失。
  • ssh 端口 : 暴露一个 LoadBalancer 类型的 Service,将容器的 22 端口映射出来。 为了安全,一定要使用 SSH Key 登录(禁止密码)并设置严格的安全组(准入)
  • Kubernetes API 鉴权 : 使用 IAM Role for Service Account(IRSA) 将有相应权限的 IAM Role 绑定到 Pod 使用的 ServiceAccount 上。
  • 使用 StatefulSet
  1. 使用 StatefulSet 部署 Pod,参考以下配置

    ## 定义 PVC,使用 storageClassName: gp3
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
    name: eks-cluser-admin-bastion-pvc
    spec:
    accessModes:
    - ReadWriteOnce
    resources:
    requests:
    storage: 20Gi
    storageClassName: gp3
    ---

    ## 镜像初始化脚本,安装常用软件,添加账户,设置密码,配置 sshd 等
    apiVersion: v1
    kind: ConfigMap
    metadata:
    name: eks-cluser-admin-bastion-init-script
    data:
    setup.sh: |
    #!/bin/bash
    # 1. 安装必要组件 (加入 sudo)
    apk update && apk add --no-cache \
    openssh-server \
    curl \
    python3 \
    py3-pip \
    bash \
    sudo

    # 2. 配置 SSH 密钥
    ssh-keygen -A

    # 3. 创建用户 op 并设置密码
    # -D 表示不创建密码(后面统一设),-s 指定 shell
    if ! id "op" &>/dev/null; then
    adduser -D -s /bin/bash op
    echo "op:YourStrongPassword" | chpasswd
    fi

    # 4. 配置 sudo (允许 op 组免密执行 sudo)
    echo "op ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/op
    chmod 0440 /etc/sudoers.d/op

    # 5. SSH 安全配置
    # 禁止 root 登录
    sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin no/' /etc/ssh/sshd_config
    # 确保允许密码登录(如果你不使用 SSH Key 的话)
    sed -i 's/PasswordAuthentication no/PasswordAuthentication yes/' /etc/ssh/sshd_config

    # 6. 启动 SSH 服务
    echo "Starting sshd..."
    exec /usr/sbin/sshd -D
    ---

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
    name: eks-cluser-admin-bastion
    spec:
    serviceName: "eks-admin-bastion"
    replicas: 1
    selector:
    matchLabels:
    app: eks-cluser-admin-bastion-pod
    template:
    metadata:
    labels:
    app: eks-cluser-admin-bastion-pod
    spec:
    containers:
    - name: bastion
    image: alpine:latest # 使用极小镜像
    command: ["/bin/sh", "/mnt/scripts/setup.sh"]
    volumeMounts:
    - name: scripts
    mountPath: /mnt/scripts
    # # 挂载 PVC 里的 root 子目录到容器的 /root
    - name: eks-cluser-admin-bastion-data
    mountPath: /root/ # 持久化 /root 目录
    subPath: root
    # 挂载 PVC 里的 home 子目录到容器的 /home
    - name: eks-cluser-admin-bastion-data
    mountPath: /home
    subPath: home
    volumes:
    - name: scripts
    configMap:
    name: eks-cluser-admin-bastion-init-script
    - name: eks-cluser-admin-bastion-data
    persistentVolumeClaim:
    claimName: eks-cluser-admin-bastion-pvc

    eks-cluser-admin-bastion-pod 部署成功后,可以在集群中启动一个临时的测试 Pod( kubectl run netshoot-tmp --image=nicolaka/netshoot -it --rm -- /bin/bash ) 测试是否能通过 ssh 连接到 Bastion Pod

    netshoot-tmp:~# ssh -v op@10.1.26.100
    debug1: OpenSSH_10.2p1, OpenSSL 3.5.4 30 Sep 2025
    debug1: Reading configuration data /etc/ssh/ssh_config
    debug1: /etc/ssh/ssh_config line 22: include /etc/ssh/ssh_config.d/*.conf matched no files
    debug1: Connecting to 10.1.26.100 [10.1.26.100] port 22.
    debug1: Connection established.
    ...
    This key is not known by any other names.
    Are you sure you want to continue connecting (yes/no/[fingerprint])?

    可以正常 ssh 连接 Bastion Pod,说明以上配置无误,可正常工作。

  2. 为 Bastion Pod 创建面向互联网的 NLB(Network Load Balancer)。创建 type: LoadBalancer 的 Service 对象。


    apiVersion: v1
    kind: Service
    metadata:
    name: eks-cluser-admin-bastion-svc
    annotations:
    # 强制指定为公网负载均衡器
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
    # 建议同时指定使用 NLB (网络负载均衡器),更适合 SSH
    service.beta.kubernetes.io/aws-load-balancer-type: "external"
    service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "instance"
    spec:
    type: LoadBalancer
    ports:
    - port: 22
    targetPort: 22
    selector:
    app: eks-cluser-admin-bastion-pod

    NLB 创建成功后,从互联网测试访问。

  3. EKS Admin Bastion Pod 可以正常从互联网访问后,接着需要为其授权可管理 EKS 集群。因为 Pod 在 EKS 集群内部,只需要使用 IRSA(IAM Role for Service Account) 为其 ServiceAccount 绑定一个合适的 IAM Role 即可授予其对应的权限。不在容器里放 AWS 密钥,从而避免在容器内硬编码 Access Key

    以下配置基于 IRSA(IAM Roles for Service Accounts) 机制,新版本(大于等于 1.34 EKS)使用了 Pod Identity(IRSA 的进化版)机制实现了让 Pod 获得权限。EKS Pod Identity 它更符合云原生的简洁逻辑,配置也更简单,新版本建议使用。

    前提条件:

    • EKS 集群必须启用 OIDC Provider,用于 Pod 关联 IAM Role

      每个 EKS 集群都有一个唯一的 OIDC 发行者 URL。你需要确保 AWS IAM 中已经存在对应的身份提供者。执行命令获取 URL:

      $ aws eks describe-cluster --name <集群名称> --query "cluster.identity.oidc.issuer" --output text
      https://oidc.eks.ap-east-1.amazonaws.com/id/7785E5DC362954034E73

      ## 检查是否已经注册
      $ aws iam list-open-id-connect-providers

      如果你还没关联(注册)过,执行以下命令(推荐使用 eksctl ,最简便),或在 AWS 控制台 EKS → Cluster → Configuration → Authentication → Associate OIDC Provider

      eksctl utils associate-iam-oidc-provider --cluster <你的集群名> --approve
    • 你需要有 管理员权限,可创建 IAM Role / Policy / ServiceAccount

    • kubectl 可以访问 EKS API

    1. 创建 IAM Role 并配置信任策略

      你需要创建一个 IAM Role 或者使用现有 Role,并授予它管理 EKS 的权限(例如集群管理策略 AmazonEKSClusterPolicy 或自定义权限)。假设你想给 Pod 完全 EKS 权限( kubectl、awscli ),创建 Policy

      以下示例创建一个给运维人员使用的 Role,禁止 删除整个集群 但是能查看集群,能使用 Kubernetes API

      aws iam create-policy \
      --policy-name EKSClusterOpsAdminPolicy \
      --policy-document '{
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Action": [
      # "eks:*", # 全权管理 EKS。包括创建/删除集群、更新版本、增删节点组(Nodegroup)、配置 Fargate Profile、管理插件等。谨慎授予此权限
      "eks:Describe*",
      "eks:List*", # eks:Describe* / List*: 允许他看集群状态。
      "eks:AccessKubernetesApi", # 至关重要。没有这个权限,他连 kubectl 认证都过不去。
      "ec2:Describe*",
      "iam:ListRoles", # 列出账号下所有 IAM 角色。在创建集群或节点组时,用于在下拉列表中选择已有的 Role。
      "iam:GetRole" # 查看特定 IAM 角色的详情。用于验证所选角色的信任关系是否正确。
      ],
      "Resource": "*"
      }
      ]
      }'

      可以根据需要收紧权限,例如只允许 eks:DescribeCluster 或指定 Cluster ARN

      信任策略 (Trust Policy)

      该 Role 必须允许你的 EKS OIDC 身份提供者来“扮演”它。信任策略示例如下:

      {
      "Version": "2012-10-17",
      "Statement": [
      {
      "Effect": "Allow",
      "Principal": {
      "Federated": "arn:aws:iam::<账号ID>:oidc-provider/<OIDC地址,如 oidc.eks.ap-east-1.amazonaws.com/id/ABCDE1234567890>"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
      "StringEquals": {
      "<OIDC地址,如 oidc.eks.ap-east-1.amazonaws.com/id/ABCDE1234567890>:sub": "system:serviceaccount:<命名空间>:<ServiceAccount名称>",
      "<OIDC地址>:aud": "sts.amazonaws.com"
      }
      }
      }
      ]
      }

      创建 IAM Role
      aws iam create-role \
      --role-name eks-admin-bastion-role \
      --assume-role-policy-document file://trust.json

      绑定 Policy
      aws iam attach-role-policy \
      --role-name eks-admin-bastion-role \
      --policy-arn arn:aws:iam::<ACCOUNT_ID>:policy/EKSClusterOpsAdminPolicy

    2. 创建 Kubernetes ServiceAccount 。在集群中创建一个 ServiceAccount,并通过 Annotation (注解) 将其指向刚才创建的 IAM Role。

      apiVersion: v1
      kind: ServiceAccount
      metadata:
      name: eks-bastion-admin-sa
      namespace: default
      annotations:
      # 替换为你创建的 IAM Role ARN
      eks.amazonaws.com/role-arn: arn:aws:iam::<账号ID>:role/<Role名称>

      执行命令创建 ServiceAccount kubectl apply -f serviceaccount.yaml

    3. 在 StatefulSet 中引用 ServiceAccount 。最后,修改你的 StatefulSet 配置,在 spec.template.spec 中指定 serviceAccountName

      apiVersion: apps/v1
      kind: StatefulSet
      metadata:
      name: eks-cluser-admin-bastion
      spec:
      template:
      spec:
      serviceAccountName: eks-admin-sa # 引用刚才创建的 SA
      containers:
      - name: bastion
      image: alpine:latest
      # ... 其他配置保持不变

部署完成后,检查 Pod 是否挂载了上面创建的 ServiceAccount

$ kubectl describe pod eks-cluser-admin-bastion-0
Name: eks-cluser-admin-bastion-0
Namespace: default
Priority: 0
Service Account: eks-bastion-admin-sa

Service Account: eks-bastion-admin-sa 存在说明已经成功挂载到 ServiceAccount。

进入 Pod 后,导入相关环境变量即可获取到 AWS Role 对应的权限,

export AWS_ROLE_ARN=arn:aws:iam::<ACCOUNT_ID>:role/eks-admin-bastion-role
export AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token
export AWS_DEFAULT_REGION=ap-east-1

要永久生效将其写入 ~/.bashrc

cat <<EOF >> ~/.bashrc
# AWS IRSA Credentials
export AWS_ROLE_ARN=arn:aws:iam::<ACCOUNT_ID>:role/eks-admin-bastion-role
export AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token
export AWS_DEFAULT_REGION=ap-east-1
EOF

# 立即生效
source ~/.bashrc

此时检查环境变量中会包含 AWS 相关的凭证

$ env | grep AWS
AWS_DEFAULT_REGION=ap-east-1
AWS_ROLE_ARN=arn:aws:iam::<ACCOUNT_ID>:role/eks-admin-bastion-role
AWS_WEB_IDENTITY_TOKEN_FILE=/var/run/secrets/eks.amazonaws.com/serviceaccount/token

$ aws sts get-caller-identity
{
"UserId": "AROA4P24OBGGM3AHEHKWG:botocore-session-1771588635",
"Account": "<ACCOUNT_ID>",
"Arn": "arn:aws:sts::<ACCOUNT_ID>:assumed-role/eks-admin-bastion-role/botocore-session-1771588635"
}

执行以下命令更新 kubeconfig 配置

$ aws eks update-kubeconfig --name <YOUR_CLUSTER_NAME> --region ap-east-1
Added new context arn:aws:eks:ap-east-1:<ACCOUNT_ID>:cluster/<CLUSTER_NAME> to ~/.kube/config

此时访问集群会报错

$ kubectl get pods 
E0220 12:14:50.804935 1048 memcache.go:265] "Unhandled Error" err="couldn't get current server API group list: the server has asked for the client to provide credentials"

此时你的 aws sts get-caller-identity 成功了,意味着在 AWS 资源层面(非 Kubernetes 集群内)已经承认你是这个 IAM Role,可以访问这个 Role 关联的 Policy 中定义的资源权限。

但 EKS 集群(Kubernetes API)还不认识这个 IAM Role,在 EKS 中, 即便你是 AWS 的管理员 Role,也必须在集群的 Access Entries 中显式登记。此处登记的 Policy 才决定了你对 Kubernetes 集群有怎样的权限

EKS 的 Access Entry 中 Policies 实际上是 AWS 预定义的、对应了 K8s 内部 ClusterRole:

  • AmazonEKSClusterAdminPolicy : 映射到 K8s 内部的 cluster-admin
  • AmazonEKSViewerPolicy : 映射到 K8s 内部的 view
  1. 打开 AWS EKS 控制台 -> 点击你的集群

  2. 进入 Access (访问) 选项卡。

  3. 点击 Create access entry

    • IAM Role ARN : 填入你的 arn:aws:iam::<ACCOUNT_ID>:role/eks-admin-bastion-role

    • Type : 选择 Standard

    • 关联策略:

      点击 Add policy

      选择 AmazonEKSClusterAdminPolicy ,这是 Kubernetes 集群管理员权限,也可以根据需求给其他权限,如 AmazonEKSViewerPolicy (允许查看集群级别和所有命名空间的资源)、 AmazonEKSViewPolicy (较低级别的查看权限) 。

      Access scope 选择 Cluster

后续如果需要调整此 Role 在 Kubernetes 中的权限,只需要要更改 EKS Access Entries 中对应 Role 关联的 Policy 即可。

可通过以下命令验证验证权限已绑定

$ aws eks list-associated-access-policies \
--cluster-name <你的集群名> \
--principal-arn arn:aws:iam::<ACCOUNT_ID>:role/eks-admin-bastion-role \
--region ap-east-1
{
"associatedAccessPolicies": [
{
"policyArn": "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy",
"accessScope": {
"type": "cluster",
"namespaces": []
},
"associatedAt": "2026-02-20T12:31:20.639000+00:00",
"modifiedAt": "2026-02-20T12:31:20.639000+00:00"
}
],
"clusterName": "vpdevops",
"principalArn": "arn:aws:iam::<ACCOUNT_ID>:role/eks-admin-bastion-role"
}

应该能在返回的 associatedPolicies 列表中看到 AmazonEKSClusterAdminPolicy

再次检查,可正常看到集群资源

$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
i-0281a8c776b23ad3c Ready <none> 2d7h v1.35.0-eks-ac2d5a0
i-0537347b41b4dd314 Ready <none> 35h v1.35.0-eks-ac2d5a0

常见错误

集群角色缺少建议的托管策略

EKS 自治模式 的集群创建过程中缺少必要的权限

集群角色缺少建议的托管策略
集群角色必须具有以下托管策略或等效权限才能使用 EKS 自治模式:
- AmazonEKSBlockStoragePolicy
- AmazonEKSComputePolicy
- AmazonEKSLoadBalancingPolicy
- AmazonEKSNetworkingPolicy

EKS 自治模式 接管了原本需要手动管理的节点、存储和网络配置,因此它需要一组非常具体且强大的权限. 解决方法如下

  1. 登录 IAM 控制台,找到“角色 (Roles)”。

  2. 搜索并点击你为 EKS 集群创建的角色名称,本示例中为 eksClusterRole

  3. 权限 (Permissions) 选项卡下,点击 添加权限 (Add permissions) -> 附加策略 (Attach policies)

  4. 在搜索框中分别搜索并勾选上述四个策略:

    • AmazonEKSComputePolicy
    • AmazonEKSBlockStoragePolicy
    • AmazonEKSNetworkingPolicy
    • AmazonEKSLoadBalancingPolicy

最终的 权限策略 如下图所示:

集群角色信任策略缺少必需的操作

EKS 自治模式 的集群创建过程中缺少必要的权限

集群角色信任策略缺少必需的操作
集群角色必须具有其信任策略中指定的以下操作才能使用 EKS 自治模式:
- sts:TagSession

在 EKS 自治模式下,EKS 需要使用 sts:TagSession 来为它替你创建的资源(如自动生成的节点)进行身份标识和追踪。

修改 IAM 角色的 信任关系 (Trust relationships) ,将 sts:TagSession 操作添加到允许列表中。

  1. 进入 IAM 控制台 -> 角色 (Roles)。
  2. 搜索并点击你的 EKS 集群角色,本示例中为 eksClusterRole
  3. 点击 信任关系 (Trust relationships) 选项卡。
  4. 点击 编辑信任策略 (Edit trust policy) 。默认内容如下
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Principal": {
    "Service": "eks.amazonaws.com"
    },
    "Action": "sts:AssumeRole"
    }
    ]
    }
    修改为以下内容,在 Action 列表中添加 sts:TagSession
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Principal": {
    "Service": "eks.amazonaws.com"
    },
    "Action": ["sts:AssumeRole",
    "sts:TagSession"
    ]}
    ]
    }
  5. 修改完成后,点击 更新策略 (Update policy)

EKS 集群相关配置及操作

修改 EKS 集群 API server endpoint 访问权限

默认 EKS 集群部署后,API server endpoint access 模式提供了三种:

  • Public Only :API Server endpoint 仅通过公网访问。
  • Public and Private :同时开启。VPC 内流量走私有 Endpoint,外部走公网。
  • Private Only :彻底关闭公网入口。这是安全性最高但也最复杂的模式。

默认为 Public and private

因此 API server endpoint 可以公网和 VPC 私网中访问。

要修改,可以在控制台 Cluster –> Networking: Manage –> endpoint access 进行修改,如果配置为 Public 或者 Public and Private ,可以通过修改 Add/edit sources to public access endpoint. 为公网访问添加白名单,提高安全性。

也可通过 AWS CLI 修改

aws eks update-cluster-config \
--name <cluster-name> \
--resources-vpc-config endpointPublicAccess=false,endpointPrivateAccess=true

如果开启了 仅限私有访问 ,你必须确保 VPC 满足以下条件,否则集群将无法正常工作:

  • 启用私有 DNS 支持

    VPC 必须开启 enableDnsHostnamesenableDnsSupport 。这样 EKS 才能在私有网络内解析 API Server 的域名。

  • VPC 端点 (Interface VPC Endpoints)

    由于 Node 无法访问公网,它们必须通过 VPC Endpoints 连接 AWS 服务。你通常需要为以下服务创建 Interface Endpoint:

    • ec2 (用于挂载卷/管理网卡)

    • ecr.apiecr.dkr(用于拉取镜像)

    • s3 (Gateway Endpoint)

    • logs (CloudWatch 日志)

  • 管理通道

    你必须拥有一个进入 VPC 的手段(如 AWS Client VPN 或 堡垒机 (Bastion Host)),否则你将无法运行任何 kubectl 命令。

为 EKS 集群安装 AWS Loadbalancer Controller

在集群中使用 AWS LoadBalance 向互联网提供 EKS 集群中的服务,需要在集群中安装 AWS Load Balancer Controller (LBC) ,类似要使用 Ingress Nginx 则需要在集群中安装 Ingress Nginx Controller 一样。

AWS 负载均衡器控制器(AWS Load Balancer Controller)官方文档

LBC 会在您创建 Kubernetes Ingress 时创建 AWS 应用程序负载均衡器(ALB)。

若集群所在 VPC 中存在公有子网和私有子网,为了让 EKS 自动识别哪些子网用于存放负载均衡器,哪些用于存放 Pod,你需要确保子网拥有正确的标签(只有共有子网可忽略此配置):

  • 公有子网 (NAT Gateway 所在的子网)

    • 标签: kubernetes.io/role/elb = 1
  • 私有子网 (EKS 节点所在的子网)

    • 标签:kubernetes.io/role/internal-elb = 1

检查集群中是否安装了 AWS Load Balancer Controller

kubectl get pods -n kube-system | grep -i controller

使用 Helm 和 eksctl 安装 AWS Load Balancer Controller(负载均衡器控制器)

安装 Helm

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-4
chmod 700 get_helm.sh
./get_helm.sh

参考以下步骤安装 AWS Load Balancer Controller,本示例版本 v3.0.0

  1. 下载 AWS 负载均衡器控制器(Load Balancer Controller)的 IAM 策略,该策略允许负载均衡器代表您调用 AWS API。

    curl -o iam_policy.json https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/v3.0.0/docs/install/iam_policy.json
  2. 使用上一步中下载的策略创建一个 IAM 策略。

    ## 检查是否已存在策略 AWSLoadBalancerControllerIAMPolicy
    # aws iam list-policies | grep -i AWSLoadBalancerControllerIAMPolicy

    ## 使用下载的策略文件创建新策略 AWSLoadBalancerControllerIAMPolicy
    # aws iam create-policy \
    --policy-name AWSLoadBalancerControllerIAMPolicy \
    --policy-document file://iam_policy.json

    # aws iam list-policies | grep -B 1 -A 10 -i AWSLoadBalancerControllerIAMPolicy
    {
    "PolicyName": "AWSLoadBalancerControllerIAMPolicy",
    "PolicyId": "ANPATVYVE6LERMKGVRCSF",
    "Arn": "arn:aws:iam::<AWS_ACCOUNT_ID>:policy/AWSLoadBalancerControllerIAMPolicy",
    "Path": "/",
    "DefaultVersionId": "v1",
    "AttachmentCount": 0,
    "PermissionsBoundaryUsageCount": 0,
    "IsAttachable": true,
    "CreateDate": "2026-02-09T12:44:19+00:00",
    "UpdateDate": "2026-02-09T12:44:19+00:00"
    },

  3. 在 EKS 集群中创建 iamserviceaccount ,替换命令中集群名称、区域代码和账户 ID 的值。

    # eksctl create iamserviceaccount \
    --cluster=<cluster-name> \
    --namespace=kube-system \
    --name=aws-load-balancer-controller \
    --attach-policy-arn=arn:aws:iam::<AWS_ACCOUNT_ID>:policy/AWSLoadBalancerControllerIAMPolicy \
    --override-existing-serviceaccounts \
    --region <aws-region-code> \
    --approve

    ## 检查 EKS 系统中的 iamserviceaccount
    # eksctl get iamserviceaccount --cluster <cluster-name>
    NAMESPACE NAME ROLE ARN
    kube-system aws-load-balancer-controller arn:aws:iam::<AWS_ACCOUNT_ID>:role/eksctl-<cluster-name>-addon-iamserviceaccount-kube-syst-Role1-dUL3ua7Mv2Gv

    如果创建报错: no IAM OIDC provider associated with cluster, try 'eksctl utils associate-iam-oidc-provider --region=ap-east-1 --cluster=<cluster-name>' ,先执行下面的命令 为 EKS 集群关联 OIDC Provider 然后在创建 iamserviceaccount

    eksctl utils associate-iam-oidc-provider \
    --region <aws-region-code> \
    --cluster <cluster-name> \
    --approve
  4. 安装 AWS 负载均衡器控制器(AWS Load Balancer Controller)

    # helm repo add eks https://aws.github.io/eks-charts

    # helm repo list
    NAME URL
    eks https://aws.github.io/eks-charts

    # helm repo update eks
    Hang tight while we grab the latest from your chart repositories...
    ...Successfully got an update from the "eks" chart repository
    Update Complete. ⎈Happy Helming!⎈

    ## 获取集群使用的 VPC ID,安装 aws-load-balancer-controller 时需要显式指定
    # aws eks describe-cluster --name <cluster-name> --query "cluster.resourcesVpcConfig.vpcId" --output text
    vpc-05840086...

    # helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
    -n kube-system \
    --set clusterName=<cluster-name> \
    --set serviceAccount.create=false \
    --set serviceAccount.name=aws-load-balancer-controller \
    --set vpcId=<VPC_ID> \
    --version 3.0.0

    NAME: aws-load-balancer-controller
    LAST DEPLOYED: Mon Feb 9 13:11:30 2026
    NAMESPACE: kube-system
    STATUS: deployed
    REVISION: 1
    DESCRIPTION: Install complete
    TEST SUITE: None
    NOTES:
    AWS Load Balancer controller installed!

  5. 验证控制器是否已安装成功,最主要是要有 ingressClass alb

    # kubectl get pod -A
    NAMESPACE NAME READY STATUS RESTARTS AGE
    kube-system aws-load-balancer-controller-949f9d848-4qtlz 1/1 Running 0 41s
    kube-system aws-load-balancer-controller-949f9d848-ww5jv 1/1 Running 0 23s

    # kubectl get deployment -n kube-system aws-load-balancer-controller
    NAME READY UP-TO-DATE AVAILABLE AGE
    aws-load-balancer-controller 2/2 2 2 41m

    # kubectl get ingressclass -A
    NAME CONTROLLER PARAMETERS AGE
    alb ingress.k8s.aws/alb <none> 43m

AWS Load Balancer controller 相关错误

AWS Load Balancer controller 部署后 Pod 状态为 CrashLoopBackOff

AWS Load Balancer controller 版本: v3.0.0

# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-load-balancer-controller-bd997488d-gwc7q 0/1 CrashLoopBackOff 5 (95s ago) 5m19s
kube-system aws-load-balancer-controller-bd997488d-mknn4 0/1 CrashLoopBackOff 5 (93s ago) 5m19s

# kubectl describe pod -n kube-system aws-load-balancer-controller-bd997488d-gwc7q
...
Warning BackOff 31s (x21 over 14m) kubelet Back-off restarting failed container aws-load-balancer-controller in pod aws-load-balancer-controller-bd997488d-gwc7q_kube-system(a66700e5-c2b8-40d6-ad88-c277551a6626)

# kubectl logs -f -n kube-system aws-load-balancer-controller-bd997488d-gwc7q
{"level":"info","ts":"2026-02-09T13:15:42Z","msg":"version","GitVersion":"v2.14.0","GitCommit":"d847890e67b4c3a78f230bd7f7caf2bfcab01df1","BuildDate":"2025-10-02T19:02:22+0000"}
{"level":"error","ts":"2026-02-09T13:15:47Z","logger":"setup","msg":"unable to initialize AWS cloud","error":"failed to get VPC ID: failed to fetch VPC ID from instance metadata: error in fetching vpc id through ec2 metadata: get mac metadata: operation error ec2imds: GetMetadata, canceled, context deadline exceeded"}

关键报错信息 failed to get VPC ID: failed to fetch VPC ID from instance metadata: error in fetching vpc id through ec2 metadata: get mac metadata: operation error ec2imds: GetMetadata, canceled, context deadline exceeded

ALB Controller 启动时必须知道自己在哪个 VPC ,此报错说明控制器无法从 EC2 元数据服务 (IMDS) 获取 VPC ID。可以为控制器显式指定 VPC ID

# aws eks describe-cluster --name <CLUSTER_NAME> --query "cluster.resourcesVpcConfig.vpcId" --output text
vpc-05840086...

## 使用 upgrade 更新配置
# helm upgrade aws-load-balancer-controller eks/aws-load-balancer-controller \
-n kube-system \
--set clusterName=<cluster-name> \
--set serviceAccount.create=false \
--set serviceAccount.name=aws-load-balancer-controller \
--set vpcId=<VPC_ID> \
--version 3.0.0
Release "aws-load-balancer-controller" has been upgraded. Happy Helming!
NAME: aws-load-balancer-controller
LAST DEPLOYED: Mon Feb 9 13:49:09 2026
NAMESPACE: kube-system
STATUS: deployed
REVISION: 3
DESCRIPTION: Upgrade complete
TEST SUITE: None
NOTES:
AWS Load Balancer controller installed!

## 更新 VPC ID 后 ALB Controller 正常启动
# kubectl get pod -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system aws-load-balancer-controller-949f9d848-4qtlz 1/1 Running 0 41s
kube-system aws-load-balancer-controller-949f9d848-ww5jv 1/1 Running 0 23s

unable to resolve at least one subnet

Ingress 部署后,ALB 未成功创建

$ kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress alb * 80 2m41s

$ kubectl describe ingress nginx-ingress
Name: nginx-ingress
Labels: <none>
Namespace: default
Address:
Ingress Class: alb
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
*
/ nginx-service:80 (10.1.30.0:80,10.1.42.163:80)
Annotations: alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedBuildModel 2s (x17 over 5m32s) ingress Failed build model due to couldn't auto-discover subnets: unable to resolve at least one subnet. Evaluated 0 subnets: 0 are tagged for other clusters, and 0 have insufficient available IP addresses

$ kubectl logs -f -n kube-system -l "app.kubernetes.io/name=aws-load-balancer-controller"
{"level":"info","ts":"2026-02-17T07:48:09Z","logger":"setup","msg":"starting collect cache size"}
{"level":"info","ts":"2026-02-17T07:48:09Z","logger":"setup","msg":"starting collect top talkers"}
{"level":"info","ts":"2026-02-17T07:48:09Z","logger":"controller-runtime.metrics","msg":"Starting metrics server"}
{"level":"error","ts":"2026-02-17T07:53:05Z","msg":"Reconciler error","controller":"ingress","object":{"name":"nginx-ingress","namespace":"default"},"namespace":"default","name":"nginx-ingress","reconcileID":"fbf14592-b735-49d4-95ac-eb5e0734c626","error":"couldn't auto-discover subnets: unable to resolve at least one subnet. Evaluated 0 subnets: 0 are tagged for other clusters, and 0 have insufficient available IP addresses"}
{"level":"error","ts":"2026-02-17T07:53:06Z","msg":"Reconciler error","controller":"ingress","object":{"name":"nginx-ingress","namespace":"default"},"namespace":"default","name":"nginx-ingress","reconcileID":"3d2a4e4b-e567-418c-b5b9-4517bf187d81","error":"couldn't auto-discover subnets: unable to resolve at least one subnet. Evaluated 0 subnets: 0 are tagged for other clusters, and 0 have insufficient available IP addresses"}

关键报错信息 "error":"couldn't auto-discover subnets: unable to resolve at least one subnet. Evaluated 0 subnets: 0 are tagged for other clusters, and 0 have insufficient available IP addresses"

目前 VPC 架构如图所示,EKS 专用的 VPC 中,存在三个子网,且最终路由都指向了 Nat Gateway,因此都是 私有子网(Private Subnet) 。不具备被公有互联网访问的条件(只能出不能进)。

在此中架构下(EKS 资源运行于 NAT Gateway 网络下),VPC 中需要有 公有子网(Public Subnet) 用于部署 ALB 以能在互联网上访问 ALB。

你需要在同一个 VPC ( eks-hk-vpc ) 中 新建至少两个公有子网来部署 ALB 。并为其打上标签 kubernetes.io/role/elb=1

Target is in an Availability Zone that is not enabled for the load balancer

原因为 ALB 可用区只有两个,而 Pod 可用区有 3 个,当 Pod 部署在 ALB 不可用的区域时会发生此错误

在 EKS 自动模式集群中检查 Amazon EBS CSI 控制器状态

EKS 自动模式(EKS Auto Mode)默认无需在集群上安装 Amazon EBS CSI 控制器。官方文档说明

查看集群中已经安装的 CSI Driver 。EKS 自动模式(EKS Auto Mode)默认安装了 ebs.csi.eks.amazonaws.com efs.csi.aws.com 两个 SCI Driver 用于创建 EBS 和 EFS 类型的 StorageClass

$ kubectl get csidrivers
NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE
ebs.csi.eks.amazonaws.com true false false <unset> false Persistent 7d16h
efs.csi.aws.com false false false <unset> false Persistent 7d16h

查看 StorageClass 信息,EKS 自动模式(EKS Auto Mode)使用 provisioner: ebs.csi.eks.amazonaws.com ,普通 EKS 集群安装的 AWS EBS SCSI Drive 使用 provisioner: ebs.csi.aws.com

$ kubectl get storageclasses
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp3 ebs.csi.eks.amazonaws.com Delete WaitForFirstConsumer true 10s

$ kubectl describe storageclass gp3
Name: gp3
IsDefaultClass: No
Annotations: kubectl.kubernetes.io/last-applied-configuration={"allowVolumeExpansion":true,"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"gp3"},"parameters":{"fsType":"ext4","type":"gp3"},"provisioner":"ebs.csi.eks.amazonaws.com","reclaimPolicy":"Delete","volumeBindingMode":"WaitForFirstConsumer"}

Provisioner: ebs.csi.eks.amazonaws.com
Parameters: fsType=ext4,type=gp3
AllowVolumeExpansion: True
MountOptions: <none>
ReclaimPolicy: Delete
VolumeBindingMode: WaitForFirstConsumer
Events: <none>

此 Storageclass gp3 对应的 YAML 配置文件如下

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.eks.amazonaws.com
parameters:
type: gp3
fsType: ext4
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
allowVolumeExpansion: true

为集群分配只读权限的账户

EKS 账户权限是 AWS IAM 权限 + Kubernetes RBAC 两层权限一起管。

本示例目标是:用户能看集群资源( kubectl get/describe ),但不能改( create/update/delete )。

  1. 在 AWS IAM 中创建用户如 EKSReadOnlyUSER ,确保该 IAM 用户或角色在 AWS 层面能够“看到”集群。创建一个名为 EKSReadOnlyPolicy 的策略并关联给该用户

    EKSReadOnlyPolicy
    {
    "Version": "2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Action": [
    "eks:DescribeCluster",
    "eks:ListClusters"
    ],
    "Resource": "*"
    }
    ]
    }
  2. 使用 EKS 的 Access Entries (访问条目) 机制为集群访问创建 访问条目 (Access Entry)

    新版本的 EKS 集群启用了 API 身份验证模式 (API Authentication Mode) 。可以直观的通过 访问条目 (Access Entry) 控制对集群的访问

    AWS Console(控制台)查看 Access Entry

    aws 命令查看 Access Entry

    # aws eks list-access-entries --cluster-name MY_CLUSTER
    {
    "accessEntries": [
    "arn:aws:iam::25291...:role/aws-service-role/eks.amazonaws.com/AWSServiceRoleForAmazonEKS",
    "arn:aws:iam::25291...:role/eksNodeRole",
    "arn:aws:iam::252910...:user/CLUSTER_USER"
    ]
    }

    EKS 的 Access Policies 中有个内置的策略 AmazonEKSViewPolicy ,已经实现了只读效果(能 get / list / watch 不能 create / update / delete ),因此只需要创建新的 IAM access entry 并将 AmazonEKSViewPolicy 策略附加其上即可。

  3. 在客户端使用 IAM 用户 EKSReadOnlyUSER 的身份凭证登陆即可进行验证

    # kubectl get nodes
    Error from server (Forbidden): nodes is forbidden: User "arn:aws:iam::25....:user/EKSReadOnlyUSER" cannot list resource "nodes" in API group "" at the cluster scope

    # kubectl get pods
    NAME READY STATUS RESTARTS AGE
    netshoot-daemonset-s5sbr 1/1 Running 0 6h42m
    nginx-deployment-5746cdf7c8-9vw9w 1/1 Running 0 4h49m
    nginx-deployment-5746cdf7c8-j772t 1/1 Running 0 4h49m

如果 EKS 集群接入 Rancher 进行管理,可以直接通过 Rancher 的 RBAC 机制进行用户权限分配,会比 EKS 和原生 K8S 更加的直观方便。

启用 EKS 中的 Ingress 的 Access Log 记录

EKS 中创建的 Ingress 的 IngressClass 为 alb 时,AWS Load Balancer Controller 会为 Ingress 创建对应的 ALB(AWS Load Balancer),ALB 默认的访问日志(Access Logs)是关闭的。要 开启访问日志(Access Logs),需要通过修改 Kubernetes Ingress 资源的 Annotation(注解) 来实现

在 AWS 的架构设计中,S3 是 ALB 访问日志的法定落脚点。目前 ALB 的访问日志(七层请求详情)在 AWS 控制台或 API 配置中,仅支持写入 S3。它不支持直接推送至 CloudWatch Logs 或 Kinesis

因此要开启 ALB 的访问日志(七层请求详情),要首先准备好 S3 桶和权限。S3 要注意以下事项:

  • S3 Bucket 必须与 ALB 处于同一个 AWS 区域(例如都在 ap-southeast-1 新加坡)。
  • 如果 S3 配置不正确,日志投递会失败,但这绝不会影响 ALB 的正常流量转发。
  • ALB 将日志发送到同一个区域的 S3 是免收流量费的
  • 记得给 S3 设置 生命周期规则(Lifecycle Policy),比如 30 天后自动删除或转入冷存储,否则长期积累会导致存储费上涨。

参考以下步骤配置 S3,为 Application Load Balancer 启用访问日志官方文档

  1. 创建 S3 存储桶(Bucket), 桶的区域 (Region) 必须和 ALB 一致,该存储桶和负载均衡器可由不同的账户拥有

  2. 配置 Bucket Policy(存储桶策略),S3 存储桶必须具有为 Elastic Load Balancing 授予将访问日志写入存储桶的权限的存储桶策略

    在 Permissions (权限) 选项卡中,编辑 Bucket Policy。

    {
    "Version":"2012-10-17",
    "Statement": [
    {
    "Effect": "Allow",
    "Principal": {
    "Service": "logdelivery.elasticloadbalancing.amazonaws.com"
    },
    "Action": "s3:PutObject",
    "Resource": "arn:aws:s3:::<BUCKET NAME>/*"
    }
    ]
    }

然后修改 Ingress 配置。在 Ingress 中添加 Annotation

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
# 开启访问日志
alb.ingress.kubernetes.io/load-balancer-attributes: access_logs.s3.enabled=true,access_logs.s3.bucket=<你的-s3-bucket-名字>,access_logs.s3.prefix=<logs-prefix>
spec:
# ... 其他配置
  • alb.ingress.kubernetes.io/load-balancer-attributes: access_logs.s3.enabled=true,access_logs.s3.bucket=<你的-s3-bucket-名字>,access_logs.s3.prefix=<logs-prefix> 配置指定启用 Access Logs 写入 S3, 指定日志写入 S3 中的路径,多项目多集群可以按照项目或集群多目录分割,如 access_logs.s3.prefix=EKS_CLUSTER_A/PROJECT_A

部署 ALB 后,可在 AWS Console 中查看 ALB 中是否有日志传送相关配置, AWS Console -> EC2 -> Load balancers -> Attributes: Monitoring

当你修改了 EKS 的 Ingress Annotation 开启日志后,可以去 S3 桶里看看

  • 测试文件 : ALB 开启成功后的几分钟内,通常会先往桶里写入一个名为 ELBAccessLogTestFile 的文件。
  • 看到这个文件,就说明权限配置完全正确。

需要分析时可下载日志解压查看内容

http 2026-02-13T05:22:42.367084Z app/k8s-argocd-argocd-8e8cb645d5/026e67072db1ff28 54.254.220.119:57674 172.31.68.217:8080 0.000 -1 -1 460 - 1537 0 "GET http://k8s-argocd-argocd-8e8cb645d5-1951055800.ap-east-1.elb.amazonaws.com:80/api/v1/stream/applications?resourceVersion=3228300&fields=result.type%2Cresult.application.metadata.name%2Cresult.application.metadata.namespace%2Cresult.application.metadata.annotations%2Cresult.application.metadata.labels%2Cresult.application.metadata.creationTimestamp%2Cresult.application.metadata.deletionTimestamp%2Cresult.application.spec%2Cresult.application.operation.sync%2Cresult.application.status.sourceHydrator%2Cresult.application.status.sync.status%2Cresult.application.status.sync.revision%2Cresult.application.status.health%2Cresult.application.status.operationState.phase%2Cresult.application.status.operationState.finishedAt%2Cresult.application.status.operationState.operation.sync%2Cresult.application.status.summary%2Cresult.application.status.resources&selector=&appNamespace= HTTP/1.1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36" - - arn:aws:elasticloadbalancing:ap-east-1:252910564041:targetgroup/k8s-argocd-argocdse-b493e951a4/7f99bffde71cf22d "Root=1-698eb521-7f4353266a582d904a42b4a2" "-" "-" 1 2026-02-13T05:22:41.230000Z "forward" "-" "-" "172.31.68.217:8080" "-" "-" "-" TID_2642ce98c4c35148ad54404d5523a955 "-" "-" "-"

ALB 日志字段参考 :

  • type : 协议类型( http, https, h2, ws, wss )。
  • timestamp : ALB 收到请求并完成响应的时间。
  • elb : ALB 名称/资源 ID(app/k8s-argocd-argocd-8e8cb645d5/026e67072db1ff28
  • client:port : 发起请求的客户端 IP 和端口。
  • target:port : 后端 Target(Pod) 的私网 IP 和端口。 如果为 - 表示请求未到达后端。
  • request_processing_time : 请求处理时间
  • target_processing_time : 后端 Target(Pod) 的处理时间
  • response_processing_time : 响应处理时间
  • elb_status_code : ALB 返回给客户端的状态码。
  • target_status_code : 后端 Pod 返回的状态码。 如果是 - 说明 ALB 自己挂了或主动拦截了。
  • request_bytes : ALB 收到的字节数
  • response_bytes : ALB 发送给客户端的字节数。
  • request : 完整的 HTTP 请求行。
  • user_agent : 客户端浏览器信息。
  • ssl_cipher : SSL 加密套件和协议(非 HTTPS 请求则为 - )。
  • ssl_protocol : SSL 加密套件和协议(非 HTTPS 请求则为 - )。
  • target_group_arn : 处理该请求的 Target Group 的 ARN。
  • trace_id : X-Amzn-Trace-Id,可用于全链路追踪。
  • domain_name : 请求匹配的 Host 头部,如果没有 Host 匹配规则则为 -
  • chosen_cert_arn : 匹配到的 ACM 证书 ARN(HTTPS Listener)
  • matched_rule_priority : 匹配到的 Listener Rule 优先级
  • request_creation_time : ALB 接收到请求的时间
  • actions_executed : 执行的动作,可能值: forward, redirect, fixed-response, authenticate, waf
  • redirect_url : 如果执行 redirect ,显示重定向 URL
  • error_reason : 错误原因(当发生错误时),如 Target.ResponseCodeMismatch , Target.Timeout , ELB.5XX
  • target:port_list : 如果多个目标,列出所有目标
  • target_status_code_list : 多个目标返回状态码
  • classification : 请求分类,如 waf , monitoring , health-check
  • classification_reason : 分类原因说明

EKS 部署 Prometheus 监控

  • kube-prometheus-stack-82.2.0 helm Chart Version: v0.89.0

最标准的部署方式是使用 kube-prometheus-stack 。这套方案不仅包含 Prometheus 本身,还集成了 Operator、Grafana、告警管理以及预设的 K8s 监控面板。

可以参考以下配置文件 kube-prometheus-stack-values.yam 部署服务

kube-prometheus-stack-values.yam
#### 部署命令如下
# helm install eks-monitor prometheus-community/kube-prometheus-stack --namespace monitoring -f kube-prometheus-stack-values.yaml
#
### 更新配置命令如下
# helm upgrade eks-monitor prometheus-community/kube-prometheus-stack --namespace monitoring -f kube-prometheus-stack-values.yaml
#
## 禁用不需要的组件使用 enabled: false ,启用组件使用 enabled: true
## EKS 中无法监控 管理组件,直接 disable
kubeControllerManager:
enabled: false

kubeScheduler:
enabled: false

kubeEtcd:
enabled: false

kubeProxy:
enabled: false

## 启用核心指标采集组件
prometheusOperator:
enabled: true

# 收集 K8s 对象指标 (Deployment, Pod 状态等)
kube-state-metrics:
enabled: true

# 收集物理节点指标 (CPU, Mem, Disk)
prometheus-node-exporter:
enabled: true

# 收集 Kubelet 指标 (基础容器监控)
kubelet:
enabled: true

# 使用 AlertManager 发送告警消息,如果无需 AlertManager,配置 enabled: false
alertmanager:
enabled: true

alertmanagerSpec:
replicas: 1

config:
global:
resolve_timeout: 5m

route:
receiver: telegram
group_by: ['alertname', 'cluster']
group_wait: 10s
repeat_interval: 1h

receivers:
- name: 'null'
- name: telegram # 发送告警消息到 Telegram
telegram_configs:
- bot_token: "<TG_TOKEN>"
chat_id: <TG_GROUP_ID>
send_resolved: false
parse_mode: "HTML"
message: |
🚨 <b>{{ .CommonAnnotations.summary }}</b>

<b>Alert:</b> {{ .CommonLabels.alertname }}
<b>Cluster:</b> {{ .CommonLabels.cluster }}
<b>Namespace:</b> {{ .CommonLabels.namespace }}
<b>Severity:</b> {{ .CommonLabels.severity }}

<b>Description:</b>
{{ .CommonAnnotations.description }}

## Prometheus 默认配置了很多告警规则,如果想要禁用某些告警规则,可以参考以下配置
## 如果想要查看 Prometheus 规则集和具体规则,参考以下命令
## 查看 Prometheus 规则集
# $ kubectl get prometheusrules -n monitoring

## 查看规则集中的具体规则,如规则集 eks-monitor-kube-prometheu-kubernetes-resources,里面也包含了规则名称,下面禁用具体规则时需要使用,这些内容也可以在 Prometheus Explorer 中的 Alerts 中查看
# $ kubectl get prometheusrule eks-monitor-kube-prometheu-kubernetes-resources -n monitoring -o yaml

## 禁用特定的默认告警规则 (添加在这里)
defaultRules:
disabled:
KubeCPUOvercommit: true
KubeMemoryOvercommit: true


## Prometheus 实例配置
prometheus:
enabled: true

strategy:
type: Recreate # 将默认的 RollingUpdate 改为 Recreate,Recreate 策略会先杀掉旧的 Pod,释放存储挂载,然后再启动新 Pod。这在单副本且使用物理卷(EBS/PVC)时非常安全
prometheusSpec:
# 自动发现 ServiceMonitor
serviceMonitorSelectorNilUsesHelmValues: false
# 数据保留时长
retention: 7d
# 存储配置 (根据需要修改,这里使用 gp3)
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
externalLabels: # 添加额外标签。要注意此 Label 不会直接注入到 Prometheus 本地抓取(Scrape)的原始指标中。比如通过 Prometheus Explorer 或者 Grafana 接入不会看到此处的标签
cluster: <集群标识> # 主要用于 Federation(级联)、Remote Write(远程写入,如发给 Thanos/Mimir/Amazon Managed Prometheus) 以及 Alertmanager(告警)。
# 当 Prometheus 将数据“发送”到外部系统时,它会带上这个标签,用于区分数据来源。


# 暴露 Prometheus 给外部访问
service:
type: ClusterIP # 配合 Ingress 对外暴露服务
port: 9090
targetPort: 9090

ingress:
enabled: true

ingressClassName: alb
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/healthcheck-path: /-/healthy

paths:
- /
pathType: Prefix

# Grafana 配置,如果要启用 Grafan,配置 enabled: true
grafana:
enabled: false


service:
type: ClusterIP
port: 3000
targetPort: 3000

ingress:
enabled: true

ingressClassName: alb
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/healthcheck-path: /api/health

path: /
pathType: Prefix


执行部署

# 添加仓库
$ helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
"prometheus-community" has been added to your repositories

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "prometheus-community" chart repository
Update Complete. ⎈Happy Helming!⎈

# 创建命名空间
$ kubectl create namespace monitoring
namespace/monitoring created

# 部署

$ helm install eks-monitor prometheus-community/kube-prometheus-stack --namespace monitoring -f eks-monitor-kube-prometheus-stack-values.yaml
NAME: eks-monitor
LAST DEPLOYED: Fri Feb 13 16:53:08 2026
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
DESCRIPTION: Install complete
TEST SUITE: None
NOTES:
kube-prometheus-stack has been installed. Check its status by running:
kubectl --namespace monitoring get pods -l "release=eks-monitor"

Get Grafana 'admin' user password by running:

kubectl --namespace monitoring get secrets eks-monitor-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo

Access Grafana local instance:

export POD_NAME=$(kubectl --namespace monitoring get pod -l "app.kubernetes.io/name=grafana,app.kubernetes.io/instance=eks-monitor" -oname)
kubectl --namespace monitoring port-forward $POD_NAME 3000

Get your grafana admin user password by running:

kubectl get secret --namespace monitoring -l app.kubernetes.io/component=admin-secret -o jsonpath="{.items[0].data.admin-password}" | base64 --decode ; echo


Visit https://github.com/prometheus-operator/kube-prometheus for instructions on how to create & configure Alertmanager and Prometheus instances using the Operator.

检查相关资源

$ kubectl get pods,svc,ingresses -n monitoring
NAME READY STATUS RESTARTS AGE
pod/eks-monitor-kube-prometheu-operator-7c44f5855b-bshnl 1/1 Running 0 17m
pod/eks-monitor-kube-state-metrics-f85cbcc45-9d5kj 1/1 Running 0 17m
pod/eks-monitor-prometheus-node-exporter-fdr48 1/1 Running 0 17m
pod/eks-monitor-prometheus-node-exporter-h8cf7 1/1 Running 0 17m
pod/eks-monitor-prometheus-node-exporter-vclx7 1/1 Running 0 17m

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/eks-monitor-kube-prometheu-operator ClusterIP 10.100.10.252 <none> 443/TCP 17m
service/eks-monitor-kube-prometheu-prometheus ClusterIP 10.100.170.77 <none> 9090/TCP,8080/TCP 17m
service/eks-monitor-kube-state-metrics ClusterIP 10.100.148.216 <none> 8080/TCP 17m
service/eks-monitor-prometheus-node-exporter ClusterIP 10.100.82.224 <none> 9100/TCP 17m

NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/prometheus-ingress alb * k8s-monitori-promethe-36bab4990d-682688554.ap-east-1.elb.amazonaws.com 80 3m58s

相关案例或错误排查

自治模式创建的集群无法部署 Pod 上去

自治模式(EKS Auto Mode)的集群节点上,默认会为节点配置特定的 污点(Taints) ,如果 Pod 配置中没有设置对应的 Tolerations(容忍度),Pod 会无法调度到对应的节点上去。

比如以下 DaemonSet 配置,在 EKS 集群上可能无法成功部署

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: netshoot-daemonset
labels:
app: netshoot
spec:
selector:
matchLabels:
name: netshoot
template:
metadata:
labels:
name: netshoot
spec:
# 如果你需要调试节点主机的网络(如查看 NAT 路由),开启下面这行
# hostNetwork: true
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["/bin/bash"]
args: ["-c", "while true; do sleep 30; done"]
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 10m
memory: 64Mi

查看 DaemonSet 状态

# kubectl describe daemonset netshoot-daemonset
Name: netshoot-daemonset
Namespace: default
Selector: name=netshoot
Node-Selector: <none>
Labels: app=netshoot
Annotations: deprecated.daemonset.template.generation: 1
Desired Number of Nodes Scheduled: 0
Current Number of Nodes Scheduled: 0
Number of Nodes Scheduled with Up-to-date Pods: 0
Number of Nodes Scheduled with Available Pods: 0
Number of Nodes Misscheduled: 0
Pods Status: 0 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: name=netshoot
Containers:
netshoot:
Image: nicolaka/netshoot
Port: <none>
Host Port: <none>
Command:
/bin/bash
Args:
-c
while true; do sleep 30; done
Limits:
cpu: 100m
memory: 128Mi
Requests:
cpu: 10m
memory: 64Mi
Environment: <none>
Mounts: <none>
Volumes: <none>
Node-Selectors: <none>
Tolerations: <none>
Events: <none>

其中没有可调度的节点

Desired Number of Nodes Scheduled: 0
Current Number of Nodes Scheduled: 0

检查节点的 Taints 信息,可以看到节点配置了 Taints effect:NoSchedule key:CriticalAddonsOnly

# kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
NAME TAINTS
i-008751c [map[effect:NoSchedule key:CriticalAddonsOnly]]
i-0256d1d [map[effect:NoSchedule key:CriticalAddonsOnly]]

为了让 Pod 能调度到此节点上去,可以为 DaemonSet 配置添加 Tolerations

apiVersion: apps/v1
kind: DaemonSet
metadata:
name: netshoot-daemonset
spec:
selector:
matchLabels:
name: netshoot
template:
metadata:
labels:
name: netshoot
spec:
# --- 添加以下容忍度以匹配你的节点污点 ---
tolerations:
- key: "CriticalAddonsOnly"
operator: "Exists"
# 如果你希望它更“强悍”,能上任何节点,也可以用下面这个全能配置:
# - operator: "Exists"
# ---------------------------------------
containers:
- name: netshoot
image: nicolaka/netshoot
command: ["/bin/bash"]
args: ["-c", "while true; do sleep 30; done"]
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 10m
memory: 64Mi

EKS 部署 Nginx 服务并在互联网上可以访问

本示例中的 Worker Nodes 和 Pod 子网为 私有子网 (Private Subnet),通过 NAT Gateway 访问互联网

首先要确保 EKS 集群的 AWS Load Balancer Controller 正常安装,才能通过 ALB 对外提供服务。

参考以下配置文件,部署 Nginx 服务相关资源

nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
# 容忍度配置:确保 Pod 能调度到带有 CriticalAddonsOnly 污点的节点上
tolerations:
- operator: "Exists"
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
resources:
requests:
cpu: 100m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: ClusterIP

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
# 负载均衡器是面向互联网的
alb.ingress.kubernetes.io/scheme: internet-facing
# 目标类型:在 Auto Mode 下推荐使用 ip 模式,直接转发给 Pod
alb.ingress.kubernetes.io/target-type: ip
# 自动关联你之前规划的子网(可选,通常通过标签 kubernetes.io/role/internal-elb = 1 自动发现)
# alb.ingress.kubernetes.io/subnets: subnet-xxxx, subnet-yyyy
spec:
# 指定使用 aws ALB
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80

使用以下命令部署服务

kubectl apply -f nginx.yaml

部署后检查服务相关服务状态

# kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-5746cdf7c8-9vw9w 1/1 Running 0 41h 172.31.129.84 i-02d6d78308d456d1d <none> <none>
nginx-deployment-5746cdf7c8-j772t 1/1 Running 0 41h 172.31.129.83 i-02d6d78308d456d1d <none> <none>

# kubectl get services -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.100.0.1 <none> 443/TCP 3d15h <none>
nginx-service ClusterIP 10.100.197.117 <none> 80/TCP 41h app=nginx

# kubectl get endpointslice -o wide
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
kubernetes IPv4 443 172.31.138.166,172.31.78.162 3d15h
nginx-service-dnckv IPv4 80 172.31.129.83,172.31.129.84 41h

# kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress alb * k8s-default-nginxing-f6eb483edf-2017046049.ap-east-1.elb.amazonaws.com 80 41h

部署成功后,AWS Load Balancer Controller(LBC) 会为服务生成 ALB(AWS Load Balancer)地址,通过此地址(k8s-default-nginxing-f6eb483edf-2017046049.ap-east-1.elb.amazonaws.com) 即可在互联网上访问此服务。

如果需要绑定自己的域名,参考以下步骤:

  • 如果域名 NS 指向 AWS Route 53(域名解析在 AWS Route 53),在 Route 53 选择自有域名,添加/修改解析

    Record Type: A
    Alias:✅ 打开
    Alias target: ALB DNS(`k8s-default-nginxing-f6eb483edf-2017046049.ap-east-1.elb.amazonaws.com`)
    Routing policy:Simple

  • 如果域名 NS 不是指向 AWS Route 53(域名解析未在 AWS Route 53),就用 CNAME

    Record Type: CNAME
    CNAME Value: ALB DNS(`k8s-default-nginxing-f6eb483edf-2017046049.ap-east-1.elb.amazonaws.com`)

本示例中的 Ingress 未指定域名(HOSTS: *),任意域名解析到此 ALB 都会命中 nginx 服务

 kubectl get ingress -o wide
NAME CLASS HOSTS ADDRESS PORTS AGE
nginx-ingress alb * k8s-default-nginxing-f6eb483edf-2017046049.ap-east-1.elb.amazonaws.com 80 41h

如果需要为 Ingress 绑定特定域名,使用 host 参数,如 host: www.example.com

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
# 负载均衡器是面向互联网的
alb.ingress.kubernetes.io/scheme: internet-facing
# 目标类型:在 Auto Mode 下推荐使用 ip 模式,直接转发给 Pod
alb.ingress.kubernetes.io/target-type: ip
# 自动关联你之前规划的子网(可选,通常通过标签 kubernetes.io/role/internal-elb = 1 自动发现)
# alb.ingress.kubernetes.io/subnets: subnet-xxxx, subnet-yyyy
spec:
# 指定使用 aws ALB
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
host: www.example.com

绑定特定域名后查看 Ingress

# kubectl get ingress
NAME CLASS HOSTS ADDRESS
nginx-ingress alb www.example.com k8s-default-nginxing-xxx.elb.amazonaws.com

此时,只有 www.example.com 可以访问,其他域名访问会返回 404.

ALB 域名无法访问排查步骤

部署了 IngressClassName: alb 类型的 Ingress 后,无法正常访问

$ kubectget ingress -A -o wide
NAMESPACE NAME CLASS HOSTS ADDRESS PORTS AGE
argocd argocd alb * k8s-argocd-argocd-8e8cb645d5-1951055800.ap-east-1.elb.amazonaws.com 80 122m

此时可以先检查 AWS Load Balancer 中对应自由的状态,登录 AWS 控制台 -> EC2 -> Load Balancers ,检查对应的 ALB 状态:

  • ALB 的 State 是否为 Active ,如果是 ProvisioningFailed ,说明还在创建中或配置有误。
  • 检查监听器 (Listeners) 是否监听了对应的端口
  • 检查安全组 (Security Groups) 是否放通了相关端口
  • 检查 Resource Map ,看后端 Targets 是否检测正常
  • AWS 控制台 -> EC2 -> Target Groups 中检查相关的后端 Target (Pod)是否正常

Pod 挂载 EBS PV 失败

Pod 状态不正常

$ kubectl get PODS -n monitoring
NAME READY STATUS RESTARTS AGE
prometheus-eks-monitor-kube-prometheu-prometheus-0 0/2 Pending 0 13m


$ kubectl describe pod -n monitoring prometheus-eks-monitor-kube-prometheu-prometheus-0
Name: prometheus-eks-monitor-kube-prometheu-prometheus-0
Namespace: monitoring
Priority: 0
Service Account: eks-monitor-kube-prometheu-prometheus
Node: <none>
Labels: app.kubernetes.io/instance=eks-monitor-kube-prometheu-prometheus
app.kubernetes.io/managed-by=prometheus-operator
app.kubernetes.io/name=prometheus
app.kubernetes.io/version=3.9.1
apps.kubernetes.io/pod-index=0
controller-revision-hash=prometheus-eks-monitor-kube-prometheu-prometheus-569cf67d6d
operator.prometheus.io/name=eks-monitor-kube-prometheu-prometheus
operator.prometheus.io/shard=0
prometheus=eks-monitor-kube-prometheu-prometheus
statefulset.kubernetes.io/pod-name=prometheus-eks-monitor-kube-prometheu-prometheus-0
Annotations: kubectl.kubernetes.io/default-container: prometheus
Status: Pending
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 4m default-scheduler running PreBind plugin "VolumeBinding": binding volumes: context deadline exceeded


Pod 状态 Pending ,报错 running PreBind plugin "VolumeBinding": binding volumes: context deadline exceeded

错误指向 存储绑定失败 ,接着检查存储相关

$ kubectl get STORAGECLASS
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp2 kubernetes.io/aws-ebs Delete WaitForFirstConsumer false 7d


$ kubectl get pvc -n monitoring
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
prometheus-eks-monitor-kube-prometheu-prometheus-db-prometheus-eks-monitor-kube-prometheu-prometheus-0 Pending gp2 <unset> 16m

$ kubectl describe pvc -n monitoring prometheus-eks-monitor-kube-prometheu-prometheus-db-prometheus-eks-monitor-kube-prometheu-prometheus-0
Name: prometheus-eks-monitor-kube-prometheu-prometheus-db-prometheus-eks-monitor-kube-prometheu-prometheus-0
Namespace: monitoring
StorageClass: gp2
Status: Pending
Volume:
Labels: app.kubernetes.io/instance=eks-monitor-kube-prometheu-prometheus
app.kubernetes.io/managed-by=prometheus-operator
app.kubernetes.io/name=prometheus
operator.prometheus.io/name=eks-monitor-kube-prometheu-prometheus
operator.prometheus.io/shard=0
prometheus=eks-monitor-kube-prometheu-prometheus
Annotations: volume.beta.kubernetes.io/storage-provisioner: ebs.csi.aws.com
volume.kubernetes.io/selected-node: i-088a321d769903fec
volume.kubernetes.io/storage-provisioner: ebs.csi.aws.com
Finalizers: [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode: Filesystem
Used By: prometheus-eks-monitor-kube-prometheu-prometheus-0
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal WaitForFirstConsumer 16m persistentvolume-controller waiting for first consumer to be created before binding
Normal ExternalProvisioning 84s (x63 over 16m) persistentvolume-controller Waiting for a volume to be created either by the external provisioner 'ebs.csi.aws.com' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.

EKS 默认不包含 EBS 驱动。如果没有驱动,Kubernetes 无法调用 AWS API 去创建 EBS 磁盘。 检查 AWS EBS CSI 驱动是否运行

$ kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-ebs-csi-driver
No resources found in kube-system namespace.

以上结果说明 EKS 中未安装 EBS CSI 驱动,需要为 EKS 安装这个 Add-on

加入 PVC 报错信息如下:

Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ExternalProvisioning 3m52s (x463 over 119m) persistentvolume-controller Waiting for a volume to be created either by the external provisioner 'ebs.csi.aws.com' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.
Normal Provisioning 2m34s (x15 over 49m) ebs.csi.aws.com_ebs-csi-controller-6849f9b895-84wdt_d7687021-7146-4198-ba00-c42d48ee814b External provisioner is provisioning volume for claim "monitoring/prometheus-eks-monitor-kube-prometheu-prometheus-db-prometheus-eks-monitor-kube-prometheu-prometheus-0"
Warning ProvisioningFailed 2m34s (x15 over 49m) ebs.csi.aws.com_ebs-csi-controller-6849f9b895-84wdt_d7687021-7146-4198-ba00-c42d48ee814b error generating accessibility requirements: no topology key found for node i-088a321d769903fec

说明 AWS EBS CSI 驱动工作正常,但是 EBS CSI 驱动想要创建磁盘,但它 不知道这个节点到底在哪个可用区 (Availability Zone) 。EBS 磁盘是不能跨可用区挂载的。正常情况下,节点应该带有 topology.ebs.csi.aws.com/zone 标签,驱动靠这个标签来决定在哪个 AZ 创建磁盘。

这种情况在 手动创建节点EBS CSI 驱动在节点加入集群后才安装 时经常发生。节点上的 CSI 插件没有正确上报拓扑信息。

检查 StorageClass 配置

$ kubectl get storageclass gp2 -o yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"storage.k8s.io/v1","kind":"StorageClass","metadata":{"annotations":{},"name":"gp2"},"parameters":{"fsType":"ext4","type":"gp2"},"provisioner":"kubernetes.io/aws-ebs","volumeBindingMode":"WaitForFirstConsumer"}
creationTimestamp: "2026-02-06T09:35:14Z"
name: gp2
resourceVersion: "258"
uid: 4cde6368-d05a-44da-addc-9fca4d7c6fb0
parameters:
fsType: ext4
type: gp2
provisioner: kubernetes.io/aws-ebs
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer

其中的 provisioner: kubernetes.io/aws-ebs ,这是过时的旧的内建驱动,已被废弃,且无法识别 CSI 驱动特有的拓扑标签(即报错中的 topology.ebs.csi.eks.amazonaws.com/zone )。它在较新的 K8s 版本中兼容性较差。 使用新的 EBS CSI 驱动 ( ebs.csi.aws.com )

删除旧的 storageclass gp2


$ kubectl delete storageclass gp2
storageclass.storage.k8s.io "gp2" deleted

创建正确的 CSI StorageClass ,使用 provisioner: ebs.csi.aws.com

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
volumeBindingMode: WaitForFirstConsumer

查看新的 StorageClass

$ kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
gp3-csi ebs.csi.aws.com Delete WaitForFirstConsumer false 5s

之后 PVC 依旧报错

Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal WaitForPodScheduled 107s persistentvolume-controller waiting for pod prometheus-eks-monitor-kube-prometheu-prometheus-0 to be scheduled
Normal Provisioning 44s (x7 over 107s) ebs.csi.aws.com_ebs-csi-controller-6849f9b895-tpbhp_e1da4dcf-1ddf-49f7-9b83-b3973b11647f External provisioner is provisioning volume for claim "monitoring/prometheus-eks-monitor-kube-prometheu-prometheus-db-prometheus-eks-monitor-kube-prometheu-prometheus-0"
Warning ProvisioningFailed 44s (x7 over 107s) ebs.csi.aws.com_ebs-csi-controller-6849f9b895-tpbhp_e1da4dcf-1ddf-49f7-9b83-b3973b11647f error generating accessibility requirements: no topology key found for node i-019f302416033febc
Normal ExternalProvisioning 1s (x9 over 107s) persistentvolume-controller Waiting for a volume to be created either by the external provisioner 'ebs.csi.aws.com' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.

这大概率是因为只有 ebs-csi-controller 而没有 ebs-csi-node 。CSI 驱动依赖一个叫做 CSINode 的集群资源来识别节点支持哪些驱动及其所在区域。确保每个节点对应的 ebs-csi-node-xxxx 都是 Running 状态。

$ kubectl get pods -n kube-system 
NAME READY STATUS RESTARTS AGE
aws-load-balancer-controller-949f9d848-8d8nt 1/1 Running 0 45m
aws-load-balancer-controller-949f9d848-nzkz7 1/1 Running 0 45m
ebs-csi-controller-6849f9b895-fx42c 6/6 Running 0 43m
ebs-csi-controller-6849f9b895-tpbhp 6/6 Running 0 45m
metrics-server-5bb789d889-7n2vv 1/1 Running 0 45m
metrics-server-5bb789d889-vx5bl 1/1 Running 0 44m

没有 ebs-csi-node DaemonSet