亚马逊AWS官方博客

中国区部署Smokeping构建轻量化网络监控及告警平台小指南

1. 概述

1.1 背景需求

在亚马逊云科技中国区,由于缺乏托管的网络监控管理服务如Network Synthetic Monitor,客户在以下场景中面临监控挑战:

  • 专线(Direct Connect)网络质量监控
  • Overlay 网络可达性监控
  • 跨区域服务访问性能监控
  • 关键业务端口和服务可用性监控

一些主流的监控方案如 Prometheus blackbox-exporter + Grafana 虽然功能强大,但部署和维护成本较高,需要较多的计算资源和体系化的运维能力。有些客户在特定场景需要一个轻量级但功能完备的网络监控方案,可以在单台小型实例(如 t3.small)上运行,同时提供直观的可视化界面。

1.2 方案介绍

本方案采用 SmokePing 作为核心监控工具。SmokePing 是一个轻量级但功能强大的网络延迟监测工具,具有以下特点:

核心优势:

  • 部署简单:基于 Docker 容器化部署,最小化依赖
  • 资源占用低:适合在小型实例上运行
  • 配置灵活:支持多种监控协议和探测方式
  • 可视化友好:提供直观的网络性能趋势图表

主要功能:

  • 精确的延迟测量:同时监控数据包丢失和延迟变化
  • 多协议支持:包括 ICMP、TCP、DNS、HTTP 等
  • 告警机制:可配置多级告警规则
  • 历史数据存储:使用 RRD 数据库高效存储监控数据,方便溯源和提供故障发生时的证据。
  • 支持 Master/Slave 架构:可以部署多个 Slave 节点分布在不同AZ或者区域

本篇内容会通过step by step的指南,让客户可以快速搭建起一个轻量级但实用的网络监控系统,实现对关键网络链路和服务的持续监控。本方案还支持通过SMTP或者与 Amazon SNS 集成以及第三方API,及时推送告警通知,帮助运维团队快速发现和响应网络问题。

2.安装前准备

本方案的部署环境要求和准备工作如下:

2.1 准备EC2 访问密钥对(用于 SSH 登录)

2.2 准备一个安全组配置(需开放SSH以及监控页面访问端口,默认 8888)

2.3 EC2 IAM 角色(用于访问亚马逊云科技服务)

这个Role根据以下原则去构建:

  • 如果需要使用自建的ECR作为镜像源,需要ECR相关权限,如下代码示例:
#Role Policy for EC2 pull image from ECR
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ecr:GetAuthorizationToken",
                "ecr:BatchCheckLayerAvailability",
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage"
            ],
            "Resource": "*"
        }
    ]
}
  • 如果需要使用告警的能力,比如使用SNS发送通知,或者通过Lambda触发一个自定义告警脚本,则需要SNS及Lambda相关权限。

2.4 (可选)如果这个EC2部署的subnet没有互联网访问,则需要部署ECR, SNS, Lambda等需要的服务的VPC endpoint

3.安装smokeping

3.1 (可选)通过ECR构建最新的image。

因为linuxserver/docker-smokeping的官方镜像下载可能会遇到网络问题,所以推荐将Image下载,更新组件以后打包更新到ECR, 方便后续使用。

3.2 由于官方的dockerfile没有安装python, 无法使用自定义的python脚本作为告警方式,因此如果需要自定义告警推荐使用这个repo: mengchen-tam/docker-smokeping.

#需要使用python脚本实现SNS, lambda或者自己的API去告警:
git clone https://github.com/mengchen-tam/docker-smokeping
#使用SMTP方式告警则可以直接使用官方的repo:
#git clone https://github.com/linuxserver/docker-smokeping 

3.3 使用如下bash脚本构建ECR 镜像,更新参数以后直接执行即可。

#!/bin/bash
set -e

# 默认参数
ECR_ACCOUNT="<account-id>"
ECR_REGION="<region>"
ECR_REPO_NAME="<repo name>"
TAG="latest"
DOCKER_DIR="/xxxx/docker-smokeping"

# 构建完整的 ECR 仓库 URL
ECR_URL="${ECR_ACCOUNT}.dkr.ecr.${ECR_REGION}.amazonaws.com.cn"
ECR_REPO="${ECR_URL}/${ECR_REPO_NAME}"
FULL_IMAGE_NAME="${ECR_REPO}:${TAG}"

echo "===== SmokePing Docker 构建和推送脚本 ====="
echo "ECR 账号: $ECR_ACCOUNT"
echo "ECR 区域: $ECR_REGION"
echo "ECR URL: $ECR_URL"
echo "仓库名称: $ECR_REPO_NAME"
echo "镜像标签: $TAG"
echo "目标镜像: $FULL_IMAGE_NAME"

