prometheus监控、告警与存储

一、kube-state-metrics

1.1 kube-state-metrics介绍

github地址:https://github.com/kubernetes/kube-state-metrics

镜像地址:https://hub.docker.com/r/bitnami/kube-state-metrics

博客介绍:https://xie.infoq.cn/article/9e1fff6306649e65480a96bb1

kube-state-metrics是通过监听API Server生成有关资源对象的状态指标,比如Deployment、Node、Pod,需要注意的是kube-state-metrics只是简单的提供一个metrics数据,并不会存储这些指标数据,所以我们可以使用Prometheus来抓取这些数据然后存储,主要关注的是业务相关的一些元数据,比如Deployment、Pod、副本状态等,调度了多少个replicas?现在可用的有几个?多少个Pod是running/stopped/terminated状态?Pod重启了多少次?目前由多少job在运行中

1.2 部署kube-state-metrics

  1. 编写基于deploy控制器的yaml文件
  2. 编写svc的yaml文件,端口暴露为NodePort
  3. 部署

1.3 验证数据

1647239359506.png
1647239341078.png

1.4 prometheus数据采集

    - job_name: 'kube-state-metrics'
      static_configs:
        - targets: ["IP:PORT"]

k8s配置文件configmap缩进格式

1.5 验证prometheus状态

1647240390922.png

1.6 grafana导入模板

  1. 13824
  2. 14518

因为版本不同,可根据对应版本进行设置

Dashboard模板网址:https://grafana.com/grafana/dashboards/

二、监控示例

基于第三方exporter实现对目标服务的监控

2.1 tomcat

  • 构建镜像

github地址:https://github.com/nlighten/tomcat_exporter

根据tomcat官方镜像添加jar包

ADD metrics.war /data/tomcat/webapps
ADD simpleclient-0.8.0.jar  /usr/local/tomcat/lib/
ADD simpleclient_common-0.8.0.jar /usr/local/tomcat/lib/
ADD simpleclient_hotspot-0.8.0.jar /usr/local/tomcat/lib/
ADD simpleclient_servlet-0.8.0.jar /usr/local/tomcat/lib/
ADD tomcat_exporter_client-0.0.12.jar /usr/local/tomcat/lib/
  • prometheus采集
    - job_name: 'kube-state-metrics'
      static_configs:
        - targets: ["IP:PORT"]

k8s配置文件configmap缩进格式

  • prometheus验证
1647244807763.png
  • grafana导入模板

github地址:https://github.com/nlighten/tomcat_exporter/blob/master/dashboard/example.json

下载这个json文件导入grafana即可

2.2 redis

通过redis_exporter监控redis服务装态

github网址:https://github.com/oliver006/redis_exporter

  • 部署redis

一个pod两个容器,redis和redis-exporter

  • prometheus采集
    - job_name: 'redis-metrics'
      static_configs:
        - targets: ["IP:PORT"]

k8s配置文件configmap缩进格式

1647308852240.png
  • grafana导入模板
  1. 14615
  2. 11692

2.3 mysql

通过mysqld_exporter监控MySQL服务的运行状态

github网址:https://github.com/prometheus/mysqld_exporter

  • 安装mariadb-server
apt install -y mariadb
  • 修改配置文件/etc/mysql/mariadb.conf.d/50-server.cnf监听地址,修改为0.0.0.0

bind-address = 0.0.0.0

重启mariadb

  • 创建mysql_exporter用户
create user 'mysql_exporter'@'localhost' identified by 'password';
  • 测试用户名密码连接
mysql -umysql_exporter -hlocalhost -ppassword
  • 下载mysql_exporter
# 下载
wget https://github.com/prometheus/mysqld_exporter/releases/download/v0.13.0/mysqld_exporter-0.13.0.linux-amd64.tar.gz
# 解压
tar xvf mysqld_exporter-0.13.0.linux-amd64.tar.gz
# 查看启动参数
./mysqld_exporter --help
  • 创建免密登陆文件/root/.my.cnf
cat >> /root/.my.cnf <<EOF
[client]
user=mysql_exporter
password=123321
EOF
  • 创建mysqld_service文件并启动
# 创建软链接
ln -sv /apps/mysqld_exporter-0.13.0.linux-amd64 /apps/mysqld_exporter

# 创建service文件
cat >> /etc/systemd/system/mysqld_exporter.service <<EOF
[Unit]
Description=Prometheus Mysql Exporter
After=network.target

[Service]
ExecStart=/apps/mysqld_exporter/mysqld_exporter --config.my-cnf=/root/.my.cnf

[Install]
WantedBy=multi-user.target
EOF

# 重新加载配置
systemctl daemon-reload

# 启动mysqld_exporter
systemctl start mysqld_exporter.service
  • 验证metrics
1647316276383.png
  • 验证prometheus
1647316313220.png
  • grafana导入模板
  1. 13106
  2. 11323

2.4 haproxy

通过haproxy_exporter监控haproxy

github网址:https://github.com/prometheus/haproxy_exporter

  • 安装haproxy
apt install -y haproxy
  • 修改配置文件,监听一个服务
listen SERVICE
  bind BIND_IP:PORT
  mode tcp
  server SERVER_NAME LISTEN_IP:PORT check inter 3s fall 3 rise 3

确保sock文件是admin用户(level后边的admin)

    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
  • 重启haproxy
systemctl restart haproxy

检查监听端口是否正常

  • 下载haproxy_exporter
# 下载
wget https://github.com/prometheus/haproxy_exporter/releases/download/v0.13.0/haproxy_exporter-0.13.0.linux-amd64.tar.gz
# 解压
tar xvf haproxy_exporter-0.13.0.linux-amd64.tar.gz
# 创建软链接
ln -sv /apps/haproxy_exporter-0.13.0.linux-amd64 /apps/haproxy_exporter
  • 配置文件启动haproxy_expoter
./haproxy_exporter --haproxy.scrape-uri=unix:/run/haproxy/admin.sock

端口默认监听9101

  • 配置haproxy状态页
