生产环境EKS集群五大支柱:网络、安全、可观测性、成本与备份

📅 2026/7/16 3:50:32 👁️ 阅读次数 📝 编程学习
生产环境EKS集群五大支柱:网络、安全、可观测性、成本与备份

1. 为什么生产环境EKS集群不能“照着教程点点点”就完事?

“生产环境AWS EKS/K8s集群搭建全流程,看完这篇直接上手”——这个标题里藏着一个巨大的认知陷阱。很多刚接触云原生的工程师,看到“全流程”“直接上手”就以为能像装个Ubuntu桌面一样,复制粘贴几条命令、点点控制台按钮,集群就稳稳当当地跑起来了。我2019年第一次在客户现场部署EKS时,也是这么想的。结果呢?集群创建成功了,kubectl get nodes返回了3个节点,kubectl get svc也看到了kubernetes服务,但第二天业务上线,第一个API请求就超时,监控面板一片红,日志里全是Connection refusedi/o timeout。排查了整整36小时,最后发现是VPC子网路由表里漏配了一条指向NAT网关的默认路由——而这条路由,在AWS官方文档里被埋在“VPC网络设计最佳实践”的第7节附录B里,连个加粗都没有。

这就是生产环境和测试环境最本质的区别:测试环境只验证“能不能跑”,生产环境必须回答“能不能扛住、能不能稳住、能不能快速恢复”。EKS本身是个托管服务,AWS替你管好了控制平面(Control Plane)的高可用和安全补丁,但这绝不意味着你就能当甩手掌柜。恰恰相反,EKS把最关键的“责任共担模型”(Shared Responsibility Model)划得比任何其他AWS服务都更清晰:AWS负责Kubernetes API Server、etcd、Scheduler这些组件的可用性与安全;而你,必须对网络拓扑、节点配置、安全策略、可观测性、备份恢复、成本治理这五大支柱负全责。这五大支柱,任何一个环节出问题,轻则服务抖动,重则整个业务系统雪崩。

举个最典型的例子:很多人在创建集群时,图省事直接用eksctl的--vpc-private-subnets参数指定两个私有子网,却忽略了子网的“可用区分布”要求。AWS要求EKS集群的私有子网必须跨至少两个可用区(AZ),这是为了确保当某个AZ发生故障时,你的工作节点(Worker Node)不会全部挂掉。但如果你只指定了同一个AZ里的两个子网(比如us-east-1a里的subnet-01和subnet-02),表面上集群创建成功了,describe-cluster返回ACTIVE,但一旦那个AZ宕机,你的所有Pod瞬间失联,而Kubernetes的自我修复机制根本无从下手——因为底层EC2实例已经物理不可达了。这种问题,在测试环境里永远暴露不出来,只有在真实流量洪峰下才会血淋淋地打脸。

再比如“直接上手”这个词,它暗示着一种零门槛的幻觉。但现实是,一个合格的生产级EKS集群,其复杂度远超一个简单的Kubernetes安装包。你需要理解:为什么VPC的CIDR块不能和Kubernetes Service CIDR重叠?为什么CoreDNS的副本数要根据集群规模动态调整?为什么Node Security Group必须严格限制入站规则,连SSH端口都不能开放?为什么kube-proxy的模式选择(iptables vs ipvs)会直接影响Service的连接建立延迟?这些问题,没有一个是eksctl create cluster命令能自动帮你决策的。它们背后是网络工程、操作系统内核、分布式系统原理的深度交织。所以,这篇博文不叫“EKS快速入门”,而叫“生产环境EKS集群搭建全流程”——流程不是线性的步骤清单,而是围绕五大支柱构建的一套防御纵深体系。接下来,我会带你一层层拆解,每一步都告诉你“为什么必须这么做”,而不是“应该怎么做”。

2. 核心细节解析:生产环境五大支柱的底层逻辑与实操铁律

生产环境EKS集群的稳定性,不取决于你用了多少酷炫的新特性,而取决于你是否在五大支柱上筑起了足够高的墙。这五大支柱不是并列关系,而是存在严格的依赖链条:网络是地基,安全是围墙,可观测性是哨兵,成本是血液,备份是保险。任何一环的缺失或薄弱,都会成为整个系统的单点故障。下面我将逐个拆解,不仅告诉你该做什么,更要讲透背后的“为什么”。

