查看: 830|回复: 3

Ansible批量部署Node Exporter实战

[复制链接]
发表于 昨天 14:00 | 显示全部楼层 |阅读模式
主机数量少时,逐台登录安装 Node Exporter 还能接受;主机扩展到几十台后,手动下载、创建用户、编写 systemd 服务、检查状态,容易出现版本不一致、路径不同和漏配。Ansible 基于 SSH 和无代理方式,把安装步骤写成 Inventory、变量和 Playbook,重复执行时具备幂等性。本文按原文环境,在 Ubuntu 控制机安装 Ansible,准备 systemd 模板,编写 Playbook 完成下载、解压、建用户、启动服务和开机自启,并说明异地 SSH 映射与 Prometheus 验证边界。

一、控制机安装 Ansible 并准备 Inventory
原文使用 Ubuntu 和 APT。先更新系统并安装 Ansible,然后验证版本:
  1. sudo apt update
  2. sudo apt upgrade -y
  3. apt install -y ansible
  4. ansible --version
复制代码
原文发现 /etc/ansible 下没有现成配置文件,于是手动创建目录、hosts 和 ansible.cfg。下面的配置用于本地连通性验证:
  1. mkdir -p /etc/ansible
  2. cat > /etc/ansible/hosts <<EOF
  3. [local]
  4. localhost ansible_connection=local
  5. EOF
  6. cat > /etc/ansible/ansible.cfg <<EOF
  7. [defaults]
  8. inventory = /etc/ansible/hosts
  9. host_key_checking = False
  10. remote_user = root
  11. stdout_callback = yaml
  12. EOF
  13. ansible localhost -m ping
复制代码
这里的 host_key_checking = False 和 remote_user = root 适合实验环境,但不适合作为长期默认配置。Inventory 也不建议长期保存 root 明文密码。

