用Java实现kubernetes的List-Watch

这篇博客介绍了如何使用Java的kubernetes-client库来实现Kubernetes的List-Watch功能。作者强调了版本管理的重要性,特别是解决因依赖冲突导致的问题,并提供了详细的代码示例,包括自定义资源定义和事件监听处理。此外,还展示了如何处理资源的添加、更新和删除事件。
摘要由CSDN通过智能技术生成

前言

一般对于k8s的操作都用go语言,所以大部分的k8s的operator都是用的go语言,但是也有一些用Java写的kubernetes-client,其中fabric8就是一款不错的k8s-client工具,最近研究了一下k8s用Java实现List-watch,供大家参考。

依赖

有一些spring-cloud依赖中带有了kubernetes-client的版本,所以有时候你导入版本的时候总会导入4.10.3的版本,导致一些类是找不到的,就是因为版本问题(博主就是遇到了这个bug,最后排查了好长时间才解决),所以要设置版本依赖,这个依赖管理一定要放在第一个。

<dependency>
    <groupId>io.fabric8</groupId>
    <artifactId>kubernetes-client</artifactId>
</dependency>
<dependencyManagement>
        <dependencies>
            <!-- spring-cloud-dependencies里面包含了kubernetes-client-bom,并且版本为4.10.3,
            所以引入的kubernetes-client不能指定版本, 在此引入kubernetes-client的版本控制, 这个要放在第一个 -->
            <dependency>
                <groupId>io.fabric8</groupId>
                <artifactId>kubernetes-client-project</artifactId>
                <version>5.12.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

代码

这是本人的部分测试代码,如要实际应用需要根据自定义开发。

自定义资源

@Group("harmonycloud.cn")
@Version("v1beta1")
@Kind("NodePool")
@Singular("nodepool")
@Plural("nodepools")
public class NodePool extends CustomResource<NodePoolSpec, Void> {
}
@Data
public class NodePoolSpec {

    private Map<String, String> labels;
    private List<Taint> taints;
}

@Data
public class Taint {
    private String key;
    private String value;
    private String effect;
    private String timeAdded;
}

List-watch测试代码

package com.victor.watch;

import com.alibaba.fastjson.JSON;
import com.victor.client.K8sClient;
import com.victor.common.util.ThreadHelper;
import com.victor.model.NodePool;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.WatcherException;
import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class ListWatch implements ApplicationRunner {

    private final BlockingQueue<NodePoolEvent> queue = new LinkedBlockingQueue<>();

    @Override
    public void run(ApplicationArguments args) {
        log.info("list-watch启动");
        // 资源被修改时,k8sClient底层会起一个Thread去回调eventReceived, 因此自己不用
        // 再重新启动一个线程
        K8sClient.getClient().customResources(NodePool.class).watch(new Watcher<>() {
            @Override
            public void eventReceived(Action action, NodePool nodePool) {
                try {
                    queue.put(new NodePoolEvent(action, nodePool));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }

            @Override
            public void onClose(WatcherException cause) {
                log.info("Watcher close due to: ", cause);
            }
        });

        // 这个线程可以是多余的, 其实可以直接在eventReceived方法里书写逻辑, 原本watch就是阻塞的,
        // 事件是按照顺序一个一个去执行的,所以没有必再加一个阻塞队列
        /*new Thread(() -> {
            for (; ; ) {
                NodePoolEvent nodePoolEvent;
                try {
                    nodePoolEvent = queue.take();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                log.info("NodePool {} {}", nodePoolEvent.getAction().name(), JSON.toJSONString(nodePoolEvent.getNodePool()));
            }
        }).start();*/

        // List-Watch
        // 执行的时候这个会阻塞,只有当没有事件的时候才会继续往下执行,因此专门启动一个线程去执行它,让主线程继续执行
        ThreadHelper.run(() -> {
            K8sClient.getClient().customResources(NodePool.class).inform(new ResourceEventHandler<>() {
                @Override
                public void onAdd(NodePool nodePool) {
                    log.info("add nodepool:{}", JSON.toJSONString(nodePool));
                    try {
                        // 事件是按照阻塞队列的方式去调用的,只有当上一个执行完毕后才能执行下一个
                        TimeUnit.SECONDS.sleep(10);
                        // 即使抛出异常,也不会影响下一个事件的执行
//                        throw new RuntimeException("错误啦...");
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }

                @Override
                public void onUpdate(NodePool oldNodePool, NodePool newNodePool) {
                    log.info("update nodepool oldNodePool:{}, newNodePool:{}",
                            JSON.toJSONString(oldNodePool, true), JSON.toJSONString(newNodePool, true));
                }

                @Override
                public void onDelete(NodePool nodePool, boolean deletedFinalStateUnknown) {
                    log.info("delete nodepool:{}, deletedFinalStateUnknown:{}", nodePool, deletedFinalStateUnknown);
                }
            });

            K8sClient.getClient().informers().addSharedInformerEventListener(ex ->
                    log.error("Exception occurred, message:{}", ex.getMessage(), ex));
        });

    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class NodePoolEvent {
        private Watcher.Action action;
        private NodePool nodePool;
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值