K8S部署ELK管理集群日志

前言:ELK是目前主流的日志解决方案,尤其是容器化集群的今天,ELK几乎是集群必备的一部分能力;ELK在K8S落地有多种组合模式:
比如:fluentd+ELK或filebeat+ELK或log-pilot+ELK
而本文采用的是功能更强大的后者:log-pilot 采集--->logstash过滤加工--->ES存储与索引--->Kibana展示的方案,日志量大的集群建议再加一层kafka提升吞吐,降低logstash的负载。

1.ES集群安装

我们计划安装两个节点的集群环境:
节点1IP:192.168.0.137
节点2IP:192.168.0.230
关于安装的版本:
从 6.8.0 和 7.1.0 版本开始, Elastic Stack安全功能免费提供,在Elasticsearch7.3,x-pack已经作为默认的插件集成在Elasticsearch里面了,为了今后方便的的添加安全策略,我们建议安装7.3之后的版本
本文我们安装7.5.0版本,es和kibana版本使用同样的版本号。

以下命令在两个节点分别执行

docker pull elasticsearch:7.5.0
mkdir /data/es/data   请逐级创建目录
mkdir /data/es/config 请逐级创建目录
chmod 777 /data/es
vim /etc/sysctl.conf
加入如下内容:
vm.max_map_count=262144  
然后:wq保存
启用配置:
sysctl -p
注:这一步是为了防止启动容器时,报出如下错误:
bootstrap checks failed max virtual memory areas vm.max_map_count [65530] likely too low, increase to at least [262144]

节点1上执行命令:

cd /data/es/config
vim es1.yml  创建yml文件,内容如下
#集群名称
cluster.name: es-cluster
#节点名称
node.name: node-a
#是不是有资格竞选主节点
node.master: true
#是否存储数据
node.data: true
#最大集群节点数
node.max_local_storage_nodes: 10
#网关地址
network.host: 0.0.0.0
network.publish_host: 192.168.0.137
#端口
http.port: 9200
#内部节点之间沟通端口
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
#es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["192.168.0.137:9300","192.168.0.230:9300"]
#es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-a"]
#数据存储路径
path.data: /usr/share/elasticsearch/data
#日志存储路径
path.logs: /usr/share/elasticsearch/data/logs

节点2上执行命令如下:

cd /data/es/config
vim es2.yml  创建yml文件,内容如下
#集群名称
cluster.name: es-cluster
#节点名称
node.name: node-b
#是不是有资格竞选主节点
node.master: true
#是否存储数据
node.data: true
#最大集群节点数
node.max_local_storage_nodes: 10
#网关地址
network.host: 0.0.0.0
network.publish_host: 192.168.0.230
#端口
http.port: 9200
#内部节点之间沟通端口
transport.tcp.port: 9300
http.cors.enabled: true
http.cors.allow-origin: "*"
#es7.x 之后新增的配置,写入候选主节点的设备地址,在开启服务后可以被选为主节点
discovery.seed_hosts: ["192.168.0.137:9300","192.168.0.230:9300"]
#es7.x 之后新增的配置,初始化一个新的集群时需要此配置来选举master
cluster.initial_master_nodes: ["node-a"]
#数据存储路径
path.data: /usr/share/elasticsearch/data
#日志存储路径
path.logs: /usr/share/elasticsearch/data/logs

创建容器

节点1,节点2均执行以下命令:
docker run -e ES_JAVA_OPTS="-Xms512m -Xmx512m" -d -p 9200:9200 -p 9300:9300 -v /data/es/config/es.yml:/usr/share/elasticsearch/config/elasticsearch.yml -v /data/es/data:/usr/share/elasticsearch/data --name ES elasticsearch:7.5.0

等约2分钟左右查看两个节点状态
http://192.168.0.137:9200
http://192.168.0.230:9200

使用elasticsearch-head前端框架(可选内容)

#拉取镜像
docker pull mobz/elasticsearch-head:5
#启动容器
docker run -d -p 9100:9100 --name es-manager  mobz/elasticsearch-head:5

浏览器访问http://192.168.0.137:9100/
并连接http://192.168.0.137:9200/

附:yml文件参数说明