二、修正 systemd 模板中的段名和二进制路径
原文模板里 [Service 少了右方括号,同时 ExecStart 写成了 {{ install_dir }}/node_exporter,但 Playbook 会把解压目录重命名为 {{ install_dir }}/node_exporter,实际二进制位于 {{ install_dir }}/node_exporter/node_exporter。按原文部署逻辑,模板应修正为:
  1. [Unit]
  2. Description=Node Exporter
  3. After=network.target
  4. [Service]
  5. User=node_exporter
  6. Group=node_exporter
  7. Type=simple
  8. ExecStart={{ install_dir }}/node_exporter/node_exporter --collector.systemd --collector.processes
  9. Restart=on-failure
  10. RestartSec=5
  11. [Install]
  12. WantedBy=multi-user.target
复制代码
模板保留 --collector.systemd 和 --collector.processes 参数,服务用户为 node_exporter。若目标系统没有同名组,需要同时确认组配置,否则 Group=node_exporter 可能启动失败。

三、Playbook 任务拆解与执行
Playbook 的关键变量是 node_exporter_version、node_exporter_url 和 install_dir。原文手动步骤下载 v1.10.2,而 Playbook 变量写的是 1.8.2,下载地址和目录名都依赖版本号,执行前必须统一。下面示例沿用原文 Playbook 中的 1.8.2,并把 URL、目录和 systemd 模板串起来:
  1. ---
  2. - name: 安装node_exporter
  3.   hosts: test
  4.   become: yes
  5.   vars:
  6.     node_exporter_version: '1.8.2'
  7.     node_exporter_url: 'https://ghproxy.net/https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gz'
  8.     install_dir: '/shan'
  9.   tasks:
  10.     - name: 创建存储目录
  11.       file:
  12.         path: '{{ install_dir }}'
  13.         state: directory
  14.         mode: '0755'
  15.     - name: 下载node_exporter
  16.       get_url:
  17.         url: '{{ node_exporter_url }}'
  18.         dest: '{{ install_dir }}/node_exporter.tar.gz'
  19.         mode: '0644'
  20.         timeout: 30
  21.       retries: 3
  22.       delay: 10
  23.     - name: 解压node_exporter
  24.       unarchive:
  25.         src: '{{ install_dir }}/node_exporter.tar.gz'
  26.         dest: '{{ install_dir }}'
  27.         remote_src: yes
  28.     - name: 清理压缩包
  29.       file:
  30.         path: '{{ install_dir }}/node_exporter.tar.gz'
  31.         state: absent
  32.     - name: 重命名解压目录为 node_exporter
  33.       command: mv '{{ install_dir }}/node_exporter-{{ node_exporter_version }}.linux-amd64' '{{ install_dir }}/node_exporter'
  34.       args:
  35.         creates: '{{ install_dir }}/node_exporter'
  36.     - name: 删除旧目录
  37.       file:
  38.         path: '{{ install_dir }}/node_exporter-{{ node_exporter_version }}.linux-amd64'
  39.         state: absent
  40.     - name: 创建专用用户
  41.       user:
  42.         name: node_exporter
  43.         system: yes
  44.         shell: /sbin/nologin
  45.         createhome: no
  46.     - name: 配置systemd服务
  47.       template:
  48.         src: node_exporter.service.j2
  49.         dest: /etc/systemd/system/node_exporter.service
  50.         owner: root
  51.         group: root
  52.         mode: '0644'
  53.     - name: 重载systemd配置
  54.       systemd:
  55.         daemon_reload: yes
  56.     - name: 启动并启用node_exporter服务
  57.       systemd:
  58.         name: node_exporter
  59.         enabled: yes
  60.         state: started
复制代码
Inventory 中先放入目标主机,原文示例为:
  1. [test]
  2. ip ansible_ssh_user=用户名 ansible_ssh_pass=密码
复制代码
进入 Playbook 目录执行:
  1. cd /etc/ansible
  2. ansible-playbook node_exporter.yml
复制代码
再到目标主机检查:
  1. systemctl status node_exporter
复制代码
部署成功只代表服务已安装并启动,不代表 Prometheus 已经开始监控。还需要确认 Node Exporter 实际监听的 9100 端口可被 Prometheus 访问,把对应地址加入 Prometheus 的 scrape_configs,并在 Targets 页面确认目标状态为 UP。

四、异地主机通过 cpolar 映射 SSH
如果目标主机不在同一局域网,原文用 cpolar 把目标机 22 端口映射到公网 TCP 地址,让 Ansible 通过公网地址和端口建立 SSH 连接。安装并检查服务:
  1. sudo curl https://get.cpolar.sh | sh
  2. sudo systemctl status cpolar
复制代码
浏览器访问 http://目标IP:9200,登录 cpolar 管理界面创建隧道。原文示例隧道名称为 ssh,协议为 tcp,本地地址为 22,端口类型为随机临时 TCP,地区为 China Top。创建后会得到类似 tcp.cpolar.top 的域名和随机端口,Inventory 可写成:
  1. [dbservers]
  2. 2.tcp.cpolar.top ansible_user=root ansible_port=16198 ansible_password=***
复制代码
随后执行 ansible-playbook node_exporter.yml。临时端口会变化,原文进一步保留固定 TCP 地址,例如 China VIP 下的 15.tcp.cpolar.top:13633,再把固定地址填入隧道配置并更新 Inventory,避免端口变化导致连接信息失效。公网映射 SSH 会扩大暴露面,长期使用应改用普通运维账号、SSH 密钥、become 提权和 Ansible Vault,并限制来源地址。

五、批量执行前的检查清单
正式批量执行前,先在一台测试主机验证 systemd 文件、二进制路径和 /metrics 页面,再逐步扩大主机组。重点检查:systemd 模板的 [Service] 段和 ExecStart 路径已修正;Node Exporter 版本在手动命令、Playbook 变量、下载 URL 和目录名中保持一致;Inventory 不长期保存 root 明文密码;host_key_checking = False 只用于测试;ARM 等架构要换对应安装包;下载文件增加版本固定和校验;最后在 Prometheus 的 scrape_configs 和 Targets 页面确认 9100 端口监控状态。

按上述流程,Ansible 控制机可以根据 Inventory 向目标 Linux 主机统一下发 Node Exporter,完成目录创建、下载、解压、用户创建、systemd 服务生成、启动和开机自启。cpolar 解决的是异地 SSH 部署链路,监控是否生效仍要回到 Prometheus 抓取配置和目标状态上确认。
回复

使用道具 举报

发表于 昨天 19:00 | 显示全部楼层

Re: Ansible批量部署Node Exporter实战

这篇把几个容易踩的坑都点出来了,尤其是模板里 [Service 缺右方括号、以及 ExecStart 少一层 node_exporter 目录这两处,实际报错信息很模糊,新手很容易卡半天。 顺着往下补几点实践里的做法: 版本号建议只留一个来源。既然下载地址、解压目录名、重命名路径都依赖 node_exporter_version,就别在文档或手动步骤里再写另一个版本,最好在 tasks 开头加个 assert 校验变量格式,避免哪天改了一半。install_dir 也统一走变量,别在模板和任务里各写各的。 重命名那步用 command 加 creates 能挡住重复执行,但本质不是幂等操作。更省事的做法是 unarchive 时加 extra_opts 带 --strip-components=1 直接解到目标目录,把 mv 和清理旧目录两步都省掉,目录结构也更可控。 下载建议补上 checksum 校验,走了代理的情况下文件完整性更值得确认一下。另外 get_url 失败重试已经有了,可以顺手加上 force 或 backup 的考量。 用户和组那部分正文里没展开,建议明确 group 先建、user 用 system yes 加 shell /sbin/nologin、create_home no,否则 Group=node_exporter 找不到组,服务起不来还只报个 st
回复 支持 反对

使用道具 举报

发表于 昨天 19:10 | 显示全部楼层

Re: Ansible批量部署Node Exporter实战

这篇实战梳理得比较完整,尤其是把 systemd 模板里 [Service 少右方括号、二进制实际路径应为 install_dir/node_exporter/node_exporter、以及手动步骤和 Playbook 版本变量不一致这几个坑点出来,很有参考价值。 实际落地时我会重点再补几处:先把 node_exporter_version、下载目录名和模板路径统一,最好在 Playbook 开头加个变量校验;systemd 模板里 User 和 Group 都写成 node_exporter 的话,Playbook 里应明确创建用户和组,否则目标机没有同名组时服务可能起不来;重命名目录用 command 加 creates 有初步幂等性,但更稳妥的是先判断目录状态,避免重复执行时逻辑含糊。host_key_checking = False 和 remote_user = root 确实只适合实验环境,生产上建议换成普通用户加 sudo、SSH 密钥和 known_hosts 管理,Inventory 里也不要长期放明文密码。 另外,首帖任务片段主要到解压和重命名,服务模板下发、daemon_reload、enable/start 以及最终状态检查最好也串进 Playbook,用 template 加 systemd 模块配合 handler 会更清晰。最后加一个本机端口或 sy
回复 支持 反对

使用道具 举报

发表于 昨天 19:20 | 显示全部楼层

Re: Ansible批量部署Node Exporter实战

楼主这篇梳理得挺细的,尤其是把 systemd 模板里 `[Service` 少右括号、`ExecStart` 路径多一层目录这两个坑单独拎出来讲,很多人第一次照着跑就是卡在这种地方。版本号那个不一致也点得很关键,下载地址和目录名都吃版本号,手动步骤和变量各写一个版本,跑起来必然对不上。 补充几个我实际踩过的点,供交流: 一是 Playbook 里最好把创建用户和组也写进去,用 `user` 模块指定 `name=node_exporter`、`system=yes`、`shell=/usr/sbin/nologin`、`create_home=no`,这样模板里的 `User` 和 `Group` 才有依据,不然换一台干净机器启动就可能直接失败。楼主已经提醒了组配置的风险,补上这个任务会更省事。 二是用 `command: mv` 重命名虽然加了 `creates` 兜底,但重复执行时如果目标目录已存在、源目录也在,会静默跳过,留下两个目录。更稳的做法是解压时直接用 `extra_opts` 配合 `--strip-components`,或者把 `install_dir` 下的版本目录作为软链指向,后续升级只换软链,模板路径不用动。 三是服务启停和开机自启建议用 `systemd` 模块(`daemon_reload: yes`、`enabled: yes`、`state: s
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-10-27 16:31 , Processed in 0.028663 second(s), 29 queries , Gzip On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部