jacoco dump基于k8s的实现

这篇具有很好参考价值的文章主要介绍了jacoco dump基于k8s的实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题描述

众所周知,jacoco 的dump操作如果是使用server模式只需要使用以下命令就能获取到exec文件

java -jar jacococli.jar dump --address 192.169.110.1 --port 6300 --destfile ./jacoco-demo.exec

如果是非k8s的集群,也只需要遍历执行这条命令即可,但是对于k8s服务的处理有有点力所不逮
当我们使用k8s部署服务后,应用实例将会无状态话,用户不再去关心实例的ip,端口等信息,service自动会帮我们做负载均衡等操作,pod不会暴露出ip和端口等信息给集群外部访问,这样对我们的dump操作带来了困难。

问题解决

针对上述问题,网络上也有一些解决方案,最常用的方式是切换jacooc server模式为client模式,这样当jvm关闭时就会将dump 数据写入指定服务的文件里。虽然能从一定程度解决问题,但是这样生成报告的节奏就会被打断,就不能随时生成报告了,这里提供一种解决方式。
首先,我们还是采用server模式,在服务启动时注入

 -javaagent:/jacoco/agent/jacocoagent.jar=includes=*,output=tcpserver,port=6300,address=0.0.0.0

然后,当我们想要去获取exec文件时,可以在pod中执行

java -jar /jacoco/agent/jacococli.jar dump --address 127.0.0.1 --port 36300 --destfile /app/jacoco.exec

