Watch out for faulty ingress definitions

Categories: Kubernetes

Summary

Ingress objects can interfere between each other in the cluster. If you deploy incorrect ingress definition (and kubernetes won't detect the error), Nginx Ingress Controller will fall into restart loop and won't accept any new configuration. This will lead to broken deployments from that time onwards.

Description

I have been trying out how wildcards in Nginx Ingress Controller work. This is required when you want to have an URL prefixed with the application's language or a country.

Let say you want to host an application on a URL somehost.com/[Country code]/, for example somehost.com/uk/. If you want to do this for all of the countries in the world, you would have quite a few ingress defitions. The easier way is to use wildcard URLs.

NOTE Please remember that ingresses and especially ingress wildcards are very badly documented and there is still not a clear direction from a community how wildcards with ingress should work.

This post is about Ingresses used in conjunction with Nginx Ingress Controller version 0.9-beta15. In order for this tutorial to work with newer versions of ingress you need to change annotatios from ingress.kubernetes.io to nginx.ingress.kubernetes.io.

NOTE 2 Despite poorly documented, you need to make use of URL rewrite annotation in order to leverage wildcards in Ingress paths.

Let's see how an wildcard ingress would look like.

You can deploy hello world application to your cluster so that we can test it in the browser.

``` apiVersion: extensions/v1beta1 kind: Deployment metadata: name: hello-world namespace: hello-world spec: replicas: 1 template: metadata: labels: app: hello-world spec: containers: - name: hello-world image: tutum/hello-world ports: - containerPort: 80 resources: requests: memory: "40Mi" cpu: "10m" limits: memory: "80Mi" cpu: "100m" ```

Let's now create a wildcard ingress that works:

``` apiVersion: extensions/v1beta1 kind: Ingress metadata: name: hello-world-ingress namespace: hello-world annotations: kubernetes.io/tls-acme: "true" ingress.kubernetes.io/rewrite-target: / spec: rules: - host: ingress-working.k8s.cwienczek.com http: paths: - path: /[a-z][A-Z]+/hello/world backend: serviceName: hello-world servicePort: 80 tls: - secretName: ingress-working-tls hosts: - ingress-working.k8s.cwienczek.com ```

Now if you go to:

```

You shall see that the application is still accessible, but not on root / anymore.

Let's now break ingress by changin the path line to - path: /[a-z][A-Z]{2}/hello/world

The application will still work, because nginx won't update the configuration to a non-working rule, however, at this point you cannot deploy any other ingress as nginx has falled into reload loop.

At this point nobody can deploy or update any ingress configuration in your cluster. In order to fix this you need to delete or fix your faulty ingress rule.

You can see that by doing kubectl logs [your ingress controller pod] -n [your ingress controller namespace] --follow

The line that says your ingress configuration is wrong:

```

Why this is happening despite the fact that we have define a proper POSIX regex? It turns out that ingress controller does not quote the paths when using ingress. This means that not all regex rules will work at this moment. E.g. any rule that uses the {} curly brackets (for limiting the number of characters to intert) cannot be used right now.

In conclusion: always make sure that the ingress works, otherwise you might end up debugging another application in the cluster wondering why it's not accessible when in fact, there is an ingress definition somewhere that is broken, but passed Kubernetes validation.

All the files from the demo can be found here: https://github.com/mcwienczek/nginx-ingress-demo

See also

Share this post with your friends

comments powered by Disqus