1

The Problem:

When I try to apply the config below using kubectl apply -f config.yaml the following error message is printed: nginx: [emerg] unknown "name" variable even though the variable is defined by the map-directive in the same annotations block/section.

Elaboration:

For each request towards a 'hello-world' example, I want to parse the first 32 characters of the query-parameter 'token' to do the following:

  1. be my new path (rewrite-target)
  2. ensure that every call with this 32-character-token gets routed to the same pod (upstream-hash-by)

Therefore I created the following config:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  annotations:
    nginx.ingress.kubernetes.io/http-snippet: |
      map $arg_token $name {
        default                "default";
        "^(?<short>.{32}).*$"  $short;
      }
    nginx.ingress.kubernetes.io/rewrite-target: /$name
    nginx.ingress.kubernetes.io/upstream-hash-by: $name
spec:
  rules:
    - host: hello-world.info
      http:
        paths:
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: nginx-deployment
                port:
                  number: 8080

An example call would be curl hello-world.info/example?token=1234567890abcdefghijhlmnopqrstuvwxyz. The idea is to cut down this 36 character long token stored in $arg_token to 1234567890abcdefghijhlmnopqrstuv (32 characters), store it in $name and use this new variable as parameter for the rewrite-target and upstream-hash-by ConfigMap resources.

My Question:

As written in this answer to a question in the same context, the config-map directive should only be used in the http-context and that variables in NGINX are always defined global. Why is the variable $name still unknown?

TL;DR: Variable defined in custom http-snippet prints error unknown when accessed.

EDIT: Complete Stack-Trace:

Error from server (BadRequest): error when applying patch:
{"metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"networking.k8s.io/v1\",\"kind\":\"Ingress\",\"metadata\":{\"annotations\":{\"nginx.ingress.kubernetes.io/http-snippet\":\"map $1 $name {\\n  default                 0;\\n  123*  \\t\\t\\t1;\\n}\\n\",\"nginx.ingress.kubernetes.io/rewrite-target\":\"/$name\",\"nginx.ingress.kubernetes.io/upstream-hash-by\":\"$name\"},\"name\":\"example-ingress\",\"namespace\":\"ingress-nginx\"},\"spec\":{\"rules\":[{\"host\":\"hello-world.info\",\"http\":{\"paths\":[{\"backend\":{\"service\":{\"name\":\"nginx-deployment\",\"port\":{\"number\":8080}}},\"path\":\"/(.*)\",\"pathType\":\"Prefix\"}]}}]}}\n","nginx.ingress.kubernetes.io/http-snippet":"map $1 $name {\n  default                 0;\n  123*  \t\t\t1;\n}\n","nginx.ingress.kubernetes.io/rewrite-target":"/$name","nginx.ingress.kubernetes.io/upstream-hash-by":"$name"}}}
to:
Resource: "networking.k8s.io/v1, Resource=ingresses", GroupVersionKind: "networking.k8s.io/v1, Kind=Ingress"
Name: "example-ingress", Namespace: "ingress-nginx"
for: "ingress-config.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request:
-------------------------------------------------------------------------------
Error: exit status 1
2022/08/04 11:28:25 [warn] 263#263: the "http2_max_field_size" directive is obsolete, use the "large_client_header_buffers" directive instead in /tmp/nginx/nginx-cfg3947851792:143
nginx: [warn] the "http2_max_field_size" directive is obsolete, use the "large_client_header_buffers" directive instead in /tmp/nginx/nginx-cfg3947851792:143
2022/08/04 11:28:25 [warn] 263#263: the "http2_max_header_size" directive is obsolete, use the "large_client_header_buffers" directive instead in /tmp/nginx/nginx-cfg3947851792:144
nginx: [warn] the "http2_max_header_size" directive is obsolete, use the "large_client_header_buffers" directive instead in /tmp/nginx/nginx-cfg3947851792:144
2022/08/04 11:28:25 [warn] 263#263: the "http2_max_requests" directive is obsolete, use the "keepalive_requests" directive instead in /tmp/nginx/nginx-cfg3947851792:145
nginx: [warn] the "http2_max_requests" directive is obsolete, use the "keepalive_requests" directive instead in /tmp/nginx/nginx-cfg3947851792:145
2022/08/04 11:28:25 [emerg] 263#263: unknown "name" variable
nginx: [emerg] unknown "name" variable
nginx: configuration file /tmp/nginx/nginx-cfg3947851792 test failed
ErikWe
  • 191
  • 3
  • 18

1 Answers1

1

I faced the same issue, here is how I solved this.

  1. Injecting http block via ConfigMap.
apiVersion: v1
kind: ConfigMap
metadata:
  name: ingress-nginx-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
data:
  http-snippet: |
    map $arg_token $name {
        default                "default";
        "^(?<short>.{32}).*$"  $short;
    }

Make sure namespace: ingress-nginx since it's the default namespace for ingress controller in k8s

  1. Move rewrite to configuration-snippet
nginx.ingress.kubernetes.io/configuration-snippet: |
      rewrite "/(.*)" /$name break;
Akarshan
  • 21
  • 1
  • Thanks, this works.. just feels like magic. nginx.ingress.kubernetes.io/http-snippet: should do the same thing right?! – Lallen Nov 23 '22 at 15:45
  • @Lallen Thanks. I tried using nginx.ingress.kubernetes.io/http-snippet directive but encountered `unknown "name" variable`. The only way to do this is via ConfigMap. – Akarshan Nov 30 '22 at 14:05