跳过正文

AWS EKS 实战指南

·877 字·5 分钟·
目录

EKS 架构概述
#

EKS(Elastic Kubernetes Service)托管控制面,AWS 负责 etcd、API Server、Controller Manager、Scheduler 的高可用和版本维护,用户只需管理数据面(Worker Node)。

三种计算模式对比
#

模式适用场景成本模型限制
托管节点组(Managed Node Group)通用工作负载EC2 按需/Spot需维护 AMI 版本
自管节点组(Self-managed)需要定制内核/AMIEC2完全自管升级
Fargate无状态、短生命周期vCPU+内存按用计费不支持 DaemonSet、HostPath

Fargate 最大的坑:每个 Pod 独占一个 micro VM,调度延迟较高,且无法运行需要宿主机挂载的 DaemonSet(如 Fluent Bit node-level 采集)。


eksctl 常用操作
#

创建集群
#

eksctl create cluster \
  --name prod-cluster \
  --region us-west-2 \
  --version 1.30 \
  --nodegroup-name standard-workers \
  --node-type m5.xlarge \
  --nodes 3 \
  --nodes-min 2 \
  --nodes-max 10 \
  --managed \
  --with-oidc \
  --ssh-access \
  --ssh-public-key ~/.ssh/id_rsa.pub

--with-oidc 是关键参数,不加的话后续 IRSA 无法用。

用配置文件创建(推荐生产环境)
#

# cluster.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: prod-cluster
  region: us-west-2
  version: "1.30"

iam:
  withOIDC: true

managedNodeGroups:
  - name: ng-general
    instanceType: m5.xlarge
    minSize: 2
    maxSize: 20
    desiredCapacity: 3
    volumeSize: 100
    volumeType: gp3
    privateNetworking: true
    labels:
      role: general
    tags:
      k8s.io/cluster-autoscaler/enabled: "true"
      k8s.io/cluster-autoscaler/prod-cluster: "owned"
    iam:
      attachPolicyARNs:
        - arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
        - arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
        - arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
eksctl create cluster -f cluster.yaml

节点组扩缩
#

# 手动调整节点数
eksctl scale nodegroup \
  --cluster prod-cluster \
  --name ng-general \
  --nodes 5 \
  --nodes-min 2 \
  --nodes-max 20

# 查看节点组状态
eksctl get nodegroup --cluster prod-cluster

# 滚动更新节点组(AMI 更新后)
eksctl upgrade nodegroup \
  --cluster prod-cluster \
  --name ng-general \
  --force-upgrade

删除节点组
#

# 先 drain 节点,再删除
eksctl delete nodegroup \
  --cluster prod-cluster \
  --name ng-old \
  --drain

aws cli 操作 EKS
#

更新 kubeconfig
#

# 更新本地 kubeconfig
aws eks update-kubeconfig \
  --name prod-cluster \
  --region us-west-2

# 指定 profile
aws eks update-kubeconfig \
  --name prod-cluster \
  --region us-west-2 \
  --profile prod-account

# 重命名 context
aws eks update-kubeconfig \
  --name prod-cluster \
  --region us-west-2 \
  --alias eks-prod

获取 token(调试用)
#

# 获取临时 token(有效期 15 分钟)
aws eks get-token --cluster-name prod-cluster

# 查看集群信息
aws eks describe-cluster --name prod-cluster --region us-west-2

# 列出所有集群
aws eks list-clusters --region us-west-2

EKS Add-on 管理
#

EKS Add-on 是 AWS 托管的核心组件,支持独立版本管理,不跟集群版本强绑定。

核心 Add-on
#

# 查看已安装的 add-on
aws eks list-addons --cluster-name prod-cluster

# 查看某个 add-on 的支持版本
aws eks describe-addon-versions \
  --addon-name vpc-cni \
  --kubernetes-version 1.30

# 创建/更新 add-on
aws eks create-addon \
  --cluster-name prod-cluster \
  --addon-name vpc-cni \
  --addon-version v1.18.1-eksbuild.3 \
  --resolve-conflicts OVERWRITE

# 更新到最新版本
aws eks update-addon \
  --cluster-name prod-cluster \
  --addon-name coredns \
  --addon-version v1.11.1-eksbuild.9 \
  --resolve-conflicts PRESERVE

常用 Add-on 版本对应关系(K8s 1.30)
#

Add-on推荐版本说明
vpc-cniv1.18.xENI/IP 分配
corednsv1.11.x集群 DNS
kube-proxyv1.30.xiptables/ipvs 规则
aws-ebs-csi-driverv1.35.xEBS 存储
aws-efs-csi-driverv2.0.xEFS 共享存储

IRSA:IAM Roles for Service Accounts
#

原理
#

IRSA 通过 OIDC 联合身份实现 Pod 级别的 AWS 权限,无需在 EC2 上绑定大权限 Instance Profile。

流程:

  1. EKS 集群暴露 OIDC Issuer URL
  2. 创建 IAM Role,信任策略引用该 OIDC Provider
  3. K8s ServiceAccount 通过 annotation 绑定 IAM Role ARN
  4. Pod 启动时 EKS Pod Identity webhook 注入临时凭据(AWS_WEB_IDENTITY_TOKEN_FILE
  5. AWS SDK 自动读取 token 并调用 STS 换取临时 AK/SK

配置步骤
#

# 1. 确认 OIDC provider 已创建
aws iam list-open-id-connect-providers

# 2. 获取集群 OIDC issuer
OIDC_URL=$(aws eks describe-cluster \
  --name prod-cluster \
  --query "cluster.identity.oidc.issuer" \
  --output text)
echo $OIDC_URL
# 输出类似: https://oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE

# 3. 用 eksctl 快速创建 IRSA
eksctl create iamserviceaccount \
  --cluster prod-cluster \
  --namespace default \
  --name my-service-sa \
  --attach-policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess \
  --approve

手动创建 IAM Role 信任策略
#

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:default:my-service-sa",
          "oidc.eks.us-west-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com"
        }
      }
    }
  ]
}