2.1 网络支柱:VPC与子网设计——不是选填题,是必答题

很多人把VPC当成一个“容器”,只要把集群塞进去就行。这是致命误区。VPC是EKS集群的“呼吸系统”,它的设计直接决定了集群的生死存亡。

核心逻辑:EKS集群的网络通信分为三个层面:控制平面(Control Plane)与工作节点(Worker Node)之间的通信、工作节点与Pod之间的通信、Pod与外部世界(互联网或VPC内其他服务)的通信。这三个层面,全部依赖于VPC的底层网络能力。

实操铁律一:CIDR规划的“三不重叠”原则

  • 不重叠原则1:VPC CIDR与Service CIDR不重叠。Kubernetes Service的ClusterIP默认从10.100.0.0/16分配。如果你的VPC CIDR是10.0.0.0/16,那么10.100.0.0/16就完全落在VPC地址空间内。这会导致一个问题:当Pod尝试访问一个ClusterIP Service时,流量会错误地被VPC路由表导向VPC内部,而不是被kube-proxy拦截处理。结果就是Service完全不可用。解决方案:为Service CIDR单独规划一个“干净”的网段,比如172.20.0.0/16,并确保它与你的VPC CIDR(如10.0.0.0/16)、以及你VPC内所有其他子网(如数据库子网10.1.0.0/24)都不重叠。
  • 不重叠原则2:VPC CIDR与Pod CIDR不重叠。Amazon VPC CNI插件默认从VPC子网中为Pod分配IP。如果Pod IP和VPC内其他资源(如RDS、ElastiCache)的IP重叠,就会产生ARP冲突,导致网络丢包。因此,你必须为Pod预留一个独立的、不与任何现有VPC资源冲突的IP段。通常做法是:在VPC CIDR内,为Pod专门划分一个大子网(如10.0.0.0/16的VPC,可划出10.100.0.0/20给Pod使用),并在CNI配置中显式指定--pod-cidr
  • 不重叠原则3:不同可用区的子网CIDR不重叠。这是新手最容易犯的错。AWS允许你在同一个VPC下,为不同AZ创建CIDR重叠的子网(比如us-east-1a的10.0.1.0/24和us-east-1b的10.0.1.0/24)。这在理论上可行,但在EKS场景下是灾难性的。因为CNI插件会为每个节点分配来自其所在子网的IP,如果两个AZ的子网CIDR相同,CNI会无法区分,导致Pod IP分配混乱,跨AZ通信失败。铁律:每个子网的CIDR必须全局唯一。

