批处理工具Ansible快速入门 - 自动化运维研究

Ansible介绍

Ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令等功能。

Ansible的特点:

  1. no agent: 不需要在被管控主机上安装任何软件,
  2. no server: 无服务器端,使用时直接运行命令即可,
  3. modules in any languages:基于模块工作,可使用任意语言开发模块,
  4. yaml,not code:使用yaml语言定制剧本playbook,
  5. ssh by default:基于SSH工作
  6. strong multi-tier solution:可实现多级指挥

Ansible的优点

  1. 轻量级,无需在客户端安装agent,更新时,只需在操作机上进行一次更新即可;
  2. 批量任务执行可以写成脚本,而且不用分发到远程就可以执行;
  3. 使用python编写,维护更简单,ruby语法过于复杂;
  4. 支持sudo。

Ansible是基于模块工作的,本身没有批量部署的能力。真正具有批量部署的是Ansible所运行的模块,ansible只是提供一种框架。主要包括:

  1. 连接插件connection plugins:负责和被监控端实现通信;
  2. host inventory:指定操作的主机,是一个配置文件里面定义监控的主机;
  3. 各种模块核心模块、command模块、自定义模块;
  4. 借助于插件完成记录日志邮件等功能;
  5. playbook:剧本执行多个任务时,非必需可以让节点一次性运行多个任务。


    Ansible架构图

Ansible安装

  1. Ansible安装非常简单,只需两条命令即可完成。
[root@crazyting1 ~]# yum install epel -y 
[root@crazyting1 ~]# yum install ansible -y
  1. Ansible配置文件
    2.1. ansible 应用程序的 主配置文件:/etc/ansible/ansible.cfg
    2.2. Host Inventory 定义管控主机 :/etc/ansible/hosts

配置管控主机

  1. 当ansible管理主机时,可以基于ssh的用户密码验证,也可以基于用户的密钥验证
[root@crazyting1 ~]# cat /etc/ansible/hosts 
[tencent]
IP地址 ansible_ssh_pass=密码 asible_ssh_user=用户名

1.1. Hosts部分中经常用到的变量部分:

变量 说明
ansible_ssh_host 用于指定被管理的主机的真实IP
ansible_ssh_port 用于指定连接到被管理主机的ssh端口号,默认是22
ansible_ssh_user ssh连接时默认使用的用户名
ansible_ssh_pass ssh连接时的密码
ansible_sudo_pass 使用sudo连接用户时的密码
ansible_sudo_exec 如果sudo命令不在默认路径,需要指定sudo命令路径
ansible_ssh_private_key_file 秘钥文件路径,秘钥文件如果不想使用ssh-agent管理时可以使用此选项
ansible_shell_type 目标系统的shell的类型,默认sh
ansible_connection SSH 连接的类型: local , ssh , paramiko,在 ansible 1.2 之前默认是 paramiko ,后来智能选择,优先使用基于 ControlPersist 的 ssh (支持的前提)
ansible_python_interpreter 用来指定python解释器的路径,默认为/usr/bin/python 同样可以指定ruby 、perl 的路径
ansible_*_interpreter 其他解释器路径,用法与ansible_python_interpreter类似,这里"*"可以是ruby或才perl等
  1. 免登陆配置
    如果需要管理的服务器较多,建议使用免登陆配置
# 创建密钥,-f 指定存放位置,-P 密钥加密的密码  -q 减少信息输出
[root@crazyting1 ~]# ssh-keygen -t rsa -f /root/.ssh/id_rsa -P "" -q
[root@crazyting1 ~]# ssh-copy-id -i /root/.ssh/id_rsa crazyting2

Ansible语法说明

  1. 语法说明:
ansible HOST-PATTERN [-f FORKS] [-M MOD_NAME] [-a MOD_ARGS]
-f FORKS:表示一批处理几台主机,也就是当被管控主机很多时,ansible不是对所有主机同时发起管理操作,而是一批处理几台,然后再换一批,直到所有主机被处理完成,如果不指定,则默认是5台
-m MOD_NAME:指明调用哪个模块执行操作,各个模块所能实现的功能不同,如果不指定,默认是用-m command模块
-a MOD_ARGS:指明使用该模块的执行操作时的参数