listen stats
  bind :PORT
  stats enable
  stats uri /haproxy-status
  stats realm HAProxy\ Stats\ Page
  stats auth haadmin:123456
  stats auth admin:123456

编辑/etc/haproxy/haproxy.cfg添加如上配置内容

  • 状态页启动haproxy
./haproxy_exporter --haproxy.scrape-uri="http://admin:123456@127.0.0.1:PORT/haproxy-status;csv"

需要指定用户名密码,csv是指定以csv形式展示

  • 验证exporter
1647397779547.png
  • prometheus数据采集
  - job_name: "haproxy-exporter"
    static_configs:
      - targets: ["127.0.0.1:9101"]

虚拟机prometheus.yml配置缩进格式

./promtool check config prometheus.yml # 修改后检查配置文件是否正确

  • 重启prometheus
systemctl restart prometheus.service
  • 验证prometheus
1647398984397.png
  • grafana导入模板
  1. 367
  2. 2428

2.5 nginx

通过nginx_exporter监控ngix

github模块依赖网址:https://github.com/vozlt/nginx-module-vts

  • 安装nginx
# 克隆依赖模块
git clone https://github.com/vozlt/nginx-module-vts.git
# 下载nginx源码
wget http://nginx.org/download/nginx-1.20.2.tar.gz
# 解压
tar xvf nginx-1.20.2.tar.gz
# 安装nginx编译依赖包
apt install -y libgd-dev libgeoip-dev libpcre3 libpcre3-dev libssl-dev gcc make
# 编译nginx
cd nginx-1.20.2
./configure --prefix=/apps/nginx \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_realip_module \
--with-http_stub_status_module  \
--with-http_gzip_static_module \
--with-pcre \
--with-file-aio \
--with-stream \
--with-stream_ssl_module \
--with-stream_realip_module \
--add-module=/usr/local/src/nginx-module-vts/
# make
make
# make install
make install
  • 修改配置文件
http {
    vhost_traffic_status_zone;

    ...

    server {

        ...

        location /status {
            vhost_traffic_status_display;
            vhost_traffic_status_display_format html;
        }
    }
}

参考https://github.com/vozlt/nginx-module-vts添加配置

  • 启动nginx
# 检查配置文件
/apps/nginx/sbin/nginx -t
# 启动nginx
/apps/nginx/sbin/nginx
  • 配置nginx的upstream
    # http模块里边,server模块同级
    upstream SERVICE {
      server IP:PORT;
    }
        # server模块里边,转发首页
        location / {
            #root   html;
            #index  index.html index.htm;
            proxy_pass http://SERVICE;
        }
  • 检查状态页
1647401678523.png
1647401779003.png

可以以json模式显示数据

  • 安装nginx_exporter
# 下载
wget https://github.com/hnlq715/nginx-vts-exporter/releases/download/v0.10.3/nginx-vts-exporter-0.10.3.linux-amd64.tar.gz
# 解压
tar xvf nginx-vts-exporter-0.10.3.linux-amd64.tar.gz
# 创建软链接
ln -sv /apps/nginx-vts-exporter-0.10.3.linux-amd64 nginx-vts-exporter
# 启动nginx_exporter
./nginx-vts-exporter  -nginx.scrape_uri http://IP/status/format/json

默认监听端口号9913

  • 验证数据
1647402416180.png
  • prometheus数据采集
  - job_name: "nginx-exporter"
    static_configs:
      - targets: ["127.0.0.1:9913"]

虚拟机prometheus.yml配置文件缩进格式

  • prometheus验证数据
1647402636512.png
  • grafana导入模板
  1. 2949

2.6 blockbox监控url

官方地址:https://prometheus.io/download/#blackbox_exporter

blockbox_exporter是prometheus官方提供的一个exporter,可以通过http,https,dns,tcp和icmp对被监控节点进行监控和数据采集

http/https:url/api可用性检测

TCP:端口监听检测

ICMP:主机存活检测

DNS:域名解析

  • 部署blackbox_exporter
# 下载
wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.19.0/blackbox_exporter-0.19.0.linux-amd64.tar.gz
# 解压
tar xvf blackbox_exporter-0.19.0.linux-amd64.tar.gz
# 创建软链接
ln -sv /apps/blackbox_exporter-0.19.0.linux-amd64 blackbox_exporter
  • 创建blackbox-exporter.service文件
cat > /etc/systemd/system/blackbox-exporter.service <<EOF
[Unit]
Description=Prometheus Blackbox Exporter
Documentation=https://prometheus.io/download/#blackbox_exporter

After=network.target

[Service]
Type=simple
User=root
Group=root
Restart=on-failure
ExecStart=/apps/blackbox_exporter/blackbox_exporter --config.file=/apps/blackbox_exporter/blackbox.yml     --web.listen-address=:9115

[Install]
WantedBy=multi-user.target
EOF
  • 启动blackbox_exporter
systemctl daemon-reload
systemctl restart blackbox-exporter
  • 验证数据
1647413347284.png

默认监听端口9115

  • blackbox exporter监控url

prometheus数据采集

  - job_name: "http_status"
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets: ["domainname1","domainname2"]
        labels:
          instance: http_status
          group: web
    relabel_configs:
      - source_labels: [__address__] # relbel通过将__address__(当前目标地址)写入__param_tartget标签来创建一个label
        target_label: __param_target # 监控目标domainname,作为__address__的value
      - source_labels: [__param_target] # 监控目标
        target_label: url # 将监控目标与url创建一个label
      - target_label: __address__
        replacement: BLACKBOX_EXPORTER:PORT

虚拟机prometheus.yml配置文件缩进格式

  • 验证prometheus状态
1647415432973.png
  • 查看blackbox页面
1647415523065.png
  • blockbox_exporter监控icmp

