Kubernetes ingress returning 404

6/23/2019

I have Kubernetes running in Docker for Windows.

I am using NGINX ingress controller, I have applied the mandatory.yaml and the cloud-generic.yaml.

> kubectl get services -n ingress-nginx
NAME            TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   LoadBalancer   10.110.198.161   localhost     80:30037/TCP,443:31218/TCP   5h

I have an image in my local registry test-app/mock-service:1.0.0 which exposes port 8080 running a server with a single endpoint GET /mocks. Running this in Docker using docker run -d -p 8080:8080 test-app/mock-service:1.0.0 works and I can see the expected result.

My intention is to deploy this using Kubernetes.

I created a deployment and service resource:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: test-app-mock-service-deployment
  namespace: test-app
spec:
  selector:
    matchLabels:
      app: test-app-mock-service
  replicas: 1
  template:
    metadata:
      labels:
        app: test-app-mock-service
    spec:
      containers:
      - name: test-app-mock-service-container
        image: "test-app/mock-service:1.0.0"
---
apiVersion: v1
kind: Service
metadata:
  name: test-app-mock-service
  namespace: test-app
spec:
  type: ClusterIP
  selector:
    app: test-app-mock-service
  ports:
  - port: 8080
    targetPort: 8080
    protocol: TCP

And an ingress resource:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-app-ingress
  namespace: test-app
  annotations:
    ingress.kubernetes.io/ssl-redirect: "true"
spec:
  rules:
  - http:
      paths:
      - path: /mocks
        backend:
          serviceName: test-app-mock-service
          servicePort: 8080

I can see the service:

> kubectl get services -n test-app
NAME                    TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
test-app-mock-service   ClusterIP   10.108.10.246   <none>        8080/TCP   1h

And the pod:

> kubectl get pods -n test-app
NAME                                                READY     STATUS    RESTARTS   AGE
test-app-mock-service-deployment-6b9b58fcb9-mdskn   1/1       Running   0          59m

I can see the ingress:

> kubectl describe ingress test-app-ingress -n test-app
Name:             test-app-ingress
Namespace:        test-app
Address:          localhost
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host  Path  Backends
  ----  ----  --------
  *
        /mocks  test-app-mock-service:8080 (<none>)
Annotations:
  ingress.kubernetes.io/ssl-redirect:                true
  kubectl.kubernetes.io/last-applied-configuration:  {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"ingress.kubernetes.io/ssl-redirect":"true"},"name":"test-app-ingress","namespace":"test-app"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"test-app-mock-service","servicePort":8080},"path":"/mocks"}]}}]}}

Events:
  Type    Reason  Age               From                      Message
  ----    ------  ----              ----                      -------
  Normal  CREATE  1h                nginx-ingress-controller  Ingress test-app/test-app-ingress
  Normal  UPDATE  53m (x2 over 1h)  nginx-ingress-controller  Ingress test-app/test-app-ingress

However when I browse to http://localhost/mocks i get a 308 to https://localhost/mocks where I get a 404.

I'm not sure if the ingress is incorrectly configured or if it is another problem.

-- Neilos
docker
docker-for-windows
kubernetes
nginx-ingress

1 Answer

6/23/2019

What is likely happening is that the SSL portion is using SNI and since there is no host or default backend set nginx doesn't know where to send the request. There are two things you can do to solve this.

Default Backend

You can add an annotation to set a default backend for requests without a host or route. The documentation for this is at https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#default-backend. In your example it would be:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-app-ingress
  namespace: test-app
  annotations:
    ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/default-backend: test-app-mock-service
spec:
  rules:
  - http:
      paths:
      - path: /mocks
        backend:
          serviceName: test-app-mock-service
          servicePort: 8080

Add Hosts

Your spec contains no TLS hostname. Adding one should allow SNI to know what name needs to be used for the routing rules specified:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test-app-ingress
  namespace: test-app
  annotations:
    ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/default-backend: test-app-mock-service
spec:
  tls:
  - hosts:
    - localhost
    secretName: tls-secret
  rules:
  - http:
      paths:
      - path: /mocks
        backend:
          serviceName: test-app-mock-service
          servicePort: 8080

Though, if you are using the self-signed certificate you will likely need to find the name of it. You may need to generate your own. See https://kubernetes.github.io/ingress-nginx/user-guide/tls/ for more information on that.

-- Andy Shinn
Source: StackOverflow