<p>Initially, I've deployed my frontend web application and all the backend APIS in <code>AWS ECS</code>, each of the backend APIs has a <code>Route53</code> record, and the frontend is connected to these APIs in the <code>.env</code> file. Now, I would like to migrate from <code>ECS</code> to <code>EKS</code> and I am trying to deploy all these application in a <code>Minikube</code> local cluster. I would like to keep my <code>.env</code> in my frontend application unchanged(using the same URLs for all the environment variables), the application should first look for the backend API inside the local cluster through service discovery, if the backend API doesn't exist in the cluster, it should connect to the the external service, which is the API deployed in the <code>ECS</code>. In short, first local(<code>Minikube cluster</code>)then external(<code>AWS</code>). How to implement this in <code>Kubernetes</code>?</p>
<p>http:// backendapi.learning.com --&gt; backend API deployed in the pod --&gt; if not presented --&gt; backend API deployed in the ECS</p>
<p>.env</p>
<pre><code>BACKEND_API_URL = http://backendapi.learning.com
</code></pre>
<p>one of the example in the code in which the frontend is calling the backend API</p>
<pre><code>export const ping = async _ =&gt; {
    const res = await fetch(`${process.env.BACKEND_API_URL}/ping`);
    const json = await res.json();
    return json;
}
</code></pre>

<p>Assuming that your setup is:</p>
<ul>
<li>Basing on microservices architecture.</li>
<li>Applications deployed in Kubernetes cluster (<code>frontend</code> and <code>backend</code>) are <code>Dockerized</code></li>
<li>Applications are capable to be running on top of Kubernetes.</li>
<li>etc.</li>
</ul>
<p>You can configure your Kubernetes cluster (<code>minikube</code> instance) to relay your request to different locations by using <code>Services</code>.</p>
<hr />
<h3>Service</h3>
<p>In Kubernetes terminology &quot;Service&quot; is an abstract way to expose an application running on a set of Pods as a network service.</p>
<p>Some of the types of <code>Services</code> are following:</p>
<blockquote>
<ul>
<li><code>ClusterIP</code>: Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the default <code>ServiceType</code>.</li>
<li><code>NodePort</code>: Exposes the Service on each Node's IP at a static port (the <code>NodePort</code>). A <code>ClusterIP</code> Service, to which the <code>NodePort</code> Service routes, is automatically created. You'll be able to contact the NodePort Service, from outside the cluster, by requesting <code>&lt;NodeIP&gt;</code>:<code>&lt;NodePort&gt;</code>.</li>
<li><code>LoadBalancer</code>: Exposes the Service externally using a cloud provider's load balancer. <code>NodePort</code> and <code>ClusterIP</code> Services, to which the external load balancer routes, are automatically created.</li>
<li><code>ExternalName</code>: Maps the Service to the contents of the <code>externalName</code> field (e.g. <code>foo.bar.example.com</code>), by returning a <code>CNAME</code> record with its value. No proxying of any kind is set up.</li>
</ul>
<p><a href="https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types" rel="nofollow noreferrer">https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types</a></p>
</blockquote>
<p><strong>You can use <code>Headless Service with selectors</code> and <code>dnsConfig</code> (in <code>Deployment</code> manifest) to achieve the setup referenced in your question</strong>.</p>
<p>Let me explain more:</p>
<hr />
<h3>Example</h3>
<p>Let's assume that you have a <code>backend</code>:</p>
<ul>
<li><code>nginx-one</code> - located <strong>inside</strong> and <strong>outside</strong></li>
</ul>
<p>Your <code>frontend</code> manifest in most basic form should look following:</p>
<ul>
<li><code>deployment.yaml</code>:</li>
</ul>
<pre class="lang-yaml prettyprint-override"><code>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
        - &quot;infinity&quot; 
      dnsConfig: # &lt;--- IMPORTANT 
        searches: 
        - DOMAIN.NAME 
</code></pre>
<p>Taking specific look on:</p>
<pre><code>      dnsConfig: # &lt;--- IMPORTANT 
        searches: 
        - DOMAIN.NAME 