prometheus数据采集

  - job_name: "ping_status"
    metrics_path: /probe
    params:
      module: [icmp]
    static_configs:
      - targets: ["IP1","IP2"]
        labels:
          instance: 'ping_status'
          group: 'icmp'
    relabel_configs:
      - source_labels: [__address__] 
        target_label: __param_target 
      - source_labels: [__param_target]
        target_label: ip # 将ip与__param_target创建一个label
      - target_label: __address__
        replacement: BLACKBOX_EXPORTER:PORT

虚拟机prometheus.yml配置文件缩进格式

  • 验证prometheus状态
1647417886518.png
  • blackbox_exporter监控端口

prometheus数据采集

# 端口监控
  - job_name: "port_status"
    metrics_path: /probe
    params:
      module: [tcp_connect]
    static_configs:
      - targets: ["IP:PORT","IP:PORT"]
        labels:
          instance: 'port_status'
          group: 'port'
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target 
      - source_labels: [__param_target] 
        target_label: ip
      - target_label: __address__
        replacement: BLACKBOX_EXPORTER:PORT
  • 验证prometheus状态
1647418487723.png
  • grafana导入模板
  1. 9965
  2. 13587

三、告警

3.1 Alertmanager

prometheus-->触发阈值-->超出持续时间-->alertmanager-->分组|抑制|静默-->媒体类型-->邮件|钉钉|微信等

prometheus server通过配置监控规则,实现告警发送,然后把告警push给Alertmanager,匹配Alertmanager配置的Router,以WeChat、Email或Webhook方式发送给对应的Receiver

分组(group):将类似性质的告警合并为单个通知,比如网络通知、主机通知、服务通知

静默(silences):是一种简单的特定时间静音的机制,例如:服务器要升级维护可以先设置这个时间段告警静默

抑制(inhibition):当告警发出后,停止重复发送由此告警引发的其他告警;即合并由一个故障引起的多个告警事件,可以消除冗余告警

  • 安装alertmanager
# 下载
wget https://github.com/prometheus/alertmanager/releases/download/v0.23.0/alertmanager-0.23.0.linux-amd64.tar.gz
# 解压
tar xvf alertmanager-0.23.0.linux-amd64.tar.gz
# 创建软链接
ln -sv /apps/alertmanager-0.23.0.linux-amd64 /apps/alertmanager
  • 创建alertmanager.service文件
cat > /etc/systemd/system/alertmanager.service <<EOF
[Unit]
Description=Prometheus alertmanager
After=network.target

[Service]
ExecStart=/apps/alertmanager/alertmamager --config.file="/apps/alertmanager/alertmanager.yml"

[Install]
WantedBy=multi-user.target
EOF
  • 启动alertmanager
systemctl start alertmanager.service

默认监听端口9093,9094

监控配置官方网址:https://prometheus.io/docs/alerting/latest/configuration/

  • 验证alertmanager状态
1647481599806.png

3.2 邮件

官方网址:https://prometheus.io/docs/alerting/latest/configuration/#email_config

  • 配置文件介绍

alertmanager.yml配置文件

global:
  resolve_timeout: 5m # alertmanager在持续多久没有收到新告警后标记为resolved
  smtp_from:  # 发件人邮箱地址
  smtp_smarthost:  # 邮箱smtp地址
  smtp_auth_username:  # 发件人的登陆用户名,默认和发件人地址一致
  smtp_auth_password:  # 发件人的登陆密码,有时候是授权码
  smtp_hello:
  smtp_require_tls:  # 是否需要tls协议。默认是true
  
route:
  group_by: [alertname] # 通过alertname的值对告警进行分类
  group_wait: 10s # 一组告警第一次发送之前等待的时延,即产生告警10s将组内新产生的消息合并发送,通常是0s~几分钟(默认是30s)
  group_interval: 2m # 一组已发送过初始告警通知的告警,接收到新告警后,下次发送通知前等待时延,通常是5m或更久(默认是5m)
  repeat_interval: 5m # 一组已经发送过通知的告警,重复发送告警的间隔,通常设置为3h或者更久(默认是4h)
  receiver: 'default-receiver' # 设置告警接收人

receivers:
- name: 'default-receiver'
  email_configs:
  - to: 'EMAIL@DOMAIN.com'
    send_resolved: true # 发送恢复告警通知
    
inhibit_rules: # 抑制规则
  - source_match:  # 源匹配级别,当匹配成功发出通知,其他级别产生告警将被抑制
      severity: 'critical' # 告警时间级别(告警级别根据规则自定义)
    target_match: 
      severity: 'warning' # 匹配目标成功后,新产生的目标告警为'warning'将被抑制
    equal: ['alertname','dev','instance'] # 基于这些标签抑制匹配告警的级别
# 时间示例解析
# group_wait: 10s # 第一次产生告警,等待10s,组内有新增告警,一起发出,没有则单独发出
# group_interval: 2m # 第二次产生告警,先等待2m,2m后没有恢复就进入repeat_interval
# repeat_interval: 5m # 在第二次告警时延过后,再等待5m,5m后没有恢复,就发送第二次告警

如上配置,如果告警没有恢复,第二次告警会等待2m+5m,即7分钟后发出

  • 配置告警规则
groups:
  - name: alertmanager_pod.rules
    rules:
    - alert: Pod_all_cpu_usage
      expr: (sum by(name)(rate(container_cpu_usage_seconds_total{image!=""}[5m]))*100) > 1
      for: 2m
      labels:
        serverity: critical
        service: pods
      annotations:
        description: 容器 {{ $labels.name }} CPU 资源利用率大于 10% , (current value is {{ $value }})
        summary: Dev CPU 负载告警

    - alert: Pod_all_memory_usage
      expr: sort_desc(avg by(name)(irate(node_memory_MemFree_bytes {name!=""}[5m]))) > 2147483648 # 内存大于2G
      for: 2m
      labels:
        severity: critical
      annotations:
        description: 容器 {{ $labels.name }} Memory 资源利用大于 2G , (current value is {{ $value }})
        summary: Dev Memory 负载告警

    - alert: Pod_all_network_receive_usage
      expr: sum by(name)(irate(container_network_reveive_bytes_total{container_name="POD"}[1m])) > 52428800 # 大于50M
      for: 2m
      labels:
        severity: critical
      annotations:
        description: 容器 {{ $labels.name }} network_receive 资源利用大于 50M , (current value is {{ $value }})

    - alert: node内存可用大小
      expr: node_memory_MemFree_bytes < 4294967296 # 内存小于4G
      for: 2m
      labels:
        severity: critical
      annotations:
        description: node可用内存小于4G

