MySQL 监控总在重复配置?用 Shell 自动部署 mysqld_exporter,再让 Prometheus 远程抓取

MySQL 监控总在重复配置?用 Shell 自动部署 mysqld_exporter,再让 Prometheus 远程抓取

前言

第一次部署 mysqld_exporter 时,下载二进制、建 MySQL 监控账号、写连接配置、补 systemd 服务,看起来都不难;真正烦的是机器一多,这些步骤就会不停重复。更麻烦的是,少一个权限、路径写错一处、服务忘了开机自启,最后往往不是"安装失败"这么直接,而是 Prometheus 抓不到指标后再倒回来排查。我更愿意把这类固定动作写进脚本,让重复部署尽量变成一套可复用流程,但同时也会保留对账号、密码、端口和权限的检查。尤其监控组件一旦开始批量铺开,真正难维护的往往不是安装本身,而是不同机器之间版本不一致、配置不一致、凭据散落和后续无法追溯,这些问题比"多敲几条命令"更麻烦。

这次我在 CentOS 7 上使用 Shell 脚本部署 mysqld_exporter v0.18.0:脚本自动安装依赖、下载程序到 /app/mysqld_exporter、创建 prometheus 系统用户和 MySQL 监控用户、生成 localhost_db.cnf、注册 systemd,并让服务监听 9105。随后先让 Prometheus 在局域网抓取 192.168.42.146:9105,再安装 cpolar,把 9105 Web 指标入口映射到公网,验证随机地址抓取,最后配置固定二级子域名 mysqll。我更看重"脚本到底自动化了哪些步骤、Prometheus 实际抓到了什么",而不是把"一键执行"直接等同于所有环境都能无脑复制。

1. 为什么把 mysqld_exporter 部署写成 Shell 脚本?

这类监控组件最适合自动化的地方,就是安装步骤高度重复。

如果每台机器都手工做一遍,通常要反复处理这些事情:

  • 下载并解压 mysqld_exporter;
  • 创建专用运行用户;
  • 创建 MySQL 监控账号并授权;
  • 写数据库连接配置;
  • 设置配置文件权限;
  • 创建 systemd 服务;
  • 启用开机自启;
  • 检查指标端口。

机器少的时候,手工还能接受;机器一多,真正消耗时间的是重复操作和后续排错。

所以我更愿意把目标定得简单一点:

脚本负责把固定部署步骤标准化,Prometheus 负责抓指标,cpolar 只在跨网络场景下提供 9105 的公网访问入口。

这三层职责分开以后,后面哪一层出问题也更容易定位。

2. 这份脚本具体自动化了什么?

当前脚本使用的版本是:

v0.18.0

安装目录:

/app/mysqld_exporter

监听端口:

9105

整体流程包括:

  1. 检查是否以 root 运行;
  2. 安装 wgettar
  3. 下载并解压 mysqld_exporter;
  4. 创建 prometheus 系统用户;
  5. 使用 MySQL root 账号测试连接;
  6. 创建 mysqld_exporter 数据库监控用户;
  7. 授予 REPLICATION CLIENTPROCESSperformance_schema 查询权限;
  8. 生成 localhost_db.cnf
  9. 将配置文件权限设为 600
  10. 创建并启动 mysqld_exporter.service

完整脚本如下:

shell 复制代码
#!/bin/bash
# 一键安装 mysqld_exporter for CentOS 7
# 使用固定 MySQL root密码自动建用户
# 监控用户: mysqld_exporter / Sjixin520!

set -e

VERSION="v0.18.0"
INSTALL_DIR="/app/mysqld_exporter"
PORT="9105"

MYSQL_ROOT_USER="root"
MYSQL_ROOT_PASS="Sjixin52!"
EXPORTER_USER="mysqld_exporter"
EXPORTER_PASS="Sjixin52!"

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

