[实战]Spring Boot打成Docker镜像运行下载文件报Fatal glibc error: cannot get entropy for arc4random

      同事反馈使用只要下载文件,日志中会打印Fatal glibc error: cannot get entropy for arc4random,之后系统自动重启,下载文件失败。

直接搜索Fatal glibc error: cannot get entropy for arc4random并未得到太多的有效信息。baidu和google还有bing我都尝试了。我是一个地道 的搜索引擎工程师。

查到一种方案为使用rngd自动补充熵池,尝试没有效果,无法解决。

继续排查,项目工程代码如下:

    @GetMapping("/export")
    @Operation(summary = "数据导出")
    public void export(CableTunnelQueryParam queryParam, HttpServletResponse response) throws IOException {
        log.info("start export:{}", JSONObject.toJSONString(queryParam));
        try {
            List<CableTunnelDO> list = cableTunnelService.listAll(queryParam);
            // 输出
            ExcelUtils.write(response,
                    "附件.xls",
                    "数据",
                    CableTunnelVO.class,
                    BeanUtils.toBean(list, CableTunnelVO.class));
        } catch (Exception e) {
            log.error("导出excel失败", e);
        }
        log.info("end export:{}", JSONObject.toJSONString(queryParam));

    }

     ExcelUtils.write代码如下

    public static <T> void write(HttpServletResponse response, String filename, String sheetName,
                                 Class<T> head, List<T> data, List<KeyValue<ExcelColumn, List<String>>> selectMap) throws IOException {
        // 输出 Excel
        EasyExcel.write(response.getOutputStream(), head)
                .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度
                .registerWriteHandler(new SelectSheetWriteHandler(selectMap)) // 基于固定 sheet 实现下拉框
                .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度
                .sheet(sheetName).doWrite(data);
        // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, StandardCharsets.UTF_8.name()));
        response.setContentType("application/vnd.ms-excel;charset=UTF-8");
    }

该代码在windows下运行正常。查看服务日志只打印了【start export】这行日志,后面的【导出excel失败】和【end export】均未打印,在【start export】后输出了一句Fatal glibc error: cannot get entropy for arc4random,紧接着系统无法访问,开始了自动重启。

在Docker宿主机和虚机内执行以下代码都可以正常获取随机数

cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n1
cat /dev/random | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n1

Dockerfile文件中已经使用了-Djava.security.egd=file:/dev/./urandom 代码如下

CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar

之后在Docker启动中也增加了-v /dev/urandom:/dev/random

问题仍未解决。

我就是个java开发,对C还有C++并不了解,对glibc 和arc4random也不清楚是啥。随后便尝试切换了jdk镜像文件进行解决。

原镜像文件使用的是eclipse-temurin:8-jre,更新为openjdk:8-jdk-alpine

正常启动后,导出Excel报如下错误:

java.lang.NullPointerException: null
        at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
        at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)
        at sun.awt.FontConfiguration.init(FontConfiguration.java:107)
        at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)
        at sun.font.SunFontManager$2.run(SunFontManager.java:431)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.font.SunFontManager.<init>(SunFontManager.java:376)
        at sun.awt.FcFontManager.<init>(FcFontManager.java:35)
        at sun.awt.X11FontManager.<init>(X11FontManager.java:57)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at java.lang.Class.newInstance(Class.java:442)
        at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)

网上查找原因:

根据报错信息是缺少某个字体,而docker打包镜像默认是没有该字体;或者因为使用了openjdk而没有使用oraclejdk,缺少依赖。

在Dockerfile中增加以下代码,重新打包运行成功。

RUN apk add --update;apk add ttf-dejavu;apk add fontconfig

问题解决。

对于Fatal glibc error: cannot get entropy for arc4random的根本原因我没有找到。如果有大佬了解什么原因还请指教。

关于为什么-Djava.security.egd=file:/dev/./urandom 中/dev/./urandom中有一个".",原因是这里是jdk中的一个bug,在这个bug的连接里有人反馈及时对securerandom.source设置为/dev/urandom它也仍然使用的/dev/random,有人提供了变通的解决方法,其中一个变通的做法是对securerandom.source,设置为/dev/./urandom才行

关于openjdk:8-jdk-alpine 参考

https://zhuanlan.zhihu.com/p/667075764

关于rngd补充熵池:

Linux下熵池大小导致的一些问题-CSDN博客

参考: 

https://blog.51cto.com/riverxyz/5105735

JVM的随机数与熵池策略 - 简书

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值