Kibana编译坑记

需要编译Kibana的背景

目前所在的公司使用的Elasticsearch大多是5.4.3版本,使用自研插件的方式,通过添加自研header实现了索引级别的鉴权。

此种方式的鉴权便要求所有到es的请求都必须添加指定的自定义header。在这种场景下,kibana也应该配置自定义header,以适配自研的鉴权。

经调查,Kibana可以通过配置 elasticsearch.customHeaders 属性来添加自定义header。本以为到这就可以完成调试安心使用kibana对接开启自研权限的Elasticsearch了,但是调试的时候发现,面板可以正常使用,而DevTools并不能正确发送请求,经查看发现,DevTools中发送的请求并没有带上自定义的header,再通过科学搜索,发现这确实是es的一个bug,已经在高版本修复。

根据官方issue显示,该bug被解决的版本,最低是 kibana 5.5.2。而由于kibana兼容性只能保持在第三位版本号,故无法使用修复该问题的5.5.2版本kibana来配合5.4.3,因此便需要自行修改5.4.x版本来patch这个问题,也就需要自己修改kibana代码并进行相应的release。

Kibana 源码架构

了解一个开源项目,首先需要了解其工程的架构。一个工程的架构,主要包括以下几个部分:

  • 项目分支管理模式:项目按照什么模式来进行拉分支,版本release与分支的关系
  • 项目主要语言与框架:项目使用什么语言开发,同时使用了哪些该语言之上的框架
  • 依赖管理模式:项目采用何种依赖管理工具,来管理第三方依赖
  • 构建模式:项目采用何种构建工具进行构建

以上四个问题,是开始学习/二次开发一个开源项目的基石,下面我们就按照这些问题,来进行Kibana的解读。

Kibana 分支管理

由github中浏览kibana仓库的分支,可看出其分支以二位版本号为基准,如5.4、6.3。在此基础上查看其tag,可以看到tag是三位版本,如v5.4.3。由此些信息可以总结到,Kibana的代码组织结构也是遵循了开源软件的一贯标准,即分支以二位版本号命名,在二位版本号的分支上,持续release三位版本号号的具体版本,并在release的同时使用tag进行标记管理。

了解了Kibana的分支管理,我们也可以明确我们的目标,即在5.4分支上修复问题,并发布snapshot和release。具体的工作流也可以定义为:fork仓库 -> clone 5.4分支代码 -> 修改 -> 运行调试 -> 发布shapshot -> 发布release

项目语言及依赖管理体系

由源码可知,Kibana其实并没有过多的复杂业务逻辑,主要是起到一个dashboard作用,其多维度的聚合主要是通过拼接DSL交由Elasticsearch执行得到,可能是基于此考量(仅猜测),Kibana是使用NodeJS开发。其依赖也随之由npm管理。在官方的 CONTRIBUTING.md 中,针对于依赖下载和启动均有具体的介绍,故在此不过多赘述,仅针对自身遇到的坑,进行记录。

在Kibana的源码下载编译过程中,主要出现了如下问题:

  1. 通过npm install 无法自动下载,很多包需要手动下载。该问题使用npm官方源和淘宝源均无法解决,最终换用yarn管理依赖解决;

  2. 本地有使用brew安装的v12.x.x的高版本node,但是Kibana 5.4源码需要依赖6.x.x版本node。该问题通过引入了nvm来解决。

Kibana整体使用NodeJS,项目本身并不是特别繁重,所以编译起来并没有很多坑,主要的坑便是上述两个问题。

使用nvm管理多版本node

通常涉及到历史代码的维护场景,都需要本地开发环境有多版本的sdk。在NodeJS的环境中,nvm是一个node管理工具,可以用其来管理多版本node,并通过nvm命令实现多版本node的下载,切换。

nvm 在 MacOS 上可以很容易的通过 Homebrew 进行安装,并配置,简单记录如下:

  1. 执行使用brew下载nvm

    1
    brew install nvm
  2. 追加如下两行到环境变量,本例中为 ~/.bash_profile

    1
    2
    export NVM_DIR=~/.nvm
    source $(brew --prefix nvm)/nvm.sh
  3. 完成后使环境变量生效(可采用source的方式),即可使用nvm管理node。常用命令如下:

    1
    2
    3
    4
    5
    6
    # 查看远端可用node版本
    nvm ls-remote
    # 下载某版本node
    nvm install <version>
    # 使用某版本node
    nvm use <version>

