ITPub博客

首页 > 应用开发 > IT综合 > 远程服务器监控方案:node_exporter与内网穿透的集成实践

远程服务器监控方案:node_exporter与内网穿透的集成实践

翻译 IT综合 作者:bhluo 时间:2026-02-03 11:40:28 0 删除 编辑

## 远程服务器监控方案:node_exporter与内网穿透的集成实践


在远程办公和分布式系统运维日益普及的今天,如何有效监控分布在不同网络环境的服务器成为技术团队面临的共同挑战。本文将详细介绍如何通过node_exporter与cpolar内网穿透工具的结合,构建一个安全、高效的远程服务器监控方案,使运维人员能够随时随地掌握服务器运行状态。


### 远程监控的技术挑战


传统服务器监控方案通常依赖本地网络访问或复杂的VPN配置,在远程办公场景下面临诸多限制。直接暴露监控端口到公网存在安全风险,而VPN方案又增加了网络复杂性和维护成本。node_exporter作为Prometheus生态中广泛使用的节点监控工具,提供了丰富的系统指标,但其默认设计面向内网环境。


```bash

# node_exporter基础安装与运行

wget https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz

tar xvfz node_exporter-1.6.0.linux-amd64.tar.gz

cd node_exporter-1.6.0.linux-amd64

./node_exporter --web.listen-address=":9100"

```


上述配置仅在本地网络可访问,无法满足远程监控需求。


### 监控系统架构设计


本方案采用分层架构:数据采集层(node_exporter)、安全隧道层(cpolar)、数据聚合层(Prometheus)和可视化层(Grafana)。核心思想是在不改变服务器网络配置的前提下,通过加密隧道安全地暴露监控数据。


```yaml

# docker-compose.yml - 完整监控栈配置

version: '3.8'


services:

  node_exporter:

    image: quay.io/prometheus/node-exporter:latest

    container_name: node_exporter

    restart: unless-stopped

    volumes:

      - /proc:/host/proc:ro

      - /sys:/host/sys:ro

      - /:/rootfs:ro

    command:

      - '--path.procfs=/host/proc'

      - '--path.rootfs=/rootfs'

      - '--path.sysfs=/host/sys'

      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'

      - '--web.listen-address=:9100'

    network_mode: "host"

    pid: "host"


  cpolar:

    image: cpolar/cpolar:latest

    container_name: cpolar_tunnel

    restart: unless-stopped

    volumes:

      - ./cpolar.yml:/etc/cpolar/cpolar.yml

      - ./data:/data

    environment:

      - CPOLAR_AUTH_TOKEN=${CPOLAR_TOKEN}

    command: ["serve", "--config=/etc/cpolar/cpolar.yml"]


  prometheus:

    image: prom/prometheus:latest

    container_name: prometheus

    restart: unless-stopped

    volumes:

      - ./prometheus.yml:/etc/prometheus/prometheus.yml

      - prometheus_data:/prometheus

    command:

      - '--config.file=/etc/prometheus/prometheus.yml'

      - '--storage.tsdb.path=/prometheus'

      - '--web.console.libraries=/etc/prometheus/console_libraries'

      - '--web.console.templates=/etc/prometheus/consoles'

      - '--storage.tsdb.retention.time=30d'

    ports:

      - "9090:9090"


  grafana:

    image: grafana/grafana:latest

    container_name: grafana

    restart: unless-stopped

    volumes:

      - grafana_data:/var/lib/grafana

      - ./grafana/provisioning:/etc/grafana/provisioning

    environment:

      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}

    ports:

      - "3000:3000"


volumes:

  prometheus_data:

  grafana_data:

```


### node_exporter深度配置与优化


基础监控往往无法满足生产需求,需要根据具体场景进行深度配置。


