title: How do I get one pod to network to another pod in Kubernetes? (SIMPLE)
body: <p>I've been banging my head against this wall on and off for a while. There is a ton of information on Kubernetes on the web, but it's all assuming so much knowledge that n00bs like me don't really have much to go on.</p>
  
  <p>So, can anyone share a <strong>simple</strong> example of the following (as a yaml file)? All I want is</p>
  
  <ul>
  <li>two pods</li>
  <li>let's say one pod has a backend (I don't know - node.js), and one has a frontend (say React). </li>
  <li>A way to network between them.</li>
  </ul>
  
  <p>And then an example of calling an api call from the back to the front.</p>
  
  <p>I start looking into this sort of thing, and all of a sudden I hit this page - <a href="https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-achieve-this" rel="noreferrer">https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-achieve-this</a>. This is <strong>super unhelpful</strong>. I don't want or need advanced network policies, nor do I have the time to go through several different service layers that are mapped on top of kubernetes. I just want to figure out a trivial example of a network request.</p>
  
  <p>Hopefully if this example exists on stackoverflow it will serve other people as well.</p>
  
  <p>Any help would be appreciated. Thanks.</p>
  
  <p><strong>EDIT;</strong> it looks like the easiest example may be using the Ingress controller. </p>
  
  <p><strong>EDIT EDIT;</strong> </p>
  
  <p>I'm working to try and get a minimal example deployed - I'll walk through some steps here and point out my issues.</p>
  
  <p>So below is my <code>yaml</code> file:</p>
  
  <pre><code>apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: frontend
    labels:
      app: frontend
  spec:
    replicas: 3
    selector:
      matchLabels:
        app: frontend
    template:
      metadata:
        labels:
          app: frontend
      spec:
        containers:
        - name: nginx
          image: patientplatypus/frontend_example
          ports:
          - containerPort: 3000
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: frontend
  spec:
    type: LoadBalancer
    selector:
      app: frontend
    ports:
      - protocol: TCP
        port: 80
        targetPort: 3000
  ---
  apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: backend
    labels:
      app: backend
  spec:
    replicas: 3
    selector:
      matchLabels:
        app: backend
    template:
      metadata:
        labels:
          app: backend
      spec:
        containers:
        - name: nginx
          image: patientplatypus/backend_example
          ports:
          - containerPort: 5000
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: backend
  spec:
    type: LoadBalancer
    selector:
      app: backend
    ports:
      - protocol: TCP
        port: 80
        targetPort: 5000
  ---
  apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    name: frontend
  spec:      
    rules:
    - host: www.kubeplaytime.example
      http:
        paths:
        - path: /
          backend:
            serviceName: frontend
            servicePort: 80
        - path: /api
          backend:
            serviceName: backend
            servicePort: 80
  </code></pre>
  
  <p>What I believe this is doing is </p>
  
  <ul>
  <li><p>Deploying a frontend and backend app - I deployed <code>patientplatypus/frontend_example</code> and <code>patientplatypus/backend_example</code> to dockerhub and then pull the images down. One open question I have is, what if I don't want to pull the images from docker hub and rather would just like to load from my localhost, is that possible? In this case I would push my code to the production server, build the docker images on the server and then upload to kubernetes. The benefit is that I don't have to rely on dockerhub if I want my images to be private.</p></li>
  <li><p>It is creating two service endpoints that route outside traffic from a web browser to each of the deployments. These services are of type <code>loadBalancer</code> because they are balancing the traffic among the (in this case 3) replicasets that I have in the deployments.</p></li>
  <li><p>Finally, I have an ingress controller which is <em>supposed</em> to allow my services to route to each other through <code>www.kubeplaytime.example</code> and <code>www.kubeplaytime.example/api</code>. However this is not working.</p></li>
  </ul>
  
  <p>What happens when I run this?</p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:09:17:50$kubectl create -f kube-deploy.yaml
  deployment.apps "frontend" created
  service "frontend" created
  deployment.apps "backend" created
  service "backend" created
  ingress.extensions "frontend" created
  </code></pre>
  
  <ul>
  <li><p>So first, it appears to create all the parts that I need fine with no errors.</p>
  
  <p><code>patientplatypus:~/Documents/kubePlay:09:22:30$kubectl get --watch services</code></p>
  
  <p><code>NAME         TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)        AGE</code></p>
  
  <p><code>backend      LoadBalancer   10.0.18.174   &lt;pending&gt;     80:31649/TCP   1m</code></p>
  
  <p><code>frontend     LoadBalancer   10.0.100.65   &lt;pending&gt;     80:32635/TCP   1m</code></p>
  
  <p><code>kubernetes   ClusterIP      10.0.0.1      &lt;none&gt;        443/TCP        10d</code></p>
  
  <p><code>frontend   LoadBalancer   10.0.100.65   138.91.126.178   80:32635/TCP   2m</code></p>
  
  <p><code>backend   LoadBalancer   10.0.18.174   138.91.121.182   80:31649/TCP   2m</code></p></li>
  <li><p>Second, if I watch the services, I eventually get IP addresses that I can use to navigate in my browser to these sites. Each of the above IP addresses works in routing me to the frontend and backend respectively.</p></li>
  </ul>
  
  <p><strong>HOWEVER</strong></p>
  
  <p>I reach an issue when I try and use the ingress controller - it seemingly deployed, but I don't know how to get there.</p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:09:24:44$kubectl get ingresses
  NAME       HOSTS                      ADDRESS   PORTS     AGE
  frontend   www.kubeplaytime.example             80        16m
  </code></pre>
  
  <ul>
  <li>So I have no address I can use, and <code>www.kubeplaytime.example</code> does not appear to work.</li>
  </ul>
  
  <p>What it appears that I have to do to route to the ingress extension I just created is to use a service and deployment on <em>it</em> in order to get an IP address, but this starts to look incredibly complicated very quickly.</p>
  
  <p>For example, take a look at this medium article: <a href="https://medium.com/@cashisclay/kubernetes-ingress-82aa960f658e" rel="noreferrer">https://medium.com/@cashisclay/kubernetes-ingress-82aa960f658e</a>.</p>
  
  <p>It would appear that the necessary code to add for just the service routing to the Ingress (ie what he calls the <strong>Ingress Controller</strong>) appears to be this:</p>
  
  <pre><code>---
  kind: Service
  apiVersion: v1
  metadata:
    name: ingress-nginx
  spec:
    type: LoadBalancer
    selector:
      app: ingress-nginx
    ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https
  ---
  kind: Deployment
  apiVersion: extensions/v1beta1
  metadata:
    name: ingress-nginx
  spec:
    replicas: 1
    template:
      metadata:
        labels:
          app: ingress-nginx
      spec:
        terminationGracePeriodSeconds: 60
        containers:
        - image: gcr.io/google_containers/nginx-ingress-controller:0.8.3
          name: ingress-nginx
          imagePullPolicy: Always
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
            - name: https
              containerPort: 443
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /healthz
              port: 10254
              scheme: HTTP
            initialDelaySeconds: 30
            timeoutSeconds: 5
          env:
            - name: POD_NAME
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: POD_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          args:
          - /nginx-ingress-controller
          - --default-backend-service=$(POD_NAMESPACE)/nginx-default-backend
  ---
  kind: Service
  apiVersion: v1
  metadata:
    name: nginx-default-backend
  spec:
    ports:
    - port: 80
      targetPort: http
    selector:
      app: nginx-default-backend
  ---
  kind: Deployment
  apiVersion: extensions/v1beta1
  metadata:
    name: nginx-default-backend
  spec:
    replicas: 1
    template:
      metadata:
        labels:
          app: nginx-default-backend
      spec:
        terminationGracePeriodSeconds: 60
        containers:
        - name: default-http-backend
          image: gcr.io/google_containers/defaultbackend:1.0
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
              scheme: HTTP
            initialDelaySeconds: 30
            timeoutSeconds: 5
          resources:
            limits:
              cpu: 10m
              memory: 20Mi
            requests:
              cpu: 10m
              memory: 20Mi
          ports:
          - name: http
            containerPort: 8080
            protocol: TCP
  </code></pre>
  
  <p>This would seemingly need to be appended to my other <code>yaml</code> code above in order to get a service entry point for my ingress routing, and it does appear to give an ip:</p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:09:54:12$kubectl get --watch services
  NAME                    TYPE           CLUSTER-IP    EXTERNAL-IP   PORT(S)                      AGE
  backend                 LoadBalancer   10.0.31.209   &lt;pending&gt;     80:32428/TCP                 4m
  frontend                LoadBalancer   10.0.222.47   &lt;pending&gt;     80:32482/TCP                 4m
  ingress-nginx           LoadBalancer   10.0.28.157   &lt;pending&gt;     80:30573/TCP,443:30802/TCP   4m
  kubernetes              ClusterIP      10.0.0.1      &lt;none&gt;        443/TCP                      10d
  nginx-default-backend   ClusterIP      10.0.71.121   &lt;none&gt;        80/TCP                       4m
  frontend   LoadBalancer   10.0.222.47   40.121.7.66   80:32482/TCP   5m
  ingress-nginx   LoadBalancer   10.0.28.157   40.121.6.179   80:30573/TCP,443:30802/TCP   6m
  backend   LoadBalancer   10.0.31.209   40.117.248.73   80:32428/TCP   7m
  </code></pre>
  
  <p>So <code>ingress-nginx</code> appears to be the site I want to get to. Navigating to <code>40.121.6.179</code> returns a default 404 message (<code>default backend - 404</code>) - it does not go to <code>frontend</code> as <code>/</code> aught to route. <code>/api</code> returns the same. Navigating to my host namespace <code>www.kubeplaytime.example</code> returns a 404 from the browser - no error handling. </p>
  
  <p><strong>QUESTIONS</strong></p>
  
  <ul>
  <li><p>Is the Ingress Controller strictly necessary, and if so is there a less complicated version of this?</p></li>
  <li><p>I feel I am close, what am I doing wrong?</p></li>
  </ul>
  
  <p><strong>FULL YAML</strong></p>
  
  <p>Available here: <a href="https://gist.github.com/patientplatypus/fa07648339ee6538616cb69282a84938" rel="noreferrer">https://gist.github.com/patientplatypus/fa07648339ee6538616cb69282a84938</a></p>
  
  <p><em>Thanks for the help!</em></p>
  
  <p><strong>EDIT EDIT EDIT</strong></p>
  
  <p>I've attempted to use <strong>HELM</strong>. On the surface it appears to be a simple interface, and so I tried spinning it up: </p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:12:13:00$helm install stable/nginx-ingress
  NAME:   erstwhile-beetle
  LAST DEPLOYED: Sun May  6 12:13:30 2018
  NAMESPACE: default
  STATUS: DEPLOYED
  
  RESOURCES:
  ==&gt; v1/ConfigMap
  NAME                                       DATA  AGE
  erstwhile-beetle-nginx-ingress-controller  1     1s
  
  ==&gt; v1/Service
  NAME                                            TYPE          CLUSTER-IP   EXTERNAL-IP  PORT(S)                     AGE
  erstwhile-beetle-nginx-ingress-controller       LoadBalancer  10.0.216.38  &lt;pending&gt;    80:31494/TCP,443:32118/TCP  1s
  erstwhile-beetle-nginx-ingress-default-backend  ClusterIP     10.0.55.224  &lt;none&gt;       80/TCP                      1s
  
  ==&gt; v1beta1/Deployment
  NAME                                            DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
  erstwhile-beetle-nginx-ingress-controller       1        1        1           0          1s
  erstwhile-beetle-nginx-ingress-default-backend  1        1        1           0          1s
  
  ==&gt; v1beta1/PodDisruptionBudget
  NAME                                            MIN AVAILABLE  MAX UNAVAILABLE  ALLOWED DISRUPTIONS  AGE
  erstwhile-beetle-nginx-ingress-controller       1              N/A              0                    1s
  erstwhile-beetle-nginx-ingress-default-backend  1              N/A              0                    1s
  
  ==&gt; v1/Pod(related)
  NAME                                                             READY  STATUS             RESTARTS  AGE
  erstwhile-beetle-nginx-ingress-controller-7df9b78b64-24hwz       0/1    ContainerCreating  0         1s
  erstwhile-beetle-nginx-ingress-default-backend-849b8df477-gzv8w  0/1    ContainerCreating  0         1s
  
  
  NOTES:
  The nginx-ingress controller has been installed.
  It may take a few minutes for the LoadBalancer IP to be available.
  You can watch the status by running 'kubectl --namespace default get services -o wide -w erstwhile-beetle-nginx-ingress-controller'
  
  An example Ingress that makes use of the controller:
  
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.class: nginx
      name: example
      namespace: foo
    spec:
      rules:
        - host: www.example.com
          http:
            paths:
              - backend:
                  serviceName: exampleService
                  servicePort: 80
                path: /
      # This section is only required if TLS is to be enabled for the Ingress
      tls:
          - hosts:
              - www.example.com
            secretName: example-tls
  
  If TLS is enabled for the Ingress, a Secret containing the certificate and key must also be provided:
  
    apiVersion: v1
    kind: Secret
    metadata:
      name: example-tls
      namespace: foo
    data:
      tls.crt: &lt;base64 encoded cert&gt;
      tls.key: &lt;base64 encoded key&gt;
    type: kubernetes.io/tls
  </code></pre>
  
  <p>Seemingly this is really nice - it spins everything up and gives an example of how to add an ingress. Since I spun up helm in a blank <code>kubectl</code> I used the following <code>yaml</code> file to add in what I thought would be required.</p>
  
  <p>The file: </p>
  
  <pre><code>apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: frontend
    labels:
      app: frontend
  spec:
    replicas: 3
    selector:
      matchLabels:
        app: frontend
    template:
      metadata:
        labels:
          app: frontend
      spec:
        containers:
        - name: nginx
          image: patientplatypus/frontend_example
          ports:
          - containerPort: 3000
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: frontend
  spec:
    type: LoadBalancer
    selector:
      app: frontend
    ports:
      - protocol: TCP
        port: 80
        targetPort: 3000
  ---
  apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: backend
    labels:
      app: backend
  spec:
    replicas: 3
    selector:
      matchLabels:
        app: backend
    template:
      metadata:
        labels:
          app: backend
      spec:
        containers:
        - name: nginx
          image: patientplatypus/backend_example
          ports:
          - containerPort: 5000
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: backend
  spec:
    type: LoadBalancer
    selector:
      app: backend
    ports:
      - protocol: TCP
        port: 80
        targetPort: 5000
  ---
  apiVersion: extensions/v1beta1
  kind: Ingress
  metadata:
    annotations:
      kubernetes.io/ingress.class: nginx
  spec:
    rules:
      - host: www.example.com
        http:
          paths:
            - path: /api
              backend:
                serviceName: backend
                servicePort: 80
            - path: /
              frontend:
                serviceName: frontend
                servicePort: 80
  </code></pre>
  
  <p>Deploying this to the cluster however runs into this error:</p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:11:44:20$kubectl create -f kube-deploy.yaml
  deployment.apps "frontend" created
  service "frontend" created
  deployment.apps "backend" created
  service "backend" created
  error: error validating "kube-deploy.yaml": error validating data: [ValidationError(Ingress.spec.rules[0].http.paths[1]): unknown field "frontend" in io.k8s.api.extensions.v1beta1.HTTPIngressPath, ValidationError(Ingress.spec.rules[0].http.paths[1]): missing required field "backend" in io.k8s.api.extensions.v1beta1.HTTPIngressPath]; if you choose to ignore these errors, turn validation off with --validate=false
  </code></pre>
  
  <p>So, the question then becomes, well crap how do I debug this?
  If you spit out the code that helm produces, it's basically non-readable by a person - there's no way to go in there and figure out what's going on. </p>
  
  <p>Check it out: <a href="https://gist.github.com/patientplatypus/0e281bf61307f02e16e0091397a1d863" rel="noreferrer">https://gist.github.com/patientplatypus/0e281bf61307f02e16e0091397a1d863</a> - over a 1000 lines!</p>
  
  <p>If anyone has a better way to debug a helm deploy add it to the list of open questions.</p>
  
  <p><strong>EDIT EDIT EDIT EDIT</strong></p>
  
  <p>To simplify <em>in the extreme</em> I attempt to make a call from one pod to another only using namespace. </p>
  
  <p>So here is my React code where I make the http request:</p>
  
  <pre><code>axios.get('http://backend/test')
  .then(response=&gt;{
    console.log('return from backend and response: ', response);
  })
  .catch(error=&gt;{
    console.log('return from backend and error: ', error);
  })
  </code></pre>
  
  <p>I've also attempted to use <code>http://backend.exampledeploy.svc.cluster.local/test</code> without luck.</p>
  
  <p>Here is my node code handling the get:</p>
  
  <pre><code>router.get('/test', function(req, res, next) {
    res.json({"test":"test"})
  });
  </code></pre>
  
  <p>Here is my <code>yaml</code> file that I uploading to the <code>kubectl</code> cluster:</p>
  
  <pre><code>apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: frontend
    namespace: exampledeploy
    labels:
      app: frontend
  spec:
    replicas: 3
    selector:
      matchLabels:
        app: frontend
    template:
      metadata:
        labels:
          app: frontend
      spec:
        containers:
        - name: nginx
          image: patientplatypus/frontend_example
          ports:
          - containerPort: 3000
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: frontend
    namespace: exampledeploy
  spec:
    type: LoadBalancer
    selector:
      app: frontend
    ports:
      - protocol: TCP
        port: 80
        targetPort: 3000
  ---
  apiVersion: apps/v1beta1
  kind: Deployment
  metadata:
    name: backend
    namespace: exampledeploy
    labels:
      app: backend
  spec:
    replicas: 3
    selector:
      matchLabels:
        app: backend
    template:
      metadata:
        labels:
          app: backend
      spec:
        containers:
        - name: nginx
          image: patientplatypus/backend_example
          ports:
          - containerPort: 5000
  ---
  apiVersion: v1
  kind: Service
  metadata:
    name: backend
    namespace: exampledeploy
  spec:
    type: LoadBalancer
    selector:
      app: backend
    ports:
      - protocol: TCP
        port: 80
        targetPort: 5000
  </code></pre>
  
  <p>The uploading to the cluster appears to work as I can see in my terminal: </p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:14:33:20$kubectl get all --namespace=exampledeploy 
  NAME                            READY     STATUS    RESTARTS   AGE
  pod/backend-584c5c59bc-5wkb4    1/1       Running   0          15m
  pod/backend-584c5c59bc-jsr4m    1/1       Running   0          15m
  pod/backend-584c5c59bc-txgw5    1/1       Running   0          15m
  pod/frontend-647c99cdcf-2mmvn   1/1       Running   0          15m
  pod/frontend-647c99cdcf-79sq5   1/1       Running   0          15m
  pod/frontend-647c99cdcf-r5bvg   1/1       Running   0          15m
  
  NAME               TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
  service/backend    LoadBalancer   10.0.112.160   168.62.175.155   80:31498/TCP   15m
  service/frontend   LoadBalancer   10.0.246.212   168.62.37.100    80:31139/TCP   15m
  
  NAME                             DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
  deployment.extensions/backend    3         3         3            3           15m
  deployment.extensions/frontend   3         3         3            3           15m
  
  NAME                                        DESIRED   CURRENT   READY     AGE
  replicaset.extensions/backend-584c5c59bc    3         3         3         15m
  replicaset.extensions/frontend-647c99cdcf   3         3         3         15m
  
  NAME                       DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
  deployment.apps/backend    3         3         3            3           15m
  deployment.apps/frontend   3         3         3            3           15m
  
  NAME                                  DESIRED   CURRENT   READY     AGE
  replicaset.apps/backend-584c5c59bc    3         3         3         15m
  replicaset.apps/frontend-647c99cdcf   3         3         3         15m
  </code></pre>
  
  <p>However, when I attempt to make the request I get the following error:</p>
  
  <pre><code>return from backend and error:  
  Error: Network Error
  Stack trace:
  createError@http://168.62.37.100/static/js/bundle.js:1555:15
  handleError@http://168.62.37.100/static/js/bundle.js:1091:14
  App.js:14
  </code></pre>
  
  <p>Since the <code>axios</code> call is being made from the browser, I'm wondering if it is simply not possible to use this method to call the backend, even though the backend and the frontend are in different pods. I'm a little lost, as I thought this was the simplest possible way to network pods together.</p>
  
  <p><strong>EDIT X5</strong></p>
  
  <p>I've determined that it is possible to curl the backend from the command line by exec'ing into the pod like this:</p>
  
  <pre><code>patientplatypus:~/Documents/kubePlay:15:25:25$kubectl exec -ti frontend-647c99cdcf-5mfz4 --namespace=exampledeploy -- curl -v http://backend/test
  * Hostname was NOT found in DNS cache
  *   Trying 10.0.249.147...
  * Connected to backend (10.0.249.147) port 80 (#0)
  &gt; GET /test HTTP/1.1
  &gt; User-Agent: curl/7.38.0
  &gt; Host: backend
  &gt; Accept: */*
  &gt; 
  &lt; HTTP/1.1 200 OK
  &lt; X-Powered-By: Express
  &lt; Content-Type: application/json; charset=utf-8
  &lt; Content-Length: 15
  &lt; ETag: W/"f-SzkCEKs7NV6rxiz4/VbpzPnLKEM"
  &lt; Date: Sun, 06 May 2018 20:25:49 GMT
  &lt; Connection: keep-alive
  &lt; 
  * Connection #0 to host backend left intact
  {"test":"test"}
  </code></pre>
  
  <p>What this means is, without a doubt, because the front end code is being executed in the browser it needs Ingress to gain entry into the pod, as http requests from the front end are what's breaking with simple pod networking. I was unsure of this, but it means Ingress is necessary.</p>