# 进入 docker-smokeping 目录
cd "$DOCKER_DIR"

# 构建 Docker 镜像
echo "正在构建 Docker 镜像..."
docker build \
  --no-cache \
  --pull \
  -t "$FULL_IMAGE_NAME" .

# 登录到 ECR
echo "正在登录到 ECR..."
aws ecr get-login-password --region $ECR_REGION | docker login --username AWS --password-stdin $ECR_URL

# 检查仓库是否存在,如果不存在则创建
if ! aws ecr describe-repositories --repository-names $ECR_REPO_NAME --region $ECR_REGION &> /dev/null; then
    echo "创建 ECR 仓库 $ECR_REPO_NAME..."
    aws ecr create-repository --repository-name $ECR_REPO_NAME --region $ECR_REGION
fi

# 推送镜像到 ECR
echo "正在推送镜像到 ECR..."
docker push "$FULL_IMAGE_NAME"

echo "===== 完成! ====="
echo "镜像已成功构建并推送到: $FULL_IMAGE_NAME"

3.4 Launch一台 Ubuntu 24 EC2 (默认Ubuntu AMI),推荐使用small以上机型。

3.5 附加在步骤2中准备好的key和SG

3.6 Metadata response hop limit需要设置为2

3.7 Launch EC2以后Modify IAM role, 添加准备好的EC2 Role。

3.8 登录EC2, 安装软件

sudo snap install aws-cli --classic
sudo apt update
sudo apt upgrade
sudo apt install docker.io docker-compose

3.9 安装一次smokeping docker,并且copy出配置文件

# 第1步:将当前用户添加到 docker 组(执行后需要重新登录或运行 newgrp docker)
sudo usermod -aG docker $USER
newgrp docker

# 第2步:设置环境变量
export AWS_ACCOUNT_ID="<account-id>"
export AWS_REGION="<region>"
export REPO_NAME="<repo_name>"
export ECR_REGISTRY="${AWS_ACCOUNT_ID}.dkr.ecr.${AWS_REGION}.amazonaws.com.cn"
export IMAGE_TAG="latest"

# 第3步:ECR登录
aws ecr get-login-password --region ${AWS_REGION} | docker login --username AWS --password-stdin ${ECR_REGISTRY}

# 第4步:拉取和标记镜像
docker pull ${ECR_REGISTRY}/${REPO_NAME}:${IMAGE_TAG}
docker tag ${ECR_REGISTRY}/${REPO_NAME}:${IMAGE_TAG} smokeping:${IMAGE_TAG}

# 第5步:首次运行容器
docker run --name smokeping -d --rm -p 8888:80 -e TZ=Asia/Shanghai smokeping:${IMAGE_TAG}

# 第6步:准备数据目录
sudo mkdir -p /data/smokeping
sudo chown -R $USER:$USER /data/smokeping

# 第7步:复制初始配置文件到EC2文件系统中
docker cp smokeping:/data/ /data/smokeping/
docker cp smokeping:/config/ /data/smokeping/

# 第8步:停止临时容器
docker stop smokeping

# 第9步:尝试挂载本地文件,启动smokeping
docker run --name smokeping -d \
    --restart unless-stopped \
    -p 8888:80 \
    -e TZ=Asia/Shanghai \
    -v ~/smokeping/data:/data \
    -v ~/smokeping/config:/config \
    smokeping:${IMAGE_TAG}

3.10 到这里安装工作就完成了。我们来看一下/data/smokeping的目录结构:

smokeping/
├── config/           # 配置文件目录
│   ├── Alerts       # 告警配置文件,定义告警规则和触发条件
│   ├── Database     # 数据库配置文件,定义 RRD 数据库存储参数
│   ├── General      # 通用配置文件,包含基本设置如所有者信息、网站标题等
│   ├── Presentation # 展示配置文件,定义网页显示相关参数
│   ├── Probes      # 探测器配置文件,定义不同类型的监控探测方式
│   ├── Slaves      # 从节点配置文件,用于分布式监控设置
│   └── Targets     # 监控目标配置文件,定义要监控的主机和服务
└── data/            # 数据存储目录
    ├── DNS/         # DNS监控相关的数据目录
    ├── DNSProbes/   # DNS探测器的数据目录

3.11 其中Targets, Alerts是最重要的。其他的内容可以保持默认。现在我们需要自己替换EC2里/data/smokeping/config里面的内容,自定义需要监控的内容。让我们做一个属于自己的监控目标,例如:

*** Targets ***

probe = FPing

menu = Top
title = AWS China Network Latency
remark = AWS中国区网络延迟监控