```yaml

# node_exporter自定义配置

# config.yml - 启用特定收集器并设置参数

---

collectors:

  enabled:

    - cpu

    - meminfo

    - diskstats

    - filesystem

    - loadavg

    - netdev

    - netstat

    - stat

    - time

    - systemd

    - process


collector:

  cpu:

    enabled: true

    flags: "--collector.cpu.info"

  filesystem:

    enabled: true

    mount-points-exclude: "^/(sys|proc|dev|host|etc)($$|/)"

    fs-types-exclude: "^tmpfs$|^devtmpfs$|^overlay$|^aufs$"

  diskstats:

    enabled: true

    devices-exclude: "^loop[0-9]+$|^dm-[0-9]+$"

  netdev:

    enabled: true

    devices-exclude: "^lo$|^docker[0-9]+$|^veth[0-9a-f]+$"

  process:

    enabled: true

    process-names: ["nginx", "mysql", "redis", "docker"]


telemetry:

  max-requests: 40

  enable-openmetrics: true


web:

  listen-address: ":9100"

  telemetry-path: "/metrics"

  max-requests: 40

  web-config-file: "/etc/node_exporter/web.yml"


# web.yml - TLS和安全配置

tls_server_config:

  cert_file: /etc/ssl/node_exporter.crt

  key_file: /etc/ssl/node_exporter.key

  client_auth_type: RequireAndVerifyClientCert

  client_ca_file: /etc/ssl/ca.crt


basic_auth_users:

  prometheus: "$2y$10$hashed_password_here"

```


启动脚本示例:


```bash

#!/bin/bash

# start_node_exporter.sh


CONFIG_DIR="/etc/node_exporter"

LOG_DIR="/var/log/node_exporter"

DATA_DIR="/var/lib/node_exporter"


# 创建必要目录

mkdir -p ${CONFIG_DIR} ${LOG_DIR} ${DATA_DIR}


# 生成TLS证书(如需)

if [ ! -f "${CONFIG_DIR}/ssl/node_exporter.crt" ]; then

    mkdir -p ${CONFIG_DIR}/ssl

    openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 \

        -keyout ${CONFIG_DIR}/ssl/node_exporter.key \

        -out ${CONFIG_DIR}/ssl/node_exporter.crt \

        -subj "/C=CN/ST=Beijing/L=Beijing/O=Company/CN=node_exporter.local"

fi


# 创建systemd服务

cat > /etc/systemd/system/node_exporter.service << EOF

[Unit]

Description=Node Exporter

After=network.target


[Service]

Type=simple

User=node_exporter

Group=node_exporter

ExecStart=/usr/local/bin/node_exporter \

    --web.config.file=${CONFIG_DIR}/web.yml \

    --collector.textfile.directory=${DATA_DIR}/textfile_collector \

    --collector.processes \

    --collector.systemd \

    --collector.perf \

    --web.listen-address=127.0.0.1:9100 \

    --web.max-requests=40 \

    --log.level=info


Restart=always

RestartSec=10

StandardOutput=syslog

StandardError=syslog

SyslogIdentifier=node_exporter


[Install]

WantedBy=multi-user.target

EOF


# 创建专用用户

useradd -rs /bin/false node_exporter


# 设置权限

chown -R node_exporter:node_exporter ${CONFIG_DIR} ${LOG_DIR} ${DATA_DIR}

chmod 600 ${CONFIG_DIR}/ssl/*


# 启动服务

systemctl daemon-reload

systemctl enable node_exporter

systemctl start node_exporter


echo "Node Exporter已启动,监听在 127.0.0.1:9100"

```


### cpolar安全隧道配置


cpolar的配置需要平衡安全性与便利性,以下为生产级配置示例:


```yaml

# cpolar.yml - 完整隧道配置

version: '2.0'

<"j3.a8k1.org.cn"><"n7.a8k1.org.cn"><"w9.a8k1.org.cn">

log:

  level: info

  file: /data/cpolar.log

  max_size: 100

  max_backups: 3

  max_age: 30


tunnels:

  node_exporter_monitor:

    proto: http

    addr: 127.0.0.1:9100

    hostname: node-metrics

    region: cn

    scheme: https

    auth:

      type: basic

      username: "${MONITOR_USER}"

      password: "${MONITOR_PASSWORD}"

    tls:

      crt: /data/ssl/tunnel.crt

      key: /data/ssl/tunnel.key

    inspect:

      enabled: true

      timeout: 30s

    compression: true

    proxy_protocol: false


  prometheus_remote_write:

    proto: tcp

    addr: 127.0.0.1:9090

    remote_port: 29090

    region: cn

    tls:

      crt: /data/ssl/prometheus.crt

      key: /data/ssl/prometheus.key

    access_control:

      allowed_ips:

        - 0.0.0.0/0


authtoken: "${CPOLAR_AUTH_TOKEN}"


update:

  enabled: true

  check_interval: 24h


heartbeat:

  enabled: true

  interval: 60s

  timeout: 10s

```


