通过VPC peering模拟On-Premise进行EKS Hybrid Nodes部署的实践指南

EKS Hybrid Nodes 的核心设计是控制平面与数据平面的物理解耦:

  • 控制平面:AWS 托管,运行在 AWS 云端(API Server、etcd、Controller Manager、Scheduler)
  • 数据平面:运行在用户自管理的本地/边缘基础设施上

控制平面通过弹性网络接口(ENI)连接到客户 VPC。这些 ENI 放置在集群创建时指定的子网中,是控制平面与所有节点(包括混合节点)通信的桥梁。

flowchart TB subgraph AWSCloud["AWS Cloud"] subgraph EKSCP["EKS Control Plane(AWS托管)"] APS["API Server"] ETCD["etcd"] CM["Controller Manager"] SCH["Scheduler"] APS <--> ETCD end subgraph CustVPC["Customer VPC"] RT["路由表<br/>10.0.0.0/16 → local<br/>10.80.0.0/16 → vgw<br/>10.85.0.0/16 → vgw"] VGW["VGW/TGW"] EC2Node["EC2 Nodes(VPC CNI)"] end EKSCP -- ENI(10.0.0.132,10.0.1.23) --> CustVPC RT --- VGW end linkStyle 0 stroke:#2980b9,stroke-width:2px subgraph OnPrem["On-Premises 本地机房"] OPR["本地路由器<br/>路由表:<br/>10.0.0.0/16→AWS网关<br/>10.85.1.0/24→10.80.0.2<br/>10.85.2.0/24→10.80.0.3"] N1["Node1<br/>10.80.0.2<br/>Pod:10.85.1.*"] N2["Node2<br/>10.80.0.3<br/>Pod:10.85.2.*"] OPR --> N1 OPR --> N2 end VGW -- Direct Connect/VPN --> OPR

创建集群时通过 RemoteNetworkConfig 配置:

CIDR 类型 配置项 来源 用途
VPC CIDR 集群 VPC AWS VPC 控制平面 ENI、云端节点和 Pod
Service CIDR serviceIpv4Cidr Kubernetes ClusterIP Service 地址空间
RemoteNodeNetwork remoteNodeNetworks.cidrs 本地网络分配 混合节点主机 IP 范围
RemotePodNetwork remotePodNetworks.cidrs(可选) CNI 分配 混合节点上 Pod IP 范围(overlay 模式)

约束条件:

  • 所有 CIDR 必须是 RFC-1918 私有地址

  • RemoteNodeNetwork:最小 /32,最大 /8

  • 四个 CIDR 之间不能重叠

    The on-premises node and pod CIDR blocks must meet the following requirements:

    1. Be within RFC-1918 or CGNAT ranges
    2. Not overlap with each other, the VPC CIDR for your EKS cluster, or your Kubernetes service IPv4 CIDR
  • VPC 路由表需要手动添加 RemoteNodeNetwork 和 RemotePodNetwork 的路由(EKS 不会自动添加)

  • EKS 会自动在集群安全组中添加 RemoteNodeNetwork 和 RemotePodNetwork 的入站规则

image-20260521085643546

凭证与身份认证机制

混合节点位于 AWS 之外,无法像 EC2 实例那样通过 Instance Metadata Service 获取 IAM 凭证。EKS Hybrid Nodes 提供两种凭证机制。

SSM Hybrid Activations

初始注册阶段:

flowchart LR Admin[管理员] -->|创建 Activation| SSM[SSM Service] SSM -->|返回 Activation ID + Code| Admin Admin -->|配置到 nodeConfig.yaml| Node[本地节点]

运行时凭证流程:

flowchart TB A["SSM Agent (节点上)<br/>使用 Activation ID/Code 向 SSM 区域端点注册"] --> B["SSM 返回临时 IAM 凭证<br/>有效期 1 小时,不可更改"] B --> C["凭证写入 /root/.aws/credentials"] C --> D["nodeadm 使用凭证调用 eks:DescribeCluster<br/>获取集群信息(endpoint、CA 证书、Service CIDR)"] D --> E["生成 kubelet kubeconfig"] E --> F["kubelet 通过 AWS IAM Authenticator 认证到 API Server"] B -.->|"凭证过期前自动轮换(约每 30 分钟检查一次)"| A
特性 说明
凭证有效期 固定 1 小时,不可配置
自动轮换 SSM Agent 在过期前自动刷新
轮换失败重试 指数退避,最大间隔 30 分钟(SSM Agent ≥ 3.3.808.0)
Activation 有效期 默认 24 小时,仅用于初始注册
凭证存储位置 /root/.aws/credentials

