本地 Minikube 集群和 AWS 中的水平分割 DNS
Split Horizon DNS in local Minikube cluster and AWS
最初,我在 AWS ECS
中部署了我的前端 Web 应用程序和所有后端 APIS,每个后端 APIs 都有一个 Route53
记录,并且前端连接到 .env
文件中的这些 API。现在,我想从 ECS
迁移到 EKS
,我正在尝试将所有这些应用程序部署到 Minikube
本地集群中。我想在我的前端应用程序中保持我的 .env
不变(对所有环境变量使用相同的 URL),应用程序应该首先通过服务发现在本地集群中寻找后端 API,如果后端 API 不存在于集群中,它应该连接到外部服务,即部署在 ECS
中的 API。简而言之,首先是本地 (Minikube cluster
),然后是外部 (AWS
)。如何在 Kubernetes
?
中实现
http:// backendapi.learning.com --> 后端API 部署在pod中 --> 如果没有呈现 --> 后端API 部署在ECS中
.env
BACKEND_API_URL = http://backendapi.learning.com
前端调用后端的代码示例之一API
export const ping = async _ => {
const res = await fetch(`${process.env.BACKEND_API_URL}/ping`);
const json = await res.json();
return json;
}
假设您的设置是:
- 基于微服务架构。
- 部署在 Kubernetes 集群(
frontend
和 backend
)中的应用程序是 Dockerized
- 应用程序能够 运行 在 Kubernetes 之上。
- 等等
您可以配置您的 Kubernetes 集群(minikube
实例)使用 Services
将您的请求转发到不同的位置。
服务
在 Kubernetes 术语中,“服务”是一种抽象方式,用于将一组 Pods 上的应用程序 运行 作为网络服务公开。
Services
的部分类型如下:
ClusterIP
: Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the default ServiceType
.
NodePort
: Exposes the Service on each Node's IP at a static port (the NodePort
). A ClusterIP
Service, to which the NodePort
Service routes, is automatically created. You'll be able to contact the NodePort Service, from outside the cluster, by requesting <NodeIP>
:<NodePort>
.
LoadBalancer
: Exposes the Service externally using a cloud provider's load balancer. NodePort
and ClusterIP
Services, to which the external load balancer routes, are automatically created.
ExternalName
: Maps the Service to the contents of the externalName
field (e.g. foo.bar.example.com
), by returning a CNAME
record with its value. No proxying of any kind is set up.
https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
您可以使用 Headless Service with selectors
和 dnsConfig
(在 Deployment
清单中)来实现您的问题中引用的设置。
让我再解释一下:
示例
假设您有一个 backend
:
nginx-one
- 位于内部和外部
您的 frontend
最基本形式的清单应如下所示:
deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
replicas: 1
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: ubuntu
image: ubuntu
command:
- sleep
- "infinity"
dnsConfig: # <--- IMPORTANT
searches:
- DOMAIN.NAME
具体看:
dnsConfig: # <--- IMPORTANT
searches:
- DOMAIN.NAME
剖析以上部分:
-
dnsConfig
- the dnsConfig field is optional and it can work with any dnsPolicy
settings. However, when a Pod's dnsPolicy
is set to "None
", the dnsConfig
field has to be specified.
-
searches
: a list of DNS search domains for hostname lookup in the Pod. This property is optional. When specified, the provided list will be merged into the base search domain names generated from the chosen DNS policy. Duplicate domain names are removed. Kubernetes allows for at most 6 search domains.
至于 Services
你的 backends
.
service.yaml
:
apiVersion: v1
kind: Service
metadata:
name: nginx-one
spec:
clusterIP: None # <-- IMPORTANT
selector:
app: nginx-one
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
Above Service
将告诉您的前端您的 backends
(nginx
) 之一可通过 Headless service
访问(为什么 Headless
会出现稍后在手!)。默认情况下,您可以通过以下方式与其通信:
service-name
(nginx-one
)
service-name.namespace.svc.cluster.local
(nginx-one.default.svc.cluster.local
) - 仅限本地
正在连接到您的后端
假设您使用 curl
(为简单起见)发送从 frontend
到 backend
的请求,当涉及到 DNS
时,您将有一个特定的顺序分辨率:
- 查看集群内的
DNS
记录
- 检查
dnsConfig
中指定的DNS
记录
连接到您的 backend
的细节如下:
- 如果
Pod
与您的 backend
在集群中可用,DNS
解析将指向 Pod 的 IP(而不是 ClusterIP
)
- 如果
Pod
backend
由于各种原因在集群中不可用,DNS
解析会先检查内部记录,然后选择使用DOMAIN.NAME
在 dnsConfig
中(在 minikube
之外)。
- 如果没有
Service
与特定的 backend
(nginx-one
) 关联,DNS
分辨率将使用 [=35] 中的 DOMAIN.NAME
=] 在集群外搜索它。
A side note!
The Headless Service with selector
comes into play here as its intention is to point directly to the Pod
's IP and not the ClusterIP
(which exists as long as Service
exists). If you used a "normal" Service
you would always try to communicate with the ClusterIP
even if there is no Pods
available matching the selector. By using a headless
one, if there is no Pod
, the DNS
resolution would look further down the line (external sources).
其他资源:
- Minikube.sigs.k8s.io: Docs: Start
- Aws.amazon.com: Blogs: Compute: Enabling dns resolution for amazon eks cluster endpoints
编辑:
您还可以查看其他选项:
备选方案 1:
- 使用 CoreDNS 中的重写规则插件将
backendapi.learning.com
的 DNS 查询重写为 backendapi.default.svc.cluster.local
备选方案 2:
- 将 hostAliases 添加到前端 Pod
您还可以使用 Configmaps 来重复使用 .env
个文件。
最初,我在 AWS ECS
中部署了我的前端 Web 应用程序和所有后端 APIS,每个后端 APIs 都有一个 Route53
记录,并且前端连接到 .env
文件中的这些 API。现在,我想从 ECS
迁移到 EKS
,我正在尝试将所有这些应用程序部署到 Minikube
本地集群中。我想在我的前端应用程序中保持我的 .env
不变(对所有环境变量使用相同的 URL),应用程序应该首先通过服务发现在本地集群中寻找后端 API,如果后端 API 不存在于集群中,它应该连接到外部服务,即部署在 ECS
中的 API。简而言之,首先是本地 (Minikube cluster
),然后是外部 (AWS
)。如何在 Kubernetes
?
http:// backendapi.learning.com --> 后端API 部署在pod中 --> 如果没有呈现 --> 后端API 部署在ECS中
.env
BACKEND_API_URL = http://backendapi.learning.com
前端调用后端的代码示例之一API
export const ping = async _ => {
const res = await fetch(`${process.env.BACKEND_API_URL}/ping`);
const json = await res.json();
return json;
}
假设您的设置是:
- 基于微服务架构。
- 部署在 Kubernetes 集群(
frontend
和backend
)中的应用程序是Dockerized
- 应用程序能够 运行 在 Kubernetes 之上。
- 等等
您可以配置您的 Kubernetes 集群(minikube
实例)使用 Services
将您的请求转发到不同的位置。
服务
在 Kubernetes 术语中,“服务”是一种抽象方式,用于将一组 Pods 上的应用程序 运行 作为网络服务公开。
Services
的部分类型如下:
ClusterIP
: Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the defaultServiceType
.NodePort
: Exposes the Service on each Node's IP at a static port (theNodePort
). AClusterIP
Service, to which theNodePort
Service routes, is automatically created. You'll be able to contact the NodePort Service, from outside the cluster, by requesting<NodeIP>
:<NodePort>
.LoadBalancer
: Exposes the Service externally using a cloud provider's load balancer.NodePort
andClusterIP
Services, to which the external load balancer routes, are automatically created.ExternalName
: Maps the Service to the contents of theexternalName
field (e.g.foo.bar.example.com
), by returning aCNAME
record with its value. No proxying of any kind is set up.https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
您可以使用 Headless Service with selectors
和 dnsConfig
(在 Deployment
清单中)来实现您的问题中引用的设置。
让我再解释一下:
示例
假设您有一个 backend
:
nginx-one
- 位于内部和外部
您的 frontend
最基本形式的清单应如下所示:
deployment.yaml
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
spec:
selector:
matchLabels:
app: frontend
replicas: 1
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: ubuntu
image: ubuntu
command:
- sleep
- "infinity"
dnsConfig: # <--- IMPORTANT
searches:
- DOMAIN.NAME
具体看:
dnsConfig: # <--- IMPORTANT
searches:
- DOMAIN.NAME
剖析以上部分:
-
dnsConfig
- the dnsConfig field is optional and it can work with anydnsPolicy
settings. However, when a Pod'sdnsPolicy
is set to "None
", thednsConfig
field has to be specified. -
searches
: a list of DNS search domains for hostname lookup in the Pod. This property is optional. When specified, the provided list will be merged into the base search domain names generated from the chosen DNS policy. Duplicate domain names are removed. Kubernetes allows for at most 6 search domains.
至于 Services
你的 backends
.
service.yaml
:
apiVersion: v1
kind: Service
metadata:
name: nginx-one
spec:
clusterIP: None # <-- IMPORTANT
selector:
app: nginx-one
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
Above Service
将告诉您的前端您的 backends
(nginx
) 之一可通过 Headless service
访问(为什么 Headless
会出现稍后在手!)。默认情况下,您可以通过以下方式与其通信:
service-name
(nginx-one
)service-name.namespace.svc.cluster.local
(nginx-one.default.svc.cluster.local
) - 仅限本地
正在连接到您的后端
假设您使用 curl
(为简单起见)发送从 frontend
到 backend
的请求,当涉及到 DNS
时,您将有一个特定的顺序分辨率:
- 查看集群内的
DNS
记录 - 检查
dnsConfig
中指定的DNS
记录
连接到您的 backend
的细节如下:
- 如果
Pod
与您的backend
在集群中可用,DNS
解析将指向 Pod 的 IP(而不是ClusterIP
) - 如果
Pod
backend
由于各种原因在集群中不可用,DNS
解析会先检查内部记录,然后选择使用DOMAIN.NAME
在dnsConfig
中(在minikube
之外)。 - 如果没有
Service
与特定的backend
(nginx-one
) 关联,DNS
分辨率将使用 [=35] 中的DOMAIN.NAME
=] 在集群外搜索它。
A side note!
The
Headless Service with selector
comes into play here as its intention is to point directly to thePod
's IP and not theClusterIP
(which exists as long asService
exists). If you used a "normal"Service
you would always try to communicate with theClusterIP
even if there is noPods
available matching the selector. By using aheadless
one, if there is noPod
, theDNS
resolution would look further down the line (external sources).
其他资源:
- Minikube.sigs.k8s.io: Docs: Start
- Aws.amazon.com: Blogs: Compute: Enabling dns resolution for amazon eks cluster endpoints
编辑:
您还可以查看其他选项:
备选方案 1:
- 使用 CoreDNS 中的重写规则插件将
backendapi.learning.com
的 DNS 查询重写为backendapi.default.svc.cluster.local
备选方案 2:
- 将 hostAliases 添加到前端 Pod
您还可以使用 Configmaps 来重复使用 .env
个文件。