K8s 侧配置
#

apiVersion: v1
kind: ServiceAccount
metadata:
  name: my-service-sa
  namespace: default
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/my-irsa-role

Pod 引用该 ServiceAccount 后,会自动注入:

env:
- name: AWS_WEB_IDENTITY_TOKEN_FILE
  value: /var/run/secrets/eks.amazonaws.com/serviceaccount/token
- name: AWS_ROLE_ARN
  value: arn:aws:iam::123456789012:role/my-irsa-role

网络:VPC CNI 与 IP 限制
#

ENI IP 数量限制
#

EKS 默认使用 VPC CNI,每个 Pod 占用一个 VPC IP。每种 EC2 实例类型的 ENI 数量和每个 ENI 的 IP 数量有上限:

最大 Pod 数 = (ENI 数量 × 每 ENI IP 数) - 1

常见实例型的限制:

实例类型最大 ENI每 ENI IP最大 Pod 数
t3.medium3617
m5.large31029
m5.xlarge41558
m5.4xlarge830234

突破 IP 限制:prefix delegation
#

启用 prefix delegation 后每个 ENI 可以分配 /28 前缀(16 个 IP),大幅提升 Pod 密度:

# 启用 prefix delegation
kubectl set env daemonset aws-node \
  -n kube-system \
  ENABLE_PREFIX_DELEGATION=true \
  WARM_PREFIX_TARGET=1

EKS 升级流程
#

升级顺序:控制面 → Add-on → 节点组,不能跨版本跳升。

# 1. 升级控制面
aws eks update-cluster-version \
  --name prod-cluster \
  --kubernetes-version 1.31

# 等待升级完成
aws eks wait cluster-active --name prod-cluster

# 2. 升级 add-on
aws eks update-addon \
  --cluster-name prod-cluster \
  --addon-name vpc-cni \
  --addon-version v1.19.0-eksbuild.1

# 3. 升级节点组(触发滚动替换)
eksctl upgrade nodegroup \
  --cluster prod-cluster \
  --name ng-general \
  --kubernetes-version 1.31

常见问题排查
#

节点加入失败
#

# 查看节点状态
kubectl get nodes
kubectl describe node <node-name>

# 检查 bootstrap 日志(在节点上)
sudo cat /var/log/cloud-init-output.log
sudo journalctl -u kubelet -f

# 常见原因:
# 1. 安全组没有开放 443 到控制面
# 2. aws-auth ConfigMap 没有添加节点组 Role
kubectl edit configmap aws-auth -n kube-system

aws-auth 正确格式:

apiVersion: v1
kind: ConfigMap
metadata:
  name: aws-auth
  namespace: kube-system
data:
  mapRoles: |
    - rolearn: arn:aws:iam::123456789012:role/eksctl-prod-cluster-NodeInstanceRole
      username: system:node:{{EC2PrivateDNSName}}
      groups:
        - system:bootstrappers
        - system:nodes

IRSA 权限问题排查
#

# 在 Pod 内验证身份
kubectl exec -it <pod> -- aws sts get-caller-identity

# 预期输出
{
    "UserId": "AROA...:botocore-session-...",
    "Account": "123456789012",
    "Arn": "arn:aws:sts::123456789012:assumed-role/my-irsa-role/botocore-session-..."
}

# 检查 token 文件是否注入
kubectl exec -it <pod> -- env | grep AWS
# 应该看到 AWS_ROLE_ARN 和 AWS_WEB_IDENTITY_TOKEN_FILE

# 常见原因:
# 1. ServiceAccount annotation 拼错 role ARN
# 2. IAM 信任策略中 sub 条件与实际 namespace/sa 名称不匹配
# 3. Pod 没有引用正确的 ServiceAccount

Pod 调度到错误节点组
#

# 给节点组打 taint 隔离工作负载
kubectl taint nodes -l role=gpu dedicated=gpu:NoSchedule

# Pod 侧加 toleration
tolerations:
- key: "dedicated"
  operator: "Equal"
  value: "gpu"
  effect: "NoSchedule"
nodeSelector:
  role: gpu
Wenzhuo Huang
作者
Wenzhuo Huang
搞运维的工程师,写代码的运维人。专注 Kubernetes、AWS、GitOps 与基础设施可靠性。这个博客既是我的技术笔记本,也是我踩过的坑的受害者档案。

相关文章

AWS EKS 生产实践:网络、安全与多集群管理

·792 字·4 分钟
管理多套 EKS 集群两年下来,踩了不少坑。本文系统整理网络选型、IAM 权限、节点管理、集群升级、安全加固和成本控制这六个核心话题,每个话题都有具体配置示例和实际遇到的问题。

Kubernetes 集群升级实践

·1554 字·8 分钟
K8s 集群升级全流程:从版本兼容性检查、etcd 备份、EKS 托管升级命令,到节点蓝绿替换、PDB 配置、pluto 工具检测废弃 API,再到常见升级问题处理。

Karpenter 弹性节点管理实战

·1734 字·9 分钟
Karpenter 替代 Cluster Autoscaler 的完整实践:NodePool 约束配置、EC2NodeClass 实例选型、consolidation 节点整合降本、Spot 实例容错,以及多套集群配置的组织方式。