ansible

ansible是一款自动化运维工具,基于python开发,他是基于各个模块来工作的,主要由以下几个组件:

  • connection plugins:用来和需要操作的远程主机通信的,由于ansible是无agent方式,所以需要一种连接方式,一般使用ssh来作为通信方式;
  • host inventory:用来指定需要操作的远程主机ip地址,配置文件默认为/etc/ansible/hosts;
  • playbook:剧本,就是将事先定义好的需要在哪些远程主机上执行什么操作,写到playbook文件中,然后让ansibles去读取剧本文件并操作;
  • core modules:核心模块,ansible是通过模块去到远程主机上执行操作的
  • custom modules:自定义模块,除了自带的模块,用户也可以自定义模块
  • plugins:一些功能插件,用来实现日志,邮件等功能

结构图如下:

ansible命令

ansible命令是命令行工具,不需要读取playbook文件
ansible :

  • -m:指名模块
  • -a:给模块指定参数,写在“”里边,如果是命令就直接写进去就行
  • -C:测试执行,不真正执行
  • -f:一批处理几个,默认为5
  • -i:指定hosts文件
  • --list-hosts:列出这次操作对哪些主机执行,只是列出
  • --syntax-check:检查语法
  • -t:在文件中定义tags后使用这个选项只运行tags那一部分
  • -c:连接方式 smart为默认,智能选择合适的方式
  • -u USERNAME:连接时使用的用户名,默认为none
  • -s:sudo
  • -S:su

ansible-playbook命令

运行playbook使用ansible-playbook命令,常用参数如下:

  • --syntax-check:检测语法
  • -C:测试运行,检查错误时候使用,不是真正在目标主机上运行
  • --list-hosts:显示要执行的主机
  • -t TAGS:使用文件中有标签的地方,只执行标签处的任务
    -e VARS:使用变量

模块

ansible是通过模块来工作的,所以下面介绍各种功能的模块:
首先用ansible-doc -l命令可以列出模块,可以看到有非常多的模块可以使用,这里我们就据介绍一些比较重要的经常用的模块,使用ansible-doc -s 模块名可以查看模块的参数,用来定义模块的期望值
模块可以定义期望的目标状态,而且操作必须时幂等的(重复数次的结果是相同的,都是定义的期望的状态),如下为一些常用的模块,例子都是使用命令行工具ansible来写的:

1.group模块

ansible all -m group -a "gid=3000 name=mygrp state=present system=no" 

state=absent表示删除组,present表示创建组,system=no表示不是系统组
2.user模块

ansible all -m usre -a "uid=5000 name=testuser state=present groups=mygrp shell=/bin/tcsh"

表示用户的uid为5000,用户名为testuser,状态为创建用户,组名为mygrp,使用默认shell为/bin/tcsh
3.copy模块
src选项的值为目录时,最后带/斜杠表示不复制目录本身,不带就表示复制目录本身,src可以为空,用content表示所跟的内容直接生成到目标远程主机文件,不跟dest就源是哪里,目标目录就是哪里,remote_src表示使用远程的源,state=absent表示删除

ansible all -m copy -a "src=/etc/fstab dest=/tmp/test mode=600"
ansible all -m  copy -a "content='haha\nhehe\n‘ dest =/tmp/hehe  owner=testuser"

4.fetch模块
将远程主机复制到本机,偶尔会用到,不用指定多个主机

command模块
远程主机执行命令:chdir,切换目录;executable,由哪个shell发起执行命令.command命令在执行时不适用shell,所以传递|或者>等参数时不识别,所以要使用shell模块
6.shell模块
解决了command的不识别,其他和command一样
7.file模块
用来创建文件(不推荐,一般用copy,content=空去创建),设定文件属性,path=定义目标文件,state=file|directory

ansible all -m file  -a "path=/tmp/hello.dir state=directory"

8.cron模块
指定计划任务,分时日月周和crontab一样,要定义哪个就将哪个写进去

ansible all -m cron -a "minute=*/3 job='/usr/sbin/ntpdate 172.16.0.1 &> /dev/null' name=None "

9.yum模块
name=要安装的包名;state=installd|removed|latest;disable_gpg_check=yes表示禁用gpgcheck

ansible all -m yum -a "name=nginx state=installed disabled_gpg_check=yes"

10.service模块
name=服务名;enabled=yes表示开机启用;runlevel在设置开机启用后指定运行的级别;state=started|stopped|restarted|reloaded;

