4

I am using Spring Cloud Kubernetes + Spring Cloud Gateway(SCG) and I have some trouble to deploy my app on GKE. SCG does not find k8s service, I still get this error:

There was an unexpected error (type=Service Unavailable, status=503).
Unable to find instance for uiservice

uiservice is Angular app.

When I take a look at .../actuator/gateway/routes I have this result:

[
  {
    "route_id": "CompositeDiscoveryClient_gateway",
    "route_definition": {
      "id": "CompositeDiscoveryClient_gateway",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "pattern": "/gateway/**"
          }
        }
      ],
      "filters": [
        {
          "name": "RewritePath",
          "args": {
            "regexp": "/gateway/(?<remaining>.*)",
            "replacement": "/${remaining}"
          }
        }
      ],
      "uri": "lb://gateway",
      "order": 0
    },
    "order": 0
  },
  {
    "route_id": "CompositeDiscoveryClient_uiservice",
    "route_definition": {
      "id": "CompositeDiscoveryClient_uiservice",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "pattern": "/uiservice/**"
          }
        }
      ],
      "filters": [
        {
          "name": "RewritePath",
          "args": {
            "regexp": "/uiservice/(?<remaining>.*)",
            "replacement": "/${remaining}"
          }
        }
      ],
      "uri": "lb://uiservice",
      "order": 0
    },
    "order": 0
  },
  {
    "route_id": "uiservice_route",
    "route_definition": {
      "id": "uiservice_route",
      "predicates": [
        {
          "name": "Path",
          "args": {
            "_genkey_0": "/*"
          }
        }
      ],
      "filters": [],
      "uri": "lb://uiservice",
      "order": 0
    },
    "order": 0
  },
  ....
]

Please note that services are well discovered because of that: "route_id": "CompositeDiscoveryClient_gateway" and "route_id": "CompositeDiscoveryClient_uiservice", those routes are not mine (I did not define them).

I took a look at this post:How to set up Spring Cloud Gateway application so it can use the Service Discovery of Spring Cloud Kubernetes? without success.

My configuration:

   spring:
      profiles:
        active: prod
      cloud:
        kubernetes:
          reload:
            enabled: true
        gateway:
          discovery:
            locator:
              enabled: true 
              lower-case-service-id: true
          globalcors:
            cors-configurations: 
              '[/**]':
                allowedOrigins: uiservice
                allowedMethods: "*"
                allowCredentials: true
                maxAge: 7200
                allowedHeaders: "*"
                exposedHeaders:
                - "Access-Control-Allow-Origin"
                - "Access-Control-Allow-Methods"
                - "Access-Control-Max-Age"
                - "Access-Control-Allow-Headers"
                - "Cache-Control"
                - "Authorization"
                - "Content-Type"
          routes:
          #======UISERVICE========
          - id: uiservice_route
            uri: lb://uiservice 
            predicates:
            - Path=/* #default route

          - id: uiservice_route_assets
            uri: lb://uiservice
            predicates:
            - Path=/assets/**
   management:
      endpoints:
        web:
          exposure:
            include: "*"
      endpoint:
          restart:
            enabled: true

Also, how can I disable gateway autodiscovering? I don't want the "route_id": "CompositeDiscoveryClient_gateway"

Dependencies:

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-kubernetes-all</artifactId>
</dependency>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Thanks for your help

Jason
  • 628
  • 3
  • 10
akuma8
  • 4,160
  • 5
  • 46
  • 82

4 Answers4

9

I finally found a solution after losing an afternoon. I think there is an issue on service discovering when using Ribbon. I use k8s dns service discovering instead of relying on Ribbon, so my new config is:

routes:
- id: uiservice_route
  uri: http://uiservice:4200 # switch 'lb://' to 'http://'
  predicates:
  - Path=/* 

K8s uiservice config:

apiVersion: v1
kind: Service
metadata:
  name: uiservice
spec:
  sessionAffinity: ClientIP
  selector:
    app: uiservice
  ports:
    - name: http
      port: 4200
      targetPort: ui-port

A new question arised: Why using Ribbon to load balance requests since k8s services natively do that?

akuma8
  • 4,160
  • 5
  • 46
  • 82
  • I know this is old but answering your "new question", you probably won't need to use Ribbon (see https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/index.html#kubernetes-native-service-discovery) unless you specifically want client side load balancing: spring-cloud-starter-kubernetes-ribbon – Daniel Arechiga Jan 17 '22 at 05:01
3

Set the following property

spring:
  cloud:
    gateway:
      discovery:
        locator:
          enabled: false
spencergibb
  • 24,471
  • 6
  • 69
  • 75
  • Thanks, setting the property to `false` solved auto-discovering issue but I still have `Unable to find instance for uiservice`. – akuma8 Aug 21 '19 at 15:09
  • Do you think that could be a ribbon issue, because when I set `url-expression: "uri"` everything works but it's a bad solution since requests are no longer load-balanced. – akuma8 Aug 21 '19 at 17:09
  • I finally found a solution, see above, could you answer the last question? Thanks – akuma8 Aug 22 '19 at 08:59
  • @akuma8 It seems you have spent good amount of time fighting with this issue. Were you able to resolve it? I am in the same boat and my gateway is not able to discover the services. Will you be able to provide some guidance ? – Amit Mar 18 '21 at 11:40
  • @Amit see my answer below https://stackoverflow.com/a/57605600/6643803 – akuma8 Mar 18 '21 at 12:16
  • @akuma8 thanks for the response. Why do you have a service port hardcoded to uri: http://uiservice:4200 its should be discoverable just by the service name correct? So basically spring cloud gateway is working with DiscoveryClient for lookup and making then K8s native call to invoke service? – Amit Mar 18 '21 at 13:58
2

It should be look like this:

spring:
  application.name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          url-expression: "'http://'+serviceId+':'+getPort()"
          lower-case-service-id: true

When call http://gateway/my-service-name/api/etc, and then will call my-service-name/api/etc if the service is present in kubernetes

So you need makesure there have a service like :

apiVersion: v1
kind: Service
metadata:
  name: my-service-name
  namespace: default
  labels:
    app: my-service-name
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30080
  selector:
    app: my-service-name
HelloWood
  • 727
  • 4
  • 13
0

I don't think you added starter-ribbon dependency, which would take the response for finding your service instance in k8s environment.

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
Liam lin
  • 385
  • 1
  • 3
  • 10