个人随记 —— 不同 VPC 下 EKS 跨集群服务访问
背景
在本文的问题前,需要对 AWS 的产品进行解释:
- VPC:Virtual Private Cloud,AWS 在单 region 下提供的私有网络,每个 VPC 都拥有一个独立网段,并且和其他 VPC 进行完全的私网隔离-
- EC2:Elastic Compute Cloud,AWS 提供的弹性计算虚拟节点
- EKS:Elastic Kubernetes Service,AWS 提供的全托管 K8S 服务
在两个不同的 VPC 下,我们各创建一个 EKS 部署服务,当出现其中一个集群的 Pod 需要通过访问另一个集群的服务时应该如何解决?
解决方案
VPC 网络打通
面临的第一个问题就是如何联通两个 VPC 网络,AWS 提供了两种方式:VPC Peering 和 PraviteLink:
- 前者是直接打通两个 VPC 的整个网段,使双方访问对方网段时和自身网段一样;
- 而后者是在两个 VPC 上打通一个通道,提供服务方创建一个 endpoint service,访问方创建一个 endpoint,访问方只能通过这个 PraviteLink 通道访问对方提供的服务。
方案 | 优势 | 劣势 |
---|---|---|
VPC Peering | - 建立方便 - 几乎没有成本 - 可以跨region | - 依赖 vpc cidr 互不冲突 - 打通后隔离性依赖安全组设置 |
PraviteLink | - vpc cidr无限制 - 只能通过 endpoint 访问,安全性较好 | - 不可以跨region - 成本高 - 使用较复杂 |
方案一:PrivateLink + k8s LB Service
- 首先我们可以先给服务集群挂在一个内网 LB Service,这样子在 EKS A 集群中就可以有一个四层的负载均衡设施
- 再给 LB 上创建一个 PrivateLink Service,把服务提供出去
- EKS B 中创建一个和 PrivateLink Service 对接的 endpoint,EKS B 中的 pod 通过 endpoint 通信访问 Service。
方案二:VPC Peering + k8s LB Service
- 首先我们可以先给服务集群挂在一个内网 LB Service,这样子在 EKS A 集群中就可以有一个四层的负载均衡设施
- 通过 VPC Peering 打通两个 VPC
- EKS B 中的 pod 通过 LB 来 通信访问 Service。
方案三:VPC Peering + Local DNS
通过 VPC Peering 打通两个 VPC 的网络隔离后,其实每个 EKS 中的服务一般都会使用 K8S 原生的 Service,使得集群内部可以通过这个 Service 来访问各自的服务,那我们只要能够使得 EKS B 集群的 Pod 能够解析 EKS A 中的 Service DNS 就好了。
目前 K8S 提供两种 DNS 解析服务:
KubeDNS
KubeDNS是Kubernetes官方推荐的DNS解析服务,kubeDNS由3个部分组成:
- kubedns: 依赖 client-go 中的 informer 机制监视 k8s 中的 Service 和 Endpoint 的变化,并将这些结构维护进内存来服务内部 DNS 解析请求
- dnsmasq: 区分 Domain 是集群内部还是外部,给外部域名提供上游解析,内部域名发往 10053 端口,并将解析结果缓存,提高解析效率。
- sidecar: 对 kubedns 和 dnsmasq 进行健康检查和收集监控指标。
此外 kubeDNS 提供配置文件实现不同DNS域名解析的路由,两种都可以使用
点击查看代码
apiVersion: v1
kind: ConfigMap
metadata:
labels:
addonmanager.kubernetes.io/mode: EnsureExists
name: kube-dns
namespace: kube-system
data:
stubDomains: |
{
"upstream.svc.cluster.local": [
"nlb address"
]
}
CoreDNS
CoreDNS 是由 CNCF 托管的可扩展的 DNS 服务, 允许用户通过编写插件的形式去自行处理 DNS 数据,同样提供 corefile 配置文件形式,实现不同 DNS 域名解析路由的功能
点击查看代码
apiVersion: v1
kind: ConfigMap
metadata:
labels:
addonmanager.kubernetes.io/mode: EnsureExists
name: kube-dns
namespace: kube-system
data:
.:53 {
log
errors
health
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance round_robin
}
upstream.svc.cluster.local:53 {
errors
cache 30
forward . [nlb address] {
prefer_udp
}
}
那么我们的方案也就出来了:
- 通过 VPC peering打通网络
- 在 EKS A 集群里创建 LB 挂在到 EKS A 集群 CoreDNS 服务的端口
- 在 EKS B集群创建 CoreDNS 的配置文件,将 EKS A 集群的域名解析到 EKS A 申请的 LB IP 上,EKS B 集群的域名解析到本地的 CoreDNS 服务上,这样我们可以通过自建的 CoreDNS 服务 route 对应的域名
- 修改 Pod 的 DNSConfig 填写我们自建的 CoreDNS Service 的 ClusterIP,DnsPolicy 填 None。
- EKS B 中 POD 可以通过解析 EKS A Service 的 IP 来访问,因为 VPC Peering 已经打通了网络。
总结
- 方案一:
优点:安全性高,无 CIDR 依赖
缺点:成本高,不可跨 Region - 方案二:
优点:成本较低,操作较简单,可跨 Region
缺点:有 CIDR 依赖,安全性依赖安全组设置 - 方案三:
优点:打通两套 K8S 的 DNS 解析,更加灵活。
缺点:有 CIDR 依赖,安全性依赖安全组设置,操作复杂。