ansible all -m service -a "name=nginx enabled=true state=started"

11.script模块
本地文件在远程执行,远程自己的脚本用shell模块就行

ansible all -m script  -a "脚本路径"

12.setup模块
用来收集对应主机的信息,信息中有很多内建变量可以直接使用,下面讲到变量时候再说这个模块

playbook

命令行方式不能复用,我们可以讲每台主机需要执行的操作写入配置文件playbook,让ansible去读取并执行。
YAML格式:ansible相关文件的格式为YAML,是一种可读性高,用来表达数据序列的格式,基本数据结构为:标量,数组,关联数组.

playbook基本元素:

  • hosts:运行指定任务的目标主机
    remoute_user:远程主机上执行任务的用户
    sudo_user:sudo的用户
  • tasks:任务
    name:任务名字
    module:模块参数
    tags:标签,可以使用ansible-playbook 的-t选项来指定,只执行本标签的任务
  • handlers:特定条件触发的任务,在一个任务中定义notify,然后这个任务触发之后会通知这个handlers执行操作

还有一些别的元素我们在下面的大标题中挨个讲解,我们先来看这些基础元素的用法:

下面我们来创建一个playbook文件,并执行,注意,一定要缩进:

[root@localhost ansible]# vim /etc/ansible/test.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: install redis
    yum: name=redis state=latest
  - name: start redis
    service: name=redis state=started

然后去检测

[root@localhost ansible]# ansible-playbook --syntax-check  test.yml

playbook: test.yml
[root@localhost ansible]# ansible-playbook -C  test.yml

PLAY [172.16.200.107] **********************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.107]

TASK [install redis] ***********************************************************
ok: [172.16.200.107]

TASK [start redis] *************************************************************
changed: [172.16.200.107]

PLAY RECAP *********************************************************************
172.16.200.107             : ok=3    changed=1    unreachable=0    failed=0   

检测成功后就可以执行了

ansible-playbook  test.yml

执行成功的返回结果和测试的一样,所以就不再显示了

变量variables:

变量有四种:
1.内建变量
facter -p:收集本机信息,ansible中有个同样功能的模块,叫做setup,用ansible-doc -s setup查看这个模块
用ansible 172.16.200.107 -m setup 就可以收集目标主机的很多信息了,比facter收集到的信息更多,有很多内建的变量,直接就可以使用了.
使用示例:

[root@localhost ansible]# vim /etc/ansible/test1.yml                                                                         
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: copy file
    copy: content={{ ansible_env }} dest=/tmp/ansible_env    #{{}}和变量名字之间要加上空格
[root@localhost ansible]# ansible-playbook --syntax-check  test1.yml
[root@localhost ansible]# ansible-playbook -C  test1.yml
[root@localhost ansible]# ansible-playbook   test1.yml

然后到172.16.200.107的/tmp目录中查看ansible_env文件,看到里边是本机的各种信息,这个ansible_env就是变量

2.自定义变量
先在文件中定义变量

[root@localhost ansible]# vim /etc/ansible/test2.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: install {{ packgs }}    #{{}}和变量名字之间要加上空格
    yum: name={{ packgs }} state=latest

然后使用的时候调用定义的变量就可以了

[root@localhost ansible]# ansible-playbook --syntax-check test2.yml
[root@localhost ansible]# ansible-playbook  -e packgs=httpd  -C test2.yml
[root@localhost ansible]# ansible-playbook  -e packgs=httpd test2.yml

3.Host Inventory主机文件变量
就是定义在主机文件中的变量,主机文件默认为/etc/ansible/hosts文件,其格式分为两种,变量也有两种,一种可以自定义变量,在模板文件中可以调用,另一种是使用系统本身自带的invertory参数,这个参数是用于定义ansible远程连接目标主机时使用的参数,而非传递给playbook的变量,常用的有以下几种:
ansible_ssh_host
ansible_ssh_port
ansible_ssh_user
ansible_ssh_pass
ansbile_sudo_pass
两种格式:
(a) 单台主机变量
向不同的主机传递不同的变量,在每台主机之后加上变量=值就可以调用了,格式为
IP/HOSTNAME varaiable=value var2=value2
为了验证,首先,我们给172.16.200.107上创建用户feng,密码设置为123

