本地 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 集群(frontendbackend)中的应用程序是 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 selectorsdnsConfig(在 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(为简单起见)发送从 frontendbackend 的请求,当涉及到 DNS 时,您将有一个特定的顺序分辨率:

  • 查看集群内的DNS记录
  • 检查dnsConfig中指定的DNS记录

连接到您的 backend 的细节如下:

  • 如果 Pod 与您的 backend 在集群中可用,DNS 解析将指向 Pod 的 IP(而不是 ClusterIP
  • 如果Podbackend由于各种原因在集群中不可用,DNS解析会先检查内部记录,然后选择使用DOMAIN.NAMEdnsConfig 中(在 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).


其他资源:


编辑:

您还可以查看其他选项:

备选方案 1:

  • 使用 CoreDNS 中的重写规则插件将 backendapi.learning.com 的 DNS 查询重写为 backendapi.default.svc.cluster.local

备选方案 2:

您还可以使用 Configmaps 来重复使用 .env 个文件。