在/apps/prometheus/目录下创建rules目录,创建pods_rule.yaml文件,内容如上

注意缩进格式,如果文件格式有误,重启prometheus的时候,promethues会一直起不来,可以先用promtool检查配置文件格式,因为加载告警配置的时候,引入了这个文件,所以在检查promethues.yml文件的时候也会检查自定义的pods_rule.yaml文件

  • promethues加载告警配置
# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          - IP:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  - "/apps/prometheus/rules/pods_rule.yaml"

注:如果修改rule_files中的内容,需要先重启prometheus,加载修改后的配置,然后修改alertmanager,不然修改后的告警内容不会生效

  • 重启prometheus
systemctl restart prometheus.service
  • 验证prometheus状态
1647485649096.png

在prometheus页面,点击Alerts查看告警状态,当前为PENDING,说明已经检测到告警,还没满足发邮件的时间规则

1647485888388.png

FIRING证明告警已成功,此时应该已经收到邮件

  • 查看alertmanager告警
1647486260854.png
  • 查看告警邮件
1647485953827.png

点击Source链接,跳转的是主机名加prometheus-server的端口,无法解析就跳转不过去

  • 使用amtool查看告警
./amtool alert --alertmanager.url=http://IP:9093
1647485846885.png

3.3 钉钉

  • 钉钉添加机器人

创建机器人官方网址:https://open.dingtalk.com/document/robots/custom-robot-access

1647503102681.png
1647503128995.png
1647503182899.png
1647503236505.png
1647503444049.png
  • 发送消息脚本
vim /data/scripts/dingding-keywords.sh
MESSAGE=$1

/usr/bin/curl -X POST 'https://oapi.dingtalk.com/robot/send?access_token=TOKEN'\
-H 'Content-Type: application/json' \
-d '{"msgtype": "text",
     "text": {
        "content": "${MESSAGE}"
     }
    }'
  • 测试发送消息
1647506928206.png

发送的消息内容中,必须包含自定义的关键字,不然发送消息会失败,发送脚本发送消息成功后,群里会收到

  • 部署webhook-dingtalk
# 下载
wget https://github.com/timonwong/prometheus-webhook-dingtalk/releases/download/v1.4.0/prometheus-webhook-dingtalk-1.4.0.linux-amd64.tar.gz
# 解压
tar xvf prometheus-webhook-dingtalk-1.4.0.linux-amd64.tar.gz
# 创建软链接
ln -sv /apps/prometheus-webhook-dingtalk-1.4.0.linux-amd64 prometheus-webhook-dingtalk

下载的webhook-dingtalk版本最好跟这个保持一直,新版本有些地方不兼容

  • 启动webhook-dingtalk
cd /apps/prometheus-webhook-dingtalk
./prometheus-webhook-dingtalk --web.listen-address="0.0.0.0:8060" --ding.profile="KEYWORD=https://oapi.dingtalk.com/robot/send?access_token=TOKEN" 

指定监听端口8060

KEYWORD必须是创建机器人时的自定义关键字,不然告警发布出去,会报错

  • 配置alertmanager
- name: 'dingding'
  webhook_configs:
  - url: 'http://IP:8060/dingtalk/alertsen/send'
    send_resolved: true
  • 重启alertmanager
systemctl restart alertmanager.service

prometheus加载的alertmanager告警规则里边,也必须含有自定义关键字才可以告警出来,不然也会报错"keywords not in content",自定义关键字在key还是value中,都可以

  • 验证发送告警信息
1647510006990.png
  • 查看dingtalk日志
1647510136964.png

返回码为200

  • 查看钉钉消息
1647510179108.png
  • 钉钉标签签名python脚本

dingtalk签名脚本官方网址:https://open.dingtalk.com/document/robots/customize-robot-security-settings

#python 3.8
import time
import hmac
import hashlib
import base64
import urllib.parse

timestamp = str(round(time.time() * 1000))
secret = 'this is secret'
secret_enc = secret.encode('utf-8')
string_to_sign = '{}\n{}'.format(timestamp, secret)
string_to_sign_enc = string_to_sign.encode('utf-8')
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
print(timestamp)
print(sign)

注意python版本,按照示例指定版本,执行用"/usr/bin/python3.8 脚本名字"启动

  • 钉钉发送消息shell脚本
#!/bin/bash

source /etc/profile
MESSAGE=$1
secret='SECxxxxxx'
getkey=$(/usr/bin/python3.8 SCRIPT)
timestamp=${getkey:0:13}
sign=$(echo "${getkey:13:100}"|tr -d '\n')
DateStamp=$(date -d @${getkey:0:10} "+%F %H:%m%s")

/usr/bin/curl -X POST "https://oapi.dingtalk.com/robot/send?access_token=xxxxxx&timestamp=${timestamp}&sign=${sign}" \
-H 'Content-Type: application/json' \
-d '{"msgtype":"text",
     "text":{
       "content": "'${MESSAGE}'"
     }
   }'
  • alertmanager发送告警

prometheus-webhook-dingtalk配置文件

targets:
  webhook1:
    url: https://oapi.dingtalk.com/robot/send?access_token=xxxxxx
    # secret for signature
    secret: SECxxxxxx

指定token和secret

alertmanager配置文件

- name: 'dingding'
  webhook_configs:
  - url: 'http://IP:8060/dingtalk/webhook1/send' # webhook1对应prometheus-webhook-dingtalk配置文件中的名字
    send_resolved: true
  • 启动prometheus-webhook-dingtalk
./prometheus-webhook-dingtalk --web.listen-address="0.0.0.0:8060" --config.file=config.yml

启动程序和配置文件同路径下可不指定"--config.file"

