聊聊spring-cloud-kubernetes-client-discovery

news/2024/7/4 7:47:37 标签: kubernetes, 容器, 云原生

本文主要研究一下spring-cloud-kubernetes-client-discovery

DiscoveryClient

org/springframework/cloud/client/discovery/DiscoveryClient.java

public interface DiscoveryClient extends Ordered {

	/**
	 * Default order of the discovery client.
	 */
	int DEFAULT_ORDER = 0;

	/**
	 * A human-readable description of the implementation, used in HealthIndicator.
	 * @return The description.
	 */
	String description();

	/**
	 * Gets all ServiceInstances associated with a particular serviceId.
	 * @param serviceId The serviceId to query.
	 * @return A List of ServiceInstance.
	 */
	List<ServiceInstance> getInstances(String serviceId);

	/**
	 * @return All known service IDs.
	 */
	List<String> getServices();

	/**
	 * Can be used to verify the client is valid and able to make calls.
	 * <p>
	 * A successful invocation with no exception thrown implies the client is able to make
	 * calls.
	 * <p>
	 * The default implementation simply calls {@link #getServices()} - client
	 * implementations can override with a lighter weight operation if they choose to.
	 */
	default void probe() {
		getServices();
	}

	/**
	 * Default implementation for getting order of discovery clients.
	 * @return order
	 */
	@Override
	default int getOrder() {
		return DEFAULT_ORDER;
	}

}

spring-cloud-commons提供了DiscoveryClient接口,它定义了description、getInstances、getServices、probe、getOrder方法

KubernetesInformerDiscoveryClient

spring-cloud-kubernetes-client-discovery/src/main/java/org/springframework/cloud/kubernetes/client/discovery/KubernetesInformerDiscoveryClient.java

public class KubernetesInformerDiscoveryClient implements DiscoveryClient {

	private static final LogAccessor LOG = new LogAccessor(LogFactory.getLog(KubernetesInformerDiscoveryClient.class));

	private final List<SharedInformerFactory> sharedInformerFactories;

	private final List<Lister<V1Service>> serviceListers;

	private final List<Lister<V1Endpoints>> endpointsListers;

	private final Supplier<Boolean> informersReadyFunc;

	private final KubernetesDiscoveryProperties properties;

	private final Predicate<V1Service> filter;

	private final ServicePortSecureResolver servicePortSecureResolver;

	// visible only for testing and
	// must be constructor injected in a future release
	@Autowired
	CoreV1Api coreV1Api;

	@Override
	public String description() {
		return "Kubernetes Client Discovery";
	}

	@Override
	public List<String> getServices() {
		List<String> services = serviceListers.stream().flatMap(serviceLister -> serviceLister.list().stream())
				.filter(service -> matchesServiceLabels(service, properties)).filter(filter)
				.map(s -> s.getMetadata().getName()).distinct().toList();
		LOG.debug(() -> "will return services : " + services);
		return services;
	}

	@PostConstruct
	public void afterPropertiesSet() {
		postConstruct(sharedInformerFactories, properties, informersReadyFunc, serviceListers);
	}

	@Override
	public int getOrder() {
		return properties.order();
	}

	//......
}	

spring-cloud-kubernetes-client-discovery的KubernetesInformerDiscoveryClient实现了DiscoveryClient接口;其description方法返回的是Kubernetes Client Discovery,其getServices方法使用的是serviceListers的list方法获取service,加上service.metadata的label与KubernetesDiscoveryProperties的serviceLabels匹配过滤而来

getInstances

	public List<ServiceInstance> getInstances(String serviceId) {
		Objects.requireNonNull(serviceId, "serviceId must be provided");

		List<V1Service> allServices = serviceListers.stream().flatMap(x -> x.list().stream())
				.filter(scv -> scv.getMetadata() != null).filter(svc -> serviceId.equals(svc.getMetadata().getName()))
				.filter(scv -> matchesServiceLabels(scv, properties)).toList();

		List<ServiceInstance> serviceInstances = allServices.stream().filter(filter)
				.flatMap(service -> serviceInstances(service, serviceId).stream())
				.collect(Collectors.toCollection(ArrayList::new));

		if (properties.includeExternalNameServices()) {
			LOG.debug(() -> "Searching for 'ExternalName' type of services with serviceId : " + serviceId);
			List<V1Service> externalNameServices = allServices.stream().filter(s -> s.getSpec() != null)
					.filter(s -> EXTERNAL_NAME.equals(s.getSpec().getType())).toList();
			for (V1Service service : externalNameServices) {
				ServiceMetadata serviceMetadata = serviceMetadata(service);
				Map<String, String> serviceInstanceMetadata = serviceInstanceMetadata(Map.of(), serviceMetadata,
						properties);

				K8sInstanceIdHostPodNameSupplier supplierOne = externalName(service);
				K8sPodLabelsAndAnnotationsSupplier supplierTwo = externalName();

				ServiceInstance externalNameServiceInstance = serviceInstance(null, serviceMetadata, supplierOne,
						supplierTwo, new ServicePortNameAndNumber(-1, null), serviceInstanceMetadata, properties);
				serviceInstances.add(externalNameServiceInstance);
			}
		}

		return serviceInstances;
	}

getInstances方法用serviceListers来对service.metadata.name与serviceId进行匹配获取到service,之后通过serviceInstances方法得到serviceInstances,最后加上ExternalName类型的service

