<p>I'm trying to deploy my simple web application using Kubernetes.
I completed making the Kubernetes cluster and successfully exposed my react app using ingress.
But it seems that the domain URL of backend service received from manifest file's "env" field does not work.</p>

<p>Following is the manifest file of react application.</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  name: recofashion-client
  labels:
    app: recofashion-client
spec:
  type: NodePort
  selector:
    app: recofashion-client
  ports:
    - name: http
      port: 80
      targetPort: 3000

---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: recofashion-client
  labels:
    name: recofashion-client
spec:
  replicas: 2
  selector:
    matchLabels:
      app: recofashion-client
  template:
    metadata:
      labels:
        app: recofashion-client
    spec:
      containers:
      - name: web
        image: recofashion/client-runtime
        imagePullPolicy: Always
        ports:
        - containerPort: 3000
        env:
        - name: NODE_ENV
          value: production
        - name: REACT_APP_API_V1_ENDPOINT
          value: http://recofashion-api/api/v1
</code></pre>

<p>And I think there is no problem in k8s DNS itself. I tried to send request using curl in my "recofashion-client" pod, and it seems to work as I intended.</p>

<pre><code>curl http://recofashion-api/api/v1/user/me
{"timestamp":"2020-02-03T06:55:20.748+0000","status":403,"error":"Forbidden","message":"Access Denied","path":"/api/v1/user/me"}
</code></pre>

<p>But when I try to send request in the browser, it fails like this:</p>

<p><img src="https://i.stack.imgur.com/PEIJ2.png" alt="image"></p>

<p>And I'm receiving the external environment variables in react app from k8s like this:</p>

<pre><code>const response = await getWithAuth(`${process.env.REACT_APP_API_V1_ENDPOINT}/user/me`)
</code></pre>

<p>So what's the problem??? I searched internet a lot, but I couldn't get any appopriate answer...</p>

<p>++ the manifest file of ingress</p>