prometheus配置不需要改动

  • dingtalk日志
1647575452740.png
  • 钉钉
1647575485431.png

3.4 消息分类发送

根据消息中的属性信息设置规则,将消息分类发送,修改alertmanager配置文件

route:
  group_by: [alertname] 
  group_wait: 10s 
  group_interval: 10s 
  repeat_interval: 2m 
  receiver: 'dingding' 
  # 添加路由信息
  routes:
    - receiver: email
      group_wait: 10s
      match_re:
        instance: "IP:PORT" # 匹配成功的信息发邮件出来,其余信息发给钉钉

修改配置文件后,重启alertmanager

  • 验证消息发送

钉钉发送两台主机告警信息

1647590175858.png

邮件发送一台主机告警信息(匹配成功instance,需要包括端口号)

1647590257748.png

3.5 自定义告警模板

  • 告警规则
groups:
- name: 'node running status'
  rules:
  - alert: 'Instance Down'
    expr: 'up == 0'
    for: 5s
    annotations:
      title: 'Instance Down'
      description: "{{ $labels.instance }}down"
    labels:
      robot: 'jcss'
      severity: 'warning'
      owner: 'xxxxxxxxxxx'

- name: 'node memory usage'
  rules:
  - alert: 'memory usage'
    expr: '((node_memory_MemTotal_bytes - node_memory_MemFree_bytes) / node_memory_MemTotal_bytes * 100)> 85'
    for: 5s
    annotations:
      title: 'Mem'
      description: '{{ $labels.instance }} Memusage {{ $value }}'
    labels: 
      robot: 'jcss'
      ops: 'true'
      severity: 'warning'
      owner: "xxxxxxxxxxx"

引用网址:https://www.cnblogs.com/liy36/p/15494040.html

  • 自定义模板(wechat)
{{ define "wechat.default.message" }}
{{ range $i, $alert :=.Alerts }}
=======alertmanager监控告警======
告警状态: {{   .Status }}
告警级别: {{ $alert.Labels.severity }}
告警类型: {{ $alert.Labels.alertname }}
告警应用: {{ $alert.Annotations.summary }}
告警主机: {{ $alert.Labels.instance }}
告警主题: {{ $alert.Annotations.summary }}
告警阀值: {{ $alert.Annotations.value }}
告警详情: {{ $alert.Annotations.description }}
告警时间: {{ $alert.StartsAt.Format "2006-01-02 15:04:05" }}
================end===============
{{ end }}
{{ end }}
  • 自定义模板(dingding)
{{ define "__subject" }}
[{{ .Status | toUpper }}{{ if eq .Status "firing" }}:{{ .Alerts.Firing | len }}{{ end }}]
{{ end }}


{{ define "__alert_list" }}{{ range . }}
---
{{ if .Labels.owner }}@{{ .Labels.owner }}{{ end }}

**告警名称**: {{ index .Annotations "title" }} 

**告警级别**: {{ .Labels.severity }} 

**告警主机**: {{ .Labels.instance }} 

**告警信息**: {{ index .Annotations "description" }}

**告警时间**: {{ dateInZone "2006.01.02 15:04:05" (.StartsAt) "Asia/Shanghai" }}
{{ end }}{{ end }}

{{ define "__resolved_list" }}{{ range . }}
---
{{ if .Labels.owner }}@{{ .Labels.owner }}{{ end }}

**告警名称**: {{ index .Annotations "title" }}

**告警级别**: {{ .Labels.severity }}

**告警主机**: {{ .Labels.instance }}

**告警信息**: {{ index .Annotations "description" }}

**告警时间**: {{ dateInZone "2006.01.02 15:04:05" (.StartsAt) "Asia/Shanghai" }}

**恢复时间**: {{ dateInZone "2006.01.02 15:04:05" (.EndsAt) "Asia/Shanghai" }}
{{ end }}{{ end }}


{{ define "default.title" }}
{{ template "__subject" . }}
{{ end }}

{{ define "default.content" }}
{{ if gt (len .Alerts.Firing) 0 }}
**====侦测到{{ .Alerts.Firing | len  }}个故障====**
{{ template "__alert_list" .Alerts.Firing }}
---
{{ end }}

{{ if gt (len .Alerts.Resolved) 0 }}
**====恢复{{ .Alerts.Resolved | len  }}个故障====**
{{ template "__resolved_list" .Alerts.Resolved }}
{{ end }}
{{ end }}


{{ define "ding.link.title" }}{{ template "default.title" . }}{{ end }}
{{ define "ding.link.content" }}{{ template "default.content" . }}{{ end }}
{{ template "default.title" . }}
{{ template "default.content" . }}

default.yml定义在prometheus-webhook-dingtalk目录下

  • 引用模板

修改alertmanager配置文件,引用模板

template:
  - "/apps/prometheus-webhook-dingtalk/templates/default.templ" # 引用模板

在alertmanager中引用模板,dingtalk的告警时间,alertmanager不识别,加进去"dateInZone"那行alertmanger起不来,去掉才可以

  • dingtalk验证
1647957682230.png

修改prometheus-webhook-dingtalk的config.yml文件,引用模板

templates:
  - /apps/prometheus-webhook-dingtalk/templates/default.templ

这里引用模板文件,可以识别告警时间信息

  • dingtalk验证
1647957619247.png

3.6 告警抑制与静默

  • 告警抑制

基于告警规则,资源使用率超过80%就不再发60%的告警,即60%的表达式触发的告警被抑制了

  - name: alertmanager_node.rules
    rules:
    - alert: 磁盘容量
      expr: 100-(node_filesystem_free_bytes{fstype=~"ext4|xfs"}/node_filesystem_size_bytes {fstype=~"ext4|xfs"}*100) > 80  #磁盘容量利用率大于80%
      for: 2s
      labels:
        severity: critical
      annotations:
        summary: "{{$labels.mountpoint}} 磁盘分区使用率过高!"
        description: "{{$labels.mountpoint }} 磁盘分区使用大于80%(目前使用:{{$value}}%)"

    - alert: 磁盘容量
      expr: 100-(node_filesystem_free_bytes{fstype=~"ext4|xfs"}/node_filesystem_size_bytes {fstype=~"ext4|xfs"}*100) > 60 #磁盘容量利用率大于60%
      for: 2s
      labels:
        severity: warning
      annotations:
        summary: "{{$labels.mountpoint}} 磁盘分区使用率过高!"
        description: "{{$labels.mountpoint }} 磁盘分区使用大于80%(目前使用:{{$value}}%)"
  • 钉钉告警验证