实操铁律二:子网类型与路由的“黄金组合”生产环境必须使用私有子网(Private Subnet)部署工作节点。公有子网(Public Subnet)只用于部署负载均衡器(ALB/NLB)或NAT网关。原因很简单:公有子网的EC2实例拥有公网IP,直接暴露在互联网上,这违背了最小权限原则。即使你关闭了所有安全组端口,EC2实例本身的元数据服务(http://169.254.169.254)也可能被恶意利用。

私有子网的路由表必须包含两条关键路由:

  • 0.0.0.0/0→ 指向NAT网关(NAT Gateway)。这是工作节点访问互联网(如拉取Docker镜像、下载系统更新、上报CloudWatch日志)的唯一出口。
  • 10.0.0.0/16(或你的VPC CIDR)→ 本地(Local)。这是VPC内所有资源(EC2、RDS、S3)之间通信的基础。

提示:NAT网关必须部署在公有子网中,并且其关联的路由表必须将0.0.0.0/0指向Internet Gateway(IGW)。这是一个经典的三层路由结构:Pod → Worker Node → NAT Gateway → IGW → Internet。任何一层缺失,都会导致节点无法联网。

2.2 安全支柱:IAM与网络策略——看不见的锁链

EKS的安全,是“纵深防御”的典范。它由两道核心锁链构成:身份认证锁链(IAM)网络访问锁链(NetworkPolicy)。这两道锁链,一道管“谁可以操作”,一道管“谁可以通信”,缺一不可。

核心逻辑:Kubernetes本身是一个强大的API系统,但它默认的RBAC(基于角色的访问控制)只管理集群内部资源。而EKS集群运行在AWS上,其底层资源(EC2实例、EBS卷、ELB)的权限,必须由AWS IAM来管控。这就是IRSA(IAM Roles for Service Accounts)诞生的原因——它让Kubernetes Pod能以最小权限原则,安全地调用AWS服务。

实操铁律一:IRSA是Pod访问AWS服务的唯一正途在EKS之前,我们常用的方式是给Worker Node的IAM Role附加一堆权限(如AmazonS3FullAccess),然后让所有Pod共享这个Role。这就像给每个员工一把公司大门的钥匙,无论他是不是保安。IRSA则完全不同:它为每个ServiceAccount创建一个独立的IAM Role,并通过OIDC Provider进行绑定。这样,一个负责上传图片的Pod,只能获得S3:PutObject权限;一个负责发送短信的Pod,只能获得SNS:Publish权限。

实现IRSA的关键步骤:

  1. 创建OIDC Provider:这是信任的根。eksctl create iamserviceaccount命令会自动为你完成,它本质上是在AWS IAM中注册一个OIDC Provider,其Issuer URL就是你的EKS集群的OpenID Connect URL(形如https://oidc.us-east-1.eks.amazonaws.com/id/ABCD1234567890ABCDEF1234567890AB)。
  2. 创建ServiceAccount并绑定Role:eksctl create iamserviceaccount --name my-app-sa --namespace default --cluster my-cluster --attach-policy-arn arn:aws:iam::123456789012:policy/MyAppS3Policy --approve。这条命令会做三件事:在Kubernetes中创建ServiceAccount、在IAM中创建Role、并将Role与OIDC Provider关联。
  3. 在Pod Spec中引用:spec.serviceAccountName: my-app-sa。从此,这个Pod内的进程,就可以用aws sts get-caller-identity命令,看到自己拥有的、精确到具体API操作的权限。

注意:IRSA的调试非常痛苦。最常见的错误是WebIdentityErr: failed to retrieve credentials。这通常是因为Pod的token文件(/var/run/secrets/eks.amazonaws.com/serviceaccount/token)没有被正确挂载,或者OIDC Provider的thumbprint不匹配。解决方法是:先用kubectl exec -it <pod> -- cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token | head -n 20确认token存在;再用openssl x509 -in <your-oidc-cert.pem> -fingerprint -noout计算证书指纹,与IAM中OIDC Provider的thumbprint对比。

实操铁律二:NetworkPolicy是Pod间通信的交通警察RBAC管的是“人”(用户、ServiceAccount)对“资源”(Pod、Deployment)的操作权限;NetworkPolicy管的是“Pod”对“Pod”的网络访问权限。在生产环境,默认拒绝所有(Default Deny)是唯一安全的选择。

一个典型的NetworkPolicy示例,只允许frontend命名空间下的Pod访问backend命名空间下的api-service

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend-to-backend namespace: backend spec: podSelector: matchLabels: app: api-service ingress: - from: - namespaceSelector: matchLabels: name: frontend podSelector: matchLabels: app: web ports: - protocol: TCP port: 8080

这条策略的意思是:“在backend命名空间里,所有标签为app=api-service的Pod,只接受来自frontend命名空间、且标签为app=web的Pod,对8080端口的TCP访问。” 其他所有访问,一律被CNI插件(如Calico)拦截。

提示:NetworkPolicy需要CNI插件支持。AWS VPC CNI本身不支持NetworkPolicy,你必须额外部署Calico或Cilium。Cilium因其eBPF技术,在性能和功能上更胜一筹,是生产环境的首选。

2.3 可观测性支柱:从“黑盒”到“透明玻璃”

在Kubernetes的世界里,“看不见”就意味着“失控”。一个没有完善可观测性的EKS集群,就像一辆没有仪表盘的汽车,你只能靠感觉判断它是否在正常行驶。

核心逻辑:可观测性(Observability)不是监控(Monitoring)的简单升级,而是从“发生了什么”(Metrics)到“为什么发生”(Traces)再到“正在发生什么”(Logs)的三位一体。三者缺一不可。

实操铁律一:Metrics采集必须分层,不能只看表面

  • 基础设施层(Infrastructure Layer):CloudWatch Metrics。这是AWS提供的“原生”指标,如EC2 CPUUtilization、EBS VolumeReadOps。它免费、稳定,但粒度粗(5分钟聚合),且无法深入到容器内部。
  • Kubernetes层(K8s Layer):Prometheus + kube-state-metrics。Prometheus是事实标准,它通过/metrics端点主动抓取指标。kube-state-metrics则将Kubernetes API对象(如Deployment、Pod、Node)的状态转化为Prometheus指标。例如,kube_pod_status_phase{phase="Pending"}可以实时反映有多少Pod卡在Pending状态,这比单纯看CPU使用率更能揭示调度问题。
  • 应用层(Application Layer):应用自身暴露的指标。一个健康的微服务,必须在/actuator/prometheus(Spring Boot)或/metrics(Go)端点暴露业务指标,如http_requests_totalorder_processing_duration_seconds。这才是真正反映业务健康度的“黄金信号”。

实操铁律二:Logs必须集中化,且保留原始上下文kubectl logs是调试利器,但绝不能作为生产环境的日志方案。原因有三:一是日志随Pod销毁而丢失;二是无法跨多个Pod聚合分析;三是缺乏结构化查询能力。

生产级方案是:Fluent Bit(Sidecar或DaemonSet) → Kinesis Data Firehose → S3/Opensearch。Fluent Bit轻量、高效,作为DaemonSet部署在每个节点上,负责收集所有容器的标准输出(stdout/stderr)。它内置丰富的过滤器(Filter),可以自动解析JSON日志、添加Kubernetes元数据(如Pod名、Namespace、Node名),并将日志按namespaceapp标签分流到不同的Firehose Delivery Stream。最终,日志被持久化到S3(低成本、高可靠)或实时索引到Opensearch(高性能、可搜索)。

注意:日志采集的性能开销必须可控。Fluent Bit的内存占用应限制在100MB以内,CPU使用率不应超过0.1核。这需要精细调整其Buffer_Chunk_SizeBuffer_Max_Size参数。一个经验法则:Buffer_Chunk_Size设为1MBuffer_Max_Size设为5M,可以在性能和可靠性之间取得良好平衡。

2.4 成本支柱:从“按需付费”到“精打细算”

EKS本身不收费,但支撑它的EC2、EBS、ELB、数据传输等资源,构成了90%以上的成本。一个未经优化的生产集群,其月度账单可能比业务收入还高。

核心逻辑:成本优化不是“砍预算”,而是“提升资源利用率”。Kubernetes的核心价值之一,就是通过调度算法,将不同业务的Pod混部在同一台物理机上,从而摊薄硬件成本。

实操铁律一:节点组(Node Group)必须按负载特征精细化划分

  • Spot Instance节点组:用于无状态、可中断的批处理任务(如数据ETL、视频转码)。Spot价格通常是On-Demand的1/3到1/5,但随时可能被回收。因此,必须配合cluster-autoscalerpriorityClassName,确保关键业务Pod有更高优先级,能在Spot被回收前被驱逐并重新调度到On-Demand节点上。
  • On-Demand节点组:用于有状态、不可中断的核心服务(如数据库代理、API网关)。这类节点必须保证100%的SLA,不能容忍任何中断。
  • Graviton节点组:使用ARM64架构的c7gm7g实例。对于Java、Go等语言编写的微服务,Graviton实例的性价比通常比同规格x86实例高出40%,且功耗更低。迁移成本极低,只需重新编译Docker镜像(docker build --platform linux/arm64 -t myapp:arm64 .)。

实操铁律二:Horizontal Pod Autoscaler(HPA)必须基于真实业务指标HPA默认基于CPU和内存使用率进行扩缩容。这在早期很有效,但很快就会失效。因为一个健康的微服务,其CPU使用率可能常年维持在20%-30%,但此时QPS可能已经翻倍,响应时间开始飙升。真正的瓶颈往往在I/O或数据库连接池。

因此,必须将HPA与Prometheus指标集成:

apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp metrics: - type: Pods pods: metric: name: http_requests_total target: type: AverageValue averageValue: 100

这个HPA会监控http_requests_total指标的每秒平均值,当它超过100时,就触发扩容。这才是与业务增长同步的弹性。

2.5 备份支柱:从“侥幸心理”到“确定性恢复”

“我的集群很稳定,不需要备份。”——这是我在客户现场听到的最多、也最危险的一句话。EKS控制平面是AWS托管的,但你的etcd数据(存储所有Kubernetes对象状态)是运行在Worker Node上的。一旦节点磁盘损坏、误删了/var/lib/etcd目录、或者执行了kubectl delete ns --all这样的毁灭性命令,没有备份,就意味着数据永久丢失。

核心逻辑:备份的目标不是“恢复集群”,而是“恢复业务”。因此,备份的对象必须是声明式(Declarative)的YAML文件,而不是命令式(Imperative)的kubectl apply操作

实操铁律一:Velero是唯一经过大规模验证的K8s备份方案Velero通过在集群中部署一个Operator,定期将Kubernetes资源(Namespace、Deployment、ConfigMap、Secret等)的YAML定义,以及相关的PV(PersistentVolume)快照,备份到S3或Azure Blob Storage中。它的优势在于:

  • 应用一致性:Velero支持Pre/Post Hooks,可以在备份前执行mysqldump,在备份后执行mysql restore,确保数据库备份与应用状态一致。
  • 增量备份:基于S3的版本控制,Velero可以只备份发生变化的资源,大幅减少存储成本和备份时间。
  • 跨集群恢复:你可以将生产环境的备份,一键恢复到开发环境,用于故障复现和压力测试。

实操铁律二:备份策略必须遵循3-2-1原则

  • 3份副本:Velero备份本身在S3中至少保留3个历史版本。
  • 2种介质:主备份存S3,副备份存Glacier(冷存储,成本更低)。
  • 1份异地:将备份同步到另一个AWS区域(如us-east-1的集群,备份同步到us-west-2)。这是应对区域性灾难(如整个AZ不可用)的最后防线。

提示:Secret资源的备份需要特别小心。Velero默认会备份Secret,但其中的敏感信息(如数据库密码)会以明文形式存储在S3中。解决方案是:在Velero安装时,启用--use-restic参数,让Restic对Secret进行加密备份;或者,将Secret的值存储在AWS Secrets Manager中,然后在Pod中通过IRSA读取,这样Velero备份的只是Secret的引用,而非明文。

3. 实操过程:从零开始构建一个生产级EKS集群的完整流水线

纸上谈兵终觉浅,绝知此事要躬行。下面,我将带你走一遍一个真实生产环境EKS集群的构建流水线。这个流水线不是一次性的手工操作,而是基于GitOps理念,所有配置都代码化(Infrastructure as Code),并通过CI/CD管道自动化执行。整个过程分为五个阶段:环境准备、集群创建、节点组部署、核心插件安装、应用部署。每一个阶段,我都会给出可直接执行的命令、详细的参数解释,以及我踩过的坑。

3.1 阶段一:环境准备——一切始于一个干净的AWS账户

在动手之前,你必须确保你的AWS账户处于一个“可部署”状态。这不是一句空话,而是有明确的检查清单。

检查清单:

  1. AWS CLI v2已安装并配置:aws --version必须返回aws-cli/2.12.3或更高版本。旧版本的CLI不支持EKS的最新API。配置命令:aws configure,输入你的Access Key IDSecret Access Key,并设置default region(如us-east-1)。
  2. eksctl已安装:eksctl version必须返回0.215.0或更高版本。eksctl是EKS的官方命令行工具,它封装了大量底层AWS API调用,极大简化了集群创建。安装命令(macOS):brew tap weaveworks/tap && brew install weaveworks/tap/eksctl
  3. kubectl已安装:kubectl version --client必须返回一个与目标Kubernetes版本兼容的客户端版本。EKS 1.35推荐使用kubectl v1.35.x。安装命令:curl -o kubectl https://s3.us-west-2.amazonaws.com/amazon-eks/1.35.0/2024-07-12/bin/darwin/arm64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
  4. IAM权限完备:执行eksctl命令的IAM用户,必须拥有以下最小权限:
    • eks:*(所有EKS相关操作)
    • ec2:Describe*(描述VPC、子网、安全组)
    • iam:ListRoles,iam:PassRole(创建和传递IAM Role)
    • cloudformation:CreateStack,cloudformation:DescribeStacks(eksctl内部使用CloudFormation)

提示:我强烈建议你为EKS部署创建一个专用的IAM用户(如eks-deployer),并为其附加一个自定义的、权限最小化的策略。不要用Root用户或AdministratorAccess策略,这是严重的安全风险。

3.2 阶段二:集群创建——用eksctl生成一个“骨架”

现在,让我们创建集群。这里的关键是:不要用eksctl create cluster的默认参数,而是用一个YAML配置文件来定义一切。这样做的好处是,配置可版本化、可复用、可审计。

创建一个名为eks-prod-cluster.yaml的文件:

# eks-prod-cluster.yaml --- apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: prod-cluster region: us-east-1 version: "1.35" tags: Environment: production Team: platform ManagedBy: eksctl # 网络配置:这是整个集群的地基 vpc: # 我们不创建新的VPC,而是复用现有的、经过精心设计的VPC id: "vpc-0abcdef1234567890" # 私有子网ID,必须跨至少两个AZ subnets: private: us-east-1a: { id: "subnet-0123456789abcdef0" } us-east-1b: { id: "subnet-0123456789abcdef1" } us-east-1c: { id: "subnet-0123456789abcdef2" } # 公有子网ID,用于部署NAT网关和ALB public: us-east-1a: { id: "subnet-0fedcba9876543210" } us-east-1b: { id: "subnet-0fedcba9876543211" } us-east-1c: { id: "subnet-0fedcba9876543212" } # Kubernetes网络配置:避免与VPC CIDR冲突 kubernetesNetworkConfig: serviceIPv4CIDR: "172.20.0.0/16" # 集群角色:定义EKS控制平面可以代表你做什么 iam: # 为集群创建一个专用的IAM Role withOIDC: true # 启用OIDC,为后续IRSA做准备 # 附加的托管策略 attachPolicyARNs: - "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" # 自定义策略,用于特定需求 # extraAttachPolicyARNs: # - "arn:aws:iam::123456789012:policy/ProdClusterExtraPolicy" # 加密:为etcd中的Secret启用KMS加密 secretsEncryption: keyARN: "arn:aws:kms:us-east-1:123456789012:key/abcd1234-5678-90ab-cdef-1234567890ab" # 日志:开启所有控制平面日志,这是故障排查的基石 logging: audit: true authenticator: true controllerManager: true scheduler: true api: true # 其他高级配置 addons: # 禁用默认安装的CoreDNS和kube-proxy,我们稍后手动安装最新版 - name: vpc-cni version: "1.15.1" attachPolicyARNs: - "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" - name: coredns version: "1.11.1" - name: kube-proxy version: "1.35.0"

执行创建命令:

eksctl create cluster -f eks-prod-cluster.yaml

参数详解与避坑指南:

  • --vpc-private-subnets参数在这里被vpc.subnets.private替代,更清晰、更安全。
  • serviceIPv4CIDR被显式设置为172.20.0.0/16,这是为了避免与VPC的10.0.0.0/16冲突。这是最重要的参数之一,漏掉它,你的Service将无法工作。
  • withOIDC: true是启用IRSA的前提。没有它,你就无法为Pod赋予精细的AWS权限。
  • secretsEncryption.keyARN指向一个你预先创建好的KMS密钥。这确保了etcd中存储的所有Secret(如数据库密码)都是加密的,符合GDPR等合规要求。
  • logging部分开启了所有日志类型。虽然会产生一些费用,但这是生产环境的必备项。没有这些日志,你将无法诊断控制平面级别的问题。

提示:eksctl create cluster命令会启动一个CloudFormation堆栈,整个过程大约需要15-20分钟。你可以通过eksctl get clusters查看状态。当状态变为ACTIVE时,集群就绪了。此时,eksctl会自动为你更新~/.kube/config文件,让你可以直接使用kubectl

3.3 阶段三:节点组部署——为集群注入“肌肉”

集群的控制平面(Control Plane)创建好了,但它现在只是一个“大脑”,没有“身体”(Worker Node)来执行任务。我们需要部署节点组。

继续编辑eks-prod-cluster.yaml,在文件末尾添加节点组配置:

# ... 上面的配置保持不变 ... # 节点组配置:按需、Spot、Graviton,三足鼎立 nodeGroups: # On-Demand节点组:用于核心服务 - name: on-demand-ng instanceType: m5.xlarge minSize: 2 maxSize: 5 desiredCapacity: 3 volumeSize: 100 # 关键:为节点组创建专用的IAM Role iam: withAddonPolicies: # 启用EBS CSI驱动所需的权限 ebs: true # 启用ALB Ingress Controller所需的权限 albIngress: true # 启用Fargate所需的权限(虽然我们不用Fargate,但留着无害) autoScaler: true # 标签,用于后续的Pod亲和性调度 labels: nodegroup: on-demand lifecycle: on-demand # 污点(Taint),防止非核心Pod被调度到这里 taints: - key: "dedicated" value: "core" effect: "NoSchedule" # Spot节点组:用于批处理任务 - name: spot-ng instanceType: c5.2xlarge minSize: 0 maxSize: 10 desiredCapacity: 0 volumeSize: 50 # 使用Spot实例 spot: true # 关键:为Spot节点组启用自动伸缩 scalingConfig: minSize: 0 maxSize: 10 desiredCapacity: 0 # 标签 labels: nodegroup: spot lifecycle: spot # 污点,确保只有打了对应容忍(Toleration)的Pod才能调度 taints: - key: "lifecycle" value: "spot" effect: "NoSchedule" # Graviton节点组:用于新业务 - name: graviton-ng instanceType: m7g.xlarge minSize: 1 maxSize: 3 desiredCapacity: 1 volumeSize: 100 # ARM64架构 amiFamily: AmazonLinux2_ARM_64 # 标签 labels: nodegroup: graviton architecture: arm64 # 污点 taints: - key: "architecture" value: "arm64" effect: "NoSchedule"

执行节点组创建命令:

eksctl create nodegroup -f eks-prod-cluster.yaml

参数详解与避坑指南:

  • minSize: 0对于Spot节点组是必须的。因为Spot实例可能随时被回收,节点数可能降到0。cluster-autoscaler会根据负载自动增减。
  • withAddonPolicies是一个便捷的开关,它会自动为节点组的IAM Role附加一系列预定义的策略。ebs: true会附加AmazonEBSCSIDriverPolicy,这是后续安装EBS CSI驱动所必需的。
  • taintslabels是Kubernetes调度的核心。taints是“排斥”,labels是“标识”。一个Pod要想被调度到Spot节点上,它必须同时满足:1) 有nodeSelector匹配lifecycle: spot;2) 有toleration容忍lifecycle=spot:NoSchedule。这确保了只有明确声明可以容忍Spot中断的Pod,才会被调度过去。