通过以上操作,便可以足够日常使用。有了nvm,便可以在不同项目的开发周期中,动态切换node版本,实现一机多版本,方便开发。

使用yarn替代npm

使用nvm方案后,关于Kibana 5.4 版本所需node版本较低的问题已经完美解决,剩下的一个老大难便是依赖下载的问题。 在官方的说明中,可使用npm作为包管理器,通过预定义的 package.json 依赖描述文件来进行依赖下载。但实际操作中,由于某些不可抗力原因,导致无论使用npm官方源还是淘宝源,都没有办法顺利完成依赖下载,在十分苦恼时,Google搜索一篇关于 yarn 包管理器的使用,映入了眼帘。由于主业是后端+大数据,看到yarn第一反应是这个东西怎么还能管理NodeJS,看过之后才知道,此 yarn 非彼 Yarn。yarn可以替代npm作为包管理器来管理依赖,方式同样可以通过package.json来管理,在绝望之时,安装了yarn来试试。

yarn 在 MacOS 上同样可以很容易通过 Homebrew 进行安装并使用,简单记录如下:

1
2
3
4
5
6
# 使用 Homebrew 安装 yarn
brew install yarn
# 使用 yarn 下载依赖
yarn install
# 使用 yarn 下载依赖,忽略定义的node版本
yarn install --ignore-engines

通过使用yarn,成功下载了依赖,项目继续npm start,也可正常运行。 关于yarn和npm的具体比较由于了解不深入,在此不进行过多赘述。但是如果遇到npm下载有问题,可以使用yarn试试,没准会同样有意外惊喜。

源码改动
成功下载依赖并完成工程运行,便可以进入代码改造的阶段。由于github中针对此issue已经有提过pr,所以代码改动并不难,可以完全参考pr来进行修改,主要就是在设置header的时候添加一些逻辑,读取配置并添加。 具体需要修改文件为 src/core_plugins/console/index.js 。仅需要改动下header生成逻辑即可,具体可参考Respects ES customHeaders config for Console

浅探Kibana打包机制

源码改动后,本以为可以直接成功打包,但是发现打包的过程中,依旧会因为下载依赖导致卡住。由于之前已经了解了 npm install 在该项目的依赖中无法正确运行,故怀疑此处卡住也是因为执行了 npm install 导致的。 有了基本的思路后,剩下就是需要了解Kibana打包的机制,找到对应命令修改成yarn并测试。

在查看Kibana项目结构的时候,可以直接看到根目录的 Gruntfile.js,由此可以看出Kibana项目是使用Grunt来进行构建的。同样,通过 package.json 对于 build 命令的描述中,也可看到 grunt 的影子。 在GruntFile定义中,可以找到项目打包时task的定义,即 tasks/build 目录,在该文件下搜索 npm install 便可定位到 install_npm_deps.js 文件,修改该文件内命令为 yarn ,便可成功下载。

至此,修复了 bug 的 kibana 已经可以正常的调试,打包和发布。

小结

本篇文章主要是记录一次踩坑记。

由于之前一直主要以Java/Golang为主要语言从事后端开发,对于NodeJS相关技术栈了解并不多。但是其实在解决问题上,有很多思路是想通的、不区分语言的。

比如说对于开源项目的源码级别研究,首先肯定需要按照上文说的一样,了解分支管理、项目语言特性、项目依赖管理模式以及打包和构建。通常情况下,开源项目都会有关于运行、调试以及构建的说明文档,可以按照其文档进行了解。在此基础上,由于初次开始,对项目肯定有很多不了解的地方,这也就会出现我们常说的“坑”。“坑”这个东西,可能每个人遇到的都会不一样,但是其实处理起来,是可以有相似的思路的。如同上文中介绍的坑一样,问题出现可能让人摸不到头脑,但是和以往的经验相结合,往往就可以想出一些另辟蹊径的思路。