1648125856304.png
  • 钉钉恢复验证
1648125792368.png

告警的时候只有>80%,恢复的时候是两个,>60%和>80%

  • 告警静默

手动静默:先找到要静默的告警事件,然后手动静默指定的事件

1648126136450.png
1648126264683.png
1648126304661.png

查看静默事件

1648126352837.png

点击Expire,静默事件失效,继续发送告警

3.7 Alertmanager高可用

  • 基于负载均衡

alertmanager是http的单次调用,不需要会话保持,所以可以部署多态alertmanager,在前边加上负载均衡器,可以通过vip做成主备或者轮训方式

  • 基于Gossip机制

网址:https://yunlzheng.gitbook.io/prometheus-book/part-ii-prometheus-jin-jie/readmd/alertmanager-high-availability

Gossip机制为多个Alertmanager之间提供了信息传递的机制。确保及时在多个Alertmanager分别接收到相同告警信息的情况下,也只有一个告警通知被发送给Receiver

1648126839049.png

gossip协议: Gossip是分布式系统中被广泛使用的协议,用于实现分布式节点之间的信息交换和状态同步。Gossip协议同步状态类似于流言或者病毒的传播

1648126755103.png
  • 搭建本地集群环境

为了能够让Alertmanager节点之间进行通讯,需要在Alertmanager启动时设置相应的参数。其中主要的参数包括:

--cluster.listen-address string: 当前实例集群服务监听地址

--cluster.peer value: 初始化时关联的其它实例的集群服务地址

1648126992449.png

3.8 PrometheusAlert

github地址:https://github.com/feiyu563/PrometheusAlert

PrometheusAlert是开源的运维告警中心消息转发系统,支持主流的监控系统Prometheus、Zabbix,日志系统Graylog2,Graylog3、数据可视化系统Grafana、SonarQube。阿里云-云监控,以及所有支持WebHook接口的系统发出的预警消息,支持将收到的这些消息发送到钉钉,微信,email,飞书,腾讯短信,腾讯电话,阿里云短信,阿里云电话,华为短信,百度云短信,容联云电话,七陌短信,七陌语音,TeleGram,百度Hi(如流)等。

四、Pushgateway

4.1 pushgateway简介

github地址:https://github.com/prometheus/pushgateway

pushgateway是采用被动推送的方式,而不是类似于prometheus server主动连接exporter获取监控数据,pushgateway可以单独运行在一个节点,然后需要自定义监控脚本把需要监控的数据主动推送给pushgateway的API接口,然后pushgateway再等待prometheus server抓取数据,即pushgateway本身没有任何抓取监控数据的功能,pushgateway只是被动的等待数据从客户端推送过来

--persistence.file="" # 数据保存的文件,默认只保存在内存中

--persistence.interval=5m # 数据持久化的间隔时间

4.2 部署pushgateway

  • 下载并启动
# 下载
wget https://github.com/prometheus/pushgateway/releases/download/v1.4.2/pushgateway-1.4.2.linux-amd64.tar.gz
# 解压
tar xvf pushgateway-1.4.2.linux-amd64.tar.gz
# 创建软链接
ln -sv pushgateway-1.4.2.linux-amd64 pushgateway
# 启动
cd pushgateway
./pushgateway

默认监听端口9091

  • 验证pushgateway页面
1648128403350.png
1648128373299.png

4.3 prometheus采集数据

  - job_name: "pushgateway-monitor"
    scrape_interval: 5s
    static_configs:
      - targets: ["IP:9091"]
    honor_labels: true # 保留抓取数据原标签

配置prometheus.yml文件,重启prometheus

honor_labels控制prometheus如何处理已经存在于抓取数据中的标签与prometheus将附加的服务器端的标签之间的冲突("job"和"instance"标签,手动配置的目标标签以及服务发现生成的标签);如果honor_labels设置为"true",则通过保留已抓取数据的标签值并忽略冲突的服务器端标签,如果设置为"false",则通过将已抓取数据中的冲突标签重命名为"exported_<original-label>"(例如"exporterd_instance","exported_job"),然后附加服务器端标签

  • 验证prometheus页面
1648129230816.png

4.4 推送数据

  • 推送单条数据

要push数据到pushgateway中,可以通过API标准接口来添加,默认URL为:

http://ip:9091/metrics/job/JOBNAME{/LABEL_NAME/LABEL_VALUE}

其中JOBNAME是必填项,为job标签值,后边可以跟任意数量的标签对,一般我们会添加一个instance/INSTANCE_NAME实例名称标签,来方便区分各个指标

# 推送job名称为test_job,key为metrics,值为111
echo "test_job 111" | curl --data-binary @- http://PUSHGATEWAY_IP:9091/metrics/job/test_job
# 推送job名称为test_job,key为metrics,值为111,instance为UPLOAD_IP
echo "test_job 111" | curl --data-binary @- http://PUSHGATEWAY_IP:9091/metrics/job/test_job/instance/UPLOAD_IP

往相同的metrics中push数据,之前的key会被新的key覆盖掉

  • pushgateway数据验证
1648130305374.png
  • 推送多条数据
cat << EOF | curl --data-binary @- http://PUSHGATEWAY_IP:9091/metrics/job/test_job/instance/UPLOAD_IP
#TYPE node_memory_usage gauge
node_memory_usage 4311744512
# TYPE memory_total gauge
node_memory_total 103481868288
EOF
  • pushgateway数据验证
1648472043575.png
  • prometheus验证