<pre><code>kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: ingress
spec:
  rules:
  - http:
      paths:
      - path: /*
        backend:
          serviceName: recofashion-client
          servicePort: 80
</code></pre>

<p>Based on all informations provided I managed to reproduce your scenario using GKE.</p>

<p><strong>TL;DR:</strong></p>

<ul>
<li>Yes, the correct service-type for your <strong>api-service</strong> is <code>ClusterIP</code></li>
<li>The correct service-type for your <strong>api-client</strong> for outside access  is <code>LoadBalancer</code>, <a href="https://cloud.google.com/kubernetes-engine/docs/how-to/exposing-apps#access_your_service_2" rel="nofollow noreferrer">doc here</a>.</li>
<li><p>Your <strong>ENV</strong> <code>REACT_APP_API_V1_ENDPOINT</code> must point to <strong>Api Service</strong> address, not to deploy or pod address. (i.e: <code>value: http://recofashion-api-svc</code>)</p></li>
<li><p>You cannot use cluster DNS externally.</p></li>
</ul>

<h2><strong>Reproduction</strong></h2>

<p>Since I don't have your react app, I'm using an echo-app to simulate the two parts of the communication. This way I'm manually reproducing what your application would do by itself.</p>

<ul>
<li>First between <code>internet</code> and <code>recofashion-client</code></li>
<li>Second between <code>recofashion-client</code> and <code>recofashion-api</code>.</li>
</ul>

<p><strong><code>recofashion-client</code> - FrontEnd</strong>:</p>

<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: recofashion-client
  labels:
    name: recofashion-client
spec:
  replicas: 2
  selector:
    matchLabels:
      app: recofashion-client
  template:
    metadata:
      labels:
        app: recofashion-client
    spec:
      containers:
      - name: web
        image: mendhak/http-https-echo
        ports:
        - name: http
          containerPort: 80
        env:
        - name: NODE_ENV
          value: production
        - name: REACT_APP_API_V1_ENDPOINT
          value: http://recofashion-api-svc
---
apiVersion: v1
kind: Service
metadata:
  name: recofashion-cli-svc
  labels:
    app: recofashion-client
spec:
  type: LoadBalancer
  selector:
    app: recofashion-client
  ports:
    - name: http
      port: 3000
      targetPort: 80
</code></pre>

<p><strong><code>recofashion-api</code> - backend API</strong>:</p>

<pre><code>kind: Deployment
apiVersion: apps/v1
metadata:
  name: recofashion-api
  labels:
    name: recofashion-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: recofashion-api
  template:
    metadata:
      labels:
        app: recofashion-api
    spec:
      containers:
      - name: api-web
        image: mendhak/http-https-echo
        imagePullPolicy: Always
        ports:
        - containerPort: 80
        env:
        - name: NODE_ENV
          value: production
---
kind: Service
apiVersion: v1
metadata:
  name: recofashion-api-svc
  labels:
    app: recofashion-api
spec:
  selector:
    app: recofashion-api
  ports:
    - name: http
      port: 80
      targetPort: 80
</code></pre>

<p>Note: <strong>I kept your Ingress intact.</strong></p>

<p><strong>Now to the terminal:</strong></p>

<pre><code>$ kubectl get nodes
NAME                                       STATUS   ROLES    AGE   VERSION
gke-cluster-1-default-pool-e0523823-06jt   Ready    &lt;none&gt;   2d    v1.15.7-gke.23
gke-cluster-1-default-pool-e0523823-vklh   Ready    &lt;none&gt;   2d    v1.15.7-gke.23

$ kubectl apply -f recofashion-full.yaml 
deployment.apps/recofashion-client created
service/recofashion-cli-svc created
deployment.apps/recofashion-api created
service/recofashion-api-svc created
ingress.extensions/reco-ingress created

$ kubectl get all 
NAME                                      READY   STATUS    RESTARTS   AGE
pod/recofashion-api-784b4d9897-9256q      1/1     Running   0          12m
pod/recofashion-api-784b4d9897-ljkfs      1/1     Running   0          12m
pod/recofashion-client-75579c8499-wd5vj   1/1     Running   0          12m
pod/recofashion-client-75579c8499-x766s   1/1     Running   0          12m

NAME                          TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)          AGE
service/kubernetes            ClusterIP      10.0.0.1     &lt;none&gt;          443/TCP          2d
service/recofashion-api-svc   ClusterIP      10.0.4.73    &lt;none&gt;          80/TCP           12m
service/recofashion-cli-svc   LoadBalancer   10.0.3.133   35.239.58.188   3000:31814/TCP   12m

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/recofashion-api      2/2     2            2           13m
deployment.apps/recofashion-client   2/2     2            2           13m

NAME                                            DESIRED   CURRENT   READY   AGE
replicaset.apps/recofashion-api-784b4d9897      2         2         2       13m
replicaset.apps/recofashion-client-75579c8499   2         2         2       13m

$ curl http://35.239.58.188:3000  
{
  "path": "/",
  "headers": {
    "host": "35.239.58.188:3000",
    "user-agent": "curl/7.66.0",
  },
  "method": "GET",
  "body": "",
  "hostname": "35.239.58.188",
  "ip": "::ffff:10.8.1.1",
  "protocol": "http",
  "os": {
    "hostname": "recofashion-client-75579c8499-x766s"
  }
}
</code></pre>

<p><a href="https://i.stack.imgur.com/ZDm3a.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/ZDm3a.png" alt="Client Access from browser from outside network"></a></p>

<p>So far no problems, we are able to <code>curl</code> from outside to the <code>recofashion-client</code>.</p>

<p><strong>Now let's connect inside <code>recofashion-client</code> and try to connect to <code>recofashion-api</code> using the ENV created during deploy:</strong></p>

<pre><code>❯ kubectl exec recofashion-client-75579c8499-x766s -it sh
/app # apk update &amp;&amp; apk add curl
OK: 10 MiB in 20 packages

/app # env
REACT_APP_API_V1_ENDPOINT=http://recofashion-api-svc
NODE_ENV=production

/app # curl $REACT_APP_API_V1_ENDPOINT
{
  "path": "/",
  "headers": {
    "host": "recofashion-api-svc",
    "user-agent": "curl/7.61.1",
    "accept": "*/*"
  },
  "method": "GET",
  "body": "",
  "hostname": "recofashion-api-svc",
  "ip": "::ffff:10.8.1.21",
  "protocol": "http",
  "os": {
    "hostname": "recofashion-api-784b4d9897-9256q"
  }
}

/app # nslookup recofashion-api-svc
Name:      recofashion-api-svc
Address 1: 10.0.4.73 recofashion-api-svc.default.svc.cluster.local
</code></pre>

<p>When we use the <code>api-service</code> name in the ENV <code>value</code>, it resolves the DNS because the service is the responsible for directing the load to the PODs.</p>

<ul>
<li>Follow this steps and you can be sure that your K8s configuration won't be an issue.</li>
</ul>

<p><strong>Edit:</strong></p>

<ul>
<li>If your React is outside the cluster, the best way you can access the backend-api is creating a service to reach to the backend pods and address your request the exposed ip and port of the service, just like we did.</li>
<li>Now, if you want this to work with external DNS names for the whole cluster, take a look on some external dns projects like this: <a href="https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/nginx-ingress.md" rel="nofollow noreferrer">https://github.com/kubernetes-sigs/external-dns/blob/master/docs/tutorials/nginx-ingress.md</a></li>
</ul>
