One Loadbalancer to rule them all ? you heard it true, Its achievable !
For AWS LoadBalancer Controller
Until couple weeks ago, we were creating a loadbalancer for each namespace ( by default from AWS), which was a waste of resources and money. Hence we thought how can we use a **single loadbalancer ** across all the namespaces.
Here’s an example of before migration, how ingress looked like for default namespace:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-default
namespace: default
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
spec:
rules:
- host: example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: deployment-A
port:
number: 80
Lets take a look at ArgoCD ingress :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-argocd
namespace: argocd
annotations:
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
spec:
rules:
- host: argocd.example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: argo-server
port:
number: 80
Now, the problem with the above configuration is, by default AWS loadbalancer contoller will create ALB for each namespace. The cost of creating ALB for each namespace is $17.99 and data transfter charges are $0.02 per GB. If you got a lot of namespaces, the cost will be alot over the year. This is not Loadbalancer are supoosed to be used as ALB can handle alot of load in a single unit.
After hunting for a while, we found that the solution lies in using a ALB annotation called group.name on the Ingress object.
The flow
- Assuming you got 5 different ingress with 5 ALB in backend in different namespaces, choose one ingress and add the annotation :
alb.ingress.kubernetes.io/group.name: <ANYTHING_MEANINGFULL>
- Now, apply the same group name annotation to all the ingress objects in all namespaces.
- AWS LoadBalancer controller will use the first ingress Loadbalcner for all ingress objects and all other 4 ALB in this case will be removed.
Below is an example for 2 different namespaces with single ALB :
#default namespace ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-default
namespace: default
annotations:
alb.ingress.kubernetes.io/group.name: staging-lb
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
spec:
rules:
- host: example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: deployment-A
port:
number: 80
#argocd namespace ingerss
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-argocd
namespace: argocd
annotations:
alb.ingress.kubernetes.io/group.name: staging-lb
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: instance
spec:
rules:
- host: argocd.example.com
http:
paths:
- path: /*
pathType: ImplementationSpecific
backend:
service:
name: argo-server
port:
number: 80
- Notice how both ingress objects are using the same annotion with same Group name.
Whenever next time you need to create a new ingress in differnt namesapce, you can just add the same *group.name * annotation and it works flawlessly.
For NGINX Ingress Controller
If you are in any other cloud, lets say DigitalOcean, its cloud provider controller doesn’t have any custom LB controller. But dont get sad there buddy, NGINX to the rescue.
You can leverage NGINX ingress controller to create & manage LB for you.
For installing NGINX ingress controller, you can refer thier documentation which has all the steps to install it.
Lets say you got 2 different namespaces with 2 different ingress objects same as above one for default and one for ArgoCD.
The solution is to add
ingressClassName: nginx
in the ingress object **Spec ** section in each ingress file.
So the final ingress file looks like this for default namespace:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-default
namespace: default
spec:
ingressClassName: nginx
rules:
- host: chartmuseum.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: chartmuseum
port:
number: 80
Argocd Ingress namespace ingress looks like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-argocd
namespace: argocd
spec:
ingressClassName: nginx
rules:
- host: argocd.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 80
Happy Loadbalancing :)