以下参数介绍来源:https://blog.csdn.net/belonghuang157405/article/details/83301937
cluster.name:用于唯一标识一个集群,不同的集群,其 cluster.name 不同,集群名字相同的所有节点自动组成一个集群。如果不配置改属性,默认值是:elasticsearch。
node.name:节点名,默认随机指定一个name列表中名字。集群中node名字不能重复
index.number_of_shards: 默认的配置是把索引分为5个分片
index.number_of_replicas:设置每个index的默认的冗余备份的分片数,默认是1
通过 index.number_of_shards,index.number_of_replicas默认设置索引将分为5个分片,每个分片1个副本,共10个结点。
禁用索引的分布式特性,使索引只创建在本地主机上:
index.number_of_shards: 1
index.number_of_replicas: 0
但随着版本的升级 将不在配置文件中配置而实启动ES后,再进行配置
bootstrap.memory_lock: true 当JVM做分页切换(swapping)时,ElasticSearch执行的效率会降低,推荐把ES_MIN_MEM和ES_MAX_MEM两个环境变量设置成同一个值,并且保证机器有足够的物理内存分配给ES,同时允许ElasticSearch进程锁住内存
network.bind_host: 设置可以访问的ip,可以是ipv4或ipv6的,默认为0.0.0.0,这里全部设置通过
network.publish_host:设置其它结点和该结点交互的ip地址,如果不设置它会自动判断,值必须是个真实的ip地址
同时设置bind_host和publish_host两个参数可以替换成network.host
network.bind_host: 192.168.0.137
network.publish_host: 192.168.0.137
=>network.host: 192.168.0.137
http.port:设置对外服务的http端口,默认为9200
transport.tcp.port: 设置节点之间交互的tcp端口,默认是9300
http.cors.enabled: 是否允许跨域REST请求
http.cors.allow-origin: 允许 REST 请求来自何处
node.master: true 配置该结点有资格被选举为主结点(候选主结点),用于处理请求和管理集群。如果结点没有资格成为主结点,那么该结点永远不可能成为主结点;如果结点有资格成为主结点,只有在被其他候选主结点认可和被选举为主结点之后,才真正成为主结点。
node.data: true 配置该结点是数据结点,用于保存数据,执行数据相关的操作(CRUD,Aggregation);
discovery.zen.minimum_master_nodes: //自动发现master节点的最小数,如果这个集群中配置进来的master节点少于这个数目,es的日志会一直报master节点数目不足。(默认为1)为了避免脑裂,个数请遵从该公式 => (totalnumber of master-eligible nodes / 2 + 1)。 * 脑裂是指在主备切换时,由于切换不彻底或其他原因,导致客户端和Slave误以为出现两个active master,最终使得整个集群处于混乱状态*
discovery.zen.ping.unicast.hosts: 集群个节点IP地址,也可以使用es-node等名称,需要各节点能够解析

安装中文分词
中文分词插件:
https://github.com/medcl/elasticsearch-analysis-ik/
版本对应关系如下图:

说明:本文是安装了7.5.0版本插件(并不是说ES7.5安装插件也必须7.5,这个看上图的对应关系,ES7安装当前最新版本都没问题的)
docker exec -it ES /bin/bash  进入容器
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.5.0/elasticsearch-analysis-ik-7.5.0.zip
等几分钟安装好后,退出容器,重启容器
docker restart es

2.安装kibana

拉取镜像,注意版本要和ES版本号一致
docker pull kibana:7.5.0

mkdir /data/es/kibana/config
mkdir /data/es/kibana/plugins
cd /data/es/kibana
chmod 777 kibana
cd /data/es/kibana/config
vim kibana.yml   制作配置文件
###################
server.name: kibana
server.host: "0.0.0.0" 
elasticsearch.hosts: [ "http://192.168.0.137:9200","http://192.168.0.230:9200"]
xpack.monitoring.ui.container.elasticsearch.enabled: true

启动容器:

docker run -d --name kibana  -p 5601:5601 -v /data/es/kibana/config/kibana.yml:/usr/share/kibana/config/kibana.yml  -v /data/es/kibana/plugins:/usr/share/kibana/plugins:rw  --name kibana   kibana:7.5.0

此时我们可以查看日志 docker logs kibana
当看到以下信息时证明启动成功:

{"type":"log","@timestamp":"2020-03-22T08:20:11Z","tags":["status","plugin:reporting@7.5.0","info"],"pid":6,"state":"green","message":"Status changed from uninitialized to green - Ready","prevState":"uninitialized","prevMsg":"uninitialized"}
{"type":"log","@timestamp":"2020-03-22T08:20:11Z","tags":["listening","info"],"pid":6,"message":"Server running at http://0.0.0.0:5601"}
{"type":"log","@timestamp":"2020-03-22T08:20:11Z","tags":["info","http","server","Kibana"],"pid":6,"message":"http server running at http://0.0.0.0:5601"}