提示:节点组创建完成后,用kubectl get nodes -o wide查看节点列表。你会看到节点名称、状态(Ready)、角色( )、年龄、版本、以及外部IP。此时,集群已经具备了执行Pod的能力,但还缺少关键的“神经系统”——网络插件。

3.4 阶段四:核心插件安装——为集群装上“眼睛”和“手脚”

一个裸集群(Bare Cluster)就像一个没有操作系统的服务器,它什么也干不了。我们必须安装一系列核心插件,让集群具备完整的网络、存储、服务发现能力。

插件安装顺序至关重要:

  1. CNI插件(VPC CNI):这是第一步,也是最重要的一步。它负责Pod的IP地址分配和网络通信。eksctl在创建集群时已经安装了它,但我们必须确保它是最新版,并且配置正确。
  2. CSI驱动(EBS CSI Driver):为Pod提供持久化存储(PersistentVolume)。
  3. Ingress Controller(ALB Ingress Controller):将外部HTTP/HTTPS流量路由到集群内的Service。
  4. Metrics Server:为HPA提供CPU/Memory指标。
  5. Prometheus Operator:为整个集群提供统一的Metrics采集和告警能力。

Step 1: 验证并升级VPC CNI

# 查看当前CNI版本 kubectl get daemonset -n kube-system aws-node -o wide # 如果版本过旧(如低于1.15.0),升级它 eksctl utils update-cni -f eks-prod-cluster.yaml --approve

**Step 2: 安装EBS CSI