网络断连时的凭证行为

flowchart TB Normal["正常运行: SSM Agent 每 ~30 分钟轮换凭证"] --> Disconnect{"网络断连"} Disconnect -->|"当前凭证仍有效(剩余有效期内)"| Valid["节点正常工作"] Disconnect -->|"凭证过期"| Expired["kubelet 无法认证 → 节点变为 NotReady"] Valid --> Reconnect{"网络恢复"} Expired --> Reconnect Reconnect -->|"自动恢复:等待下一次重试成功(最大 30 分钟间隔)"| Auto["恢复正常"] Reconnect -->|"手动加速:systemctl restart amazon-ssm-agent"| Manual["立即恢复"]

IAM Roles Anywhere

flowchart TB A["kubelet 需要凭证"] --> B["调用 aws_signing_helper credential-process"] B --> C["signing_helper 使用 X.509 证书<br/>向 IAM Roles Anywhere 发起 CreateSession 请求"] C --> D["IAM Roles Anywhere 验证证书链"] D --> E["返回临时 IAM 凭证<br/>默认 1 小时,可配置 15 分钟 ~ 12 小时"] E --> F["kubelet 使用凭证认证到 EKS API Server"]

两种方式对比

维度 SSM Hybrid Activations IAM Roles Anywhere
设置复杂度 低(无需 PKI) 高(需要 CA 和证书管理)
凭证有效期 固定 1 小时 可配置 15 分钟 ~ 12 小时
断连恢复速度 最慢 30 分钟 秒级
凭证获取模式 推送式(SSM Agent 定期刷新) 拉取式(kubelet 按需获取)
适用场景 PoC、小规模、快速入门 生产环境、企业级部署

访问控制与 RBAC

EKS Access Entry

混合节点的认证通过 EKS Access Entries 管理。

访问条目

aws eks create-access-entry \
  --cluster-name my-hybrid-cluster \
  --principal-arn arn:aws:iam::123456789012:role/HybridNodesRole \
  --type HYBRID_LINUX

注意:Access Entry type 必须是 HYBRID_LINUX(不是 EC2_LINUX)。username 自动设置为 system:node:{{SessionName}}。

Hybrid Nodes IAM Role 最小权限策略组合:

  • AWS 托管策略:AmazonEC2ContainerRegistryPullOnly + AmazonSSMManagedInstanceCore(SSM 方式)
  • 自建策略:EKSDescribeClusterPolicy(eks:DescribeCluster)

注意:eks:DescribeCluster 是 nodeadm 调用的(不是 kubelet),用于获取集群 endpoint、CA 证书等信息生成 kubelet kubeconfig。如果不授予此权限,需要在 nodeConfig 中手动指定这些信息。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["eks:DescribeCluster", "eks:ListAccessEntries"],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken",
        "ecr:BatchGetImage",
        "ecr:GetDownloadUrlForLayer"
      ],
      "Resource": "*"
    }
  ]
}

网络架构

私有连接方式

连接方式 特点 适用场景
AWS Direct Connect 专线,高带宽低延迟 企业生产环境
AWS Site-to-Site VPN IPSec 隧道 中等规模
VPC Peering 同区域 VPC 互通(模拟使用) 模拟环境

网络要求

方向 源 目标 端口 用途
入站 EKS 控制平面 ENI 混合节点 TCP 10250 kubelet API
入站 EKS 控制平面 ENI Pod CIDR TCP(webhook 端口) Webhook 回调
出站 混合节点 EKS API Server TCP 443 kubelet → API Server
双向 混合节点间 混合节点间 UDP 8472 VXLAN 封装

六大流量路径解析

官方文档 Network traffic flows for hybrid nodes 明确包含了以下章节:

  1. Hybrid node kubelet to EKS control plane — kubelet → 控制平面
  2. EKS control plane to hybrid node (kubelet server) — 控制平面 → kubelet
  3. Pods running on hybrid nodes to EKS control plane — Pod → 控制平面
    • Without CNI NAT ← 无 NAT 模式,完整的 DNAT 过程
    • With CNI NAT ← 有 NAT 模式,SNAT + DNAT 过程
  4. EKS control plane to pods running on a hybrid node (webhooks) — 控制平面 → Pod
  5. Pod-to-Pod running on hybrid nodes — Pod 间 VXLAN
  6. Pods on cloud nodes to pods on hybrid nodes (east-west traffic) — 东西向

