Spring Cloud Gateway on Kubernetes discovery locator use pod port instead o service port

2/6/2020

i'm implementing an API Gateway on openshift with spring cloud gateway and spring cloud kubernetes discovery.

I started from the project https://github.com/salaboy/s1p_gateway.

My gateway configuration is:

cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          url-expression: "'http://'+serviceId+':'+port"
    kubernetes:
      reload:
        enabled: true
        mode: polling
        period: 5000
      discovery:
        service-labels:
           type: "java-api"

When i view my /actuator/gateway/routes i can see services discovered:

{
   "predicate":"Paths: [/common/**], match trailing slash: true",
   "route_id":"ReactiveCompositeDiscoveryClient_common",
   "filters":[
      "[[RewritePath /common/(?<remaining>.*) = '/${remaining}'], order = 1]"
   ],
   "uri":"http://common:8085",
   "order":0
}

The problem is that 8085 is the targetPort (i.e. pod port) and not the service port:

kind: Service
apiVersion: v1
metadata:
  name: common
  namespace: p4p
  selfLink: /api/v1/namespaces/myspace/services/common
  uid: 1851a76f-4764-11ea-a02c-000d3aa9b693
  resourceVersion: '28657990'
  creationTimestamp: '2020-02-04T15:36:21Z'
  labels:
    app: common
    type: java-api
spec:
  ports:
    - protocol: TCP
      port: 8080
      targetPort: 8085
  selector:
    app: common
    deploymentconfig: common
  clusterIP: 172.30.7.24
  type: ClusterIP
  sessionAffinity: None
status:
  loadBalancer: {}

In order to get API gateway to work i MUST to align pod port and service port, but it sounds quite strange.

-- angcap
kubernetes
spring-boot
spring-cloud
spring-cloud-kubernetes

2 Answers

2/6/2020

Why cannot you simply set Service port (port) to 8085 so it exposes the same port as Pod does ? Nothing actually prevents you from doing so.

When i try to call rest api via gateway i get

There was an unexpected error (type=Internal Server Error, status=500). finishConnect(..) failed: Host is unreachable: common/172.30.7.24:8085

and the service is

Name: common Type: ClusterIP IP: 172.30.7.24 Port: <unset> 8080/TCP TargetPort: 8085/TCP Endpoints: 10.129.3.101:8085

It seems uses the service IP and the pod port. I have also added spring.cloud.kubernetes.ribbon.mode=SERVICE but nothing has changed.

From what you posted it looks like when you're trying to call your rest api via gateway it expects it to be exposed using your Service IP (172.30.7.24) and port 8085, so simply expose it on that port and it should work fine:

...
spec:
  ports:
    - protocol: TCP
      port: 8085
      targetPort: 8085
...

Please let me know if it helps.

-- mario
Source: StackOverflow

2/6/2020

Is Ribbon being used? Ribbon's default spring.cloud.kubernetes.ribbon.mode is POD. From the docs (quote):

spring.cloud.kubernetes.ribbon.mode supports POD and SERVICE modes.

  • The POD mode is to achieve load balancing by obtaining the Pod IP address of Kubernetes and using Ribbon. POD mode uses the load balancing of the Ribbon Does not support Kubernetes load balancing, The traffic policy of Istio is not supported.

  • the SERVICE mode is directly based on the service name of the Ribbon. Get The Kubernetes service is concatenated into service-name.{namespace}.svc.{cluster.domain}:{port} such as: demo1.default.svc.cluster.local:8080. the SERVICE mode uses load balancing of the Kubernetes service to support Istio’s traffic policy.

-- gears
Source: StackOverflow