+ Console
menu = 控制台
title = AWS控制台监控
remark = AWS中国区控制台访问监控

++ BeijingConsole
menu = 北京控制台
title = AWS北京区控制台
host = console.amazonaws.cn

++ NingxiaConsole
menu = 宁夏控制台
title = AWS宁夏区控制台
host = cn-northwest-1.console.amazonaws.cn

+ Storage
menu = 存储服务
title = AWS存储服务监控
remark = AWS中国区存储服务监控

probe = TCPPing

++ BeijingS3
menu = 北京S3
title = AWS北京区S3
host = s3.cn-north-1.amazonaws.com.cn
port = 443

++ NingxiaS3
menu = 宁夏S3
title = AWS宁夏区S3
host = s3.cn-northwest-1.amazonaws.com.cn
port = 443

+ DNS
menu = DNS服务
title = AWS DNS服务监控
remark = AWS中国区DNS服务器监控

++ DNS_115
menu = DNS-115
title = AWS DNS Server 115
host = ns-intl-115.awsdns-cn-07.com
port = 53

++ DNS_1457
menu = DNS-1457
title = AWS DNS Server 1457
host = ns-1457.awsdns-cn-27.net
port = 53

3.12 新增一个docker-compose配置

cd /data/smokeping/
cat > docker-compose.yml << 'EOF'
version: '3'

services:
  smokeping:
    container_name: smokeping
    image: smokeping
    ports:
      - "8888:80"
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Asia/Shanghai
    volumes:
      - /data/smokeping/data:/data
      - /data/smokeping/config:/config
    restart: unless-stopped
EOF 

3.13 使用docker compose启动docker

docker stop smokeping
docker remove smokeping
cd /data/smokeping/
docker-compose up -d

4.    使用smokeping

4.1 到这里我们就用可以http:<EC2-IP>:8888访问smokeping 网页端了, 由于默认probe间隔是300s,所以要等5分钟以上才会有监控数据。

4.2 如果需要更换端口可以修改/data/smokeping/docker-compose.yml

4.3 接下来就需要根据自己的需求定义监控目标,参考9的内容和官方文档,在EC2 里修改/data/smokeping/config/下面的配置,然后docker-compose restart即可。

4.4 历史监控数据是保留在/data/smokeping/data中。修改配置或者更新image不会导致数据丢失,数据是通过rdd文件保存在/data/smokeping/data/”一级目录名字+“/”二级目录名字++”/保存的,如:

├── data
│   ├── Console
│   │   ├── BeijingConsole.rrd
│   │   └── NingxiaConsole.rrd

4.5 如需看历史数据,或者某个时间段的监控,可以点击对应的图标,进入详细监控页面:

4.6 从这一层页面再点击某个监控图,就可以使用自定义的时间段去检查监控。可以通过在图形上拖选一个时间段,或者指定time range来查看特定时间段的监控。

5. 设置告警

5.1 在/data/smokeping/config/Alerts里面定义alert类型,和通知方式:

  • 有SMTP的环境可以使用配置conf,然后to可以是收告警的邮箱。
  • 比如:to = infra-ops@compay.xy
  • 如果是内网环境,可以通过触发一个脚本,脚本里面去call lambda或者SNS服务
  • 如果需要自己定义alert类型,可以参考官方文档
*** Alerts ***
to = |/config/alertsns.py
from = smokealert@company.xy

+someloss
type = loss
# in percent
pattern = >0%,*12*,>0%,*12*,>0%
comment = loss 3 times  in a row

+hostdown
type = loss
# in percent
pattern = >60%
edgetrigger = yes
comment = Massive loss for 5 mins

5.2 在config/Targets里的目录级别或者host级别配置alert。示例如下:这样会对Demo_Monitor这层下面所有的target都开启someloss和hostdown两个类型的alerts。

+ Demo_Monitor
menu = Monitor Demo (Demo using fake IP)
title = Monitor Demo (Demo using fake IP)
alerts = someloss,hostdown
#这样就会在这个1级目录下面所有监控项开启两种监控

#这样就会在这个1级目录下面所有监控项开启两种监控

5.3 SNS 告警脚本示例:

#!/usr/bin/env python3

# 导入必要的库
import sys          # 用于处理命令行参数
import time        # 用于时间戳生成
import boto3       # AWS SDK for Python
import requests    # 用于发送 HTTP 请求
import json        # 用于 JSON 数据处理
from datetime import datetime  # 用于日期时间处理

