How to have a header routing logic with nginx ingress-controller?

1/18/2020

I'm trying to achieve a header routing ingress rule with nginx. Why ? Because the same path should go to different backend based on headers. Here what i've tried:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: api-mutli-back
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      set $dataflag 0;

      if ( $http_content_type ~ "multipart\/form-data.*" ){
      set $dataflag 1;
      }

      if ( $dataflag = 1 ){
      set $service_name "backend-data";
      }

spec:
  rules:
  - host: example.com
    http:
      paths:
      - backend:
          serviceName: backend-default
          servicePort: 80
        path: /api

But the logs of nginx output this error:

unknown directive "set $service_name backend-data" in /tmp/nginx-cfg864446123:1237

which seems unlogic to me... If I check the configuration generated by nginx, each rule generate a location with something like this at the begining:

[...]
       location ~* "^/api" {

            set $namespace      "my-namespace";
            set $ingress_name   "api-multi-back";
            set $service_name   "backend-default";
[...]

What am I doing wrong ? Isn't it possible to redefine service_name variable with annotation configuration-snippet ? Is there any other method ?

Edit: My error on nginx side was due to the lack of exact spaces between set $service_name and backend-data. Then nginx generated correctly the configuration but it still not routing to another kubernetes service.

-- Kelindil
http-headers
kubernetes
nginx
nginx-ingress
routing

1 Answer

1/19/2020

You got bitten by a YAML-ism:

The indentation of your 2nd if block isn't the same as the indentation of the others, and thus YAML thinks you are starting a new key under annotations:

You have

metadata:
  name: api-mutli-back
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      set $dataflag 0;

      if ( $http_content_type ~ "multipart\/form-data.*" ){
      set $dataflag 1;
      }

     if ( $dataflag = 1 ){
     set $service_name "backend-data"
     }

but you should have:

metadata:
  name: api-mutli-back
  annotations:
    nginx.ingress.kubernetes.io/configuration-snippet: |
      set $dataflag 0;

      if ( $http_content_type ~ "multipart\/form-data.*" ){
      set $dataflag 1;
      }

      if ( $dataflag = 1 ){
      set $service_name "backend-data"
      }
-- mdaniel
Source: StackOverflow