elasticsearch-head 部署、跨域与分片可视化实战 📅 发布时间:2026/9/18 15:17:24 👁 浏览次数: 1. elasticsearch-head 到底是什么为什么老运维还留着它elasticsearch-head 这个工具我在刚接触 Elasticsearch 那几年几乎是天天开着的。它本质上就是一个跑在浏览器里的 Elasticsearch 集群管理界面纯前端靠调用 ES 暴露出来的 REST 接口干活。你在地址栏敲进那个默认的 9100 端口看到一片密密麻麻的分片方块、节点列表、索引表格那就是它。它不存数据不做计算所有动作都是把 HTTP 请求打到 ES 的 9200 端口上再把返回的 JSON 渲染成人能看懂的样子。很多人第一次听到 es head 插件这个名字会懵以为它像 Kibana 那样是个独立服务或者像当年的 site plugin 一样塞在 ES 进程里。准确的说法是它在 Elasticsearch 1.x 和 2.x 时代确实是作为内置插件安装的命令就是bin/plugin install mobz/elasticsearch-head装完访问http://localhost:9200/_plugin/head/就能用。但 ES 从 5.0 开始砍掉了 site plugin 这套机制head 被迫改造成一个独立的 Node.js Web 应用从此它和 ES 进程彻底分家监听自己的 9100 端口。它能干什么一句话概括查集群状态、看索引和 mapping、翻文档数据、跑任意 REST 请求、以及它最出名的那个分片分布可视化。适合谁来用我的答案是三类人。第一类是刚学 es 教程的新手需要有个东西把抽象的分片、副本、健康度变成看得见的图第二类是运维和中间件同学日常巡检集群、快速确认某个索引的副本是不是掉线了第三类是开发同学写 es 查询语法的时候想找个轻量工具即时验证一下不想为了跑一条 DSL 就打开整个 Kibana。我得先把丑话说在前头head 是个老工具最后一次正经更新停在很多年前它对 ES 7.x 之后的很多新特性支持得并不好对 ES 8.x 默认开启的安全认证更是几乎无感。但这不妨碍它在特定场景下依然是效率最高的那个选择。下面的内容我会把部署、跨域、六个功能页、踩坑排查、安全边界全部拆开讲尽量让你少走我当年走过的弯路。1.1 从内置插件到独立 Web 应用一次被迫的转身这个演变过程值得说清楚因为它直接决定了你今天该怎么装。老版本时代head 打包成 ES 的插件跟着 ES 进程一起启动天然同源根本不存在跨域这回事。ES 5.0 移除了 site plugin 支持之后社区被迫把 head 重构成一个独立的 grunt 项目用 Node.js 起一个静态服务器。这一改问题全来了。首先是端口变了从 9200 的路径变成了独立的 9100。其次是同源策略这道墙立起来了——浏览器里跑着 9100 的页面要往 9200 发请求属于标准的跨域请求ES 不明确放行就会被拦下。再往后是认证ES 6.8 之后 X-Pack 的基础安全能力免费开放7.x 默认还是关的到了 8.x 直接默认全开强制 HTTPS 加账号密码。head 这个项目没有跟上它的界面里压根没有登录框你只能靠往地址栏塞参数或者走反向代理来绕过。所以现在网上那些讲 es head 插件的文章如果你照着老命令去装一定会失败。正确的姿势是把它当成一个普通的 Node.js 应用来部署或者直接用现成的容器镜像。理解了这个背景后面所有关于跨域和认证的折腾你心里就有谱了。1.2 它真正值钱的地方分片分布可视化Kibana 功能比 head 强一百倍为什么还有人留着 head我自己的答案只有一个分片可视化。在 head 的界面里集群的每一个索引、每一个分片、每一个副本都会以一个个小方块的形式铺在页面上方块落在哪个节点下面一眼就能看出来分片有没有倾斜、副本有没有分配到节点上。举个我实际遇到过的场景。有次一个索引的查询特别慢我在 head 里一看这个索引有 5 个主分片但全都集中在同一台节点上另外两台节点一个分片都没有。原因后来查出来是分片分配感知配置没生效节点打标签的规则写错了。这个问题用_cat/shards命令当然也能查但那个文本输出你得一行行比对head 直接给你一张图问题在哪台机器上鼠标扫一眼就清楚了。这种空间感是纯文本接口给不了的。当然它也有代价索引多了、分片多了这个页面会卡成 PPT后面我会专门讲怎么规避。2. 四种部署方式先选对再动手部署 elasticsearch-head 这个事说简单也简单说坑多也是真多。我把能走的路都走了一遍结论是如果你只是本地研究Docker 一把梭如果是要长期挂在测试环境源码方式配合固定 Node 版本更稳如果是个人偶尔用一下浏览器扩展最省事如果公司有统一的前端托管直接把构建产物扔到 nginx 里。先上一张对比表让你有个整体判断。部署方式上手难度稳定性适用场景主要坑点Node.js 源码方式中等中等测试/内网长期使用Node 版本过高会报错grunt 配置要改Docker 容器低高本地研究、临时演示镜像较老需要自己挂配置浏览器扩展极低低个人偶尔查询扩展更新停滞域名限制多静态托管到 nginx中等高团队共用、有运维支持需要自己 build跨域仍需处理2.1 Node.js 源码方式最通吃但坑最多源码方式是我最常用的因为可控。流程大体是这几步git clone https://github.com/mobz/elasticsearch-head.git cd elasticsearch-head npm install npm run start跑起来之后默认监听 9100 端口浏览器打开http://localhost:9100就能看到界面。听起来简单实际上npm install这一步就能劝退一半人。这个项目依赖的 grunt 全家桶和 phantomjs 都是上个时代的产物Node 16 以上的环境里经常报primordials is not defined这类错误根源是旧版 graceful-fs 和高版本 Node 的兼容性问题。我踩过几次之后的稳妥做法是用 nvm 切到 Node 12 或 Node 14 再装。如果你机器上不允许装老版本 Node还有个办法是跳过前端构建只把它当静态服务器用。head 的源码里_site目录在 build 之后就是纯静态文件你可以先在有旧 Node 的机器上npm run build然后把_site拷出来用python -m http.server 9100或者任何静态服务器托管绕开整个 grunt 工具链。这个思路我用了好几年特别省心。还有一个细节npm run start实际上起的是 grunt 的 connect 任务它默认只监听 localhost。如果你想从别的机器访问得改 Gruntfile.js 里 connect 配置的 hostname或者干脆用 nginx 反向代理到 9100。我一般选后者因为顺带还能加上访问控制。提示源码方式不要把node_modules和_site一起提交到版本库这个项目的依赖目录动辄几百兆克隆会非常痛苦。2.2 Docker 方式五分钟起一个如果你只是想快速看一眼界面长什么样Docker 是最省事的docker run -d --name es-head -p 9100:9100 mobz/elasticsearch-head:5起来之后访问http://你的机器IP:9100。注意这个镜像的 tag 是 5对应的就是 head 的 5.x 版本也就是独立 Web 应用时代之后的版本。它能连的 ES 版本跨度挺大我实测从 ES 5.x 到 7.x 基本都能用8.x 因为默认开了 HTTPS 和认证会比较麻烦后面单独说。容器方式有一个认知误区要提前打破很多人以为 head 容器里配了 ES 地址就能连上其实不是。head 是纯前端应用它的连接目标是在浏览器里填的容器本身不存这个配置。所以你在浏览器里访问 head 页面后还得在页面顶部的输入框里填 ES 的地址填完点连接按钮才会真正建立通信。这一点经常让新人以为连接失败是容器的问题其实是他没在页面上填地址。另外容器方式同样要面对跨域问题。浏览器里的 head 页面要访问 ES跨域拦截是浏览器层面的事跟 head 跑在哪没关系。所以我建议在起 head 容器的同时就把 ES 的 CORS 配置改好一步到位。2.3 浏览器扩展与静态托管浏览器扩展这条路我也试过。早期 Chrome 商店里有个叫 ElasticSearch Head 的扩展点开就是个独立的标签页确实方便。但它的问题很现实一是更新早就停了二是新版本 Chrome 对扩展的权限收得越来越紧三是它同样受跨域限制该配的 CORS 一点都省不了。所以现在我不太推荐这条路除非你就是临时看一眼。静态托管反而值得认真考虑尤其是团队共用的场景。做法是先构建出静态文件再把它们放到 nginx 的某个目录下配一个内网域名前面加一层基础的访问认证。这样做的好处是所有人都用一个固定地址不用每人本地起服务版本也统一。缺点是要有人维护构建产物更新比较麻烦。如果你们团队有自己的前端发布流水线这条路是最规范的。3. 跨域与认证让 head 真正连上集群这是 elasticsearch-head 使用过程中绕不过去的一道坎也是我在各种技术群里见到提问最多的一个点。现象很典型页面打开了地址填了点连接转圈然后红色报错控制台里写着Failed to load ... has been blocked by CORS policy。下面我把这个问题彻底讲透。3.1 跨域报错的成因拆解跨域的本质是浏览器的同源策略。head 页面跑在http://localhost:9100ES 跑在http://localhost:9200端口不同浏览器就认为是两个源发起的 XMLHttpRequest 属于跨域请求。浏览器会先发一个 OPTIONS 预检请求问 ES我能不能从 9100 这个源来访问你 如果 ES 的响应里没有带上正确的 CORS 头浏览器就直接把真正的请求拦下了。关键认知这个拦截发生在浏览器里不是 ES 拒绝了你。所以你去看 ES 的日志往往什么都看不到因为请求根本没到应用层。理解这一点很重要它解释了为什么你从服务器上用 curl 访问 9200 一切正常换到浏览器里就不行。还有一个隐藏坑ES 默认不开 CORS。默认配置下http.cors.enabled是 false浏览器发出的所有跨域请求全部被拒。所以你必须主动去改 ES 的配置文件。3.2 Elasticsearch 端的配置怎么写打开 ES 的config/elasticsearch.yml加上这几行http.cors.enabled: true http.cors.allow-origin: * http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE http.cors.allow-headers: X-Requested-With, Content-Type, Content-Length, Authorization改完必须重启 ES 节点热加载不支持这几项。重启之后回到 head 页面填上http://localhost:9200点连接通常就绿了。这里有几个参数值得展开说。allow-origin写星号是放行所有源测试环境图省事可以这么干但生产环境千万别。生产上应该写成具体的源或者用正则形式比如只允许内网的某个网段http.cors.allow-origin: /https?:\/\/10\.0\.0\..*:9100/allow-headers这一行平时不显眼但一旦你的 ES 开了安全认证就必须把它加上尤其是Authorization。因为 head 走的是浏览器请求认证信息要么放在 URL 里要么放在请求头里如果不放行这个头预检请求会被拒。顺便说下allow-credentials。这个参数控制是否允许携带 Cookie。head 本身不用 Cookie 做认证所以一般不用开。而且浏览器有个硬性规定allow-origin是星号的时候allow-credentials必须为 false否则整个 CORS 配置会失效。很多人复制粘贴配置时把这两行一起抄上去结果怎么调都不通根源就在这。3.3 反向代理把 head 和 ES 放到同一个域下如果你被跨域折磨得不耐烦了我强烈推荐反向代理这个方案一劳永逸。核心思路是让浏览器觉得 head 和 ES 是同一个源。做法是用 nginx 起一个站点把 head 的静态文件放在根路径把 ES 的请求代理到/es/这样的子路径下。配置大概长这样server { listen 8080; server_name localhost; location / { root /var/www/es-head; index index.html; } location /es/ { proxy_pass http://127.0.0.1:9200/; proxy_set_header Host $host; } }然后在 head 页面里把连接地址填成http://localhost:8080/es/。因为浏览器看到的是同一个 host 和端口跨域这道墙直接消失了ES 端甚至不用开 CORS。这个方案还有个额外好处认证可以统一在 nginx 层做用auth_basic加个账号密码比在 ES 里配一堆用户角色简单得多。我自己的内网环境就是这么搭的稳定跑了好几年从没因为跨域出过问题。4. 六个页面逐个拆开讲附实操记录head 的界面很朴素顶部一排标签页从左到右依次是概览、索引、数据浏览、复合查询、以及一些辅助页面。界面虽然老但每个页面的功能密度都不低下面我按实际使用频率从高到低来讲。4.1 概览页集群健康度与节点负载怎么读概览页分上下两块。上半部分是集群的整体信息包括集群名称、节点数量、索引数量、分片总数、文档总数、磁盘占用。下半部分是节点列表每个节点显示它的 IP、名称、角色、堆内存使用率、CPU、负载。健康度那个指示灯是最需要会读的。绿色代表所有主分片和副本分片都正常分配黄色代表主分片正常但至少有一个副本没有分配红色代表至少有一个主分片没分配这时候部分数据是不可用的。我见过太多新人看到黄色就慌其实单节点集群黄色是必然的——你只部署了一个节点副本分片没地方放ES 会把它标记为未分配健康度自然就是黄色。这不是故障是正常状态。新版 ES 在概览页会显示unassigned_shards这个计数如果它是黄色的根源数字会跟副本数一致。想彻底消除黄色要么加节点要么把索引的副本数改成 0。生产环境不要为了好看去改副本数副本是容灾的底线。节点列表里我重点关注堆内存使用率。超过 75% 的时候要警惕GC 压力会明显上升。head 这个数字是采集的瞬时值看趋势得刷新几次对比。CPU 那一栏在 head 里显示的是负载值不是百分比别理解错了。4.2 索引页建索引、改副本、加别名索引页是一张表格列出所有索引的名称、健康度、状态、分片数、副本数、文档数、存储大小。右上角有个新建索引的按钮点开可以填索引名、分片数、副本数。这里有个新手容易犯的错分片数建索引后是改不了的。ES 的分片数一旦确定就固定了想改只能重建索引再 reindex。所以建索引这一步要慎重。我的经验是单分片容量控制在 10GB 到 50GB 之间按你预估的数据量反推分片数。比如预计一年 500GB 数据按 30GB 一片算大概 16 到 17 个主分片比较合适。测试环境就没必要纠结1 主 1 副足够了。副本数是可以随时改的页面上直接点那个数字就能编辑。改副本数是个很有用的应急手段集群负载太高的时候临时把副本降到 0能立刻减少写入放大等高峰期过了再调回来副本会自动开始复制。表格里每个索引行前面有个复选框选中之后可以做批量操作比如删除、关闭。关闭索引这个功能挺实用把长期不查的历史索引关掉能省下不少内存和文件句柄但要注意关闭的索引不能读写需要的时候再打开。删除索引这个操作 head 里点一下确认就执行了没有回收站手抖一下数据就没了所以我养成了一个习惯删索引之前先复制一下索引名在终端里确认一遍再点。还有个别名功能在索引页可以给索引加别名。别名这东西在做索引滚动重建的时候特别有用应用层永远查别名后端悄悄把别名指向新索引切换零感知。4.3 数据浏览页查数据、改文档、注意别手抖数据浏览页是我用得第二多的页面。左边选索引中间是一堆字段的勾选框右边显示文档列表。它的执行逻辑是发一个match_all查询把前一批文档拉回来渲染成表格。这个页面有两个实用能力。第一是字段过滤勾选你想看的字段head 会把它拼进_source的过滤参数里只返回这些字段减少传输量。第二是直接编辑文档表格里的值可以点开修改改完提交会走一个_update或者整文档覆盖的请求。这个功能方便调试但风险也大生产环境上改错一个字段可能就是脏数据所以我一般把编辑功能当查看用真要改数据还是走脚本或者 Kibana 的写入接口。还有个必须提醒的点这个页面默认拉取的文档数量不小如果索引里的文档单条很大比如每条几百 KB 的日志或者富文本浏览器内存会被迅速吃满页面直接假死。我在一个存了图片 base64 的索引上翻车过一次标签页卡了三分钟没响应。所以打开大数据索引的时候先把字段过滤配上只勾你需要的那两三个字段。4.4 复合查询页当 REST Client 用复合查询页是 head 里最被低估的功能。它本质是个 HTTP 请求构造器上面选方法中间填路径下面写请求体点提交就把请求打到 ES 上响应以格式化 JSON 的形式显示在下方。支持的语法就是标准的 es 查询语法DSL 怎么写它就怎么传。我平时写复杂的聚合查询都是先在这个页面里调试。它的好处是历史记录存在浏览器本地存储里前几天写过的查询还能翻出来复用比每次都开 Kibana 快。而且它支持任意路径不限于查询接口像_cluster/health、_cat/indices?v、_nodes/stats这些运维接口也能跑等于一个轻量版的接口调试台。用这个页面有两个注意事项。一是请求体必须写合法的 JSON注释、尾随逗号都不行写错了 ES 会返回解析错误报错信息不太友好得自己慢慢找。二是涉及删除和修改的方法比如 DELETE、PUT提交前一定要把路径多读两遍。我见过有人想删一个测试文档路径里少写了个索引名直接对着整个索引发了 DELETE那一下是真的透心凉。4.5 分片可视化它唯一没法被轻易替代的功能回到那个我最看重的功能。这个页面用圆圈表示节点用方块表示分片方块归属于哪个节点就画在哪个节点下方。方块的深浅和边框样式用来区分主分片、副本分片以及分片上的文档量。怎么用它来诊断问题我总结了几条经验。第一看分片是否均匀。正常情况下各节点的方块数量应该差不多如果某个节点明显多出一大截说明分片分配有问题可能是分配感知规则写错了也可能是某个节点之前离线过恢复后没做 rebalance。第二看有没有空心方块或者灰色方块那通常代表未分配的分片配合概览页的健康度一起看能快速定位到是哪几个索引的副本掉了。第三看方块在节点间移动的过程做 reindex 或者扩容的时候能直观看到分片在迁移迁移期间方块会同时出现在两个节点上或者闪烁。这个可视化唯一的问题就是性能。当你的集群有几十个节点、上千个分片的时候这个页面渲染会非常吃力浏览器标签页的内存占用能飙到几个 G甚至直接崩溃。我的做法是分片多的集群只在大屏上开这一个页面不要和其他标签页共享内存看完就关。日常巡检还是优先用_cat/shards命令只在需要看空间分布的时候才开这个图。5. 踩坑实录与问题速查用 head 这么多年踩过的坑能写一小本。这一节我把最常见的问题整理出来按现象、排查、解决三段式的思路给你遇到问题可以直接对照。5.1 连不上、一直转圈、白屏连不上是最常见的一类具体表现有好几种原因也各不相同。如果页面能打开但连不上 ES先看浏览器控制台。有 CORS 相关报错就是配置问题回到第 3 节把 CORS 配好。如果控制台没有报错请求一直是 pending 状态那大概率是网络不通或者端口没开用telnet 你的ES地址 9200验证一下。如果连的是 HTTPS 的 ES还要注意自签证书的问题浏览器会拦下来需要先在浏览器里单独访问一次 9200 地址手动信任证书再回 head 页面重连。如果 head 页面本身就是白屏打不开那问题在 head 自己。可能是静态文件没构建成功也可能是服务器进程挂了。看一下启动日志检查_site目录是否存在、文件是否完整。Docker 方式的话用docker logs es-head看容器日志。5.2 集群 yellow/red 在 head 上长什么样前面提过黄色健康度的含义这里补充红色怎么排查。红色意味着有主分片未分配直接在分片可视化页面找那些灰色的、没有归属的方块记下它们的索引名和分片号然后去跑curl -s localhost:9200/_cluster/allocation/explain?pretty -H Content-Type: application/json -d { index: 问题索引名, shard: 0, primary: true } 这个接口会告诉你分片为什么分配不出去常见原因是磁盘水位超限、节点数量不足、或者分片分配规则冲突。磁盘水位这个坑特别隐蔽ES 默认在磁盘使用率超过 85% 的时候停止分配分片超过 90% 会尝试把分片迁走。所以集群突然变红先去看各节点的磁盘使用率用df -h比在 head 里看更快。5.3 数据浏览页把浏览器搞崩了这个问题我在 4.3 节提过这里给具体的解决办法。第一打开索引前先勾选字段过滤只选必要字段。第二如果在地址栏里能控制返回条数就控制一下很多情况下 head 的 URL 后面可以追加 size 参数。第三不要在数据浏览页停留太久看完就切走浏览器对长时间挂着的重页面回收不及时。还有一个连带问题head 频繁查询大索引会导致 ES 端产生大量慢查询如果你发现 head 一打开集群负载就上去了那基本就是它在偷偷拉全量数据。这种情况建议限制 head 的使用或者只让它连只读的视图。5.4 常见问题速查表现象可能原因处理方式页面报 CORS 错误ES 未开启 CORS 或头配置不全修改 elasticsearch.yml 后重启请求一直 pending网络不通、端口未开、防火墙拦截telnet 验证连通性检查安全组HTTPS 连接失败自签证书未被信任浏览器先单独访问信任证书页面白屏静态文件缺失、进程挂了检查 _site 目录与服务日志健康度一直黄色单节点集群副本无处分配加节点或临时将副本数调为 0健康度红色主分片未分配、磁盘水位超限用 allocation explain 接口定位数据浏览页卡死文档体积大、拉取条数多启用字段过滤控制返回规模分片图渲染崩浏览器分片数量太多只在需要时打开用完即关6. 使用边界、安全红线与替代工具选型写到这里功能层面基本讲全了。但我觉得比怎么用更重要的是什么时候不该用这部分经验往往是用事故换来的。6.1 为什么绝对不要把 9100 端口放公网elasticsearch-head 本身没有任何认证机制。它就是一个静态页面谁访问到 9100 端口谁就能拿到完整的操作界面。再配合上你为了让它工作而放开的 CORS等于给所有人开了一扇直通集群的门。这意味着什么任何扫到你 9100 端口的人可以通过 head 的复合查询页执行任意 REST 请求——删索引、删文档、改 mapping、甚至关机节点。这不是危言耸听历史上因为把管理界面暴露到公网导致数据被清空的事件不止一起。所以我的底线规则是head 只在内网或者本机使用绝不暴露到公网。内网使用也要加一层访问控制最简单的是 nginx 的 auth_basic或者用防火墙限制来源 IP 段。如果你需要一个能远程访问、又有权限体系的管理后台那就别用 head去看 Kibana 或者 Cerebro。注意CORS 里的allow-origin: *加上无认证的 head是风险最高的组合。即使只是测试环境也建议把 origin 收窄到具体地址。6.2 Cerebro、Kibana、ElasticVue 横向对比head 不是唯一的选择这年头同类工具有好几个我按实际使用体验给你排个序。工具定位认证支持分片可视化适合场景elasticsearch-head轻量 Web 管理界面基本没有有且是亮点本地调试、内网巡检Cerebrohead 的精神续作支持基础认证有性能更好内网团队共用Kibana Dev Tools官方控制台完整支持无日常查询、生产运维ElasticVue浏览器扩展支持一般个人开发者本地用Cerebro 是 Scala 写的部署方式是单个 jar 包跑起来也简单界面比 head 现代不少最关键的是它支持配置认证适合放在内网给团队共用。Kibana 的 Dev Tools 是我日常工作里用得最多的查询体验一流还有自动补全和历史管理唯一的短板就是没有分片可视化。ElasticVue 是个 Chrome 扩展装完点开就能用适合个人开发者但功能相对薄。我的建议是组合使用Kibana Dev Tools 做日常查询head 或 Cerebro 做集群结构和分片排查。这两个场景的需求差异挺大指望一个工具全包不太现实。6.3 我现在怎么用它说点实在的。我现在的工作流是这样本地开发环境用 Docker 起一个 head连本地的 ES用来快速看数据。测试环境和生产环境head 装在内网的一台跳板机上通过 nginx 加了基础认证只有我和另外两个同事有账号。生产集群规模大的时候我基本不开分片可视化只用它的索引页和概览页做巡检因为分片太多图会卡。另外强烈建议在做 es 存储空间优化或者索引重建这类操作之前先打开 head 把当前的分片分布截图存一份。重建过程中一旦出问题有这份对照图能快速判断是哪个环节把分片搞歪了。还有个小习惯head 的复合查询页历史记录是存在浏览器本地的换机器或者清缓存就没了。我遇到特别有价值的查询语句会顺手复制到自己的笔记里攒久了就是一个自己的 es 查询语法手册比翻文档快得多。这套东西说到底就是个工具它不会让你的集群变快也不会替你做决策它的价值在于把那些藏在 API 后面的状态变成你一眼能看懂的画面。用久了你会发现判断一个 ES 集群有没有问题很多时候靠的就是那一眼。我现在打开 head 的第一件事还是看分片图看到方块整整齐齐分在几台节点上心里就踏实了。