kubelet → EKS 控制平面

flowchart LR K["kubelet<br/>10.80.0.2"] -->|"DNS 解析 → 公网 IP<br/>Src: 10.80.0.2<br/>Dst: 54.239.118.52:443"| R["本地路由器"] R -->|"公网"| AWS["AWS"] AWS --> CP["EKS 控制平面"]

Hybrid node kubelet to EKS control plane

公有模式下,混合节点 kube-proxy 到 EKS 控制平面和 kubelet 逻辑一致。

EKS 控制平面 → kubelet(logs/exec)

flowchart LR CP["API Server"] --> ENI["ENI (10.0.0.132)"] ENI --> RT["VPC 路由表<br/>10.80.0.0/16 → vgw-xxx"] RT --> VPN["VPN/DC"] VPN --> R["本地路由器"] R --> Node["Node (10.80.0.2:10250)"]

EKS control plane to hybrid node

Pod → 控制平面(无 NAT)

flowchart LR Pod["Pod (10.85.1.56)"] -->|"kube-proxy DNAT<br/>172.16.0.1 → 10.0.0.132"| Node["节点路由"] Node --> VPN["VPN/DC"] VPN --> VPC["VPC"] VPC --> ENI["ENI"] ENI --> CP["API Server"] CP -->|"响应: VPC 路由 10.85.0.0/16 → vgw"| VPN2["VPN/DC"] VPN2 -->|"本地路由器 → Node → Pod"| Pod

无 NAT 模式下 RemotePodNetwork CIDR 必须全程可路由

Hybrid nodes BGP routing

Pod → 控制平面(有 NAT)

flowchart LR Pod["Pod (10.85.1.56)"] -->|"CNI SNAT<br/>源 IP → 节点 IP (10.80.0.2)"| SNAT["SNAT"] SNAT -->|"kube-proxy DNAT<br/>→ 10.0.0.132"| VPN["VPN/DC"] VPN --> CP["API Server"] CP -->|"响应: Dst 10.80.0.2<br/>节点 IP,无需 Pod CIDR 路由"| VPN

控制平面 → Pod(Webhook 回调)

flowchart LR CP["API Server"] --> ENI["ENI"] ENI -->|"VPC 路由 10.85.0.0/16 → vgw"| VPN["VPN/DC"] VPN --> R["本地路由器"] R --> Node["Node"] Node --> CNI["CNI"] CNI --> Webhook["Webhook Pod"]

EKS control plane to pods running on a hybrid node

混合节点间 Pod-to-Pod(VXLAN)

底层网络只需节点间 IP 可达,无需感知 Pod CIDR

flowchart LR PodA["Pod A (10.85.1.56)<br/>on Node 1"] -->|"VXLAN 封装"| Encap["Outer IP: Src 10.80.0.2 → Dst 10.80.0.3<br/>UDP 8472 | VXLAN VNI | Inner Packet"] Encap --> PodB["Pod B (10.85.2.67)<br/>on Node 2"]

Pod-to Pod running on hybrid nodes

云端 Pod与混合节点 Pod

flowchart LR CloudPod["Cloud Pod (VPC CNI, 10.0.0.56)"] -->|"VPC 路由 10.85.0.0/16 → vgw"| VPN["VPN/DC"] VPN --> R["本地路由器"] R --> Node["Node"] Node --> CNI["CNI"] CNI --> HybridPod["Hybrid Pod"]

Pods on cloud nodes to pods on hybrid nodes

CNI 网络插件

为什么混合节点不能用 VPC CNI?VPC CNI 依赖 EC2 ENI 和 VPC 网络基础设施,混合节点不在 VPC 中无法使用。一个混合集群中会同时存在两种 CNI:

  • 云端节点:VPC CNI
  • 混合节点:Cilium 或 Calico

Cilium 路由模式有如下两种

  • Overlay 模式(VXLAN):网络配置最简单,无需修改本地路由器,但有封装开销。
  • Native Routing 模式(BGP):无封装开销,最佳性能,但需要网络团队配合配置 BGP。

Overlay 模式下的 Webhook 问题