[root@localhost ansible]# ansible 172.16.200.107  -m user -a "name=feng"    #注意,这里使用password=密码的选项,设置的密码不是登陆密码,所以还是要使用下一步这种方式
[root@localhost ansible]# ansible 172.16.200.107 -m shell -a "echo 123|passwd --stdin feng"

然后,修改/etc/ansible/hosts文件,这里我们用invertory参数来演示,自定义变量在说到模板时候在用

[web]
172.16.200.107 ansible_ssh_user=feng ansible_ssh_pass=123
172.16.200.108

测试

[root@localhost ansible]# ansible 172.16.200.107 -m ping
172.16.200.107 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}

(b)组变量
向组中的主机传递相同的变量,就是当组中的每个元素需要设定一个相同的变量时,就可以用这种方式来实现
[groupname:vars]
variable=value
如果107和108两个主机都需要使用feng用户登陆,而密码都是123,那么使用组变量,将之前的设置改一下就可以了,到/etc/ansible/hosts文件中

[web]
172.16.200.107
172.16.200.108 
[web:vars]
 ansible_ssh_user=feng ansible_ssh_pass=123

这样,组变量就定义好了,组中的每个元素都使用这个定义的变量

4.roles定义变量
在playbook中,加入如下这一段

vars:
 - pbvar: playbook var

就可以直接调用了,这种方式主要是在定义角色中使用,详细的在说到角色时候在说明
注意:命令行中调用的变量中间有空格会只显示空格之前的内容

模板templates

ansible-doc -s templates
内嵌一段代码,由模板引擎解析,可以实现变量替换,算数运算等功能,文件中其他内容不变,这种文件叫做模板文件。他们是用模板模块生成的,著名的模板模块叫做python-jinja2,python-jinja2是一个模板引擎,用配置文件后缀为.j2,然后写的时候用python的语法来写.
下面我们创建一个显示本主机ip地址的文件,发给172.16.200.107和108,所以每个主机收到文件内容都是不同的,就实现了模板文件的用法:

root@localhost ansible]# ansible 172.16.200.107 -m setup |less    #随便找一台主机获取显示主机ip的变量名为ansible_ens33.ipv4.address
[root@localhost ansible]# vim /etc/ansible/ip.j2    #定义模板文件,加入如下内容
ipaddress: {{ ansible_ens33.ipv4.address }}
[root@localhost ansible]# vim /etc/ansible/test3.yml    #写playbook文件,注意template模板不能在命令行中被调用
- hosts: all
  remote_user: root
  tasks:
  - name: template test
    template: src=/etc/ansible/ip.j2 dest=/tmp/
[root@localhost ansible]# ansible-playbook -C test3.yml 
[root@localhost ansible]# ansible-playbook  test3.yml 

然后到107和108中查看/tmp/ip.j2文件,发现分别为172.16.200.107和172.16.200.108,证明模板引擎已经将变量解析为本机ip了。

条件测试when

可以在tasks中使用,判定条件满足时候才会执行当前任务,我们用版本号举例,当107的版本为7时,就执行写一个centos7字符串到107主机的/tmp/versions文件中,6的话就写6

[root@localhost ansible]# vim test4.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: test when
    copy: content="centos7" dest=/tmp/versions
    when: ansible_distribution_major_version == "7"
  - name: test when
    copy: content="centos6" dest=/tmp/versions
    when: ansible_distribution_major_version == "6"
[root@localhost ansible]# ansible-playbook test4.yml     #执行

PLAY [172.16.200.107] **********************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.107]

TASK [test when] ***************************************************************
changed: [172.16.200.107]

TASK [test when] ***************************************************************
skipping: [172.16.200.107]    

PLAY RECAP *********************************************************************
172.16.200.107             : ok=2    changed=1    unreachable=0    failed=0   

我们看到第二个任务skip跳过了,就是因为107是centos7的系统,当检测不是6的时候,第二个任务就跳过了,我们也可以在107中查看/tmp/versions文件,显示的为"centos7"

循环迭代with_items

当有很多需要重复执行而任务内容不变的参数时候,重复的写任务会很麻烦,这个时候需要用到循环,更加高效的来写参数不同,但是任务过程相同的任务

[root@localhost ansible]# vim /etc/ansible/test5.yml
- hosts: 172.16.200.107
  remote_user: root
  tasks:
  - name: install {{ item }}  packges
    yum: name={{ item }} state=latest
    with_items:
    - nginx
    - varnish
[root@localhost ansible]# ansible-playbook  test5.yml

完成后,我们会看到nginx和varnish都被安装上了