然后我们从pod读取文件/app/jacoco.exec写入我们的报告生成服务即可
怎么去pod内部执行shell命令,各种手动都有,这里我们java基于一个k8s的sdk工具fabric8实现

    public List<String> dumpK8sExecData(K8sDumpParam k8sDumpParam) {
        try {
            String dumpCmd = "JAVA_TOOL_OPTIONS=\"\" java -jar /jacoco/agent/jacococli.jar dump --address 127.0.0.1 --port 6300 --destfile /app/jacoco.exec";
            if (k8sDumpParam.getResetFlag()) {
                dumpCmd += " --reset";
            }
            String[] cmd = {"sh", "-c", dumpCmd};
            K8sCmdParam k8sCmdParam = OrikaMapperUtils.map(k8sDumpParam, K8sCmdParam.class);
            k8sCmdParam.setCmd(cmd);
            k8sCmdParam.setExecutor(executor);
            return executeCmd(k8sCmdParam);
        } catch (Exception e) {
            log.error("dump操作失败,失败原因:", e);
            throw new BizException(BizCode.JACOCO_DUMP_ERROR);
        }
    public List<String> executeCmd(K8sCmdParam k8sCmdParam) {
        KubernetesClient client = K8sClientProxy.getOrCreateClient(k8sCmdParam.getKubeConfig());
        if (client == null || k8sCmdParam.getNameSpace() == null || CollectionUtil.isEmpty(k8sCmdParam.getPodList())) {
            throw new BizException(BizCode.JACOCO_DUMP_PARAM_ERROR);
        }
        List<CompletableFuture<String>> priceFuture = k8sCmdParam.getPodList().stream().map(pod ->
                CompletableFuture.supplyAsync(() -> {
                    String filename = "";
                    // 异步操作
                    dumpFileService.podExec(pod, k8sCmdParam.getCmd(), k8sCmdParam.getNameSpace(), client);
                    try {
                        //中间等待文件写入一段时间,再去尝试获取
                        Thread.sleep(1000);
                        filename = dumpFileService.downloadFile(pod, k8sCmdParam.getNameSpace(), client, k8sCmdParam.getTaskWorkspace());
                    } catch (Exception e) {
                        throw new BizException(BizCode.DUMP_FILE_GET_ERROR);
                    }
                    return filename;
                }, k8sCmdParam.getExecutor())
        ).collect(Collectors.toList());
        // 等待所有异步操作完成,多个pod并发执行以上操作,减少dump的时间消耗
        CompletableFuture.allOf(priceFuture.toArray(new CompletableFuture[0])).join();
        return priceFuture.stream().map(CompletableFuture::join).filter(Objects::nonNull).collect(Collectors.toList());
    }

    /**
     * 执行单个pod命令
     *
     * @param podName   pod名字
     * @param cmd       cmd
     * @param namespace 名称空间
     * @param client    客户端
     */
    public void podExec(String podName, String[] cmd, String namespace, KubernetesClient client) {
        try (ExecWatch watch = client.pods().inNamespace(namespace)
                .withName(podName)
                .redirectingOutput()
                .exec(cmd)) {
        }
    }


    /**
     * 获取文件
     *
     * @param podName   pod名字
     * @param namespace 名称空间
     * @param client    客户端
     * @param workspace 工作空间
     */
    @Retryable(value = {IOException.class}, backoff = @Backoff(delay = 1000))
    public String downloadFile(String podName, String namespace, KubernetesClient client, String workspace) throws IOException {
        try (InputStream is = client.pods().inNamespace(namespace)
                .withName(podName)
                .file("/app/jacoco.exec").read()) {
            String execPath = workspace + "/exec/" + podName + "/jacoco.exec";
            FileUtil.writeFromStream(is, execPath);
            return execPath;
        }
    }

这里有两个细节点

  • Thread.sleep(1000)操作,是因为执行dump命令后,我们无法判定exec文件什么时候能在本地生成完成,立马获取就会抛出IO异常,等待一定时间后即可获取到文件,这个时间的等待只是第一层保障,具体等待时间,可以视自己的dump文件大小调整,当然哪怕没调整也没有关系
  • @Retryable(value = {IOException.class}, backoff = @Backoff(delay = 1000))
    这段代码是使用了spring的一个重试框架,当文件获取失败后,默认会重试3次,每次重试间隔1秒,这是获取文件的第二步保障,用户可以通过调整重试次数来减少文件获取失败风险

这里说明下spring Retryable必须在public方法上,而且调用它的方法不能和他处于同一个类,否则不会生效重试。
通过以上手段就可以主动去dump出想要的数据,当然更好的方式是判断exec文件是否存在,或者还在写入中,等写入完成再去获取文件,这个操作也可以通过shell去完成,本文只是提供一种实现方案。
更多jacoco相关姿势可以参考这里文章来源地址https://www.toymoban.com/news/detail-431035.html

到了这里,关于jacoco dump基于k8s的实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于k8s搭建mysql5.7主从集群实现读写分离

    一,准备工作 1,拥有一个运行中的k8s集群 2,拥有一个ceph分布式存储集群,此mysql集群基于ceph块存储,部署方案可参考我前面的rook部署ceph方案 二,集群搭建 1,创建存储类storageclass       将此 StorageClass 定义保存为 storageclass.yaml : 创建存储类   2,MySQL 部署包含一个 Con

    2024年02月08日
    浏览(33)
  • 使用golang 基于 OpenAI Embedding + qdrant 实现k8s本地知识库

    文章博客地址:套路猿-使用golang 基于 OpenAI Embedding + qdrant 实现k8s本地知识库 将数据集 通过 openai embedding 得到向量+组装payload,存入 qdrant 用户进行问题搜索,通过 openai embedding 得到向量,从 qdrant 中搜索相似度大于0.8的数据 从 qdrant 中取出相似度高的数据 将获取到的QA,组装成 pr

    2024年02月08日
    浏览(31)
  • 最后的组合:K8s 1.24 基于 Hekiti 实现 GlusterFS 动态存储管理实践

    知识点 定级: 入门级 GlusterFS 和 Heketi 简介 GlusterFS 安装部署 Heketi 安装部署 Kubernetes 命令行对接 GlusterFS 实战服务器配置(架构 1:1 复刻小规模生产环境,配置略有不同) 主机名 IP CPU 内存 系统盘 数据盘 用途 ks-master-0 192.168.9.91 2 4 50 100 KubeSphere/k8s-master ks-master-1 192.168.9.92 2 4 5

    2024年02月09日
    浏览(30)
  • 【k8s问题定位】k8s中的pod不停的重启,定位问题原因与解决方法

    现象: running的pod,短时间内重启次数太多   定位问题方法: 查看pod日志 本次使用以下命令,解决了问题 问题原因: OOM,pod被kill掉,重启了( 内存不够用 )   查看该服务的deployment.yaml文件 发现我们deployment.yaml对服务的内存使用,做了限制 解决方法: 将limit的memory数值提高,然后

    2024年02月09日
    浏览(48)
  • [k8s] 基于ubuntu22部署k8s1.28记录

    k8s1.28部署已经不依赖docker了,所以不需要安装docker。同理:如果想查看镜像和运行容器,也不能用docker命令去查询了:需要使用crictl。不过crictl命令参数兼容docker,所以使用上手没有啥难度。 根据k8s官方文档:https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kube

    2024年02月11日
    浏览(40)
  • Prometheus+Grafana监控K8S集群(基于K8S环境部署)

    1、服务器及K8S版本信息: IP地址 主机名称 角色 K8S版本 16.32.15.200 master-1 Master节点 v1.23.0 16.32.15.201 node-1 Node节点 v1.23.0 16.32.15.202 node-2 Node节点 v1.23.0 2、部署组件版本: 序号 名称 版本 作用 1 Prometheus v2.33.5 收集、存储和处理指标数据 2 Node_exporter v0.16.0 采集服务器指标,如CP

    2024年02月04日
    浏览(56)
  • k8s问题汇总

    本文章为记录使用k8s遇到的问题和解决方法, 文章持续更新中... curl: (7) Failed connect to test.com:8080; Connection refused error execution phase kubelet-start: error uploading crisocket: Unauthorized To see the stack trace 网页提示信息Client sent an HTTP request to an HTTPS server. 原因: 因为直接使用ip:端口的方式是

    2024年02月12日
    浏览(84)
  • 部署 k8s问题集

    VMware虚拟机部署k8s集群_vmware k8s_异乡人hl的博客-CSDN博客 kubernetes dashboard令牌登入获取token Kubernetes之network: failed to set bridge addr: “cni0“ already has an IP address different from xxx问题 https://www.cnblogs.com/deny/p/14858596.html

    2024年02月16日
    浏览(22)
  • k8s 问题处理集锦

    当使用 Kubernetes(K8s)时,可能会遇到各种问题。以下是一些常见的 K8s 问题以及相应的处理方法集锦: Pod 状态不正常或无法正常启动: 检查 Pod 的描述文件,确保配置正确。 使用 kubectl describe pod 命令查看 Pod 的详细信息和事件,以便定位问题。 检查相关容器的日志,使用

    2024年02月11日
    浏览(35)
  • 【K8S&RockyLinux】基于开源操作系统搭建K8S高可用集群(详细版)

    角色 主机名 IP地址 系统版本 CPU/MEM master m1 192.168.200.61 Rocky Linux 8.5 2C/2GB master m2 192.168.200.62 Rocky Linux 8.5 2C/2GB master m3 192.168.200.63 Rocky Linux 8.5 2C/2GB node n1 192.168.200.64 Rocky Linux 8.5 2C/4GB node n2 192.168.200.65 Rocky Linux 8.5 2C/4GB node n3 192.168.200.66 Rocky Linux 8.5 2C/4GB VIP 192.168.200.68 !!!注意

    2024年02月09日
    浏览(36)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包