ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

CentOS 7 离线部署 Elasticsearch 7.x 实战与避坑指南

CentOS 7 离线部署 Elasticsearch 7.x 实战与避坑指南 1. 为什么离线装 ES 比在线装更考验人在完全断网或者内网隔离的 CentOS 7 机器上部署 Elasticsearch跟平时yum install一把梭完全是两码事。在线装的时候依赖缺了直接补版本不对直接换网络慢就挂个代理重试而离线环境里你手里只有一台不能出网的机器和一个 U 盘任何一个依赖没提前备好整个安装就得推倒重来。我前后在三个不同规模的内网环境里做过 ES 的离线部署踩过的坑从 JDK 版本不匹配到 systemd 启动超时几乎把能遇到的都遇了一遍。这篇内容面向的是需要在无外网 CentOS 7 服务器上部署 Elasticsearch 的运维和开发人员。我会把整个流程拆成准备什么、为什么这么准备、怎么装、装完怎么验证、出问题怎么查这几条线重点讲清楚那些在线安装时根本不会暴露、但离线环境下会要命的细节。读完你至少能拿到一套可以直接照着走的操作路径以及一份我实际踩坑后总结的排查清单。需要先明确一个前提Elasticsearch 从 7.x 开始自带了 JDK这给离线部署省了大事。但如果你选的是 6.x 或者更早的版本就得自己准备 JDK而且版本卡得很死。下面我以7.x 系列为主线来讲同时在关键位置标注 6.x 的差异方便你对号入座。2. 离线包到底该准备哪些东西2.1 主程序包的选择tar.gz 还是 rpmElasticsearch 官方提供两种离线包tar.gz和rpm。很多人第一反应是选 rpm觉得用yum localinstall更正规。但在离线场景下我强烈建议用tar.gz原因有三个。第一rpm 安装会自动创建elasticsearch用户、注册 systemd 服务、设置一堆默认路径看起来省事但它对目录权限和 SELinux 的假设很强一旦你的环境有定制反而更难改。第二rpm 的卸载和重装会牵扯到配置文件残留调试阶段反复装卸很烦。第三tar.gz 解压即用所有路径你自己说了算出问题直接删目录重来干净利落。tar.gz 包从哪来在一台能出网的同版本 CentOS 7 机器上下载即可注意要选对架构。命令很简单# 在有网的机器上执行下载 7.17.x 版本7.x 最后一个稳定系列 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.9-linux-x86_64.tar.gz # 同时下载校验文件离线环境也要验证完整性 wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.17.9-linux-x86_64.tar.gz.sha512下载完务必做一次校验U 盘拷贝过程中文件损坏是常有的事等到解压报错再回头查就浪费时间了sha512sum -c elasticsearch-7.17.9-linux-x86_64.tar.gz.sha5122.2 那些容易被忽略的依赖项ES 7.x 自带 JDK所以不用单独装 Java这是最大的便利。但有几个系统层面的依赖在线装时 yum 会自动带上离线时就得自己确认。首先是libcurl和openssl相关的库。ES 启动时会加载本地库做安全通信如果系统里缺libcurl.so或者版本太老启动日志里会出现Unable to load JNA之类的报错。CentOS 7 最小化安装通常自带但如果你用的是精简过的镜像就得检查rpm -qa | grep -E libcurl|openssl其次是ncnetcat和lsof这两个不是 ES 运行必需的但排查端口占用和网络连通性时没有它们会非常难受。离线环境建议提前把net-tools、lsof、nc这几个包的 rpm 一起备好用yum localinstall装上。还有一个隐藏项文件句柄数和内存映射数。ES 对这两个系统参数有硬性要求在线装时很多人靠ulimit -n临时改但离线生产环境必须写进配置文件否则重启就失效。这个后面单独讲。2.3 版本匹配的坑别让 JDK 拖后腿虽然 7.x 自带 JDK但如果你因为某些原因必须用 6.x那 JDK 版本就是头号大坑。ES 6.x 要求 JDK 8而且对具体小版本有要求太新的 JDK 8u 版本反而可能因为安全策略变化导致启动失败。我遇到过用 JDK 8u302 启动 ES 6.8 报java.lang.IllegalArgumentException的情况换成 8u252 就正常了。所以离线准备时JDK 的 tar.gz 也要一并下载并且在目标机器上先解压测试确认java -version输出正常再继续。别等到 ES 装到一半才发现 JDK 有问题。组件7.x 是否需要单独准备6.x 是否需要单独准备备注JDK否自带是JDK 86.x 对 JDK 小版本敏感libcurl通常自带通常自带精简镜像需检查lsof/nc建议准备建议准备排查用非运行必需systemd系统自带系统自带CentOS 7 默认有3. 系统层面的前置配置怎么调3.1 内核参数的修改逻辑ES 启动时会检查两个内核参数vm.max_map_count和文件句柄数。前者默认值是 65530而 ES 要求至少 262144。这个参数控制的是单个进程能拥有的内存映射区域数量ES 的 Lucene 底层大量使用 mmap 来读写索引文件值太小会直接导致启动失败报错信息是max virtual memory areas vm.max_map_count [65530] is too low。修改方式是在/etc/sysctl.conf里追加一行然后sysctl -p生效echo vm.max_map_count262144 /etc/sysctl.conf sysctl -p文件句柄数则要改/etc/security/limits.conf同时注意 CentOS 7 的 systemd 服务不受 limits.conf 完全控制如果后面用 systemd 管理 ES还得在 service 文件里单独声明LimitNOFILE。这一点很多人会漏导致明明改了 limits.confES 启动后ulimit -n还是 4096。# /etc/security/limits.conf 追加 * soft nofile 65536 * hard nofile 65536 * soft nproc 4096 * hard nproc 4096注意*通配符对 root 用户不生效如果你打算用 root 启动测试生产绝对不建议得单独写root soft nofile 65536。3.2 专用用户与目录权限ES 从 5.x 开始就禁止用 root 直接启动这是硬性限制绕不过去。所以离线环境里第一件事是建一个专用用户groupadd es useradd -g es -m -s /bin/bash es然后把解压后的 ES 目录整个chown给这个用户。这里有个细节如果你把 ES 放在/opt或/usr/local下父目录的权限也要确认否则 es 用户可能连目录都进不去。我习惯把 ES 放在/data/elasticsearch这种独立数据盘路径下既方便管理也避免和系统目录混在一起。mkdir -p /data tar -zxvf elasticsearch-7.17.9-linux-x86_64.tar.gz -C /data mv /data/elasticsearch-7.17.9 /data/elasticsearch chown -R es:es /data/elasticsearch3.3 关闭 swap 的必要性说明ES 官方明确建议关闭 swap原因是当 JVM 堆内存被换出到磁盘时垃圾回收的停顿时间会急剧增加导致节点响应变慢甚至被集群踢出。离线环境里这个操作更要提前做因为一旦 ES 跑起来再关 swap可能触发一次长时间的 GC。临时关闭用swapoff -a永久关闭要注释掉/etc/fstab里的 swap 行。改完用free -h确认 swap 那一行全是 0。swapoff -a # 编辑 /etc/fstab注释掉包含 swap 的行 sed -i /swap/s/^/#/ /etc/fstab4. 配置文件里必须改对的几个参数4.1 elasticsearch.yml 的最小改动集解压出来的config/elasticsearch.yml默认全是注释很多人直接启动发现只能本机访问或者集群名不对。离线单机部署至少要改这几项cluster.name: es-offline-cluster node.name: node-1 path.data: /data/elasticsearch/data path.logs: /data/elasticsearch/logs network.host: 0.0.0.0 http.port: 9200 discovery.seed_hosts: [127.0.0.1] cluster.initial_master_nodes: [node-1]这里重点说network.host。默认是localhost只监听回环地址外部访问不了。改成0.0.0.0后 ES 会进入生产模式此时它会强制检查一系列引导配置bootstrap checks如果前面说的vm.max_map_count没改启动会直接失败。所以顺序很重要先改内核参数再改 network.host。cluster.initial_master_nodes是 7.x 引入的用于首次启动时选举主节点。单机部署写自己的 node.name 即可。这个配置只在集群第一次启动时生效后续重启不需要改但留着也没关系。4.2 jvm.options 的堆内存设置ES 默认的 JVM 堆是 1GB对于稍微有点数据量的场景都不够。改堆内存要编辑config/jvm.options找到-Xms和-Xmx两行。原则是两者设成一样大避免运行期动态调整带来的性能波动不超过物理内存的 50%且不超过 31GB超过会失去指针压缩优化。# 假设机器有 16GB 内存设 8GB 堆 -Xms8g -Xmx8g离线环境里经常遇到机器内存很大但堆设得很小的情况白白浪费资源。我的经验是如果这台机器只跑 ES堆可以给到物理内存的 50%如果还跑别的服务给 30% 到 40% 比较稳妥。剩下的内存 ES 会用来做文件系统缓存这对搜索性能同样关键所以不要把内存全给堆。4.3 一个容易翻车的细节路径里的空格和中文path.data和path.logs的路径里绝对不能有空格和中文。ES 启动脚本对路径的处理不够健壮带空格的路径会导致 JVM 参数解析错乱报错信息还特别隐晦往往只显示Could not find or load main class。离线部署时目录名尽量用纯英文加下划线别图省事用中文。5. 启动方式的选择与 systemd 集成5.1 前台启动先验证别急着上 systemd第一次启动强烈建议用前台方式直接su - es然后跑bin/elasticsearch。这样所有日志直接打在终端上有任何报错立刻能看到。如果一上来就配 systemd启动失败后还得journalctl翻日志效率低很多。su - es cd /data/elasticsearch ./bin/elasticsearch看到类似publish_address {127.0.0.1:9200}和started的日志说明启动成功。此时另开一个终端curl localhost:9200应该返回一段包含 cluster_name 和 version 的 JSON。5.2 写一个靠谱的 systemd unit 文件前台验证通过后再配 systemd 做后台常驻。在/etc/systemd/system/下建elasticsearch.service[Unit] DescriptionElasticsearch Afternetwork.target [Service] Typesimple Useres Groupes EnvironmentES_HOME/data/elasticsearch EnvironmentES_PATH_CONF/data/elasticsearch/config EnvironmentJAVA_HOME/data/elasticsearch/jdk WorkingDirectory/data/elasticsearch ExecStart/data/elasticsearch/bin/elasticsearch LimitNOFILE65536 LimitNPROC4096 Restarton-failure RestartSec10 [Install] WantedBymulti-user.target几个关键点LimitNOFILE必须写否则 limits.conf 对 systemd 服务不生效Restarton-failure让 ES 意外退出后自动拉起JAVA_HOME指向自带的 JDK避免系统里其他 Java 干扰。配好后systemctl daemon-reload systemctl enable elasticsearch systemctl start elasticsearch systemctl status elasticsearch5.3 启动超时的处理systemd 默认给服务的启动超时是 90 秒。ES 在数据量大或者磁盘慢的机器上首次启动可能超过这个时间导致 systemd 判定失败并杀掉进程。如果你在status里看到start operation timed out就在[Service]段加一行TimeoutStartSec300给足启动时间。6. 装完之后怎么确认真的能用6.1 基础连通性检查curl localhost:9200返回 JSON 只是第一步。接着要确认集群健康状态curl -s localhost:9200/_cluster/health?pretty单机部署下status应该是greennumber_of_nodes是 1。如果是yellow说明有副本分片没分配单节点环境下这是正常的因为副本不能和主分片在同一节点。可以在索引模板里把副本数设为 0或者接受 yellow 状态。6.2 写入和查询的冒烟测试光看健康状态不够实际写一条数据再查出来才能确认索引功能正常# 写入 curl -X POST localhost:9200/test-index/_doc/1 -H Content-Type: application/json -d {name:offline-test,value:100} # 查询 curl -s localhost:9200/test-index/_search?pretty如果写入报cluster_block_exception说明磁盘水位触发了只读锁。离线环境里磁盘空间往往比较紧张ES 默认磁盘使用超过 95% 就会把所有索引设为只读。检查df -h确认空间必要时清理或者调整水位线。6.3 开机自启的验证systemctl enable只是设置了软链接真正验证要重启机器reboot # 重启后 systemctl status elasticsearch curl localhost:9200这一步在离线环境特别重要因为很多内网机器不允许随便重启等到真正需要重启维护时才发现自启没配好那就被动了。7. 离线环境特有的排错思路7.1 日志是第一手线索ES 的日志在logs/目录下主日志是cluster.name.log。启动失败时先看这个文件的最后几十行。常见的几类报错和处理方式我整理成表报错关键词根本原因处理方式max_map_count too low内核参数未改改 sysctl.conf 并生效max file descriptors too low句柄数不足改 limits.conf systemd LimitNOFILEcan not run elasticsearch as root用 root 启动切换到 es 用户failed to obtain node locks数据目录被占用确认没有残留进程检查 path.datajava.lang.IllegalArgumentExceptionJDK 版本不匹配6.x 换 JDK 小版本Connection refused服务没起来或端口不对查进程和端口监听7.2 端口占用与防火墙离线环境里 9200 端口被占用的概率不高但 9300集群通信端口有时会和别的服务冲突。用ss -tlnp | grep 9200确认监听情况。另外 CentOS 7 默认开 firewalld如果外部要访问得放行端口firewall-cmd --permanent --add-port9200/tcp firewall-cmd --permanent --add-port9300/tcp firewall-cmd --reload如果内网有安全组或者硬件防火墙这一步也要同步配置别只改了系统防火墙就以为通了。7.3 磁盘空间和 inode 的隐性坑ES 对磁盘空间敏感但很多人只看df -h的容量忽略了 inode。ES 会创建大量小文件inode 耗尽时同样无法写入而df -h看起来空间还很充裕。用df -i检查 inode 使用率超过 80% 就要警惕。另外path.data所在分区的挂载参数如果带了noexecES 启动时加载本地库会失败。检查/etc/fstab里对应分区的挂载选项确保没有noexec。8. 我踩过的几个真实坑和应对第一个坑是解压后直接启动忘了改目录属主。ES 启动时报AccessDeniedException日志指向 data 目录。原因是 tar 包解压后属主是 rootes 用户没有写权限。解决就是chown -R es:es但要注意如果 data 目录已经生成了文件得先清空再改属主否则残留文件还是 root 的。第二个坑是systemd 启动后ulimit -n还是 4096。查了半天发现 limits.conf 改了但没在 service 文件里写LimitNOFILE。CentOS 7 的 systemd 服务不继承 login shell 的 limits 设置这是 systemd 的设计不是 bug。加上LimitNOFILE65536后解决。第三个坑是离线机器时间不同步导致集群无法组建。虽然单机部署影响不大但如果后续要扩成多节点节点间时间差超过一定阈值会导致握手失败。离线环境没有 NTP建议手动校准时间或者在内网搭一个时间源。第四个坑是用 scp 传大包时中断文件不完整但没校验。解压时报gzip: stdin: unexpected end of file重新传一遍才好。所以前面强调的 sha512 校验一定要做别省这一步。9. 后续扩展时可以怎么调整单机跑通之后如果数据量涨上来要扩成集群离线环境的扩展思路和在线差不多但有几个点要提前想好。一是新节点的 ES 包和版本必须和现有节点完全一致离线环境里版本管理靠人工容易搞混建议在包名里带上版本号并归档。二是discovery.seed_hosts要改成所有 master 候选节点的地址列表cluster.initial_master_nodes只在首次组建集群时用扩节点时不要带这个配置。三是节点间通信端口 9300 必须互通离线内网里这个通常没问题但安全组策略要确认。另外如果后续要装 Kibana 或者 Logstash 做配套它们的离线安装思路和 ES 一样提前下好 tar.gz、确认依赖、配好 systemd。Kibana 的版本必须和 ES 严格一致小版本号都不能差这是硬性要求离线准备时别下错。我个人在实际操作中的体会是离线部署最花时间的从来不是安装本身而是前期把依赖和参数理清楚。在线装的时候这些都被 yum 和网络掩盖了离线环境把它们全部暴露出来。把上面这些点过一遍基本能覆盖 90% 的翻车场景。剩下那 10%就得靠看日志和一点点耐心了。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进