“This is the 9th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”

In the previous article (Spring-Cloud-K8S cross NS), we explained how to use K8S load balancing tools such as Ribbon to implement LB, but there are problems of cross-namespace.

K8s-based LB tools allow applications to access each other across namespaces, not via K8s native load-balancing urls. Again based on ServiceName.

Direct source

First, we create a new service provider :diff-ns-service, which provides an interface:

@requestMapping ("/ getServiceDetail ") public String getServiceDetail (@requestParam (value = value) "servicename", defaultValue = "") String servicename) { return JSON.toJSONString(discoveryClient.getInstances(servicename)); }Copy the code

This interface returns information about the specified service. For example, the Service has several pods, node information for each pod, host, etc.

If you want to implement this service discovery in conjunction with K8s, you can use this configuration:

management:
  endpoint:
    restart:
      enabled: true
    health:
      enabled: true
    info:
      enabled: true

spring:
  application:
    name: diff-ns-service
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    kubernetes:
      ribbon:
        mode: SERVICE
      discovery:
        all-namespaces: true
Copy the code

In addition, if you want to use the K8S configMap configuration to dynamically refresh the application service environment configuration, you can configure it as follows:

spring:
  application:
    name: diff-ns-service
  cloud:
    kubernetes:
      reload:
        enabled: true
        strategy: refresh

        mode: event
      config:
        name: ${spring.application.name}
        namespace: default
        sources:
          - name: ${spring.application.name}
            namespace: ns-app
Copy the code

The dynamic refresh mode has two polling modes: [Polling] and [Event]. One is to start polling, and the other is to start polling when configMap changes.

In addition, there are several strategies for this refresh:

  • Refresh: Directly refresh
  • Restart_context, the whole Spring Context is gracefully restarted and all the configuration in it is reloaded
  • Shutdown: Restarts the container

Let’s configure the Service:

apiVersion: v1
kind: Service
metadata:
  name: diff-ns-service-service
  namespace: ns-app
spec:
  type: NodePort
  ports:
  - name: diff-ns-svc
    port: 2008
    targetPort: 2001
  selector:
    app: diff-ns-service
Copy the code

Here we set the port of the Service, and the Service is created as NodePort. In the article (Spring-Cloud-K8s pits across NS), we use the default type: ClusterIp.

In this way, a simple service provider is created. Next, let’s look at service consumers.

Again, let’s first create a service, rest-Service, to create the interface:

@GetMapping("/getClientRes") public Response<Object> getClientRes() throws Exception { HttpHeaders headers = new HttpHeaders(); MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8"); headers.setContentType(type); headers.add("Accept", MediaType.APPLICATION_JSON.toString()); HttpEntity<String> formEntity = new HttpEntity<String>(null, headers); String body = ""; try { ResponseEntity<String> responseEntity = restTemplate.exchange("http://diff-ns-service-service/getservicedetail? servicename=cas-server-service", HttpMethod.GET, formEntity, String.class); System.out.println(JSON.toJSONString(responseEntity)); if (responseEntity.getStatusCodeValue() == 200) { return Response.ok(responseEntity.getBody()); } } catch (Exception e) { System.out.println(e.getMessage()); } return Response.error("failed"); }Copy the code

Similarly, the discovery of this service in conjunction with K8s can be based on this configuration:

management:
  endpoint:
    restart:
      enabled: true
    health:
      enabled: true
    info:
      enabled: true

spring:
  application:
    name: rest-service
  cloud:
    loadbalancer:
      ribbon:
        enabled: false
    kubernetes:
      ribbon:
        mode: SERVICE
      discovery:
        all-namespaces: true
Copy the code

Here, we do not use RibbonLoadBalancerClient.

In addition, if you want to use the K8S configMap configuration to dynamically refresh the application service environment configuration, you can configure it as follows:

spring:
  cloud:
    kubernetes:
      reload:
        enabled: true
        strategy: refresh

        mode: event
      config:
        name: ${spring.application.name}
        namespace: default
        sources:
          - name: ${spring.application.name}
            namespace: system-server
Copy the code

For these, as mentioned in the previous article, we need to rely on configuration:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator</artifactId>
</dependency>

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-actuator-autoconfigure</artifactId>
</dependency>

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

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

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

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

<dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>okhttp</artifactId>
</dependency>
Copy the code

We don’t use the Ribbon here. We use spring-cloud-starter-kubernetes-loadbalancer, but we still use the RestTemplate:

@LoadBalanced
@Bean
public RestTemplate restTemplate() {
        SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
        requestFactory.setReadTimeout(env.getProperty("client.http.request.readTimeout", Integer.class, 15000));
        requestFactory.setConnectTimeout(env.getProperty("client.http.request.connectTimeout", Integer.class, 3000));
        RestTemplate rt = new RestTemplate(requestFactory);
        return rt;
}
Copy the code

Next, we started to deploy the two application services. At the same time, we implemented multiple pods by service expansion:

kubectl scale --replicas=2 deployment diff-ns-service-deployment
Copy the code

We toil to see the service node information:

Query Service information:

Next, we rest – service access service: http://192.168.8.107:5556/rest-service/getClientRes, here we can see the log:

In the meantime, you can see the return result:Here, we’re asking for a fetchcas-serverThe pod distribution information for this service.

Likewise, we through the Service of Ip and port can also be accessed directly: http://192.168.8.107:30916/getservicedetail? servicename=cas-server-service

PS: If we need to implement load balancing, we still need to inject @loadBalanced. What happens if we remove this annotation?

We found that after we removed it, we couldn’t access it.

Let’s do a set of test, if we use the spring cloud. Kubernetes. Ribbon. The mode = POD, let’s see what will be the result? After modify configuration, recompile, deployment, we continue to request the urlhttp: / / 192.168.8.107:5556 / rest – service/getClientRes:

The newly discovered

If we introduce spring-cloud-starter-kubernetes-loadbalancer based on the Spring Cloud itself, and we do not remove the Ribbon based LB capability, for example: Spring. Cloud. Loadbalancer. Ribbon. Enabled = false, is likely an error:

conclusion

  • Spring Cloud itself: If the LB is based on the Spring Cloud itself, the Ribbon capabilities need to be hidden, and the @loadBalanced annotation is required for RestTemplate.

  • K8s itself: If the load of Spring Cloud is used, combined with K8S, LB of application services can be achieved. If set spring. Cloud. Kubernetes. Ribbon. Mode = POD, the ability to disable the ribbon LB, at this time will not take effect, walk or spring cloud LoadBalancer. In addition, for services, the type is set to NodePort. If the default type is used, whether LB can be implemented needs to be confirmed, because at present, the default type is not implemented, which may be a network problem. It does not mean that the default type of Service cannot be implemented.

  • The Ribbon is based on the above. Next time, we can try to implement the Ribbon LB based on NodePort Service.

Practice verification

In the previous section, we tested the Ribbon load balancing for the default Service type and found that we could not LB across NS. Next, we test the Service based on NodePort type, open spring. Cloud. Loadbalancer. Ribbon. The enabled = true, introducing depends on:

</dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
</dependency>
Copy the code

Diff-ns-service (diff-ns-service)

Return log after request:

conclusion

However, the Ribbon does not address cross-service access across NS applications. For Service types, however, it may be a network setup problem, regardless of the type.