Kubernetes Ingress gce expose two basic Sping Boot services

5/31/2021

I am trying to deploy two very basic services (Spring Boot) with an Ingress that has to redirect the traffic depending on the path. Very basic example of Ingress use, but I can't understand after hours and hours why this configuration won't work.

First controller, exposed to port 8095:

@RestController
public class MainController {

    private Logger logger = LoggerFactory.getLogger(MainController.class);

    @GetMapping({"/", ""})
    public String getDefault(HttpServletRequest request) {
        logger.debug("URL: ", makeUrl(request));
        return "Root reached: " + makeUrl(request);
    }

    @GetMapping("/foo")
    public String getSubPath(HttpServletRequest request){
        logger.debug("URL: ", makeUrl(request));
        return "First sub path reached: " + makeUrl(request);
    }

    @GetMapping("/foo/test")
    public String getSubSubPath(HttpServletRequest request){
        logger.debug("URL: ", makeUrl(request));
        return "First sub sub path reached: " + makeUrl(request);
    }

    @GetMapping("/foo/health/check")
    public String getHealthCheck(HttpServletRequest request) {
        return "Health check passed: " + makeUrl(request);
    }

    private String makeUrl(HttpServletRequest request) {
        return request.getRequestURL().toString() + "?" + request.getQueryString();
    }

}

Second controller, exposed to port 8080:

@RestController
public class MainController {

    private Logger logger = LoggerFactory.getLogger(MainController.class);

    @GetMapping({"/bar/", "/bar"})
    public String getDefault(HttpServletRequest request) {
        logger.debug("URL: ", makeUrl(request));
        return "Root reached: " + makeUrl(request);
    }

    @GetMapping("/bar/test")
    public String getSubPath(HttpServletRequest request){
        logger.debug("URL: ", makeUrl(request));
        return "First sub path reached: " + makeUrl(request);
    }

    @GetMapping("/bar/test/subsubpath")
    public String getSubSubPath(HttpServletRequest request){
        logger.debug("URL: ", makeUrl(request));
        return "First sub sub path reached: " + makeUrl(request);
    }

    @GetMapping("/bar/health/check")
    public String getHealthCheck(HttpServletRequest request) {
        return "Health check 2 passed: " + makeUrl(request);
    }

    private String makeUrl(HttpServletRequest request) {
        return request.getRequestURL().toString() + "?" + request.getQueryString();
    }

}

As we can see the endpoints of the controllers simply print some message and the URL, just to know that they are reached from outside of the cluster in which there is the Ingress.

Deployment file for kubernetes:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: prova1-deployment
spec:
  selector:
    matchLabels:
      app: deploy1
  replicas: 1
  template:
    metadata:
      labels:
        app: deploy1
    spec:
      imagePullSecrets:
        - name: gitlab-registry-prova
      containers:
        - name: prova1-deploy
          image: "registry.gitlab.com/giuxg97/reep/test1-deploy"
          ports:
            - containerPort: 8095
---
apiVersion: v1
kind: Service
metadata:
  name: prova1-service
spec:
  selector:
    app: deploy1
  ports:
    - protocol: TCP
      port: 60000
      targetPort: 8095
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: prova2-deployment
spec:
  selector:
    matchLabels:
      app: deploy2
  replicas: 1
  template:
    metadata:
      labels:
        app: deploy2
    spec:
      imagePullSecrets:
        - name: gitlab-registry-prova
      containers:
        - name: prova2-deploy
          image: "registry.gitlab.com/giuxg97/reep/test2-deploy"
          ports:
            - containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
  name: prova2-service
spec:
  selector:
    app: deploy2
  ports:
    - protocol: TCP
      port: 8090
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    # If the class annotation is not specified it defaults to "gce".
    kubernetes.io/ingress.class: "gce"
spec:
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: prova1-service
                port:
                  number: 60000
          - path: /bar
            pathType: Prefix
            backend:
              service:
                name: prova2-service
                port:
                  number: 8090

The images are taken from my private container registry on gitlab and they work as I can see from the logs of the pod after the deployment.

This is now the situation:

  • if I go to IP_INGRESS/ it will redirect me to the correct page with "Root reached: ...", but if then I go to IP_INGRESS/foo I get the error "response 404 (backend NotFound), service rules for the path non-existent " which it seems that it is an error message that is thrown when the Ingress can't find a path (i.e. if I go to IP_INGRESS/test1234 I get the same error)
  • if I go to IP_INGRESS/bar I get another error message "Error: Server Error The server encountered a temporary error and could not complete your request. Please try again in 30 seconds." and the pod don't have new logs.

So the only service that seems to be reached is the first one, but also in this case I cannot see the subpaths, but I don't know why also after have read more documentations..

I hope you can help me! Thank you in advance

-- GiuxG97
gke-networking
google-kubernetes-engine
kubernetes
spring-boot

1 Answer

6/2/2021

Hi and welcome to Stackoverflow.

For the first issue -

Your ingress definition creates rules that proxy traffic from the {path} to the {backend.serviceName}{path}. One of the possible reasons why path could not be found is that /foo is proxied to app-service: 60000/foo but you're intending on serving traffic at the ‘/’ root.

Try adding this annotation to your ingress resource:

nginx.ingress.kubernetes.io/rewrite-target: /

Source: https://github.com/kubernetes/ingress-nginx/tree/master/docs/examples/rewrite

If that doesn’t resolve the issue, the problem would likely be in your handler method for ‘/foo’ and other subpaths in your spring framework.

For the second issue -

Use Curl command (Curl -D- -s -o/dev/null <<url>>) to check if you’re able to reach the particular URL (where you’re getting a bad response) using node ip on the backend internally (without going through the Ingress ).

If you’re unable to reach the URL internally, the problem again should be lying with mapping configuration in your spring framework.

If you’re able to reach the URL internally, check the services you created in the deployment file for kubernetes. You can also try changing the deployment port and service port of troubled deployment.

Refer here for detailed instructions on deployment file configuration for GKE -

https://spring-gcp.saturnism.me/deployment/kubernetes/load-balancing/external-load-balancing#ingress-yaml

-- Anant Swaraj
Source: StackOverflow