也可以用字典来迭代:
user: name={{item.name}} group={{item.group}}
with_items:
- {name: 'feng',group:'fengkp'}
- ...
这里就不在列出字典的用法了。

角色

自包含的目录结构,就是在一个目录中放入部署这一套服务的各种需要的组件.说白了就是将playbook中的各项组件拆分在各个子文件夹中,由一个主目录将所有内容包含在其中,这样做的好处是条理清楚,修改时候比较方便。
目录结构如下:

  • files/ :存放由copy或script模块等调用的文件;
  • templates/:template模块查找所需要模板文件的目录;
  • tasks/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
  • handlers/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
  • vars/:至少应该包含一个名为main.yml的文件;其它的文件需要在此文件中通过include进行包含;
  • meta/:至少应该包含一个名为main.yml的文件,定义当前角色的特殊设定及其依赖关系;其它的文件需要在此文件中通过include进行包含;
  • default/:设定默认变量时使用此目录中的main.yml文件;

下面我们来创建一个nginx角色:

mkdir -pv /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost ansible]# cd /etc/ansible/roles/nginx/
[root@localhost nginx]# vim tasks/main.yml
- name: install nginx
  yum: name=nginx state=latest
  when: ansible_os_family == "RedHat"

有一个任务,我们就可以使用了,使用的话在playbook中调用需要使用roles 加上角色名就可以:

[root@localhost nginx]# vim /etc/ansible/nginx.yml
- hosts: 172.16.200.107
  remote_user: root
  roles:
  - nginx

测试

[root@localhost ansible]# ansible-playbook nginx.yml

当然,这里只使用了tasks元素,如果由其他元素的话,就写在相应的目录下的main.yml文件中就可以,注意写脚本的main.yml的文件时候,由于脚本没有键值,所以不是list,不用加前边的-符号。下面我们通过一个大实验来熟练ansible的操作

实验

通过ansible来实现一个架构,架构图如下:

环境:

  • 各个节点时间同步,selinux和iptables关闭
  • ansible服务器:172.16.200.109
  • 172.16.200.102:部署nginx反代调度器1,部署keepalived,部署varnish服务1
  • 172.16.200.103:部署nginx反代调度器2,部署keepalived,部署varnish服务2
  • vip:172.16.200.200
  • 172.16.200.104:后端nginx节点1,tomcat节点1,mysql主节点,redis主节点
  • 172.16.200.105:后端nginx节点2,tomcat节点2,mysql从节点和redis从节点

实现步骤:
我们将结构拆分为静态和动态两条,静态的结构如下:

先来实现静态这条路线上的nginx,tomcat和redis
1.几台主机之间设置ssh密钥互信
在ansible服务端172.16.200.109执行

[root@localhost ansible]# ssh-keygen -t rsa -P ""
[root@localhost ansible]# for i in {2..5};do ssh-copy-id 172.16.200.10$i;done

分别用ssh登陆上去测试是否已经互信,成功后进入下一步
2.在ansible主机设置/etc/ansible/hosts文件,将主机分组

[director]
172.16.200.10[2:3]

[node]
172.16.200.10[4:5]

3.实现nginx角色,并安装
在ansible主机上
设置nginx配置文件

[root@localhost ansible]# mkdir -p /etc/ansible/roles/nginx/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost ansible]# cd /etc/ansible/roles/nginx/
[root@localhost nginx]# vim files/nginx_ansible.conf
upstream varnish {
        server 172.16.200.102:6081;
        server 172.16.200.103:6081;
}
upstream tomcat {
        server 172.16.200.104:8080;
        server 172.16.200.105:8080;
}
server {
        listen 80;
        server_name www.feng.com;

        location  ~ .*\.(js|css|htm|html|gif|jpg|jpeg|png|bmp|swf|ioc|rar|zip|txt|flv|mid|doc|ppt|pdf|xls|mp3|wma)$ {
                proxy_pass http://varnish;
        }
        location ~ \.(jsp|jspx|do|action)(\/.*)?$ {
                proxy_pass http://tomcat;
        }
}

设置nginx任务文件

[root@localhost nginx]# vim tasks/main.yml
- name: install nginx
  yum: name=nginx state=latest
  when: ansible_os_family == "RedHat"
- name: delete default.conf
  shell: rm -f /etc/nginx/conf.d/default.conf
- name: install nginx config
  copy: src=nginx_ansible.conf dest=/etc/nginx/conf.d/