</code></pre>
<p>Dissecting above part:</p>
<ul>
<li>
<blockquote>
<p><code>dnsConfig</code> - the dnsConfig field is optional and it can work with any <code>dnsPolicy</code> settings. However, when a Pod's <code>dnsPolicy</code> is set to &quot;<code>None</code>&quot;, the <code>dnsConfig</code> field has to be specified.</p>
</blockquote>
</li>
<li>
<blockquote>
<p><code>searches</code>: 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.</p>
</blockquote>
</li>
</ul>
<p>As for the <code>Services</code> for your <code>backends</code>.</p>
<ul>
<li><code>service.yaml</code>:</li>
</ul>
<pre><code>apiVersion: v1
kind: Service
metadata:
  name: nginx-one
spec:
  clusterIP: None # &lt;-- IMPORTANT
  selector:
    app: nginx-one
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 80
</code></pre>
<p>Above <code>Service</code> will tell your frontend that one of your <code>backends</code> (<code>nginx</code>) is available through a <code>Headless service</code> (why it's <code>Headless</code> will come in hand later!). By default you could communicate with it by:</p>
<ul>
<li><code>service-name</code> (<code>nginx-one</code>)</li>
<li><code>service-name.namespace.svc.cluster.local</code> (<code>nginx-one.default.svc.cluster.local</code>) - only locally</li>
</ul>
<hr />
<h3>Connecting to your backend</h3>
<p>Assuming that you are sending the request using <code>curl</code> (for simplicity) from <code>frontend</code> to <code>backend</code> you will have a specific order when it comes to the <code>DNS</code> resolution:</p>
<ul>
<li>check the <code>DNS</code> record inside the cluster</li>
<li>check the <code>DNS</code> record specified in <code>dnsConfig</code></li>
</ul>
<p>The specifics of connecting to your <code>backend</code> will be following:</p>
<ul>
<li>If the <code>Pod</code> with your <code>backend</code> is available in the cluster, the <code>DNS</code> resolution will point to the Pod's IP (not <code>ClusterIP</code>)</li>
<li>If the <code>Pod</code> <code>backend</code> is not available in the cluster due to various reasons, the <code>DNS</code> resolution will first check the internal records and then opt to use <code>DOMAIN.NAME</code> in the <code>dnsConfig</code> (outside of <code>minikube</code>).</li>
<li>If there is no <code>Service</code> associated with specific <code>backend</code> (<code>nginx-one</code>), the <code>DNS</code> resolution will use the <code>DOMAIN.NAME</code> in the <code>dnsConfig</code> searching for it outside of the cluster.</li>
</ul>
<blockquote>
<p>A side note!</p>
<p>The <code>Headless Service with selector</code> comes into play here as its intention is to point directly to the <code>Pod</code>'s IP and not the <code>ClusterIP</code> (which exists as long as <code>Service</code> exists). If you used a &quot;normal&quot; <code>Service</code> you would always try to communicate with the <code>ClusterIP</code> even if there is no <code>Pods</code> available matching the selector. By using a <code>headless</code> one, if there is no <code>Pod</code>, the <code>DNS</code> resolution would look further down the line (external sources).</p>
</blockquote>
<hr />
<p>Additional resources:</p>
<ul>
<li><em><a href="https://minikube.sigs.k8s.io/docs/start/" rel="nofollow noreferrer">Minikube.sigs.k8s.io: Docs: Start</a></em></li>
<li><em><a href="https://aws.amazon.com/blogs/compute/enabling-dns-resolution-for-amazon-eks-cluster-endpoints/" rel="nofollow noreferrer">Aws.amazon.com: Blogs: Compute: Enabling dns resolution for amazon eks cluster endpoints</a></em></li>
</ul>
<hr />
<h3>EDIT:</h3>
<p>You could also take a look on alternative options:</p>
<p>Alernative option 1:</p>
<ul>
<li>Use rewrite rule plugin in CoreDNS to rewrite DNS queries for <code>backendapi.learning.com</code> to <code>backendapi.default.svc.cluster.local</code></li>
</ul>
<p>Alernative option 2:</p>
<ul>
<li>Add <a href="https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/#adding-additional-entries-with-hostaliases" rel="nofollow noreferrer">hostAliases</a> to the Frontend Pod</li>
</ul>
<p>You can also use <a href="https://cloud.google.com/kubernetes-engine/docs/concepts/configmap#creating_a_configmap" rel="nofollow noreferrer">Configmaps</a> to re-use <code>.env</code> files.</p>