def get_imdsv2_token():
    """
    获取 EC2 实例元数据服务 V2 版本的 token
    这是 AWS 推荐的安全实践,用于防止 SSRF 攻击
    
    Returns:
        str: IMDSv2 token,用于后续请求
    """
    token_url = "http://169.254.169.254/latest/api/token"
    headers = {
        "X-aws-ec2-metadata-token-ttl-seconds": "21600"  
    }
    token = requests.put(token_url, headers=headers).text
    return token

def get_credentials():
    """
    从 EC2 实例元数据服务获取临时安全凭证
    
    Returns:
        dict: 包含 AccessKeyId, SecretAccessKey 和 Token 的凭证信息
    """
    # 首先获取 IMDSv2 token
    token = get_imdsv2_token()
    headers = {
        "X-aws-ec2-metadata-token": token
    }
    
    # 获取 IAM 角色名称
    role_name_url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
    role_name = requests.get(role_name_url, headers=headers).text
    
    # 使用角色名称获取临时凭证
    credentials_url = f"http://169.254.169.254/latest/meta-data/iam/security-credentials/{role_name}"
    credentials = requests.get(credentials_url, headers=headers).json()
    return credentials

def send_sns(topic_arn, message):
    """
    发送消息到 AWS SNS 主题
    
    Args:
        topic_arn (str): SNS 主题的 ARN
        message (str): 要发送的消息内容
    
    Returns:
        dict: SNS 发布响应
        None: 发送失败时返回
    """
    # 获取临时凭证
    credentials = get_credentials()
    
    # 初始化 SNS 客户端
    sns = boto3.client(
        'sns',
        region_name='cn-north-1',  # AWS 中国北京区域
        aws_access_key_id=credentials['AccessKeyId'],
        aws_secret_access_key=credentials['SecretAccessKey'],
        aws_session_token=credentials['Token']
    )

    try:
        # 发布消息到 SNS 主题
        response = sns.publish(
            TopicArn=topic_arn,
            Message=message
        )
        print(f"Message published successfully: {response['MessageId']}")
        return response
    except Exception as e:
        print(f"Failed to publish message: {str(e)}")
        return None

def main():
    """
    主函数:处理命令行参数并发送告警
    命令行参数格式:
    alertname target losspattern rtt hostname
    """
    # 验证命令行参数数量
    if len(sys.argv) != 6:
        print("Usage: {} alertname target losspattern rtt hostname".format(sys.argv[0]))
        sys.exit(1)

    # 解析命令行参数
    alertname = sys.argv[1]    # 告警名称
    target = sys.argv[2]       # 监控目标
    losspattern = sys.argv[3]  # 丢包模式
    rtt = sys.argv[4]          # 往返时间
    hostname = sys.argv[5]      # 主机名

    # 生成当前时间戳并记录日志
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    log_message = f"""
{current_time}: Received parameters:
alertname: {alertname}
target: {target}
losspattern: {losspattern}
rtt: {rtt}
hostname: {hostname}
    """
    print(log_message)

    # 构建告警消息(管道分隔格式)
    alert_message = f"SMOKEPING_ALERT|{int(time.time())}|{alertname}|{target}|{losspattern}|{rtt}|{hostname}"
    print(alert_message)

    # 构建格式化的 SNS 消息
    sns_message = f"""
SmokePing Alert Details:
Alert Name: {alertname}
Target: {target}
Loss Pattern: {losspattern}
RTT: {rtt}
Hostname: {hostname}
Time: {current_time}
    """

    # 发送到 SNS 主题
    # 注意:需要替换实际的 AWS 账号和主题名
    topic_arn = "arn:aws-cn:sns:cn-north-1:<account>:<topic>"
    send_sns(topic_arn, sns_message)

if __name__ == "__main__":
    main()

5.4 如果需要使用alert SNS功能,还需要检查:

  • 在Target里定义哪些目标需要触发alert。(步骤2);
  • EC2必须能通过公网或者VPC endpoint访问SNS;
  • 这里SNS也可以换成其他的API比如发送短信的第三方API,需要对python脚本做一些修改。
  • SNS告警示例如下图:

6.结语

在本文中,我们详细介绍了如何在亚马逊云科技上部署开源软件SmokePing 网络监控系统。这个方案不仅实现了基础的网络性能监控,还包含了告警功能的扩展实现。本方案适合没有现有网络监控平台可用的客户,可以快速构建一个轻量化的,针对一些关键服务,比如DX的底层网络,或者某些外部依赖服务的监控及告警平台。

*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。

本篇作者

史梦晨

西云数据技术客户经理,为亚马逊云科技中国区客户提供企业级架构和技术支持。拥有10多年网络架构设计、测试和运维的经验,曾在欧洲运维跨国大规模数据中心以及欧洲高级网络测试中心(EANTC)任职开展前沿网络测试项目。