1648472296470.png

4.5 自定义收集数据

  • 自定义脚本
#!/bin/bash

total_memory=$(free | awk '/Mem/{print $2}')
used_memory=$(free | awk '/Mem/{print $3}')

job_name="custom_memory_monitor"
instance_name=`ifconfig ens33 | grep -w inet | awk '{print $2}'`
pushgateway_server="http://PUSHGATEWAY_IP:9091/metrics/job"

cat <<EOF | curl --data-binary @- ${pushgateway_server}/${job_name}/instance/${instance_name}
#TYPE node_memory_usage gauge 4G
node_memory_usage 4311744512
# TYPE memory_total gauge 96G
node_memory_total 103481868288
EOF

内存监控脚本,mem_monitor.sh 分别在不通的主机执行脚本,验证指标收集和推送

  • pushgateway验证
1648472928008.png

4.6 删除数据

先对一个组写入多个instance数据

  • pushgateway验证多条数据
1648473362497.png
  • 通过api删除指定组内指定实例的数据
curl -X DELETE http://PUSHGATEWAY_IP:9091/metrics/job/custom_memory_monitor/instance/UPLOAD_IP
  • pushgateway验证删除组内实例
1648473554810.png
  • 通过web界面删除
1648473660135.png

五、联邦集群

一台server,两台联邦,两台node,配置prometheus和node_exporter

  • 分别添加target
  - job_name: "prometheus-node1"
    static_configs:
      - targets: ["PROMETHEUS1:9100"]

promethues联邦二配置同理

  • prometheus验证数据
1648475656342.png

另一个数据同理

  • 配置采集数据prometheus-server
  - job_name: "prometheus-federate-1"
    scrape_interval: 10s
    honor_labels: true
    metrics_path: '/federate'
    params:
      'match[]':
      - '{job="prometheus"}'
      - '{__name__=~"job:.*"}'
      - '{__name__=~"node.*"}'
    static_configs:
      - targets: ["PROMETHEUS1:9090"]

  - job_name: "prometheus-federate-2"
    scrape_interval: 10s
    honor_labels: true
    metrics_path: '/federate'
    params:
      'match[]':
      - '{job="prometheus"}'
      - '{__name__=~"job:.*"}'
      - '{__name__=~"node.*"}'
    static_configs:
      - targets: ["PROMETHEUS2:9090"]
  • prometheus-server验证
1648476234639.png
  • prometheus-server查询数据验证
1648476336110.png

prometheus-node1和prometheus-node2的job被联邦节点收集数据后,又被prometheus-server端收集数据

  • grafana导入模板

模板ID:8919

1648477071218.png

六、Prometheus存储

6.1 本地存储

Prometheus有着非常高效的时间序列数据存储方法,每个采样数据仅仅占用3.5byte左右空间,上百万条时间序列,30s间隔,保留60天,大概200多G空间(引用官方内容)

  • block简介

每个block为一个data目录中以01开头的存储目录

# ll data
drwxr-xr-x 3 root root  4096 Mar 31 12:39 01FZFZSNX1SJFCKQYZAAN2J6AG/ # block
drwxr-xr-x 2 root root  4096 Mar 31 12:39 wal/ # write ahead log

默认情况下,prometheus将采集到的数据存储到本地的TSDB数据库中,路径默认为prometheus安装目录的data目录,数据写入过程为先把数据写入wal日志并放在内存,然后2小时后将内存数据保存至一个新的block块,同时再把新采集的数据写入内存,然后在2小时后再保存到一个新的block块,以此类推

  • block特性

block会压缩、合并历史数据库,以及删除过期的块,随着压缩、合并,block的数量会减少,在压缩过程中会发生三件事:定制执行压缩、合并小的block到大的block、清理过期的块

tree 01FZFZSNX1SJFCKQYZAAN2J6AG/
01FZFZSNX1SJFCKQYZAAN2J6AG/
├── chunks
│   └── 000001 # 数据目录,每个大小为512M,超过会被切成多个
├── index      # 索引文件,记录存储的数据索引信息,通过文件内的几个表来查找时序数据
├── meta.json  # block元数据信息,包括了样本数、采集数据的起始时间、压缩历史
└── tombstones # 逻辑数据,主要记载删除记录和标记要删除的内容,删除标记,在查询块时排除样本
  • 本地存储配置参数

--config.file="prometheus.yml" # 指定配置文件

--web.listen-address="0.0.0.0:9090" # 指定监听地址

--storage.tsdb.path="data/" # 指定数据存储目录

--storage.tsdb.retention.time=y, w, d, h, m, s, ms # 数据保存时长,默认是15天

--storage.tsdb.retention.size=B, KB, MB, GB, TB, PB, EB. # 指定chunk大小,默认 "512MB"

--query.timeout=2m # 默认最大查询超时时间

--query.max-concurrency=20 #默认最大查询并发数

--web.read-timeout=5m # 默认最大空闲超时时间

--web.max-connections=512 # 默认最大并发链接数

--web.enable-lifecycle # 启用或关闭API动态加载配置功能

6.2 远端存储Victoriametrics

github网址:https://github.com/VictoriaMetrics/VictoriaMetrics

官方文档网址:https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html

  • 单机部署
# 下载
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.71.0/victoria-metrics-amd64-v1.71.0.tar.gz
# 解压
tar xvf victoria-metrics-amd64-v1.71.0.tar.gz

启动参数

-httpListenAddr=0.0.0.0:8428 # 默认监听地址及端口

-storageDataPath # 数据存放目录,默认在启动目录下创建victoria-metrics-data

-retentionPeriod # h (hour), d (day), w (week), y (year),默认单位是月,保留一个月

启动

mv victoria-metrics-prod /usr/local/bin/

# 创建service文件
cat >> /etc/systemd/system/victoria-metrics-prod.service <<EOF
[Unit]
Description=victoria-metrics-prod
Documentation=https://docs.victoriametrics.com/Single-server-VictoriaMetrics.html
After=network.target