控制平面需要直接连接到 Pod IP,但 Pod IP 在 VXLAN 隧道内。解决方案:

  • 配置 RemotePodNetwork
  • 使用 hostNetwork

文章( https://medium.com/@denisstortisilva/kubernetes-eks-calico-and-custom-admission-webhooks-a2956b49bd0d )描述的是传统 EKS + Calico(替换 VPC CNI)的场景,和我们的 EKS Hybrid Nodes 场景有关键区别:

传统 EKS + Calico(文章描述的问题):

flowchart TB CP["EKS 控制平面(AWS 托管,在 VPC 外部)"] CP -->|"要连接 Webhook Pod IP<br/>Calico 分配,如 192.168.1.5"| ENI["控制平面 ENI 在 VPC 中"] ENI --> Check{"VPC 路由表检查"} Check -->|"VPC 路由表只知道 VPC CIDR"| Fail["192.168.1.5 不在 VPC CIDR 中"] Fail --> Reject["❌ Address is not allowed<br/>控制平面直接拒绝连接"] Note["根本原因:EKS 控制平面的安全策略<br/>只允许连接到 VPC CIDR 范围内的地址<br/>这不是路由问题,是安全限制"]

EKS 控制平面有一个安全限制——它只允许向已知的 CIDR 范围发起连接。在传统 EKS 中,这个范围就是 VPC CIDR。Calico overlay 的 Pod IP 不在 VPC CIDR 中,所以控制平面直接拒绝(不是路由不通,是根本不允许连接)。

EKS Hybrid Nodes 场景:

flowchart TB CP["EKS 控制平面"] CP -->|"创建集群时声明了<br/>remotePodNetworks: 10.100.0.0/16"| Know["EKS 控制平面知道 10.100.0.0/16 是合法的 Pod 地址范围"] Know --> Allow["安全策略允许向这个 CIDR 发起连接"] Allow --> SG["安全组自动添加出站规则到 Pod CIDR"] SG -->|"连接 Webhook Pod IP (10.100.1.23)"| Success["✅ Address is allowed<br/>因为在 remotePodNetworks 声明范围内"] Success --> Route["然后才是路由问题<br/>VPC 路由表需要有对应条目"]

核心区别:

传统 EKS + Calico EKS Hybrid Nodes
Pod CIDR 声明 没有机制告诉控制平面 remotePodNetworks 声明
控制平面安全策略 只允许连接 VPC CIDR 允许连接 VPC CIDR + remotePodNetworks
Webhook 到 Pod IP "Address is not allowed" 允许(如果路由也配好)
解决方案 hostNetwork: true 配置 remotePodNetworks + VPC 路由

所以 remotePodNetworks 的作用不仅仅是路由声明,更重要的是告诉 EKS 控制平面这些 Pod IP 是合法的连接目标,解除了"Address is not allowed"的安全限制。

nodeadm 节点管理

常用命令

命令 用途
nodeadm install <k8s-version> 安装 kubelet、containerd 等依赖
nodeadm init -c file://nodeConfig.yaml 初始化节点并加入集群
nodeadm debug -c file://nodeConfig.yaml 验证网络和凭证
nodeadm upgrade <version> -c file://... 升级 K8s 版本
nodeadm uninstall 卸载混合节点组件

nodeadm debug结果

nodeadm check结果

nodeadm install 安装的文件

组件 路径
nodeadm /usr/local/bin/nodeadm (v1.0.17)
kubelet /usr/bin/kubelet
kubectl /usr/local/bin/kubectl
containerd /usr/bin/containerd
CNI plugins /opt/cni/bin/
ECR Credentials Provider /etc/eks/image-credential-provider/ecr-credential-provider
AWS IAM Authenticator /usr/local/bin/aws-iam-authenticator
SSM Setup CLI /opt/ssm/ssm-setup-cli
SSM Agent /usr/bin/amazon-ssm-agent
iptables /usr/sbin/iptables
安装追踪文件 /opt/nodeadm/tracker

nodeadm init 配置的文件

文件 路径
kubelet kubeconfig /var/lib/kubelet/kubeconfig
kubelet config /etc/kubernetes/kubelet/config.json
kubelet systemd unit /etc/systemd/system/kubelet.service
kubelet CA cert /etc/kubernetes/pki/ca.crt
containerd config /etc/containerd/config.toml
AWS config /etc/aws/hybrid/config
sysctl config /etc/sysctl.d/99-nodeadm.conf

nodeadm init 执行流程

  1. SSM 注册获取 managed instance ID (mi-xxx)
  2. 获取集群信息 (eks:DescribeCluster)
  3. 验证:SSM endpoint、STS 认证、网络接口、kubelet 证书、版本偏差、K8s API 访问、代理配置、access entry
  4. 系统配置:sysctl、禁用 swap、防火墙检查
  5. 配置并启动 containerd,拉取 sandbox image (pause:3.5)
  6. 配置并启动 kubelet

日志收集

# nodeadm 内置调试(推荐)
nodeadm debug -c file:///etc/nodeadm-config.yaml --no-color > /tmp/nodeadm-debug.log 2>&1

# EKS Log Collector
curl -O https://raw.githubusercontent.com/awslabs/amazon-eks-ami/master/log-collector-script/linux/eks-log-collector.sh
chmod +x eks-log-collector.sh && sudo ./eks-log-collector.sh

nodeadm debug结果

log收集脚本正常

环境准备

环境与架构信息

组件 值
EKS 集群名称 hybirdcluster
Kubernetes 版本 1.35
EKS VPC vpc-0b6xxxxxx9f84 (CIDR: 10.0.0.0/16)
On-prem VPC(模拟) vpc-cdxxxxa6 (CIDR: 172.31.0.0/16,默认VPC)
Remote Node Network 172.31.0.0/16
Remote Pod Network 10.100.0.0/16
Service CIDR 172.16.0.0/16
CNI Calico v3.29.5

VPC 路由配置

EKS VPC 路由表:

目标 CIDR 下一跳
10.0.0.0/16 local
172.31.0.0/16 VPC Peering
10.100.0.0/16 VPC Peering

On-prem VPC 路由表(模拟):

目标 CIDR 下一跳
172.31.0.0/16 local
10.0.0.0/16 VPC Peering
10.100.0.0/16 混合节点(通过 AWS Gateway)

安全组配置

  • EKS 安全组:允许来自 on-prem VPC 的流量
  • Hybrid Node 安全组:允许 EKS VPC 流量

创建 EKS 集群

aws eks create-cluster \
  --name hybirdcluster \
  --role-arn arn:aws:iam::xxxxxxxxx:role/eksClusterRole \
  --access-config '{"authenticationMode":"API_AND_CONFIG_MAP"}' \
  --remote-network-config '{"remoteNodeNetworks":[{"cidrs":["172.31.0.0/16"]}],"remotePodNetworks":[{"cidrs":["10.100.0.0/16"]}]}' \
  --resources-vpc-config '{"subnetIds":["subnet-0628xxxxxxxx974ffd","subnet-0629xxxxxxxxx2e","subnet-0ccxxxxxxxxxxx0","subnet-0cc6e98xxxxxxxxbf455"],"securityGroupIds":["sg-0393xxxxxx3b9"]}' \

注意:remotePodNetworks 不能与 remoteNodeNetworks CIDR 重叠,否则 EKS API 会拒绝。

凭证配置

创建 IAM Role,EKSHybridNodeRole(SSM hybrid activation 用)

aws iam create-role --role-name EKSHybridNodeRole \
  --assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ssm.amazonaws.com"},"Action":"sts:AssumeRole"}]}' \
  
# 附加策略
aws iam attach-role-policy --role-name EKSHybridNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodeMinimalPolicy
aws iam attach-role-policy --role-name EKSHybridNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly
aws iam attach-role-policy --role-name EKSHybridNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

# Inline 策略
aws iam put-role-policy --role-name EKSHybridNodeRole --policy-name EKSDescribeCluster \
  --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["eks:DescribeCluster","eks:ListAccessEntries","eks:DescribeAccessEntry"],"Resource":"arn:aws:eks:us-east-2:xxxxxxxxx:cluster/hybirdcluster"}]}'

