spring-cloud-kubernetes spring cloud service discovery application development environment in k8s

     Under normal circumstances, our service line at that time under the k8s migration environment, are based on a smooth migration program. Governance and service registration centers are based on the original components. Such as spring cloud applications, in k8s environment or use the original set of registry (such as eureka), service management (hystrix, ribbon) and so on. But when we develop new applications, we can by means of service sping-cloud-kubernetes components provides us with discovery, load balancing and so to get rid of the registry like eureka. In this paper, by constructing two spring cloud service to demonstrate-Cloud-Kubernetes component the Spring How do discover services, load balancing and so on.

First, using a spring-cloud-kubernetes do service discovery

    It was developed two services, the service provider: product_infra_service, and provides an interface by way of foreign FeignClient, for consumers to call. Service consumers: product_infra_consumer. 

First, a new Module1: Product-Service-API-Infra-: the project dependency Related pom configuration file is as follows:

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

        <!--Service Interface API-->

        <!--Feign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.1.3.RELEASE</version>
        </dependency>
    </dependencies>

 

The interfaces defined in the project as follows: 

@FeignClient(name="${feign.product-infra.name:product-infra-service}",fallback = PropertyClientFallback.class)

public interface PropertyClient {

    @GetMapping(value="properties")
    List<String> getProperties();
}

The fallback hystrix class is defined as follows:

@Component
public class PropertyClientFallback implements PropertyClient{

    @Override
    public List<String> getProperties() {
        return new ArrayList<String>();
    }
}

Next, the new service provider product-infra-service projects to achieve PropertyClient interfaces in the project. pom dependent configuration file as follows:

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--Service Interface API-->
        <dependency>
            <groupId>com.maidao.center.product_infra</groupId>
            <artifactId>product-infra-service-api</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--SpringBoot Actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

Controller class is defined as follows:

@RestController
@RequestMapping
public class PropertyController  implements PropertyClient{

    @GetMapping("properties")
    public List<String> getProperties(){
        ArrayList<String> properties = new ArrayList<>();
        properties.add("properties1");
        properties.add("properties2");
        return properties;
    }

}

After compiling packaged into a mirror to project deployment K8S environment, and define the service to the service instance associated pod in K8S Environment: In this example k8s service name is defined in product-infra-service (application name and the same as defined).

 

New consumer items: product-infra-consumer, pom-dependent configuration file as follows:

 

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-kubernetes-core</artifactId>
            <version>${springcloud.kubernetes.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-kubernetes-discovery</artifactId>
            <version>${springcloud.kubernetes.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-kubernetes-ribbon</artifactId>
            <version> springcloud.kubernetes.version $ {} </ version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-commons</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>${springcloud.version}</version>
        </dependency>

        <!--Service Interface API-->
        <dependency>
            <groupId>com.maidao.center.product_infra</groupId>
            <artifactId>product-infra-service-api</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

 

Application configuration as follows:
Server: 
  Port: 8080 



Product-infra- -Service: 
  Ribbon: 
    KubernetesNamespace: $ {namespace} (K8S namespace, the real name corresponding to the configuration in accordance with its own namespace service deployment) 
 backend:  Ribbon:  Eureka:  Enabled: to false  Client:  Enabled: to true ServerListRefreshInterval : 5000 hystrix: the Command: BackendCall: Execution: Isolation: the Thread: timeoutInMilliseconds: 5000 ThreadPool: BackendCallThread: coresize The: 5 Feign: hystrix: Enabled: to true

New ProductInfraConsumerController categories: PropertyClient by reference to the interface call providers.


@RestController
@RequestMapping
public class ProductInfraConcumerController {

@Autowired
private PropertyClient propertyClient;

@GetMapping("properties")
public List<String> getProductProperties(){

return propertyClient.getProperties();

}

}

You can see the code does not change, does not change the way calls, removed the original EurekaClient found in the consumer calls the service project. Service discovery mechanism uses, the Spring-Cloud-Kubernetes-Discovery. Load balancing assembly uses: Spring-Cloud-Starter-Kubernetes-Ribbon.

After the last product-infra-consumer packaged into compiled image, to deploy the k8s environment.

Finally curl command controller calling method of product-infra-consumer in k8s environment to test the communication between the service: as follows:

[root@iZbp174tf9563rykf3bbjjZ ~]# curl http://172.30.28.100:8080/properties

["properties1","properties2"]

Turning off the product-infra-service service, initiated the request again, relegated fallback method to take effect:

[root@iZbp174tf9563rykf3bbjjZ ~]# curl http://172.30.28.98:8080/properties

[]

Can be seen in the absence of eureka registry of cases, the definition of the two services can communicate, and the code does not need to make any changes, just the introduction of spring-cloud-kubernetes related to dependence, spring-cloud service consumers -kubernetes service discovery component plays a role as well as load balancing.

 

Two, spring-cloud-kubernetes service discovery process

      spring-cloud-kubernetes framework provides the ability to invoke primary Kubernetes to serve existing SpringCloud application architecture as shown below:

从上图可以看出product-infra-consumer在调用product-infra-service时,通过FeignClient组件拿到service name信息,最底层通过ok-http3,根据service name 调用 api server 获取该service下对应的Pod信息,拿到Pod信息后通过,轮询的方式向这些pod发送请求。spring-cloud-starter-kubernetes-ribbon组件中的KubernetesServerList 继承了 ribbon-loaderbanlancer组件中的AbstractServerList以及实现了 ServerList类中的方法,并通过 KubernetesClient提供的能力向k8s api server 发送请求信息。通过服务名获取pod信息的源码如下:

public List<Server> getUpdatedListOfServers() {
        Endpoints endpoints = this.namespace != null
                ? this.client.endpoints().inNamespace(this.namespace)
                        .withName(this.serviceId).get()
                : this.client.endpoints().withName(this.serviceId).get();

        List<Server> result = new ArrayList<Server>();
        if (endpoints != null) {

            if (LOG.isDebugEnabled()) {
                LOG.debug("Found [" + endpoints.getSubsets().size()
                        + "] endpoints in namespace [" + this.namespace + "] for name ["
                        + this.serviceId + "] and portName [" + this.portName + "]");
            }
            for (EndpointSubset subset : endpoints.getSubsets()) {

                if (subset.getPorts().size() == 1) {
                    EndpointPort port = subset.getPorts().get(FIRST);
                    for (EndpointAddress address : subset.getAddresses()) {
                        result.add(new Server(address.getIp(), port.getPort()));
                    }
                }
                else {
                    for (EndpointPort port : subset.getPorts()) {
                        if (Utils.isNullOrEmpty(this.portName)
                                || this.portName.endsWith(port.getName())) {
                            for (EndpointAddress address : subset.getAddresses()) {
                                result.add(new Server(address.getIp(), port.getPort()));
                            }
                        }
                    }
                }
            }
        }
        else {
            LOG.warn("Did not find any endpoints in ribbon in namespace ["
                    + this.namespace + "] for name [" + this.serviceId
                    + "] and portName [" + this.portName + "]");
        }
        return result;
    }

 

Guess you like

Origin www.cnblogs.com/justinli/p/spring-cloud-kubernetes.html