serviceInstances

	private List<ServiceInstance> serviceInstances(V1Service service, String serviceId) {

		List<ServiceInstance> instances = new ArrayList<>();

		List<V1Endpoints> allEndpoints = endpointsListers.stream()
				.map(endpointsLister -> endpointsLister.namespace(service.getMetadata().getNamespace()).get(serviceId))
				.filter(Objects::nonNull).toList();

		for (V1Endpoints endpoints : allEndpoints) {
			List<V1EndpointSubset> subsets = endpoints.getSubsets();
			if (subsets == null || subsets.isEmpty()) {
				LOG.debug(() -> "serviceId : " + serviceId + " does not have any subsets");
			}
			else {
				ServiceMetadata serviceMetadata = serviceMetadata(service);
				Map<String, Integer> portsData = endpointSubsetsPortData(subsets);
				Map<String, String> serviceInstanceMetadata = serviceInstanceMetadata(portsData, serviceMetadata,
						properties);

				for (V1EndpointSubset endpointSubset : subsets) {

					Map<String, Integer> endpointsPortData = endpointSubsetsPortData(List.of(endpointSubset));
					ServicePortNameAndNumber portData = endpointsPort(endpointsPortData, serviceMetadata, properties);

					List<V1EndpointAddress> addresses = addresses(endpointSubset, properties);
					for (V1EndpointAddress endpointAddress : addresses) {

						K8sInstanceIdHostPodNameSupplier supplierOne = nonExternalName(endpointAddress, service);
						K8sPodLabelsAndAnnotationsSupplier supplierTwo = nonExternalName(coreV1Api,
								service.getMetadata().getNamespace());

						ServiceInstance serviceInstance = serviceInstance(servicePortSecureResolver, serviceMetadata,
								supplierOne, supplierTwo, portData, serviceInstanceMetadata, properties);
						instances.add(serviceInstance);
					}
				}

			}
		}

		return instances;
	}

serviceInstances方法通过endpointsListers根据namespace和serviceId来获取对应的Endpoints,根据其subsets,通过K8sInstanceIdHostPodNameSupplier、K8sPodLabelsAndAnnotationsSupplier来组装DefaultKubernetesServiceInstance,最后返回

小结

spring-cloud-commons提供了DiscoveryClient接口,它定义了description、getInstances、getServices、probe、getOrder方法;spring-cloud-kubernetes-client-discovery的KubernetesInformerDiscoveryClient实现了DiscoveryClient接口;其description方法返回的是Kubernetes Client Discovery,其getServices方法使用的是serviceListers的list方法获取service,加上service.metadata的label与KubernetesDiscoveryProperties的serviceLabels匹配过滤而来。


http://www.niftyadmin.cn/n/5390104.html

相关文章

选择适合你的编程语言

引言 在当今瞬息万变的技术领域中&#xff0c;选择一门合适的编程语言对于个人职业发展和技术成长至关重要。每种语言都拥有独特的设计哲学、应用场景和市场需求&#xff0c;因此&#xff0c;在决定投入时间和精力去学习哪种编程语言时&#xff0c;我们需要综合分析多个因素&a…

linux服务 宝塔控制面板,宝塔面板打不开,ssh可以链接,输入bt命令没有反应 linux 重启宝塔服务器命令

目录 问题解决方法 问题 1、宝塔面板无法开&#xff0c;显示连接失败 2、bt 没有效果 解决方法 1、第一步、首先执行下面板看看bt文件 ll /etc/init.d/2、第二步、 执行df -h看看磁盘空间 df -hT3、删除旧的宝塔快捷方式 进行备份 mv /etc/init.d/bt /tmp/bt_back4、生成…

SQL Server 连接池相关内容

查看最大连接数 SELECT MAX_CONNECTIONS查看指定数据库的连接数 SELECT * FROM master.dbo.sysprocesses WHERE dbid IN ( SELECT dbid FROM master.dbo.sysdatabases WHERE NAMEDB_WMS_KZJ )获取当前SQL服务器所有的连接详细信息 SELECT * FROM sysprocesses获取自上次启动…

eBPF讲解篇之环境搭建

文章目录 前言实验环境前置知识配置开发环境最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;本次我们学习一下eBPF&#xff0c;我们基于libbpf-bootstrap来进行我们的eBPF程序开发&#x1f917; 实验环境 一台Debian12操作系统的计算机&#xff0c;我使用的是Debian12.…

操作系统(1)——学习导论(Ⅰ)

目录 小程一言专栏链接: [link](http://t.csdnimg.cn/6grrU) 学习导论什么是操作系统主要功能强调 操作系统历史硬件层面处理器重要特点and功能 存储器磁盘I/O设备小程常用的I/O设备及其特点 小程一言 本操作系统专栏&#xff0c;是小程在学操作系统的过程中的第一步&#xff…

uni-app 人脸识别 App端

文章目录 背景介绍开发前准备基础版获取视频流人脸识别版本这时候就可以开心的调试了背景介绍 本文介绍如何制作人脸打卡等类似功能的实现。 使用nvue+live-pusher来实现。在App端这是成本较低的可以控制样式的方案了 实现了两个版本 基础版本:视频流 => 抓拍照片 => 传…

openai sora 只能根据文本生成视频?不,TA 是通用物理世界模拟器

视频生成模型作为世界模拟器 我们探索了在视频数据上进行大规模生成模型的训练。 具体来说&#xff0c;我们联合在可变持续时间、分辨率和长宽比的视频和图像上训练文本条件扩散模型。 我们利用了一个在视频和图像潜在编码的时空补丁上操作的变压器架构。 我们最大的模型So…

【SRE系列】-安装Jenkins

1、下载jenkins安装包 rootk8s-jenkins:~# wget https://mirror.tuna.tsinghua.edu.cn/jenkins/debian-stable/jenkins_2.426.2_all.deb2、配置Jenkins环境 #注意&#xff1a;部署前要确定下你所安装的Jenkins适配那个版本的java环境&#xff0c;如果java版本和Jenkins版本不适…