隧道管理脚本:


```python

#!/usr/bin/env python3

# tunnel_manager.py


import yaml

import os

import logging

from datetime import datetime

from pathlib import Path


class TunnelManager:

    def __init__(self, config_path="cpolar.yml"):

        self.config_path = Path(config_path)

        self.config = self.load_config()

        self.setup_logging()

    

    def load_config(self):

        """加载配置文件"""

        with open(self.config_path, 'r') as f:

            return yaml.safe_load(f)

    

    def setup_logging(self):

        """配置日志"""

        log_dir = Path("logs")

        log_dir.mkdir(exist_ok=True)

        

        logging.basicConfig(

            level=logging.INFO,

            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',

            handlers=[

                logging.FileHandler(f"logs/tunnel_{datetime.now().strftime('%Y%m%d')}.log"),

                logging.StreamHandler()

            ]

        )

        self.logger = logging.getLogger(__name__)

    

    def generate_tunnel_config(self, server_info):

        """动态生成隧道配置"""

        template = {

            "proto": "http",

            "addr": f"{server_info['local_ip']}:{server_info['port']}",

            "hostname": f"{server_info['name']}-{server_info['env']}",

            "region": "cn",

            "auth": {

                "type": "token",

                "token": os.getenv("TUNNEL_TOKEN")

            }

        }

        

        # 根据服务器类型添加特定配置

        if server_info.get('sensitive', False):

            template['scheme'] = "https"

            template['tls'] = {

                "crt": f"/data/ssl/{server_info['name']}.crt",

                "key": f"/data/ssl/{server_info['name']}.key"

            }

        

        return template

    

    def monitor_tunnel_health(self):

        """监控隧道健康状态"""

        import requests

        import json

        

        tunnels = self.config.get('tunnels', {})

        

        for name, config in tunnels.items():

            try:

                # 检查隧道状态

                status_url = f"http://localhost:4040/api/tunnels/{name}"

                response = requests.get(status_url, timeout=5)

                

                if response.status_code == 200:

                    status_data = response.json()

                    self.logger.info(f"隧道 {name} 状态: {status_data['status']}")

                    

                    # 记录指标

                    self.record_metrics(name, status_data)

                else:

                    self.logger.warning(f"隧道 {name} 状态检查失败")

                    

            except Exception as e:

                self.logger.error(f"检查隧道 {name} 时出错: {e}")

                

                # 尝试重启隧道

                self.restart_tunnel(name)

    

    def record_metrics(self, tunnel_name, status_data):

        """记录隧道指标到node_exporter文本收集器"""

        metrics_dir = Path("/var/lib/node_exporter/textfile_collector")

        metrics_dir.mkdir(parents=True, exist_ok=True)

        

        metrics_file = metrics_dir / f"cpolar_{tunnel_name}.prom"

        

        metrics = []

        metrics.append(f'cpolar_tunnel_up{{tunnel="{tunnel_name}"}} {1}')

        

        # 解析隧道统计信息

        if 'metrics' in status_data:

            metrics.append(f'cpolar_tunnel_bytes_in{{tunnel="{tunnel_name}"}} '

                          f'{status_data["metrics"].get("bytes_in", 0)}')

            metrics.append(f'cpolar_tunnel_bytes_out{{tunnel="{tunnel_name}"}} '

                          f'{status_data["metrics"].get("bytes_out", 0)}')

        

        with open(metrics_file, 'w') as f:

            f.write('\n'.join(metrics))

    

    def restart_tunnel(self, tunnel_name):

        """重启指定隧道"""

        self.logger.info(f"正在重启隧道: {tunnel_name}")

        

        # 实际实现中会调用cpolar的API或命令行

        import subprocess

        try:

            result = subprocess.run(

                ["cpolar", "restart", tunnel_name],

                capture_output=True,

                text=True,

                timeout=30

            )

            

            if result.returncode == 0:

                self.logger.info(f"隧道 {tunnel_name} 重启成功")

            else:

                self.logger.error(f"隧道重启失败: {result.stderr}")

                

        except subprocess.TimeoutExpired:

            self.logger.error(f"重启隧道 {tunnel_name} 超时")


if __name__ == "__main__":

    manager = TunnelManager()

    

    # 定期健康检查

    import time

    while True:

        manager.monitor_tunnel_health()

        time.sleep(300)  # 每5分钟检查一次

```