log() { echo -e "${GREEN}[INFO]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; }

if [ "$EUID" -ne 0 ]; then
    error "请以 root 用户运行此脚本!"
fi

# 安装依赖
log "安装必要工具..."
yum install -y wget tar &>/dev/null

# 下载mysqld_exporter
URL="https://github.com/prometheus/mysqld_exporter/releases/download/${VERSION}/mysqld_exporter-${VERSION#v}.linux-amd64.tar.gz"
log "正在下载mysqld_exporter ${VERSION} ..."
wget -O /tmp/mysqld_exporter.tar.gz "$URL" || error "下载失败"

# 解压到/app/mysqld_exporter
mkdir -p "$INSTALL_DIR"
tar -zxvf /tmp/mysqld_exporter.tar.gz -C "$INSTALL_DIR" --strip-components=1
chown -R root:root "$INSTALL_DIR"

# 确保prometheus用户存在
if ! id "prometheus" &>/dev/null; then
    log "创建prometheus系统用户..."
    useradd --system --shell /sbin/nologin --no-create-home prometheus
fi

# 自动创建MySQL监控用户
log "正在连接MySQL并创建监控用户 '$EXPORTER_USER' ..."

# 测试root登录是否成功
if ! mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASS" -e "SELECT 1;" >/dev/null 2>&1; then
    error "无法使用root / Sjixin52! 登录MySQL,请确认MySQL正在运行且密码正确"
fi

# 创建exporter用户
mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASS" <<SQL
CREATE USER IF NOT EXISTS '$EXPORTER_USER'@'localhost' IDENTIFIED BY '$EXPORTER_PASS';
GRANT REPLICATION CLIENT, PROCESS ON *.* TO '$EXPORTER_USER'@'localhost';
GRANT SELECT ON performance_schema.* TO '$EXPORTER_USER'@'localhost';
FLUSH PRIVILEGES;
SQL

log "MySQL监控用户创建成功!"

# 创建.my.cnf文件
cat > "$INSTALL_DIR/localhost_db.cnf" <<EOF
[client]
user=$EXPORTER_USER
password=$EXPORTER_PASS
host=localhost
EOF

chmod 600 "$INSTALL_DIR/localhost_db.cnf"
chown prometheus:prometheus "$INSTALL_DIR/localhost_db.cnf"

# 创建systemd服务
cat > /etc/systemd/system/mysqld_exporter.service <<EOF
[Unit]
Description=MySQL Exporter
After=network.target

[Service]
Type=simple
User=prometheus
ExecStart=$INSTALL_DIR/mysqld_exporter \\
    --config.my-cnf=$INSTALL_DIR/localhost_db.cnf \\
    --web.listen-address=:9105
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

# 启动服务
log "启动 mysqld_exporter 服务..."
systemctl daemon-reload
systemctl enable --now mysqld_exporter

log "✅ 安装完成!"
log "指标地址: http://$(hostname -I | awk '{print $1}'):${PORT}/metrics"
log "服务状态: systemctl status mysqld_exporter"

这里有一个我会特别留意的地方:脚本里直接写入了 MySQL root 和 exporter 的固定密码。

代码按当前内容原样保留,但如果后面准备把脚本放进 Git、Ansible 或多台机器批量使用,我不会把"能自动跑"当成"凭据管理已经解决"。脚本自动化的是部署流程,不是密码治理。

3. 把脚本保存成 mysql_exporter.sh

先创建脚本文件:

shell 复制代码
vi mysql_exporter.sh

然后写入当前完整脚本:

shell 复制代码
#!/bin/bash
# 一键安装 mysqld_exporter for CentOS 7
# 使用固定 MySQL root密码自动建用户
# 监控用户: mysqld_exporter / Sjixin520!

set -e

VERSION="v0.18.0"
INSTALL_DIR="/app/mysqld_exporter"
PORT="9105"

MYSQL_ROOT_USER="root"
MYSQL_ROOT_PASS="Sjixin52!"
EXPORTER_USER="mysqld_exporter"
EXPORTER_PASS="Sjixin52!"

RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'

log() { echo -e "${GREEN}[INFO]${NC} $1"; }
error() { echo -e "${RED}[ERROR]${NC} $1" >&2; exit 1; }

if [ "$EUID" -ne 0 ]; then
    error "请以 root 用户运行此脚本!"
fi

# 安装依赖
log "安装必要工具..."
yum install -y wget tar &>/dev/null

# 下载mysqld_exporter
URL="https://github.com/prometheus/mysqld_exporter/releases/download/${VERSION}/mysqld_exporter-${VERSION#v}.linux-amd64.tar.gz"
log "正在下载mysqld_exporter ${VERSION} ..."
wget -O /tmp/mysqld_exporter.tar.gz "$URL" || error "下载失败"

# 解压到/app/mysqld_exporter
mkdir -p "$INSTALL_DIR"
tar -zxvf /tmp/mysqld_exporter.tar.gz -C "$INSTALL_DIR" --strip-components=1
chown -R root:root "$INSTALL_DIR"

# 确保prometheus用户存在
if ! id "prometheus" &>/dev/null; then
    log "创建prometheus系统用户..."
    useradd --system --shell /sbin/nologin --no-create-home prometheus
fi

# 自动创建MySQL监控用户
log "正在连接MySQL并创建监控用户 '$EXPORTER_USER' ..."

# 测试root登录是否成功
if ! mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASS" -e "SELECT 1;" >/dev/null 2>&1; then
    error "无法使用root / Sjixin52! 登录MySQL,请确认MySQL正在运行且密码正确"
fi

# 创建exporter用户
mysql -u"$MYSQL_ROOT_USER" -p"$MYSQL_ROOT_PASS" <<SQL
CREATE USER IF NOT EXISTS '$EXPORTER_USER'@'localhost' IDENTIFIED BY '$EXPORTER_PASS';
GRANT REPLICATION CLIENT, PROCESS ON *.* TO '$EXPORTER_USER'@'localhost';
GRANT SELECT ON performance_schema.* TO '$EXPORTER_USER'@'localhost';
FLUSH PRIVILEGES;
SQL

log "MySQL监控用户创建成功!"

# 创建.my.cnf文件
cat > "$INSTALL_DIR/localhost_db.cnf" <<EOF
[client]
user=$EXPORTER_USER
password=$EXPORTER_PASS
host=localhost
EOF

chmod 600 "$INSTALL_DIR/localhost_db.cnf"
chown prometheus:prometheus "$INSTALL_DIR/localhost_db.cnf"

# 创建systemd服务
cat > /etc/systemd/system/mysqld_exporter.service <<EOF
[Unit]
Description=MySQL Exporter
After=network.target

[Service]
Type=simple
User=prometheus
ExecStart=$INSTALL_DIR/mysqld_exporter \\
    --config.my-cnf=$INSTALL_DIR/localhost_db.cnf \\
    --web.listen-address=:9105
Restart=on-failure
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

# 启动服务
log "启动 mysqld_exporter 服务..."
systemctl daemon-reload
systemctl enable --now mysqld_exporter

log "✅ 安装完成!"
log "指标地址: http://$(hostname -I | awk '{print $1}'):${PORT}/metrics"
log "服务状态: systemctl status mysqld_exporter"

这里脚本文件名叫:

mysql_exporter.sh

而实际下载的二进制、systemd 服务以及当前项目名称都使用:

mysqld_exporter

两种写法在当前流程里同时存在,我按现有内容保留,不强行统一。

4. 执行脚本

保存完成以后运行:

shell 复制代码
sh mysql_exporter.sh

如果整个流程能够顺利执行,脚本会依次完成依赖安装、下载、MySQL 用户创建、配置文件生成和 systemd 注册。

但我不会只看"脚本没报错"就结束。

真正关键的是再确认服务状态。

5. 检查 mysqld_exporter 服务

执行:

shell 复制代码
systemctl status mysqld_exporter

当前结果显示 mysqld_exporter 服务已经成功启动。

脚本中还会输出类似:

http://主机IP:9105/metrics

的指标地址。

到这里,真正验证的是:

MySQL → mysqld_exporter → 9105 → systemd 服务正常运行。

6. 先在同一局域网里让 Prometheus 抓取

mysqld_exporter 跑起来以后,再去配置 Prometheus。

打开:

shell 复制代码
vi prometheus.yml

当前示例加入:

shell 复制代码
      - targets: ["192.168.42.146:9105"]
        labels:
          app: "mysql_exporter"

这里 Prometheus 和 mysqld_exporter 不在同一台机器,所以抓取目标写的是:

192.168.42.146:9105

如果都在同一台机器,当前说明写的是可以使用 localhost

接着通过:

IP + 9090

打开 Prometheus 页面。

当前页面已经能够看到 Prometheus 抓取到:

192.168.42.146

上的 mysql_exporter 服务。

这一层先把最基础的监控链验证清楚:

MySQL → mysqld_exporter 9105 → Prometheus 局域网抓取。

7. Prometheus 和 exporter 不在同一网络怎么办?

如果 Prometheus 和 mysqld_exporter 位于同一个局域网,直接写内网 IP 就可以。

问题出现在另一种场景:

  • Prometheus 在外部服务器;
  • MySQL 和 mysqld_exporter 在内网;
  • Prometheus 无法直接访问 192.168.42.146:9105

这时候真正需要开放的是:

mysqld_exporter 的指标入口 9105

而不是把 MySQL 数据库本身直接暴露出去。

cpolar 在这套方案里的职责也只有这一层:

把本地 mysqld_exporter 的 9105 HTTP 指标页面提供给外部 Prometheus 访问。

数据库指标仍然由 mysqld_exporter 采集,Prometheus 仍然负责抓取和存储。

8. 安装 cpolar

执行当前安装命令:

shell 复制代码
sudo curl https://get.cpolar.sh | sh

安装完成以后检查服务状态:

shell 复制代码
sudo systemctl status cpolar

服务正常以后,通过主机 IP + 9200 打开 cpolar Web 管理页面。

当前页面写的是:

ip:9200

同时链接目标为:

http://localhost:9200/

实际访问时,以当前环境真正能打开的地址为准。

9. 给 mysqld_exporter 创建随机公网地址

进入【隧道管理 → 创建隧道】。

当前配置为:

  • 隧道名称:mysql_exporter
  • 协议:http
  • 本地地址:9105
  • 域名类型:随机域名
  • 地区:China Top

创建以后,到在线隧道列表查看公网地址。

当前示例得到:

38c53143.r2.cpolar.top

接下来 Prometheus 的目标配置改为:

shell 复制代码
      - targets: ["38c53143.r2.cpolar.top"]
        labels:
          app: "mysql_exporter"

随后页面显示抓取成功。

这一层真正验证的是:

内网 mysqld_exporter 9105 → cpolar HTTP 公网地址 → 外部 Prometheus 抓取。

当前 Prometheus target 按现有配置原样写为:

38c53143.r2.cpolar.top

这里不额外补端口或改写格式。

10. 随机公网地址能用以后,再配置固定入口

随机地址适合先验证跨网络抓取。

如果 Prometheus 要长期使用同一个抓取目标,地址频繁变化就不方便继续维护。

所以当前流程继续配置固定二级子域名。

进入预留页面。

选择保留二级子域名。

当前记录为:

  • 地区:china Top
  • 二级子域名:mysqll

然后回到【隧道管理 → 隧道列表】,找到:

mysql_exporter

隧道。

把域名类型改为:

二级子域名

并在:

Sub Domain

中填写已经保留的二级子域名。

地区继续选择:

China Top

更新完成以后,在线隧道列表中的随机公网地址会切换成固定二级子域名形式。

最后通过固定公网地址访问。

当前页面可以正常打开。

这里能够确认固定公网 Web 入口已经生效;但当前材料没有继续展示把 Prometheus 的 target 再改成固定二级子域名以后进行第二次抓取验证,所以我不会把这一步额外写成"固定域名 Prometheus 抓取已再次验证"。

总结

这套脚本真正省下来的,不是"敲一条命令"本身,而是把一组容易重复出错的部署步骤固定下来。

这次实际跑通的主线是:

CentOS 7 → Shell 脚本 → mysqld_exporter v0.18.0/app/mysqld_exporter → MySQL 监控用户 → localhost_db.cnfprometheus 系统用户 → systemd → 9105 → Prometheus 局域网抓取 192.168.42.146:9105 → cpolar → 随机公网 38c53143.r2.cpolar.top → Prometheus 公网抓取成功 → 固定二级子域名 mysqll

几个边界需要分清:

  • 脚本自动化的是 mysqld_exporter 的安装、授权、配置和服务注册;
  • Prometheus 才负责真正抓取指标;
  • cpolar 只负责把 9105 指标入口提供到公网,不参与 MySQL 指标采集;
  • 当前脚本把 MySQL root 和 exporter 密码直接写在脚本中,代码虽然按现有内容保留,但批量复用前要单独考虑凭据管理;
  • 随机公网地址已经实际用于 Prometheus 抓取并显示成功;
  • 固定二级子域名已经完成配置和页面访问,但现有流程没有继续展示 Prometheus 使用固定域名后的第二次抓取验证。

如果后面真的要部署很多节点,我更看重的不是"脚本能不能跑 100 台",而是版本、目录、权限、凭据和抓取目标是否都能保持一致。自动化的价值就在这里:不是省掉所有判断,而是把真正需要人工判断的部分留下,把重复动作尽量交给脚本。

相关推荐
凤城老人2 小时前
从零手写开源私有云盘|Flask+Vue3+Electron全栈网盘,单容器一键部署
python·docker·electron·vue
Dovis(誓平步青云)2 小时前
突破 32 位瓶颈:64 位 XID 如何化解事务号回卷危机
运维·服务器·人工智能·docker·容器
是店小二呀2 小时前
开源鸿蒙PC原生适配:Node版本管理器命令行移植
docker·鸿蒙pc
为你学会写情书2 小时前
Docker 从入门到实战:容器化全栈项目,再顺手编排一个 Milvus 向量数据库
docker
SatanII3 小时前
容器运行时Containerd完整学习笔记|原理、安装、ctr/nerdctl/crictl实操全梳理
运维·docker·华为云·containerd
九皇叔叔14 小时前
Kubernetes 核心概念:集群架构、核心组件与资源对象
docker·容器·kubernetes·k8s
rustfs14 小时前
MinIO 国产开源平替正式 GA
分布式·docker·云原生·rust
wdfk_prog19 小时前
ROS教程07:从 ros::start() 顺着源码读懂 Master、XML-RPC 与 Topic 注册发现
运维·缓存·docker·容器·ros
mengge.cloud19 小时前
0917Docker 小白实验教程(理论+实操)
linux·服务器·网络·docker