使用示例:

[root@crazyting1 ~]# ansible tencent -m command -a 'date'
ip地址 | SUCCESS | rc=0 >>
Mon Feb 10 17:47:30 CST 2020
  1. 列出所有模块
[root@crazyting1 ~]# ansible-doc -l | grep ping
ios_ping                                             Tests reachability using ping from Cisco IOS network devices                                    
lambda_event                                         Creates, updates or deletes AWS Lambda function event mappings.                                 
net_ping                                             Tests reachability using ping from a network device                                             
netapp_e_lun_mapping                                 Create or Remove LUN Mappings                                                                   
nxos_igmp_snooping                                   Manages IGMP snooping global configuration.                                                     
nxos_ping                                            Tests reachability using ping from Nexus switch.                                                
ping                                                 Try to connect to host, verify a usable python and return `pong' on success                     
pingdom                                              Pause/unpause Pingdom alerts                                                                    
sefcontext                                           Manages SELinux file context mapping definitions                                                
win_ping                                             A windows version of the classic ping module  
  1. 查询模块用法
[root@crazyting1 ~]# ansible-doc ping
...
EXAMPLES:
# Test we can logon to 'webservers' and execute python with json lib.
# ansible webservers -m ping

# Example from an Ansible Playbook
- ping:

# Induce an exception to see what happens
- ping:
    data: crash

RETURN VALUES:

ping:
    description: value provided with the data parameter
    returned: success
    type: string
    sample: pong

或者直接访问:Ansible模块列表

Ansible常用模块

  1. ping模块
    探测助主机是否在线
[root@crazyting1 ~]# ansible crazyting2 -m ping
crazyting2 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
[root@crazyting1 ~]# ansible all -m ping
crazyting2 | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
gz-tencent | SUCCESS => {
    "changed": false, 
    "ping": "pong"
}
  1. command模块
    在远程主机执行命令,不支持管道,重定向等shell特性
常用参数 描述
chdir= 表示指明命令在远程主机上哪个目录下运行,也就是在命令执行前切换到哪个目录下
creates= 在命令运行时创建一个文件,如果文件已存在,则不会执行创建任务
removes= 在命令运行时移除一个文件,如果文件不存在,则不会执行移除任务
executeble= 指明运行命令的shell程序
[root@crazyting1 ~]# ansible crazyting2 -m command -a "date"
crazyting2 | SUCCESS | rc=0 >>
Fri Oct 18 06:47:27 CST 2019

[root@crazyting1 ~]#  ansible crazyting2 -m command -a 'chdir=/tmp ls ./'
crazyting2 | SUCCESS | rc=0 >>
ansible_hvEh_Q
hsperfdata_root

[root@crazyting1 ~]# ansible crazyting2 -m command -a "ps aux | grep kafka"
crazyting2 | FAILED | rc=1 >>
ERROR: Garbage option.
  1. shell模块

在远程主机执行命令,相当于调用远程主机的shell进程,然后在该shell下打开一个子shell运行命令。支持shell特性,如管道,重定向等

常用参数 描述
chdir= 表示指明命令在远程主机上哪个目录下运行,也就是在命令执行前切换到哪个目录下
creates= 在命令运行时创建一个文件,如果文件已存在,则不会执行创建任务
removes= 在命令运行时移除一个文件,如果文件不存在,则不会执行移除任务
executeble= 指明运行命令的shell程序
[root@crazyting1 ~]# ansible crazyting2 -m shell -a 'echo "hello" > /tmp/aa.txt'
crazyting2 | SUCCESS | rc=0 >>

[root@crazyting1 ~]# ansible crazyting2 -m shell -a 'cat  /tmp/aa.txt'
crazyting2 | SUCCESS | rc=0 >>
hello
  1. copy模块
    拷贝ansible管理端的文件到远程主机的指定位置
常见参数 描述
dest= 指明拷贝文件的目标目录位置,使用绝对路径,如果源是目录,则目标也要是目录,如果目标文件已存在,会覆盖原有内容
src= 指明本地路径下的某个文件,可以使用相对路径和绝对路径,支持直接指定目录,如果源是目录,则目标也要是目录
mode= 指明复制时,目标文件的权限
owner= 指明复制时,目标文件的属主
group= 指明复制时,目标文件的属组
content= 指明复制到目标主机上的内容,不能与src一起使用,相当于复制content指明的数据,到目标文件中
[root@crazyting1 ~]# ansible crazyting2  -m copy -a 'src=install.log dest=/tmp mode=777 owner=nobody group=root'
crazyting2 | SUCCESS => {
    "changed": true, 
    "checksum": "6a6ad8ff65e7c9dd26d13d22b881dc555ed311d3", 
    "dest": "/tmp/install.log", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "91e9f658638e9391ed303c7525d5d42c", 
    "mode": "0777", 
    "owner": "nobody", 
    "size": 28523, 
    "src": "/root/.ansible/tmp/ansible-tmp-1581350215.73-280736596777904/source", 
    "state": "file", 
    "uid": 99
}
[root@crazyting2 tmp]# ll 
total 36
-rw-r--r--. 1 root   root     6 Oct 18 07:15 aa.txt
drwxr-xr-x  2 root   root  4096 Feb 10 23:53 hsperfdata_root
-rwxrwxrwx  1 nobody root 28523 Feb 10 23:56 install.log

[root@crazyting1 ~]# ansible crazyting2 -m copy -a 'content="hello world" dest=/tmp/test.txt mode=777'
crazyting2 | SUCCESS => {
    "changed": true, 
    "checksum": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", 
    "dest": "/tmp/test.txt", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "5eb63bbbe01eeed093cb22bb8f5acdc3", 
    "mode": "0777", 
    "owner": "root", 
    "size": 11, 
    "src": "/root/.ansible/tmp/ansible-tmp-1581351194.89-252437495810863/source", 
    "state": "file", 
    "uid": 0
}
[root@crazyting2 tmp]# cat test.txt
hello world
  1. cron模块
    管理计划任务的模块
常见参数 描述
minute= 指明计划任务的分钟,支持格式:0-59,*,*/2等,与正常cron任务定义的一样的语法,省略时,默认为*,也就是每分钟都执行
hour= 指明计划任务的小时,支持的语法:0-23,*,*/2等,省略时,默认为*,也就是每小时都执行
day= 指明计划任务的天,支持的语法:1-31,*,*/2等,省略时,默认为*,也就是每天都执行
month= 指明计划任务的月,支持的语法为:1-12,*,*/2等,省略时,默认为*,也就是每月都执行
weekday= 指明计划任务的星期几,支持的语法为:0-6,*等,省略时,默认为*,也就是每星期几都执行
reboot 指明计划任务执行的时间为每次重启之后
name= 给该计划任务取个名称,必须要给明。每个任务的名称不能一样。删除任务时,只需要给明任务的名称即可
job= 执行的任务是什么,当state=present时才有意义
state=present|absent 表示这个任务是创建还是删除,present表示创建,absent表示删除,默认是present
[root@crazyting1 ~]# ansible crazyting2 -m cron -a 'minute=10 hour=10-20 day=10 name="test cron" job="ntpdate ntp1.aliyun.com  &> /dev/null"'
crazyting2 | SUCCESS => {
    "changed": true, 
    "envs": [], 
    "jobs": [
        "test cron"
    ]
}
[root@crazyting2 ~]# crontab -u root -l
#Ansible: test cron
10 10-20 10 * * ntpdate ntp1.aliyun.com  &> /dev/null
  1. fetch模块
    从远程主机拉取文件到本地。一般情况下,只会从一个远程节点拉取数据
常见参数 描述
dest= 从远程主机上拉取的文件存放在本地的位置,一般只能是目录
src= 指明远程主机上要拉取的文件,只能是文件,不能是目录
[root@crazyting1 ~]# ansible crazyting2 -m fetch -a 'src=/tmp/test.txt dest=/tmp'
crazyting2 | SUCCESS => {
    "changed": true, 
    "checksum": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", 
    "dest": "/tmp/crazyting2/tmp/test.txt", 
    "md5sum": "5eb63bbbe01eeed093cb22bb8f5acdc3", 
    "remote_checksum": "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed", 
    "remote_md5sum": null
}
[root@crazyting1 ~]# ls -R /tmp
/tmp:
crazyting2  hsperfdata_root

/tmp/crazyting2:
tmp

/tmp/crazyting2/tmp:
test.txt
  1. file模块
    用于设定远程主机上的文件属性
    示例:
    创建软链接的用法: src= path= state=link
    修改文件属性的用法: path= owner= mode= group=
    创建目录的用法: path= state=directory
    删除文件: path= state=absent
常见参数 描述
path= 指明对哪个文件修改其属性
src= 指明path=指明的文件是软链接文件,其对应的源文件是谁,必须要在state=link时才有用
state=directory|link|absent 表示创建的文件是目录还是软链接
owner= 指明文件的属主
group= 指明文件的属组
mode= 指明文件的权限
[root@crazyting1 ~]# ansible crazyting2 -m file -a 'path=/tmp/test.txt state=absent'
crazyting2 | SUCCESS => {
    "changed": true, 
    "path": "/tmp/test.txt", 
    "state": "absent"
}
[root@crazyting1 ~]# ^C
[root@crazyting1 ~]# ^C
[root@crazyting1 ~]# ansible crazyting2 -m command -a 'ls /tmp'
crazyting2 | SUCCESS | rc=0 >>
ansible_Dcw5Ok
hsperfdata_root
install.log
  1. hostname模块
    管理远程主机上的主机名
常用参数 描述
name= 指明主机名
[root@crazyting1 ~]# ansible crazyting2 -m hostname -a "name=crazyting22"
crazyting2 | SUCCESS => {
    "ansible_facts": {
        "ansible_domain": "", 
        "ansible_fqdn": "crazyting22", 
        "ansible_hostname": "crazyting22", 
        "ansible_nodename": "crazyting22"
    }, 
    "changed": true, 
    "name": "crazyting22"
}
[root@crazyting1 ~]# ansible crazyting2 -m shell -a "hostname"
crazyting2 | SUCCESS | rc=0 >>
crazyting22
  1. yum模块
    基于yum机制,对远程主机管理程序包
常用参数 描述
name= 指明程序包的名称,可以带上版本号,不指明版本,就是默认最新版本。
state=present|latest|absent 指明对程序包执行的操作,present表示安装程序包,latest表示安装最新版本的程序包,absent表示卸载程序包
disablerepo= 在用yum安装时,临时禁用某个仓库,仓库的ID
enablerepo= 在用yum安装时,临时启用某个仓库,仓库的ID
conf_file= 指明yum运行时采用哪个配置文件,而不是使用默认的配置文件
diable_gpg_check=yes|no 是否启用gpg-check
[root@crazyting1 ~]# ansible crazyting2 -m yum -a 'name=nmap state=present'
crazyting2 | SUCCESS => {
    "changed": true, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror, security\nSetting up Install Process\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package nmap.x86_64 2:5.51-6.el6 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package        Arch             Version                   Repository      Size\n================================================================================\nInstalling:\n nmap           x86_64           2:5.51-6.el6              base           2.8 M\n\nTransaction Summary\n================================================================================\nInstall       1 Package(s)\n\nTotal download size: 2.8 M\nInstalled size: 9.7 M\nDownloading Packages:\nRunning rpm_check_debug\nRunning Transaction Test\nTransaction Test Succeeded\nRunning Transaction\n\r  Installing : 2:nmap-5.51-6.el6.x86_64                                     1/1 \n\r  Verifying  : 2:nmap-5.51-6.el6.x86_64                                     1/1 \n\nInstalled:\n  nmap.x86_64 2:5.51-6.el6                                                      \n\nComplete!\n"
    ]
}
[root@crazyting1 ~]#  ansible crazyting2 -m shell -a 'rpm -q nmap'
 [WARNING]: Consider using the yum, dnf or zypper module rather than running rpm.  If you need to use command because yum, dnf or zypper is insufficient
you can add warn=False to this command task or set command_warnings=False in ansible.cfg to get rid of this message.

crazyting2 | SUCCESS | rc=0 >>
nmap-5.51-6.el6.x86_64

[root@crazyting1 ~]# ansible crazyting2 -m yum -a 'name=nmap state=absent'
crazyting2 | SUCCESS => {
    "changed": true, 
    "msg": "", 
    "rc": 0, 
    "results": [
        "Loaded plugins: fastestmirror, security\nSetting up Remove Process\nResolving Dependencies\n--> Running transaction check\n---> Package nmap.x86_64 2:5.51-6.el6 will be erased\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package        Arch             Version                  Repository       Size\n================================================================================\nRemoving:\n nmap           x86_64           2:5.51-6.el6             @base           9.7 M\n\nTransaction Summary\n================================================================================\nRemove        1 Package(s)\n\nInstalled size: 9.7 M\nDownloading Packages:\nRunning rpm_check_debug\nRunning Transaction Test\nTransaction Test Succeeded\nRunning Transaction\n\r  Erasing    : 2:nmap-5.51-6.el6.x86_64                                     1/1 \n\r  Verifying  : 2:nmap-5.51-6.el6.x86_64                                     1/1 \n\nRemoved:\n  nmap.x86_64 2:5.51-6.el6                                                      \n\nComplete!\n"
    ]
}
[root@crazyting1 ~]#  ansible crazyting2 -m shell -a 'rpm -q nmap'
 [WARNING]: Consider using the yum, dnf or zypper module rather than running rpm.  If you need to use command because yum, dnf or zypper is insufficient
you can add warn=False to this command task or set command_warnings=False in ansible.cfg to get rid of this message.

crazyting2 | FAILED | rc=1 >>
package nmap is not installednon-zero return code
  1. service模块
    用来管理远程主机上的服务的模块
常见参数 描述
name= 被管理的服务名称
state=started|stopped|restarted started启动服务, stopped停止服务, restarted重启服务, reloaded重载配置
enabled=yes|no 表示要不要设定该服务开机自启动
runlevel= 如果设定了enabled开机自动启动,则要定义在哪些运行级别下自动启动
[root@crazyting1 ~]# ansible crazyting2 -m service -a 'name=ntpd state=started'
crazyting2 | SUCCESS => {
    "changed": true, 
    "name": "ntpd", 
    "state": "started"
}
[root@crazyting1 ~]#  ansible crazyting2 -m shell -a 'service ntpd status'
 [WARNING]: Consider using the service module rather than running service.  If you need to use command because service is insufficient you can add
warn=False to this command task or set command_warnings=False in ansible.cfg to get rid of this message.

crazyting2 | SUCCESS | rc=0 >>
ntpd (pid  12248) is running...

[root@crazyting1 ~]#  ansible crazyting2 -m service -a 'name=ntpd state=stopped'
crazyting2 | SUCCESS => {
    "changed": true, 
    "name": "ntpd", 
    "state": "stopped"
}
  1. uri模块
    如果远端是web服务器,可以利用ansible直接请求某个网页
常见参数 描述
url= 指明请求的url的路径,如:http://10.1.32.68/test.jpg
user= 如果请求的url需要认证,则认证的用户名是什么
password= 如果请求的url需要认证,则认证的密码是什么
method= 指明请求的方法,如GET、POST…
body= 指明报文中实体部分的内容,一般是POST方法或PUT方法时用到
HEADER_ 自定义请求报文中的添加的首部
  1. group模块
    用来添加或删除远端主机的用户组
常见参数 描述
name= 被管理的组名
state=present|absent 是添加还是删除,不指名默认为添加
gid= 指明GID
system=yes|no 是否为系统组
  1. user模块
    管理远程主机上的用户的账号
常见参数 描述
name= 指明要管理的账号名称
state=present|absent 指明是创建账号还是删除账号,present表示创建,absent表示删除
system=yes|no 指明是否为系统账号
uid= 指明用户UID
group= 指明用户的基本组
groups= 指明用户的附加组
shell= 指明默认的shell
home= 指明用户的家目录
move_home=yes|no 当home设定了家目录,如果要创建的家目录已存在,是否将已存在的家目录进行移动
password= 指明用户的密码,最好使用加密好的字符串
comment= 指明用户的注释信息
remove=yes|no 当state=absent时,也就是删除用户时,是否要删除用户的而家目录
  1. script模块
    将管理端的某个脚本,移动到远端主机(不需要指明传递到远端主机的哪个路径下,系统会自动移动,然后执行),
    一般是自动移动到远端主机的/root/.ansible/tmp目录下,然后自动给予其权限,然后再开个子shell然后运行脚本,运行完成后删除脚本
[root@crazyting1 ~]# cat > test.sh<<EOF
> #!/bin/bash
> echo "hello world" >> /tmp/robin.txt
> EOF
[root@crazyting1 ~]#  ansible crazyting2 -m script -a '/root/test.sh'
crazyting2 | SUCCESS => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to crazyting2 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to crazyting2 closed."
    ], 
    "stdout": "", 
    "stdout_lines": []
}
[root@crazyting2 ~]# cat /tmp/robin.txt
hello world
  1. setup模块
    可收集远程主机的facts变量的信息,相当于收集了目标主机的相关信息(如内核版本、操作系统信息、cpu、…),保存在ansible的内置变量中,之后我们有需要用到时,直接调用变量即可
[root@crazyting1 ~]# ansible crazyting2 -m setup  -a 'filter="ansible_all_ipv4_addresses"'
crazyting2 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.2.115"
        ]
    }, 
    "changed": false
}

常用列表:

参数 描述
ansible_all_ipv4_addresses 仅显示ipv4的信息。
ansible_devices 仅显示磁盘设备信息。
ansible_distribution 显示是什么系统,例:centos,suse等。
ansible_distribution_major_version 显示是系统主版本。
ansible_distribution_version 仅显示系统版本。
ansible_machine 显示系统类型,例:32位,还是64位。
ansible_eth0 仅显示eth0的信息。
ansible_hostname 仅显示主机名。
ansible_kernel 仅显示内核版本。
ansible_lvm 显示lvm相关信息。
ansible_memtotal_mb 显示系统总内存。
ansible_memfree_mb 显示可用系统内存。
ansible_memory_mb 详细显示内存情况。
ansible_swaptotal_mb 显示总的swap内存。
ansible_swapfree_mb 显示swap内存的可用内存。
ansible_mounts 显示系统磁盘挂载情况。
ansible_processor 显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus 显示cpu个数(只显示总的个数)。
  1. template模块
    基于模板方式,生成一个模板文件,复制到远程主机,让远程主机基于模板,生成符合远程主机自身的文件

注意:此模块不能在命令行使用,只能用在playbook中使用

常见的参数 描述
src= 指明管理端本地的模板文件的目录
dest= 指明将模板文件拷贝到远程主机的哪个目录下
owner= 指明拷贝到远程主机的文件的属主
group= 指明拷贝到远程主机的文件的属组
mode= 指明拷贝到远程主机的文件的权限

下一篇我们将了解一下 Ansible的高级用法

参考文档:
Ansible基础命令

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

推荐阅读更多精彩内容