### Prometheus远程采集配置


Prometheus需要配置通过cpolar隧道采集远程节点指标。


```yaml

# prometheus.yml - 远程采集配置

global:

  scrape_interval: 15s

  evaluation_interval: 15s

  external_labels:

    monitor: 'remote-cluster'


rule_files:

  - "alerts.yml"


scrape_configs:

  - job_name: 'remote_servers'

    scheme: https

    basic_auth:

      username: '${MONITOR_USER}'

      password: '${MONITOR_PASSWORD}'

    tls_config:

      ca_file: /etc/ssl/ca.crt

      cert_file: /etc/ssl/prometheus.crt

      key_file: /etc/ssl/prometheus.key

      insecure_skip_verify: false

    static_configs:

      - targets:

        - 'node-metrics.cpolar.io'

        labels:

          location: 'home-server'

          env: 'production'

    metrics_path: '/metrics'

    scrape_timeout: 30s

    relabel_configs:

      - source_labels: [__address__]

        target_label: instance

      - source_labels: [__meta_dns_name]

        target_label: hostname

<"g2.a8k1.org.cn"><"q5.a8k1.org.cn"><"t1.a8k1.org.cn">

  - job_name: 'tunnel_metrics'

    static_configs:

      - targets: ['localhost:9100']

    metrics_path: '/metrics'

    params:

      collect[]:

        - cpolar


alerting:

  alertmanagers:

    - scheme: https

      basic_auth:

        username: '${ALERT_USER}'

        password: '${ALERT_PASSWORD}'

      static_configs:

        - targets: ['alert.cpolar.io:9093']


# alerts.yml - 报警规则

groups:

  - name: node_alerts

    rules:

      - alert: HighCpuUsage

        expr: 100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80

        for: 5m

        labels:

          severity: warning

        annotations:

          summary: "高CPU使用率 {{ $labels.instance }}"

          description: "CPU使用率超过80% (当前值: {{ $value }}%)"

      

      - alert: LowMemoryAvailable

        expr: (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 < 20

        for: 5m

        labels:

          severity: warning

        annotations:

          summary: "低可用内存 {{ $labels.instance }}"

          description: "可用内存低于20% (当前值: {{ $value }}%)"

      

      - alert: TunnelDown

        expr: cpolar_tunnel_up == 0

        for: 2m

        labels:

          severity: critical

        annotations:

          summary: "监控隧道断开 {{ $labels.tunnel }}"

          description: "监控隧道已断开超过2分钟"

```


### 安全加固与访问控制


安全是远程监控的首要考量,必须实施多层防护措施。