SSM Hybrid Activation

# 创建 SSM Hybrid Activation
aws ssm create-activation --default-instance-name hybirdcluster-hybrid-node \
  --iam-role EKSHybridNodeRole --registration-limit 10 
# 返回: ActivationId: 75a23c3d-b8b0-401c-93e8-xxxxxxx6b71b
#       ActivationCode: sGHELZxxxxxxxAFc0UF

IAM Roles Anywhere

创建 CA 和节点证书

mkdir -p /tmp/hybrid-pki && cd /tmp/hybrid-pki

# CA 配置必须有 basicConstraints=CA:TRUE 和 keyUsage)
openssl req -x509 -newkey rsa:2048 -keyout ca.key -out ca.crt -days 365 -nodes -config ca.cnf

# 生成节点 CSR(CN = 节点名,将作为 K8s node name)
openssl genrsa -out node.key 4096
openssl req -new -key node.key -out node.csr -subj "/CN=hybrid-ira-node-1"

# 节点证书扩展配置(缺少会报 Untrusted certificate)
cat > node.cnf << 'EOF'
[v3_node]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
EOF

# 签发节点证书
openssl x509 -req -in node.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out node.crt -days 365 -extfile node.cnf -extensions v3_node

创建 IAM Roles Anywhere Trust Anchor