此时我们通过http://ip:5601就可以看到kibana界面,如下图:

为kinba映射一个好记的域名(可选)
到nginx confi.d文件夹建一kibana.conf,内容如下:

server
{
        listen 80;
        #listen 443 ssl;
        server_name kibana.xxxx.cn;     #域名A记录我们提前已经指好
        location / {
            proxy_redirect off;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://192.168.0.137:5601;  #kibana的安装节点及端口
        }
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
             root   /usr/share/nginx/html;
        }
}

重启nginx,就可以看到kibana的初始界面


kibana汉化
由于 kibana5.* 6.* 官方并没有支持中文,需要另外下载补丁包 推荐下面这个 https://github.com/anbai-inc/Kibana_Hanization,手动安装
7.*之后官方已经支持了中文,中文包在 /usr/share/kibana/node_modules/x-pack/plugins/translations/translations/zh-CN.jso
只需要在配置文件 kibana.yml 中加入
i18n.locale: "zh-CN"
我们修改下

 vim /data/es/kibana/config/kibana.yml
 加入一行:i18n.locale: "zh-CN"  然后保存
 docker restart kibana  重启容器

3.添加密码验证

docker exec -it ES /bin/bash #进入容器
生成证书

###生成授权证书
bin/elasticsearch-certutil ca (CA证书:elastic-stack-ca.p12)
Please enter the desired output file [elastic-stack-ca.p12]: elastic-stack-ca.p12 (输入elastic-stack-ca.p12)
Enter password for elastic-stack-ca.p12 : (输入一个密码,后面要用)
###根据授权证书生成节点证书
[root@6259c569027a elasticsearch]# bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 (生成节点证书)
 Enter password for CA (elastic-stack-ca.p12) :(输入授权证书刚才的密码)
Please enter the desired output file [elastic-certificates.p12]: elastic-certificates.p12(输入节点证书文件名elastic-certificates.p12)
Enter password for elastic-certificates.p12 : (输入节点证书密码)
然后我们将刚才输入的密码到 elasticsearch keystore 
bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password
以上命令会在config目录生成elasticsearch.keystore文件

证书创建完毕,可以看到两个证书文件在当前目录


我们把elastic-certificates.p12复制到data目录,该目录我们映射到主机,不会丢失。
cp elastic-certificates.p12 data
同时将elastic-certificates.p12文件也复制到其他节点的es/data目录。
将elasticsearch.keystore复制到其他节点的config目录(进入docker容器后上传)
修改文件的权限
[root@k8s-node1 data]# chmod 777 elastic-certificates.p12
然后我们修改各节点的es.yml文件

vim es.yml,添加这几行:
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.license.self_generated.type: basic
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /usr/share/elasticsearch/data/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /usr/share/elasticsearch/data/elastic-certificates.p12

启用密码

#master节点执行如下操作:
vim /data/es/config/es.yaml
#添加如下三行(前面已有添加过)
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.license.self_generated.type: basic
#保存后,重启Docker
docker restart ES

这时候再次打开http://ip:9200,则会弹出密码输入框,我们接下来初始化密码:

docker exec -it ES /bin/bash  #进入ES容器
bin/elasticsearch-setup-passwords interactive  #执行密码初始化,一共6个组件的密码,每个重复一次,共输入12遍,如下:
[root@6259c569027a elasticsearch]# bin/elasticsearch-setup-passwords interactive 
Initiating the setup of passwords for reserved users elastic,apm_system,kibana,logstash_system,beats_system,remote_monitoring_user.
You will be prompted to enter passwords as the process progresses.
Please confirm that you would like to continue [y/N]y


Enter password for [elastic]: 
Reenter password for [elastic]: 
Enter password for [apm_system]: 
Reenter password for [apm_system]: 
Enter password for [kibana]: 
Reenter password for [kibana]: 
Enter password for [logstash_system]: 
Reenter password for [logstash_system]: 
Enter password for [beats_system]: 
Reenter password for [beats_system]: 
Enter password for [remote_monitoring_user]: 
Reenter password for [remote_monitoring_user]: 
Changed password for user [apm_system]
Changed password for user [kibana]
Changed password for user [logstash_system]
Changed password for user [beats_system]
Changed password for user [remote_monitoring_user]
Changed password for user [elastic]