- name: start nginx
  service: name=nginx state=started

设置执行nginx的playbook文件

[root@localhost nginx]# vim nginx.yml
- hosts: director
  remote_user: root
  roles:
  - nginx

然后执行安装

[root@localhost nginx]# ansible-playbook --syntax-check nginx.yml
[root@localhost nginx]# ansible-playbook  nginx.yml 

PLAY [director] ****************************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.102]
ok: [172.16.200.103]

TASK [nginx : install nginx] ***************************************************
changed: [172.16.200.103]
changed: [172.16.200.102]

TASK [nginx : delete default.conf] *********************************************
changed: [172.16.200.103]
 [WARNING]: Consider using file module with state=absent rather than running rm

changed: [172.16.200.102]

TASK [nginx : install nginx config] ********************************************
changed: [172.16.200.103]
changed: [172.16.200.102]

TASK [nginx : start nginx] *****************************************************
changed: [172.16.200.103]
changed: [172.16.200.102]

PLAY RECAP *********************************************************************
172.16.200.102             : ok=5    changed=4    unreachable=0    failed=0   
172.16.200.103             : ok=5    changed=4    unreachable=0    failed=0

第一步成功
4.实现tomcat角色并安装
创建目录结构并设置任务文件

[root@localhost nginx]# mkdir -p /etc/ansible/roles/tomcat/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost nginx]# cd /etc/ansible/roles/tomcat/
[root@localhost tomcat]# vim tasks/main.yml
- name: install openjdk
  yum: name=java-1.8.0-openjdk-devel state=latest
  when: ansible_os_family == "RedHat"
- name: install tomcat
  yum: name={{ item }} state=latest
  with_items:
  - tomcat-lib
  - tomcat-admin-webapps
  - tomcat-docs-webapp
  - tomcat-webapps
- name: start tomcat
  service: name=tomcat state=started

设置tomcat的playbook文件

[root@localhost tomcat]# vim tomcat.yml
- hosts: node
  remote_user: root
  roles:
  - tomcat

执行安装

[root@localhost tomcat]# ansible-playbook  tomcat.yml

PLAY [node] ********************************************************************

TASK [setup] *******************************************************************
ok: [172.16.200.105]
ok: [172.16.200.104]

TASK [tomcat : install openjdk] ************************************************
changed: [172.16.200.104]
changed: [172.16.200.105]

TASK [tomcat : install tomcat] *************************************************
changed: [172.16.200.105] => (item=[u'tomcat-lib', u'tomcat-admin-webapps', u'tomcat-docs-webapp', u'tomcat-webapps'])
changed: [172.16.200.104] => (item=[u'tomcat-lib', u'tomcat-admin-webapps', u'tomcat-docs-webapp', u'tomcat-webapps'])

TASK [tomcat : start tomcat] ***************************************************
changed: [172.16.200.104]
changed: [172.16.200.105]

PLAY RECAP *********************************************************************
172.16.200.104             : ok=4    changed=3    unreachable=0    failed=0   
172.16.200.105             : ok=4    changed=3    unreachable=0    failed=0  

成功,可以接着下一步了
5.动态的安装完成后安装静态这条线
首先要安在两个调度器节点上安装varnish
创建目录并设置varnish配置文件

[root@localhost tomcat]#  mkdir -p /etc/ansible/roles/varnish/{files,templates,tasks,vars,handlers,meta,default}
[root@localhost tomcat]# cd /etc/ansible/roles/varnish/
[root@localhost varnish]# vim files/default.vcl
import directors;
backend web1 {
    .host="172.16.200.104";
    .port="80";
}

backend web2 {
    .host="172.16.200.105";
    .port="80";
}

sub vcl_init {
        new server = directors.round_robin();
        server.add_backend(web1);
        server.add_backend(web2);
}
sub vcl_recv {
    if (req.method == "PURGE") {
        return(purge);
}
    set req.backend_hint = server.backend();

}
sub vcl_pipe {
        return (pipe);
}

sub vcl_pass {
        return (fetch);
}

设置任务文件

[root@localhost varnish]# vim tasks/main.yml
- name: install varnish
  yum: name=varnish state=latest
  when: ansible_os_family == "RedHat"
- name: install varnish config
  copy: src=default.vcl dest=/etc/varnish
- name: start varnish
  service: name=varnish state=started

设置varnish的playbook

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

推荐阅读更多精彩内容