Search code examples
google-kubernetes-enginekubernetes-helmnginx-ingress

GKE install nginx ingress with static ip and fanout


I am struggling with running an nginx ingress controller in GKE with a simple fanout. I have three services behind three different paths. These are two microservices at paths /api/something and /api/somethingelse, and a frontend served at /. The apis work fine, the frontend failes with Uncaught SyntaxError: Unexpected token '<' in console. It fails to load the html/javascript/css properly.

I install the nging-ingress controller with the following command

helm install nginx-ingress stable/nginx-ingress \
--set rbac.create=true \
--set controller.publishService.enabled=true \
--set controller.service.type=LoadBalancer \
--set controller.service.loadBalancerIP=<static ip> 

When this is done, I use this controller in my ingress:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: {{ printf "%s-ingress" (include "chart.fullname" .) }}
  annotations:
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/rewrite-target: /$2
  labels:
    {{- include "chart.labels" . | nindent 4 }}
spec:
  rules:
    - host: app.example.com # dns to the ip used when creating nginx ingress controller
      http:
        paths:
          - path: "/"
            backend:
              serviceName: {{ include "frontend.fullname" . }}
              servicePort: {{ .Values.frontend.service.port }}
          - path: "/api/something(/|$)(.*)"
            backend:
              serviceName: {{ include "something.fullname" . }}
              servicePort: {{ .Values.something.service.port }}
          - path: /api/somethingelse(/|$)(.*)"
            backend:
              serviceName: {{ include "somethingelse.fullname" . }}
              servicePort: {{ .Values.somethingelse.service.port }}

The names and ports of the services are correct, and it only "partially" fails to serve the frontend service.


EDIT: I've figured out that the error is because of the way the controller does the url rewrite. When it matches /, then /$2 will be the same as /. Hence it will load the root app again and receive html where it expects for js or css. Thus the error.

The question is then, how can I map something on the root and if matched, do no url rewrite?


Solution

  • Solution was to create one ingress for the api that require url-rewrite, and one for the front that does not. From the question above, I replaced the one ingress with these two:

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: {{ printf "%s-ingress" (include "chart.fullname" .) }}
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/rewrite-target: /$2
      labels:
        {{- include "chart.labels" . | nindent 4 }}
    spec:
      rules:
        - host: app.example.com # dns to the ip used when creating nginx ingress controller
          http:
            paths:
              - path: "/api/something(/|$)(.*)"
                backend:
                  serviceName: {{ include "something.fullname" . }}
                  servicePort: {{ .Values.something.service.port }}
              - path: /api/somethingelse(/|$)(.*)"
                backend:
                  serviceName: {{ include "somethingelse.fullname" . }}
                  servicePort: {{ .Values.somethingelse.service.port }}
    
    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: {{ printf "%s-frontend-ingress" (include "chart.fullname" .) }}
      annotations:
        kubernetes.io/ingress.class: nginx
      labels:
        {{- include "chart.labels" . | nindent 4 }}
    spec:
      rules:
        - host: app.example.com # dns to the ip used when creating nginx ingress controller
          http:
            paths:
              - path: "/"
                backend:
                  serviceName: {{ include "frontend.fullname" . }}
                  servicePort: {{ .Values.frontend.service.port }}