然后分别重启两个节点的ES docker restart ES
设置密码的方法参考了一系列网上文章:
https://blog.csdn.net/mengo1234/article/details/104920667/
x-park的license有效期可参考这篇处理:https://www.cnblogs.com/gavinYang/p/11200234.html
集群和非集群x-park使用所差异,参考:
http://www.eryajf.net/3500.html
Kibana添加ES密码

vim kibana.yml
#添加下面两行后,重启kibana容器
elasticsearch.username: "kibana"
elasticsearch.password: "之前为kibana帐户创建的密码"
然后重启kibana容器,会跳转到登录界面


登录时我们用elastic帐户登录(起初尝试用kibana帐户报403)
接下来我们用kibana查看下ES集群状态

看到这个情况时,我们需要修改下es.yml文件,添加一个配置项:

两个节点的 es.yml均添加下面一行,然后docker restart ES重启ES
xpack.monitoring.collection.enabled: true

重新进入kibana就可以ES节点的详细信息了。


4.安装logstash

Logstash是一个日志收集器,可以理解为一个管道,或者中间件。
功能是从定义的输入源inputs读取信息,经过filters过滤器处理,输入到定义好的outputs输出源。
输入源可以是stdin、日志文件、数据库等,输出源可以是stdout、elesticsearch、HDFS等。

安装过程如下:
下载docker镜像
尽量保证版本号和ES一致,否则容易产生不兼容问题。
docker pull docker.elastic.co/logstash/logstash:7.5.0
创建文件夹 (用于容器文件的挂载)
mkdir /data/logstash/config
创建相关配置文件

vim logstash.yml 
http.host: "0.0.0.0"
http.port: 9600

logstash.yml相关参数编写可参考:https://segmentfault.com/a/1190000016591476

vim log4j2.properties
logger.elasticsearchoutput.name = logstash.outputs.elasticsearch
logger.elasticsearchoutput.level = debug
vim pipelines.yml
- pipeline.id: my-logstash
  path.config: "/usr/share/logstash/config/*.conf"
  pipeline.workers: 3
es.conf 文件
input {
  tcp {
    mode => "server"
    host => "0.0.0.0"
    port => 5044
  }
}
output {
  elasticsearch {
    action => "index"
    hosts  => ["192.168.0.137:9200","192.168.0.230:9200"]
    index  => "index"  #"index"是索引库名称,可以用变量自动生成索引库名
    user =>"elastic"
    password =>"xxxxxx"
  }
}

启动命令

docker run -d -p 5044:5044 -p 9600:9600 -it -v /data/logstash/config/:/usr/share/logstash/config/  --name logstash docker.elastic.co/logstash/logstash:7.5.0 

docker logs logstash 查看日志,当看到如下信息说明运行成功:

14:47:18.759 [Ruby-0-Thread-1: /usr/share/logstash/vendor/bundle/jruby/2.5.0/gems/stud-0.0.23/lib/stud/task.rb:22] INFO  logstash.agent - Pipelines running {:count=>1, :running_pipelines=>[:"my-logstash"], :non_running_pipelines=>[]}
14:47:18.769 [[my-logstash]<tcp] INFO  logstash.inputs.tcp - Starting tcp input listener {:address=>"0.0.0.0:4567", :ssl_enable=>"false"}
14:47:18.902 [Api Webserver] INFO  logstash.agent - Successfully started Logstash API endpoint {:port=>9600}

打开浏览器访问验证:http://ip:9600

5.安装log-pilot

Log-Pilot是阿里开源的一个智能容器日志采集工具,能够高效便捷地将容器日志采集输出到多种后台日志存储系统中,不仅能够采集容器标准输出日志,同时能够动态发现配置采集容器内文件日志,参考官方介绍:https://yq.aliyun.com/articles/674327

我们在k8s集群内将采用k8s的模式进行安装,便于自动管理。
准备yaml文件如下

vim log-pilot.yaml #创建文件
---
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
  name: log-pilot
  namespace: es
  labels:
    k8s-app: log-pilot
    kubernetes.io/cluster-service: "true"
