通过VPC peering模拟On-Premise进行EKS Hybrid Nodes部署的实践指南
EKS Hybrid Nodes 的核心设计是控制平面与数据平面的物理解耦:
- 控制平面:AWS 托管,运行在 AWS 云端(API Server、etcd、Controller Manager、Scheduler)
- 数据平面:运行在用户自管理的本地/边缘基础设施上
控制平面通过弹性网络接口(ENI)连接到客户 VPC。这些 ENI 放置在集群创建时指定的子网中,是控制平面与所有节点(包括混合节点)通信的桥梁。
创建集群时通过 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:
- Be within RFC-1918 or CGNAT ranges
- 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 的入站规则

凭证与身份认证机制
混合节点位于 AWS 之外,无法像 EC2 实例那样通过 Instance Metadata Service 获取 IAM 凭证。EKS Hybrid Nodes 提供两种凭证机制。
SSM Hybrid Activations
初始注册阶段:
运行时凭证流程:
| 特性 | 说明 |
|---|---|
| 凭证有效期 | 固定 1 小时,不可配置 |
| 自动轮换 | SSM Agent 在过期前自动刷新 |
| 轮换失败重试 | 指数退避,最大间隔 30 分钟(SSM Agent ≥ 3.3.808.0) |
| Activation 有效期 | 默认 24 小时,仅用于初始注册 |
| 凭证存储位置 | /root/.aws/credentials |
网络断连时的凭证行为
IAM Roles Anywhere
两种方式对比
| 维度 | 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 明确包含了以下章节:
- Hybrid node kubelet to EKS control plane — kubelet → 控制平面
- EKS control plane to hybrid node (kubelet server) — 控制平面 → kubelet
- Pods running on hybrid nodes to EKS control plane — Pod → 控制平面
- Without CNI NAT ← 无 NAT 模式,完整的 DNAT 过程
- With CNI NAT ← 有 NAT 模式,SNAT + DNAT 过程
- EKS control plane to pods running on a hybrid node (webhooks) — 控制平面 → Pod
- Pod-to-Pod running on hybrid nodes — Pod 间 VXLAN
- Pods on cloud nodes to pods on hybrid nodes (east-west traffic) — 东西向
kubelet → EKS 控制平面

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

Pod → 控制平面(无 NAT)
无 NAT 模式下 RemotePodNetwork CIDR 必须全程可路由

Pod → 控制平面(有 NAT)
控制平面 → Pod(Webhook 回调)

混合节点间 Pod-to-Pod(VXLAN)
底层网络只需节点间 IP 可达,无需感知 Pod CIDR

云端 Pod与混合节点 Pod

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(文章描述的问题):
EKS 控制平面有一个安全限制——它只允许向已知的 CIDR 范围发起连接。在传统 EKS 中,这个范围就是 VPC CIDR。Calico overlay 的 Pod IP 不在 VPC CIDR 中,所以控制平面直接拒绝(不是路由不通,是根本不允许连接)。
EKS Hybrid Nodes 场景:
核心区别:
| 传统 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 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 执行流程
- SSM 注册获取 managed instance ID (mi-xxx)
- 获取集群信息 (
eks:DescribeCluster) - 验证:SSM endpoint、STS 认证、网络接口、kubelet 证书、版本偏差、K8s API 访问、代理配置、access entry
- 系统配置:sysctl、禁用 swap、防火墙检查
- 配置并启动 containerd,拉取 sandbox image (
pause:3.5) - 配置并启动 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


环境准备
环境与架构信息
| 组件 | 值 |
|---|---|
| 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不能与remoteNodeNetworksCIDR 重叠,否则 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,因为还未安装 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:

Calico 安装
Calico 首次尝试直接 apply operator manifest 会失败:
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.29.0/manifests/tigera-operator.yaml
问题分析:
- 未指定
cni.type: Calico:Tigera Operator 检测到 EKS 环境中存在aws-node(VPC CNI) DaemonSet,自动判定 CNI 由 VPC CNI 管理,跳过了calico-cni-pluginDaemonSet 的部署 - CNI 二进制文件没有安装到节点上,kubelet 报
NetworkPluginNotReady: cni plugin not initialized - 尝试设置
encapsulation: VXLAN时报错VXLAN is invalid when using non-Calico CNI——因为 operator 认为 CNI 不是 Calico - 没有
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
最终集群状态


IAM Roles Anywhere 节点加入结果

节点 describe 结果:


浙公网安备 33010602011771号