```bash

#!/bin/bash

# security_setup.sh


echo "配置监控系统安全..."


# 1. 防火墙规则

sudo ufw default deny incoming

sudo ufw default allow outgoing

sudo ufw allow 22/tcp comment 'SSH'

sudo ufw allow from 127.0.0.1 to any port 9100 comment 'node_exporter local'

sudo ufw --force enable


# 2. 创建监控专用网络

docker network create --subnet=172.20.0.0/24 monitoring_net


# 3. 配置审计日志

sudo apt install -y auditd

sudo cat > /etc/audit/rules.d/monitoring.rules << EOF

-w /etc/prometheus/prometheus.yml -p wa -k prometheus_config

-w /etc/node_exporter/ -p wa -k node_exporter

-w /var/lib/node_exporter/ -p wa -k node_metrics

EOF


sudo systemctl restart auditd


# 4. 配置监控用户权限

sudo groupadd monitoring

sudo useradd -r -s /bin/false -g monitoring prometheus

sudo useradd -r -s /bin/false -g monitoring node_exporter


# 5. 设置目录权限

sudo chown -R prometheus:monitoring /etc/prometheus

sudo chown -R node_exporter:monitoring /etc/node_exporter

sudo chmod 750 /etc/prometheus /etc/node_exporter


# 6. 配置SELinux/AppArmor

if [ -f /etc/apparmor.d/docker ]; then

    sudo cat >> /etc/apparmor.d/docker << 'EOF'

  network inet,

  network inet6,

  capability net_admin,

  capability net_raw,

EOF

    sudo systemctl restart apparmor

fi


echo "安全配置完成"

```


### Grafana仪表板配置


通过Grafana实现监控数据的可视化展示。


```json

// dashboard.json - 服务器监控仪表板

{

  "dashboard": {

    "title": "远程服务器监控",

    "tags": ["node_exporter", "cpolar", "monitoring"],

    "timezone": "browser",

    "panels": [

      {

        "title": "CPU使用率",

        "type": "graph",

        "targets": [

          {

            "expr": "100 - (avg by(instance) (irate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100)",

            "legendFormat": "{{instance}}"

          }

        ],

        "gridPos": {"h": 8, "w": 12, "x": 0, "y": 0}

      },

      {

        "title": "内存使用",

        "type": "stat",

        "targets": [

          {

            "expr": "(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100",

            "legendFormat": "使用率"

          }

        ],

        "gridPos": {"h": 4, "w": 6, "x": 0, "y": 8}

      },

      {

        "title": "隧道状态",

        "type": "table",

        "targets": [

          {

            "expr": "cpolar_tunnel_up",

            "instant": true,

            "legendFormat": "隧道状态"

          }

        ],

        "gridPos": {"h": 6, "w": 6, "x": 6, "y": 8}

      }

    ]

  }

}

```


### 自动化部署与维护


通过Ansible等工具实现监控系统的自动化部署。


```yaml

# deploy_monitoring.yml

- hosts: all

  become: yes

  vars:

    cpolar_token: "{{ lookup('env', 'CPOLAR_TOKEN') }}"

    monitoring_user: "monitor"

    monitoring_password: "{{ lookup('password', '/dev/null length=32 chars=ascii_letters,digits') }}"

  

  tasks:

    - name: 安装node_exporter

      ansible.builtin.copy:

        src: files/node_exporter

        dest: /usr/local/bin/

        mode: '0755'

    

    - name: 创建systemd服务

      ansible.builtin.template:

        src: templates/node_exporter.service.j2

        dest: /etc/systemd/system/node_exporter.service

    

    - name: 配置cpolar

      ansible.builtin.copy:

        src: files/cpolar.yml

        dest: /etc/cpolar.yml

        mode: '0600'

    

    - name: 启动服务

      ansible.builtin.systemd:

        name: "{{ item }}"

        state: started

        enabled: yes

      loop:

        - node_exporter

        - cpolar

    

    - name: 验证服务状态

      ansible.builtin.uri:

        url: "http://localhost:9100/metrics"

        status_code: 200

```


### 总结


通过node_exporter与cpolar的结合,可以构建一个安全、高效的远程服务器监控方案。这种方案不仅解决了远程访问的技术难题,还通过多层安全防护确保了系统的安全性。实际部署时,需要根据具体环境调整配置参数,并建立完善的监控报警机制。


随着远程办公的普及,此类混合监控方案将在更多场景中发挥作用。关键在于平衡便利性与安全性,建立标准化的部署流程和应急响应机制。通过持续优化和改进,远程服务器监控能够为分布式系统的稳定运行提供有力保障,真正实现运维工作的灵活与高效。


来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3109803/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2015-11-01

  • 博文量
    895
  • 访问量
    934670