Pas intéressé par les explications ? Ticket express pour le tl;pl 🚀
Donc, vous avez un cluster Kubernetes et ingress-nginx
pour ingress controller.
Vous avez peut-être utilisé des configuration snippets pour ajouter de la configuration NGINX spécifique à un ingress, comme par exemple des headers statiques :
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header foo "bar";
Comment ajouter des headers conditionnels, e.g. seulement si absents ?
On pourrait essayer un bloc Lua :
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite_by_lua_block {
headers = ngx.req.get_headers()
if not headers["foo"] then
ngx.req.set_header["foo"] = "bar"
end
}
Pour se rendre vite compte dans les journaux ingress-nginx
que le rechargement de la configuration échoue :
[emerg] 31379#31379: is duplicate in /tmp/nginx-cfg011294657:1037
nginx: [emerg] is duplicate in /tmp/nginx-cfg011294657:1037
nginx: configuration file /tmp/nginx-cfg011294657 test failed
Et effectivement, le modèle de configuration NGINX par défaut contient déjà une directive rewrite_by_lua_block
dans la même location
:
rewrite_by_lua_block {
lua_ingress.rewrite({{ locationConfigForLua $location $all }})
balancer.rewrite()
plugins.run()
}
On pourrait choisir l’une des solutions de contournement suivantes :
rewrite_by_lua_block
existante. Cependant, nous perdrions la configuration par défaut injectée via lua_ingress.rewrite()
. Il manquerait également les configurations injectées via plugins Lua.ngx.var.host
pour savoir quels headers ajouter au rewrite()
(de façon analogue au plugin d’exemple hello_world
). Cependant, cela disjoint la définition d’un ingress de ses headers, ce qui est inélégant et peu maintenable.S’il était possible de référencer une annotation personnalisée, nous pourrions l’utiliser à notre convenance :
rewrite_by_lua_block {
lua_ingress.rewrite({{ locationConfigForLua $location $all }})
balancer.rewrite()
plugins.run()
-- Custom headers
{{ insert "my-annotations/custom-headers" }}
}
Malheureusement, les annotations ordinaires de ingress-nginx
sont récupérées dans le code Go et référencées depuis le modèle NGINX via des objets et attributs dédiés, e.g. pour un configuration snippet :
{{/* Add any additional configuration defined */}}
{{ $location.ConfigurationSnippet }}
Modifier et recompiler ingress-nginx
juste pour ajouter une annotation serait un peu excessif.
Heureusement, il existe une fonction permettant d’accéder aux informations brutes d’un ingress, et notamment à ses annotations. D’ailleurs, elle est déjà utilisée pour initialiser $ing
tout en haut de la directive location
:
{{ $ing := (getIngressInformation $location.Ingress $server.Hostname $location.Path) }}
Depuis un modèle NGINX, on peut accéder à des annotations personnalisées via $ing
:
rewrite_by_lua_block {
lua_ingress.rewrite({{ locationConfigForLua $location $all }})
balancer.rewrite()
plugins.run()
-- Custom headers
{{ if index $ing.Annotations "my-annotations/custom-headers" }}
{{ index $ing.Annotations "my-annotations/custom-headers" }}
{{ end }}
}
Il devient possible d’insérer des headers conditionnels directement dans la définition d’un ingress, de façon analogue à des headers statiques positionnés via un configuration snippet :
my-annotations/custom-headers: |
headers = ngx.req.get_headers()
if not headers["foo"] then
ngx.req.set_header["foo"] = "bar"
end