CA_CERT=$(cat ca.crt | sed ':a;N;$!ba;s/\n/\\n/g')

aws rolesanywhere create-trust-anchor \
  --name "eks-hybrid-trust-anchor" \
  --source "{\"sourceType\":\"CERTIFICATE_BUNDLE\",\"sourceData\":{\"x509CertificateData\":\"$CA_CERT\"}}" \
  --enabled
# 返回: Trust Anchor ARN

创建 IAM Role

aws iam create-role --role-name EKSHybridNodeRoleIRA \
  --permissions-boundary arn:aws:iam::xxxxxxxxx:policy/NWCDBoundaries \
  --assume-role-policy-document '{
    "Version":"2012-10-17",
    "Statement":[{
      "Effect":"Allow",
      "Principal":{"Service":"rolesanywhere.amazonaws.com"},
      "Action":["sts:AssumeRole","sts:TagSession","sts:SetSourceIdentity"],
      "Condition":{
        "StringEquals":{
          "aws:PrincipalTag/x509Subject/CN":"${aws:PrincipalTag/x509Subject/CN}"
        },
        "ArnEquals":{
          "aws:SourceArn":"arn:aws:rolesanywhere:us-east-2:xxxxxxxxx:trust-anchor/<TA_ID>"
        }
      }
    }]
  }'

# 附加策略
aws iam attach-role-policy --role-name EKSHybridNodeRoleIRA \
  --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly

aws iam put-role-policy --role-name EKSHybridNodeRoleIRA \
  --policy-name EKSDescribeCluster \
  --policy-document '{
    "Version":"2012-10-17",
    "Statement":[{
      "Effect":"Allow",
      "Action":["eks:DescribeCluster","eks:ListAccessEntries","eks:DescribeAccessEntry"],
      "Resource":"arn:aws:eks:us-east-2:xxxxxxxxx:cluster/hybirdcluster"
    }]
  }'

创建 IAM Roles Anywhere Profile

aws rolesanywhere create-profile \
  --name "eks-hybrid-profile" \
  --role-arns "arn:aws:iam::xxxxxxxxx:role/EKSHybridNodeRoleIRA" \
  --enabled \
  --accept-role-session-name \
  
# 返回: Profile ARN

创建 EKS Access Entry

# SSM 方式
aws eks create-access-entry --cluster-name hybirdcluster \
  --principal-arn arn:aws:iam::xxxxxxxxx:role/EKSHybridNodeRole \
  --type HYBRID_LINUX

# IAM Roles Anywhere 方式
aws eks create-access-entry --cluster-name hybirdcluster \
  --principal-arn arn:aws:iam::xxxxxxxxx:role/EKSHybridNodeRoleIRA \
  --type HYBRID_LINUX 

访问条目

节点加入集群

SSM 方式节点配置

# /etc/nodeadm-config.yaml
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name: hybirdcluster
    region: us-east-2
  hybrid:
    ssm:
      activationId: "<ACTIVATION_ID>"
      activationCode: "<ACTIVATION_CODE>"

IAM Roles Anywhere 方式节点配置

# /etc/nodeadm-config.yaml
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name: hybirdcluster
    region: us-east-2
  hybrid:
    iamRolesAnywhere:
      nodeName: hybrid-ira-node-1
      trustAnchorArn: arn:aws:rolesanywhere:us-east-2:xxxxxxxxx:trust-anchor/<TA_ID>
      profileArn: arn:aws:rolesanywhere:us-east-2:xxxxxxxxx:profile/<PROFILE_ID>
      roleArn: arn:aws:iam::xxxxxxxxx:role/EKSHybridNodeRoleIRA
      certificatePath: /etc/iam/pki/server.pem
      privateKeyPath: /etc/iam/pki/server.key