[Service]
Restart=on-failure
ExecStart=/usr/local/bin/victoria-metrics-prod -storageDataPath=/data/victoria -retentionPeriod=3

[Install]
WantedBy=multi-user.target
EOF
# 加载配置文件
systemctl daemon-reload
# 启动
systemctl start victoria-metrics-prod.service

验证victoria页面

1648733141056.png

vitoria ui页面

1648733492758.png

prometheus配置

remote_write:
  - url: http://192.168.96.161:8428/api/v1/write

配置完成后重启prometheus

victoria ui数据展示

1648734286884.png

若一直没有数据,需要开启导航栏的Auto-refresh按钮,然后时间选最近5分钟

查询的数据是vitoria存储目录的数据,而不是prometheus本地的data数据目录的数据

grafana配置

添加数据源:类型为prometheus,地址及端口为vitoriametrics服务器的ip和端口

模板ID:8919

  • docker-compose

github网址:https://github.com/VictoriaMetrics/VictoriaMetrics/tree/cluster/deployment/docker

安装docker-compose,克隆代码,进入目录,docker-compose up -d

是单机版启动

  • 集群部署

组件介绍

vminsert:写入组件(写),负责接收数据写入并根据对度量名称及其所有标签的一直hash结果将数据分散写入不同的后端vmstorage节点,vmstorage负责持久化数据,vminsert默认端口8400

vmstorage:查询原始数据并返回给指定时间范围内给定标签过滤器的查询数据,默认端口8482

vmselect:查询组件(读),连接vmstorage,默认端口8401

其他可选组件

vmagnet:是一个很小但功能强大的代理,它可以从node_exporter各种来源收集度量数据,并将他们存储在victoriametrics或任何其他支持远程写入协议的与prometheus兼容的存储系统中

vmalert:替换prometheus server,以vitoriametrics为数据源,基于兼容prometheus的告警规则,判断数据是否异常,并将产生的通知发送给alertmanager

vmgateway:读写victoriametrics数据的代理网关,可实现限速和访问控制等功能,目前企业版组件

vmctl:victoriametrics的命令行工具,目前主要用于将prometheus、opentsdb等数据源的数据迁移,迁移到victoriametrics

下载

# 下载
wget https://github.com/VictoriaMetrics/VictoriaMetrics/releases/download/v1.71.0/victoria-metrics-amd64-v1.71.0-cluster.tar.gz
# 解压
tar xvf victoria-metrics-amd64-v1.71.0-cluster.tar.gz

mv vm* /usr/local/bin/

选择三台主机,每台主机都需要下载安装

主要参数

-httpListenAddr string # vmselect
Address to listen for http connections (default ":8481")

-vminsertAddr string # vmstorage
TCP address to accept connections from vminsert services (default ":8400")

-vmselectAddr string # vmstorage
TCP address to accept connections from vmselect services (default ":8401")

部署vmstorage-prod组件

vmstorage负责数据的持久化,监听端口:API 8482,数据写入端口8400,数据读取端口:8401

# 创建service文件
cat >> /etc/systemd/system/vmstorage.service <<EOF
[Unit]
Description=Vmstorage Server
After=network.target

[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vmstorage-prod --loggerTimezone Asia/Shanghai -storageDataPath /data/victoriametrics-cluster/vmstorage -httpListenAddr :8482 -vminsertAddr :8400 -vmselectAddr :8401

[Install]
WantedBy=multi-user.target
EOF

# 启动
systemctl daemon-reload
systemctl start vmstorage.service

注意操作系统不同,可能配置文件路径不一样

vmstorage在cluster模式下,有三个端口,8482端口是API端口,8400是端口给vminsert写数据的,8401端口是给vmselect查询数据的

部署vminsert-prod组件

# 创建service文件
cat >> /etc/systemd/system/vminsert.service <<EOF
[Unit]
Description=Vminsert Server
After=network.target

[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vminsert-prod -httpListenAddr :8480 -storageNode=IP1:8400,IP2:8400,IP3:8400

[Install]
WantedBy=multi-user.target
EOF

# 启动
systemctl daemon-reload
systemctl start vminsert.service

注意组件名字后边的-prod,不要忘了写

vminsert监听端口8480

部署vmselect-prod组件

# 创建service文件
cat >> /etc/systemd/system/vmselect.service <<EOF
[Unit]
Description=Vmselect Server
After=network.target

[Service]
Restart=on-failure
WorkingDirectory=/tmp
ExecStart=/usr/local/bin/vmselect-prod -httpListenAddr :8481 -storageNode=IP1:8401,IP2:8401,IP3:8401

[Install]
WantedBy=multi-user.target
EOF
# 启动
systemctl daemon-reload
systemctl start vmselect.service

vmselect 监听端口8481

验证集群服务端口

curl http://IP:8480/metrics  # vminsert
curl http://IP:8481/metrics  # vmselect 
curl http://IP:8482/metrics  # vmstorage

三个服务器都需要验证

验证vmselect监听端口页面

1648820993121.png

prometheus配置

remote_write:
  - url: http://IP1:8480/insert/0/prometheus # 配置的端口是vminsert的监听端口
  - url: http://IP2:8480/insert/0/prometheus
  - url: http://IP3:8480/insert/0/prometheus

配置的端口是vminsert的监听端口

配置grafana,添加数据源

http://IP1:8481/select/0/prometheus

grafana只能配置一个地址,可以搭建负载均衡器,写负载均衡的ip,读取数据的路径需要跟prometheus的配置文件中保持一致,insert是写,select是读,后边两段uri需要一致,不然读不到数据

grafana模板

8919、13824

1648821498970.png
  • 开启数据复制

官方网址:https://docs.victoriametrics.com/Cluster-VictoriaMetrics.html#replication-and-data-safety

默认情况下,数据被vminsert的组件基于hash算法分别将数据持久化到不同的vmstorage节点

开启数据复制是启用vminsert组件支持的-replicationFactor=n(n代表几份)复制功能,将数据分别在各节点保存一份完整的副本以实现数据的高可用

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容