Search code examples
dockerkuberneteslinode

Nginx Ingress works only if nodeport is added to the host name. How to make it work without nodeport?


I'm trying a simple microservices app on a cloud Kubernetes cluster. This is the Ingress yaml:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-nginx-nginx-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: nginx  
spec:
  defaultBackend:
    service:
      name: auth-svc
      port:
        number: 5000
  rules:
  - host: "somehostname.xyz"
    http:
      paths:
      - path: "/"
        pathType: Prefix
        backend:
          service:
            name: auth-svc
            port:
              number: 5000

The problem:
When I use this URL, I'm able to access the auth service: http://somehostname.xyz:31840. However, if I use http://somehostname.xyz, I get a "This site can’t be reached somehostname.xyz refused to connect." error.
The auth service sends GET requests to other services too, and I'm able to see the response from those services if I use:
http://somehostname.xyz:31840/go or http://somehostname.xyz:31840/express. But again, these work only if the nodeport 31840 is used.

My questions:

  • What typically causes such a problem, where I can access the service using the hostname and nodeport, but it won't work without supplying the nodeport?

  • Is there a method to test this in a different way to figure out where the problem is?

  • Is it a problem with the Ingress or Auth namespace? Is it a problem with the hostname in Flask? Is it a problem with the Ingress controller? How do I debug this?

These are the results of kubectl get all and other commands.

NAME                                               READY   STATUS     RESTARTS
pod/auth-flask-58ccd5c94c-g257t                    1/1     Running    0          
pod/ingress-nginx-nginx-ingress-6677d54459-gtr42   1/1     Running    0  




NAME                                  TYPE           EXTERNAL-IP      PORT(S)             
service/auth-svc                      ClusterIP      <none>           5000/TCP            
service/ingress-nginx-nginx-ingress   LoadBalancer   172.xxx.xx.130   80:31840/TCP,443:30550/TCP 



NAME                                          READY   UP-TO-DATE   AVAILABLE 
deployment.apps/auth-flask                    1/1     1            1          
deployment.apps/ingress-nginx-nginx-ingress   1/1     1            1  

    


NAME                                                     DESIRED   CURRENT   READY 
replicaset.apps/auth-flask-58ccd5c94c                    1         1         1    
replicaset.apps/ingress-nginx-nginx-ingress-6677d54459   1         1         1 




NAME                          CLASS    HOSTS                   ADDRESS          PORTS   
ingress-nginx-nginx-ingress   <none>   somehostname.xyz   172.xxx.xx.130   80 

Describing ingress also seems normal.

kubectl describe ingress ingress-nginx-nginx-ingress
Name:             ingress-nginx-nginx-ingress
Namespace:        default
Address:          172.xxx.xx.130
Default backend:  auth-svc:5000 (10.x.xx.xxx:5000)
Rules:
  Host                   Path  Backends
  ----                   ----  --------
  somehostname.xyz  
                         /   auth-svc:5000 (10.x.xx.xxx:5000)
Annotations:             kubernetes.io/ingress.class: nginx

This is the code of Auth.

import requests
from flask import Flask

app = Flask(__name__)

@app.route('/')
def indexPage():
    return '  <!DOCTYPE html><html><head><meta charset="UTF-8" />\
    <title>Microservice</title></head> \
    <body><div style="text-align: center;">Welcome to the Auth page</div></body></html>'
       
@app.route('/go')
def getGoJson():
    return requests.get('http://analytics-svc:8082/info').content
    
@app.route('/express')
def getNodeResponse():
    return requests.get('http://node-svc:8085/express').content

if __name__ == '__main__':
    app.run(debug=True, host="0.0.0.0")

and Auth's Dockerfile:

FROM python:3.8-slim-buster
WORKDIR /usr/src/app
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
ENV FLASK_ENV=development 
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD ["flask", "run"] 

The part of docker-compose yaml for auth:

version: "3.3"
services:
  auth:
    build: ./auth/
    image: nav9/auth-flask:v1 
    ports:
    - "5000:5000"

Auth's Kubernetes manifest:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: auth-flask
spec:
  selector:
    matchLabels:
      any-name: auth-flask
  template:
    metadata:
      labels:
        any-name: auth-flask
    spec:
      containers:
        - name: auth-name
          image: nav9/auth-flask:v1
          imagePullPolicy: Always
          ports:
            - containerPort: 5000
---
apiVersion: v1
kind: Service
metadata:
  name: auth-svc
spec:
#  type: ClusterIP
  ports:
    - targetPort: 5000
      port: 5000
  selector:
    any-name: auth-flask

Solution

  • The solution has three parts:

    1. Use kubectl get all to find out the running ingress service:

      NAME                                 TYPE           EXTERNAL-IP     PORT(S)
      service/ingress-nginx-nginx-ingress  LoadBalancer   172.xxx.xx.130  80:31840/TCP,443:30550/TCP
      

    Copy the EXTERNAL-IP of the service (in this case 172.xxx.xx.130).

    1. Add a DNS A record named *.somehostname.xyz for the cloud cluster, and use the IP address 172.xxx.xx.130.

    2. When accessing the hostname via the browser, make sure that http is used instead of https.