节点安装与加入

SSM 方式:

# 安装
nodeadm install 1.35 --credential-provider ssm

# 加入集群
nodeadm init -c file:///etc/nodeadm-config.yaml

IAM Roles Anywhere 方式:

# 证书必须放在 /etc/iam/pki/ 目录
mkdir -p /etc/iam/pki
cp node.crt /etc/iam/pki/server.pem
cp node.key /etc/iam/pki/server.key

# 安装(注意 credential-provider 是 iam-ra)
nodeadm install 1.35 --credential-provider iam-ra

# 加入集群
nodeadm init --config-source file:///etc/nodeadm-config.yaml

约 3-5 分钟后:

aws eks update-kubeconfig --name hybirdcluster 
kubectl get nodes

节点未就绪notready

节点状态为 NotReady,因为还未安装 CNI。

CNI 安装

Cilium 安装

helm install cilium oci://public.ecr.aws/eks/cilium/cilium \
  --version 1.17.9-0 --namespace kube-system --values cilium-values.yaml

cilium-values.yaml:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/compute-type
          operator: In
          values:
          - hybrid
ipam:
  mode: cluster-pool
  operator:
    clusterPoolIPv4MaskSize: 25
    clusterPoolIPv4PodCIDRList:
    - 10.100.0.0/16
loadBalancer:
  serviceTopology: true
operator:
  replicas: 1
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: In
            values:
              - hybrid
  unmanagedPodWatcher:
    restart: false
envoy:
  enabled: false
kubeProxyReplacement: "false"

安装后节点变为 Ready:

cilium状态ready

Calico 安装

Calico 首次尝试直接 apply operator manifest 会失败:

kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.0/manifests/tigera-operator.yaml

问题分析:

  1. 未指定 cni.type: Calico:Tigera Operator 检测到 EKS 环境中存在 aws-node (VPC CNI) DaemonSet,自动判定 CNI 由 VPC CNI 管理,跳过了 calico-cni-plugin DaemonSet 的部署
  2. CNI 二进制文件没有安装到节点上,kubelet 报 NetworkPluginNotReady: cni plugin not initialized
  3. 尝试设置 encapsulation: VXLAN 时报错 VXLAN is invalid when using non-Calico CNI——因为 operator 认为 CNI 不是 Calico
  4. 没有 nodeSelector,组件可能调度到不存在的云端节点上

参考 eks-hybrid-examples/calico-cni 使用 helm 安装:

helm repo add projectcalico https://docs.tigera.io/calico/charts
helm install calico projectcalico/tigera-operator \
  --version v3.29.5 --namespace kube-system -f calico-values.yaml

calico-values.yaml:

  • 关键:必须指定 cni.type: Calico 和 ipam.type: Calico,否则 operator 检测到 EKS 环境会跳过 CNI 插件安装
installation:
  enabled: true
  cni:
    type: Calico
    ipam:
      type: Calico
  calicoNetwork:
    bgp: Disabled
    ipPools:
    - cidr: 10.100.0.0/16
      blockSize: 25
      encapsulation: VXLAN
      natOutgoing: Enabled
      nodeSelector: eks.amazonaws.com/compute-type == "hybrid"
    nodeAddressAutodetectionV4:
      firstFound: true
  controlPlaneReplicas: 1
  controlPlaneNodeSelector:
    eks.amazonaws.com/compute-type: hybrid
  calicoNodeDaemonSet:
    spec:
      template:
        spec:
          nodeSelector:
            eks.amazonaws.com/compute-type: hybrid
  csiNodeDriverDaemonSet:
    spec:
      template:
        spec:
          nodeSelector:
            eks.amazonaws.com/compute-type: hybrid
  calicoKubeControllersDeployment:
    spec:
      template:
        spec:
          nodeSelector:
            eks.amazonaws.com/compute-type: hybrid
  typhaDeployment:
    spec:
      template:
        spec:
          nodeSelector:
            eks.amazonaws.com/compute-type: hybrid

最终集群状态

pod列表

eks节点组状态

IAM Roles Anywhere 节点加入结果

IAM Roles Anywhere节点加入集群

节点 describe 结果:

IAM Roles Anywhere节点describe结果

参考资料

posted @ 2026-05-21 09:20  zhaojie10  阅读(31)  评论(0)    收藏  举报