spec:
  template:
    metadata:
      labels:
        k8s-app: log-es
        kubernetes.io/cluster-service: "true"
        version: v1.22
    spec:
      tolerations:
      - key: node-role.kubernetes.io/master
        effect: NoSchedule
      containers:
      - name: log-pilot
        image: registry.cn-hangzhou.aliyuncs.com/acs/log-pilot:0.9.6-filebeat
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        env:
          - name: "LOGGING_OUTPUT"
            value: "logstash"
          - name: "LOGSTASH_HOST"
            value: "192.168.0.230"
          - name: "LOGSTASH_PORT"
            value: "5044"
          - name: "LOGSTASH_LOADBALANCE"
            value: "true"
          #- name: "FILEBEAT_OUTPUT"
          #  value: "elasticsearch"
          #- name: "ELASTICSEARCH_HOST"
          #  value: "192.168.0.137"
          #- name: "ELASTICSEARCH_PORT"
          #  value: "9200"
          #- name: "ELASTICSEARCH_USER"
          #  value: "elastic"
          #- name: "ELASTICSEARCH_PASSWORD"
          #  value: "1111111"
        volumeMounts:
        - name: sock
          mountPath: /var/run/docker.sock
        - name: root
          mountPath: /host
          readOnly: true
        - name: varlib
          mountPath: /var/lib/filebeat
        - name: varlog
          mountPath: /var/log/filebeat
        securityContext:
          capabilities:
            add:
            - SYS_ADMIN
      terminationGracePeriodSeconds: 30
      volumes:
      - name: sock
        hostPath:
          path: /var/run/docker.sock
      - name: root
        hostPath:
          path: /
      - name: varlib
        hostPath:
          path: /var/lib/filebeat
          type: DirectoryOrCreate
      - name: varlog
        hostPath:
          path: /var/log/filebeat
          type: DirectoryOrCreate

在master节点执行kubectl apply -f log-pilot.yaml
其中
LOGGING_OUTPUT 是使用logstash接收log-pilot接收到的日志
LOGSTASH_HOST logstash服务的ip地址
LOGSTASH_PORT logstash服务的端口
LOGSTASH_LOADBALANCE 是否为logstash开启负载均衡模式

查看部署情况
kubectl get pods -n es
能够看出每个k8s节点均自动部署了一个log-pilot容器

log-pilot会自动打一些环境变量或标签,供接收端使用,如下图:


log-pilot相关详细参数及使用可以参考这篇,https://toutiao.io/posts/k0qse0/preview

6.验证日志写入情况

我们运行一个容器测试日志写入

master节点创建一个tomcat.yaml,如下:
apiVersion: v1
kind: Pod
metadata:
  name: tomcat
spec:
  containers:
  - name: tomcat
    image: "tomcat:7.0"
    env:
    - name: aliyun_logs_myTomcat
      value: "stdout" 
    - name: aliyun_logs_access
      value: "/usr/local/tomcat/logs/catalina.*.log" 
    volumeMounts:
      - name: tomcat-log
        mountPath: /usr/local/tomcat/logs
  volumes:
    - name: tomcat-log
      emptyDir: {}

然后执行kubectl apply -f tomcat.yaml创建pod

Kibana到management菜单--->索引模式--->创建索引模式
输入我们的索引名称加上*,如下图。
我们索引名称为index,然后下一步,配置其他项后,保存索引模式。



索引模式创建完毕后,我们点击【Discover】菜单进行查看
先切换索引,然后输入查询条件查询日志。


7.结语

ELK生产环境实施会涉及到ES集群规划,节点/分片/索引/容量规划,并非按网上文章直接部署这么简单,搭建前要详细评估。
此外ELK中logstash功能是比较强大,但其对数据处理及路由策略的设计直接关系到ES数据是否易用,如果这部分没有花精力规划,后期ES数据库将会变成数据垃圾堆。
关于logstash规则的匹配处理:
grokdebug.herokuapp.com里面可以做测试.
grokdebug.herokuapp.com/patterns 所有可用的patterns都可以在这里查到.
log-pilot组件会自动增加一些默认变量供下游使用
k8s_container_name、k8s_pod、k8s_node_name、 k8s_pod_namespace
如logstash表达式可以这么写:
output {
elasticsearch {
hosts => "${ES_URL}"
manage_template => false
index => "k8s-%{k8s_container_name}-%{+YYYY.MM.dd}"
}
}
logstash可以看这个系列:
http://doc.yonyoucloud.com/doc/logstash-best-practice-cn/index.html
logstash表达式可以看这篇文章
https://www.cnblogs.com/xiaobaozi-95/p/9214307.html
参考:
【手把手教你搭建一个 Elasticsearch 集群】
https://www.cnblogs.com/tianyiliang/p/10291305.html
【ES权威指南1】
https://www.cnblogs.com/Leo_wl/p/7685776.html
【ELK:收集k8s容器日志最佳实践】
https://www.cnblogs.com/William-Guozi/p/elk-k8s.html
【在阿里,我们是怎么做 K8S 日志实践的?】
https://toutiao.io/posts/k0qse0/preview

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

推荐阅读更多精彩内容