Ingress rule using host

7/20/2021

Can someone please help to spot the issue with ingress-2 ingress rule? why ingress-1 is working vs ingress-2 is not working.

Description of my setup, I have two deployments:

1st deployment is of nginx
2nd deployment is of httpd

Both of the deployments are exposed via ClusterIP services named nginx-svc and httpd-svc respectively. All the endpoints are proper for the services. However, while setting up the ingress for these services, I am not able to setup the ingress using host (as described in ingress-2). however, when I am using ingress-1, things work fine.

// my host file for name resolution

grep myapp.com /etc/hosts
127.0.0.1        myapp.com

// deployment details

kubectl get deployments.apps
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
nginx   3/3     3            3           29m
httpd   3/3     3            3           29m

// service details

kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.152.183.1     <none>        443/TCP   7h48m
nginx-svc    ClusterIP   10.152.183.233   <none>        80/TCP    28m
httpd-svc    ClusterIP   10.152.183.58    <none>        80/TCP    27m

// endpoints details

kubectl get ep
NAME         ENDPOINTS                                      AGE
kubernetes   10.0.2.15:16443                                7h51m
nginx-svc    10.1.198.86:80,10.1.198.87:80,10.1.198.88:80   31m
httpd-svc    10.1.198.89:80,10.1.198.90:80,10.1.198.91:80   31m

Attempt-1: ingress-1

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-1
spec:
  rules:
  - http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: nginx-svc
            port:
              number: 80

      - path: /httpd
        pathType: Prefix
        backend:
          service:
            name: httpd-svc
            port:
              number: 80

// Example showing that ingress routing is working fine when ingress-1 is used:

 curl myapp.com/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>


 curl myapp.com/httpd
<html><body><h1>It works!</h1></body></html>

// following ingress rule is not working as I was expecting

Attempt-2: ingress-2

kind: Ingress
metadata:
  name: ingress-2
spec:
  rules:
  - host: "myapp.com"
    http:
      paths:
      - pathType: Prefix
        path: "/nginx"
        backend:
          service:
            name: nginx-svc
            port:
              number: 80
      - pathType: Prefix
        path: "/httpd"
        backend:
          service:
            name: httpd-svc
            port:
              number: 80

// I could not spot any issue in the ing describe

kubectl describe  ingress ingress-2
Name:             ingress-2
Namespace:        default
Address:          127.0.0.1
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host          Path  Backends
  ----          ----  --------
  myapp.com
                /nginx   nginx-svc:80 (10.1.198.86:80,10.1.198.87:80,10.1.198.88:80)
                /httpd   httpd-svc:80 (10.1.198.89:80,10.1.198.90:80,10.1.198.91:80)
Annotations:    <none>
Events:
  Type    Reason  Age                  From                      Message
  ----    ------  ----                 ----                      -------
  Normal  Sync    9m15s (x2 over 10m)  nginx-ingress-controller  Scheduled for sync

// example showing ingress routing is not working with this ingress resource

curl myapp.com/nginx
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.21.1</center>
</body>
</html>

curl myapp.com/httpd
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL was not found on this server.</p>
</body></html>
-- monk
kubernetes
microk8s
nginx-ingress

1 Answer

7/20/2021

Difference between ingresses

I created a one node microk8s cluster following official documentation and I wasn't able to reproduce behaviour you described which is correct behaviour. Added two pods with mendhak/http-https-echo image (highly recommend: very convenient for troubleshooting ingress or understanding how ingress works) and two services for each of pods.

The difference between two ingress rules is first ingress rule listens on all domains (HOSTS):

$ mkctl get ing -o wide
NAME        CLASS    HOSTS   ADDRESS     PORTS   AGE
ingress-1   public   *       127.0.0.1   80      2m53s

$ curl -I --header "Host: myapp.com" http://127.0.0.1/httpd
HTTP/1.1 200 OK

$ curl -I --header "Host: example.com" http://127.0.0.1/httpd
HTTP/1.1 200 OK

$ curl -I --header "Host: myapp.com" http://127.0.0.1/missing_url
HTTP/1.1 404 Not Found

While the second ingress rule will serve only myapp.com domain (HOST):

$ mkctl get ing
NAME        CLASS    HOSTS       ADDRESS     PORTS   AGE
ingress-2   public   myapp.com   127.0.0.1   80      60s

$ curl -I --header "Host: myapp.com" http://127.0.0.1/httpd
HTTP/1.1 200 OK

$ curl -I --header "Host: example.com" http://127.0.0.1/httpd
HTTP/1.1 404 Not Found

What exactly happens

Last results in your question actually show that ingress is working as expected. You're getting responses not from kubernetes ingress but from pods within the cluster. First response is 404 from nginx 1.21.0 and second is 404 from apache.

This happens because ingress sends requests to pods with the same path from URL without any transformations. For instance (this output I got using image mentioned above):

$ curl myapp.com/httpd
{
  "path": "/httpd"
...

While both nginx and apache are serving on /.

How to resolve it

Nginx ingress has a lot of features and one of them is rewriting which helps to transform paths from what ingress gets to what goes to pods.

For example, if request goes to http://myapp.com/nginx then it will be directed to nginx service with /nginx path which will cause nginx to throw 404 since there's nothing on this path.

Ingress rule below fixes this by adding rewrite-target to / which we need to pass to nginx and apache services:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-2
  annotations:
#    kubernetes.io/ingress.class: nginx # this should be uncommented if ingress used in "regular" cluster
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: myapp.com
    http:
      paths:
      - path: /nginx
        pathType: Prefix
        backend:
          service:
            name: service-a
            port:
              number: 80
      - path: /httpd
        pathType: Prefix
        backend:
          service:
            name: service-b
            port:
              number: 80

Quick test how it works:

$ curl myapp.com/nginx
{
  "path": "/",
...

And

$ curl myapp.com/httpd
{
  "path": "/",
...

As you can see now path is /.

Switching image to nginx and:

$ curl myapp.com/nginx
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
...

Useful links

-- moonkotte
Source: StackOverflow