Two ways to setup HTTP redirects in Kubernetes cluster

My name is Aleksandr, and I am an engineer and technology enthusiast based in Berlin. I work as an engineering manager. My passion is to make people’s lives easier with technology
Search for a command to run...

My name is Aleksandr, and I am an engineer and technology enthusiast based in Berlin. I work as an engineering manager. My passion is to make people’s lives easier with technology
No comments yet. Be the first to comment.
With this post, I would like to start a series of posts analyzing the way different companies define and declare their culture. They say, "Culture eats strategy for breakfast." A well-established culture truly is a powerful tool that helps to keep th...

Being an Engineering manager of a team often means assisting the team in organizing its ecosystem and tooling. I mean things like product and process metrics, CI/CD, productivity tools, and maintaining team's knowledge base and documentation. In this...

Code review is one of the most common practices in software development. Any company I have worked for since 2012 had it as a required step of the development process. Despite its ubiquitousness, understanding of it differed from company to company a...

Providing regular peer feedback is a part of healthy engineering culture. It is usually collected in a written form by a manager, aggregated, and delivered to the recipient. This post intends to be a short cheat sheet for those who provide peer feedb...

When migrating from one domain name to another one may need to set up a redirect of types 301 (Moved Permanently) or 302 (Found) for a certain domain and its paths. If you have Kubernetes as your runtime, there are at least two ways to do that:
Deploy nginx server as an additional service to handle redirects.
Handle redirects at your ingress controller.
The first one is safer but a bit more complex, the second one utilizes the ingress controller of your cluster, so you get redirects "for free", but it comes with a penalty. Let's look at both of these ways in detail.
As an example, we will set up redirects from old-domain.tld to new-domain.tld for two paths:
/pages/about → /about with 301 Moved Permanently status
/ → / with 302 Found status
Not to create all k8s resources from scratch one can use Bitmani's nginx helm chart.
Here is an example of values.yaml file that configures ingress to route the traffic to an old domain to the nginx container and injects a custom "server" block to implement redirect rules:
ingress:
enabled: true
hostname: old-domain.tld
ingressClassName: nginx
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
tls: true
serverBlock: |-
server {
listen 0.0.0.0:8080;
location /pages/about {
return 301 https://new-domain.tld/about;
}
location / {
return 302 https://new-domain.tld/;
}
}
To install the chart one should run the following commands (assuming the file above is located in the current directory and named my-values.yaml):
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install redirector bitnami/nginx -f my-values.yaml
In this case, the ingress controller will proxy requests to the "redirector" instance of nginx and it will respond with appropriate redirect headers.
But why use an additional nginx container if you probably already have one in your cluster — your ingress controller? Is it possible to inject redirect configuration directly into it? The answer is yes, but there are several issues.
The only thing you need is the ingress resource looking something like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-redirector
annotations:
nginx.org/server-snippets: |
location /pages/about {
return 301 https://new-domain.tld/about;
}
location / {
return 302 https://new-domain.tld/;
}
spec:
ingressClassName: nginx
rules:
- host: "old-domain.com"
tls:
- hosts:
- "old-domain.com"
secretName: old-domain-cert
As you can see, the nginx configuration is injected via nginx.org/server-snippets annotation and follows nginx configuration syntax. Otherwise, ingress doesn't look any different from a regular one, except there is no need for backend service configuration as all the traffic will be handled by the ingress controller itself.
The "issues" I mentioned are:
Your ingress controller has to be based on nginx (maybe other controllers also can be configured for the task but they are not covered in this blog post).
Snippets configuration should be enabled on the controller level. Either with enable-snippets command-line argument or, if you use helm to deploy your ingress controller, by setting controller.enableSnippets parameter to true in your values.yaml file.
Third, it introduces a certain risk: if the configuration snippet has invalid syntax it will block configuration refresh for all the services using this ingress controller in the cluster. Even other ingress configuration changes won't apply. See more in "Disadvantages of Using Snippets".
To reduce the risk of invalid configuration, you can use a public helm chart I've created: https://github.com/obukhov/ingress-redirector. Of course, it is still possible to break it with some special character in "from", "to" or "code" parameters. But at least it is harder to do it unintentionally and values.yaml file will look a bit more friendly:
ingress:
hosts:
- host: old-domain.tld
tls:
- secretName: old-domain-tld-tls
hosts:
- old-domain.tld
redirectRules:
- from: /pages/about
to: https://new-domain.tld/about
code: 301
- from: /
to: https://new-domain.tld/
code: 302
What solution to choose depends on your situation. Do you have several development teams, and such implicit dependencies between their services in a shared runtime can cause an issue? Or is it just your pet project, and you really would like to avoid deploying an extra nginx container that will require resources? Kubernetes can serve your needs anyway.