自动化运维-ansible

目录

十五、ansible介绍
十六、ansible安装
十七、ansible远程执行命令
十八、ansible拷贝文件或目录
十九、ansible远程执行脚本
二十、ansible管理任务计划
二十一、ansible安装包和管理服务
二十二、使用ansible playbook
二十三、playbook里的变量
二十四、playbook循环
二十五、playbook中的条件判断
二十六、playbook中的handlers
二十七、用playbook安装nginx
二十八、playbook管理配置文件

十五、ansible介绍

不需要安装客户端,通过sshd去通信
基于模块工作,模块可以由任何语言开发
不仅支持命令行使用模块,也支持编写yaml格式的playbook,易于编写和阅读
安装十分简单,centos上可直接yum安装
有提供UI(浏览器图形化)www.ansible.com/tower,收费的
官方文档 http://docs.ansible.com/ansible/latest/index.html
ansible已经被redhat公司收购,它在github上是一个非常受欢迎的开源软件,github地址https://github.com/ansible/ansible
一本不错的入门电子书 https://ansible-book.gitbooks.io/ansible-first-book/

十六、ansible安装

准备两台机器,前面我们做实验的两台机器minglinux-01,minglinux-02
只需要在minglinux-01上安装ansible
yum list |grep ansible 可以看到自带源里就有ansible
yum install -y ansible
minglinux-01上生成密钥对 ssh-keygen -t rsa
把公钥放到minglinux-02上,设置密钥认证
同时对本机也设置密钥认证
vim /etc/ansible/hosts //增加
[testhost]
127.0.0.1
192.168.162.132
说明: testhost为主机组名字,自定义的。 下面两个ip为组内的机器ip。

[root@minglinux-01 /srv/salt] yum list |grep ansible |head -2
ansible.noarch                          2.7.8-1.el7                    @epel    
ansible-doc.noarch                      2.7.8-1.el7                    @epel  
[root@minglinux-01 /srv/salt] yum install -y ansible ansible-doc

#查看minglinux-01上生成的公钥,进行设置密钥认证
[root@minglinux-01 /srv/salt] ls /root/.ssh/
authorized_keys  id_rsa  id_rsa.pub  known_hosts
[root@minglinux-01 /srv/salt] cat /root/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLqBZ25bFoIDOLbZxWH54H2VWnkTXKf7lDC9vdCBN9C7ryA4Rb+iTp9Lzk1AJxy++Zu97nndhACxdLPLs0A4j90yoXBkZ07QNZl2PGqWFZB0mMMvwG24MUsYk+3POG1n+nY4l6J7U//XVJWHfic+WD/1+Y2mLo+zWALTHA2pV/ebcuRxE5AIWAbzTas3vSDbkHgcDEQxMJRa+nltVOald+wt4O/H1Ic8nbbwPbAvJlotxm3x59D8ul8HnmOiT4FqzngIOoijjUmyouUFJzCIQf+UZKgA1GiXDZ1ap5wq1PMp8XFJpUuuF+nVs5M86TBJ54kxD4eq+bDAJ4jOUR2s57 root@minglinux-01

 #对本机设置密钥认证
[root@minglinux-01 ~] cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys 
[root@minglinux-01 ~] cat .ssh/authorized_keys 
···
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLqBZ25bFoIDOLbZxWH54H2VWnkTXKf7lDC9vdCBN9C7ryA4Rb+iTp9Lzk1AJxy++Zu97nndhACxdLPLs0A4j90yoXBkZ07QNZl2PGqWFZB0mMMvwG24MUsYk+3POG1n+nY4l6J7U//XVJWHfic+WD/1+Y2mLo+zWALTHA2pV/ebcuRxE5AIWAbzTas3vSDbkHgcDEQxMJRa+nltVOald+wt4O/H1Ic8nbbwPbAvJlotxm3x59D8ul8HnmOiT4FqzngIOoijjUmyouUFJzCIQf+UZKgA1GiXDZ1ap5wq1PMp8XFJpUuuF+nVs5M86TBJ54kxD4eq+bDAJ4jOUR2s57 root@minglinux-01
[root@minglinux-01 ~] ssh minglinux-01
Last login: Tue Mar 12 16:35:13 2019 from minglinux-01
[root@minglinux-01 ~] w
 19:59:20 up  6:27,  2 users,  load average: 0.00, 0.02, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.162.1    13:34    0.00s  0.91s  0.02s ssh minglinux-01
root     pts/1    minglinux-01     19:59    0.00s  0.05s  0.01s w

#设置minglinux-02的密钥认证
[root@minglinux-02 ~] cat /root/.ssh/authorized_keys  
···
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLqBZ25bFoIDOLbZxWH54H2VWnkTXKf7lDC9vdCBN9C7ryA4Rb+iTp9Lzk1AJxy++Zu97nndhACxdLPLs0A4j90yoXBkZ07QNZl2PGqWFZB0mMMvwG24MUsYk+3POG1n+nY4l6J7U//XVJWHfic+WD/1+Y2mLo+zWALTHA2pV/ebcuRxE5AIWAbzTas3vSDbkHgcDEQxMJRa+nltVOald+wt4O/H1Ic8nbbwPbAvJlotxm3x59D8ul8HnmOiT4FqzngIOoijjUmyouUFJzCIQf+UZKgA1GiXDZ1ap5wq1PMp8XFJpUuuF+nVs5M86TBJ54kxD4eq+bDAJ4jOUR2s57 root@minglinux-01
[root@minglinux-01 /srv/salt] ssh minglinux-02
Last login: Tue Mar 12 16:35:26 2019 from minglinux-01

#设置主机组
[root@minglinux-01 ~] vim /etc/ansible/hosts
#写入以下内容
 25 [testhost]
 26 127.0.0.1
 27 minglinux-02
#testhost为自定义主机组名字。 下面两个ip为组内的机器ip。

十七、ansible远程执行命令

ansible testhost -m command -a 'w'
这样就可以批量执行命令了。这里的testhost 为主机组名,-m后边是模块名字,-a后面是命令。当然我们也可以直接写一个ip,针对某一台机器来执行命令。
ansible 127.0.0.1 -m command -a 'hostname'
错误: "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
解决: yum install -y libselinux-python
还有一个模块就是shell同样也可以实现
ansible testhost -m shell -a 'w'

[root@minglinux-01 ~] ansible  testhost -m command -a 'w' 
127.0.0.1 | CHANGED | rc=0 >>
 21:47:32 up  8:15,  2 users,  load average: 0.03, 0.06, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.162.1    13:34    4.00s  3.72s  0.01s ssh -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/root/.ansible/cp/1ad903f8ab -tt 192.168.162.132 /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1552398450.92-236475746352593/AnsiballZ_command.py && sleep 0'
root     pts/3    localhost        21:47    1.00s  0.29s  0.02s w

192.168.162.132 | CHANGED | rc=0 >>
 21:47:59 up  8:15,  2 users,  load average: 0.00, 0.01, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/0    192.168.162.1    21:34     ?     0.17s  0.17s -bash
root     pts/1    minglinux-01     21:47    1.00s  0.44s  0.01s w

[root@minglinux-01 ~] ansible  testhost -m command -a 'hostname' 
127.0.0.1 | CHANGED | rc=0 >>
minglinux-01

192.168.162.132 | CHANGED | rc=0 >>
minglinux-02

#仅针对一台机器
[root@minglinux-01 ~] ansible minglinux-02 -m command -a 'hostname' 
minglinux-02 | CHANGED | rc=0 >>
minglinux-02

# 还有一个模块就是shell同样也可以实现 
[root@minglinux-01 ~] ansible  testhost -m shell -a 'hostname' 
192.168.162.132 | CHANGED | rc=0 >>
minglinux-02

127.0.0.1 | CHANGED | rc=0 >>
minglinux-01

十八、ansible拷贝文件或目录

ansible minglinux-02 -m copy -a "src=/etc/ansible dest=/tmp/ansible_test owner=root group=root mode=0755"
注意:源目录会放到目标目录下面去,如果目标指定的目录不存在,它会自动创建。如果拷贝的是文件,dest指定的名字和源如果不同,并且它不是已经存在的目录,相当于拷贝过去后又重命名。但相反,如果desc是目标机器上已经存在的目录,则会直接把文件拷贝到该目录下面。
ansible testhost -m copy -a "src=/etc/passwd dest=/tmp/123"
这里的/tmp/123和源机器上的/etc/passwd是一致的,但如果目标机器上已经有/tmp/123目录,则会再/tmp/123目录下面建立passwd文件

#对目录的操作
[root@minglinux-01 ~] ansible minglinux-02 -m copy -a "src=/etc/ansible  dest=/tmp/ansible_test owner=root group=root mode=0755"
minglinux-02 | CHANGED => {
    "changed": true, 
    "dest": "/tmp/ansible_test/", 
    "src": "/etc/ansible"
}
#minglinux-02可以看到目标目录被创建且源目录在目标目录下面
[root@minglinux-02 ~] ls -l /tmp/ansible_test
总用量 0
drwxr-xr-x 3 root root 51 3月  12 22:08 ansible

#对文件的操作
[root@minglinux-01 ~] ansible minglinux-02 -m copy -a "src=/etc/passwd dest=/tmp/123"
[root@minglinux-02 ~] ls -l /tmp/123/passwd 
-rw-r--r-- 1 root root 1754 3月  12 22:15 /tmp/123/passwd
#因为目标机器上已经有/tmp/123目录,则会在/tmp/123目录下面建立passwd文件

[root@minglinux-01 ~] ansible minglinux-02 -m copy -a "src=/etc/passwd dest=/tmp/1.txt"
[root@minglinux-02 ~] ls -l /tmp/1.txt 
-rw-r--r-- 1 root root 1754 3月  12 22:19 /tmp/1.txt
#这里1.txt就是passwd文件
#操作时要看src和dest是文件还是目录

十九、ansible远程执行脚本

首先创建一个shell脚本
vim /tmp/1.sh //加入内容
#!/bin/bash
echo `date` > /tmp/ansible_test.txt
然后把该脚本分发到各个机器上
ansible testhost -m copy -a "src=/tmp/1.sh dest=/tmp/1.sh mode=0755"
最后是批量执行该shell脚本
ansible testhost -m shell -a "/tmp/1.sh"
shell模块,还支持远程执行命令并且带管道
ansible testhost -m shell -a "cat /etc/passwd|wc -l "

[root@minglinux-01 ~] vim /tmp/1.sh
#脚本内容如下
  1  #!/bin/bash
  2  echo `date` > /tmp/ansible_test.txt

#把该脚本分发到各个机器上
[root@minglinux-01 ~] ansible testhost -m copy -a "src=/tmp/1.sh dest=/tmp/test.sh mode=0755"
minglinux-02 | CHANGED => {
    "changed": true, 
    "checksum": "8b98a2723b00c97e5e8bee4625a90f17925bee43", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "fff8aec86bb38a5bf14d5a878664abc0", 
    "mode": "0755", 
    "owner": "root", 
    "size": 51, 
    "src": "/root/.ansible/tmp/ansible-tmp-1552400956.53-228457569305656/source", 
    "state": "file", 
    "uid": 0
}
127.0.0.1 | CHANGED => {
    "changed": true, 
    "checksum": "8b98a2723b00c97e5e8bee4625a90f17925bee43", 
    "dest": "/tmp/test.sh", 
    "gid": 0, 
    "group": "root", 
    "md5sum": "fff8aec86bb38a5bf14d5a878664abc0", 
    "mode": "0755", 
    "owner": "root", 
    "size": 51, 
    "src": "/root/.ansible/tmp/ansible-tmp-1552400956.51-98771450695458/source", 
    "state": "file", 
    "uid": 0
}
[root@minglinux-01 ~] ls /tmp/test.sh
/tmp/test.sh
[root@minglinux-01 ~] cat !$
cat /tmp/test.sh
 #!/bin/bash
 echo `date` > /tmp/ansible_test.txt


#批量执行该shell脚本
[root@minglinux-01 ~] ansible testhost -m shell -a "/tmp/test.sh"
minglinux-02 | CHANGED | rc=0 >>


127.0.0.1 | CHANGED | rc=0 >>

#脚本远程执行成功
[root@minglinux-01 ~] ls /tmp/ansible_test.txt 
/tmp/ansible_test.txt
[root@minglinux-01 ~] cat !$
cat /tmp/ansible_test.txt
2019年 03月 12日 星期二 22:31:47 CST
[root@minglinux-02 ~] ls /tmp/ansible_test.txt 
/tmp/ansible_test.txt
[root@minglinux-02 ~] cat !$
cat /tmp/ansible_test.txt
2019年 03月 12日 星期二 22:32:14 CST

#shell模块,还支持远程执行命令并且带管道,而command模块是不支持带管道的
[root@minglinux-01 ~] ansible testhost -m shell -a "cat /etc/passwd|wc -l"
minglinux-02 | CHANGED | rc=0 >>
30

127.0.0.1 | CHANGED | rc=0 >>
36

[root@minglinux-01 ~] ansible testhost -m command -a "cat /etc/passwd|wc -l"
minglinux-02 | FAILED | rc=1 >>
cat:无效选项 -- l
Try 'cat --help' for more information.non-zero return code

127.0.0.1 | FAILED | rc=1 >>
cat:无效选项 -- l
Try 'cat --help' for more information.non-zero return code

二十、ansible管理任务计划

ansible testhost -m cron -a "name='test cron' job='/bin/touch /tmp/1212.txt' weekday=6"
若要删除该cron 只需要加一个字段 state=absent
ansible testhost -m cron -a "name='test cron' state=absent"
其他的时间表示:分钟 minute 小时 hour 日期 day 月份 month

#使用cron模块创建计划任务
[root@minglinux-01 ~] ansible minglinux-02 -m cron -a "name='test cron' job='/bin/touch /tmp/121.txt' weekday=6"
minglinux-02 | CHANGED => {
    "changed": true, 
    "envs": [], 
    "jobs": [
        "test cron"
    ]
}
#查看任务计划
[root@minglinux-02 ~] crontab -l
# Lines below here are managed by Salt, do not edit
#Ansible: test cron
* * * * 6 /bin/touch /tmp/121.txt

#删除任务计划
[root@minglinux-01 ~] ansible minglinux-02 -m cron -a "name='test cron' state=absent"
minglinux-02 | CHANGED => {
    "changed": true, 
    "envs": [], 
    "jobs": []
}
#再次查看任务计划
[root@minglinux-02 ~] crontab -l
# Lines below here are managed by Salt, do not edit
[root@minglinux-02 ~] crontab -e  #把那行给删除了
crontab: installing new crontab
[root@minglinux-02 ~] crontab -l
#crontab文件中的内容不要手动更改,否则会导致使用ansible无法继续操作

二十一、ansible安装包和管理服务

ansible testhost -m yum -a "name=httpd"
在name后面还可以加上state=installed/removed
ansible testhost -m service -a "name=httpd state=started enabled=yes"
这里的name是centos系统里的服务名,可以通过chkconfig --list查到。
Ansible文档的使用
ansible-doc -l 列出所有的模块
ansible-doc cron 查看指定模块的文档

#因为02机器已经安装了httpd,所以这里先执行卸载命令
[root@minglinux-01 ~] ansible minglinux-02 -m yum -a "name=httpd state=removed"
[root@minglinux-02 ~] rpm -qa httpd

#重新安装,耗时可能较久
[root@minglinux-01 ~] ansible minglinux-02 -m yum -a "name=httpd state=installed"  
[root@minglinux-02 ~] rpm -qa httpd  
httpd-2.4.6-88.el7.centos.x86_64

#远程启动httpd
[root@minglinux-01 ~] ansible minglinux-02 -m service -a "name=httpd state=started enabled=no"
[root@minglinux-02 ~] ps aux |grep httpd
root      17984  0.1  0.2 224052  5004 ?        Ss   23:16   0:00 /usr/sbin/httpd -DFOREGROUND
apache    17985  0.0  0.1 224052  2952 ?        S    23:16   0:00 /usr/sbin/httpd -DFOREGROUND
apache    17986  0.0  0.1 224052  2952 ?        S    23:16   0:00 /usr/sbin/httpd -DFOREGROUND
apache    17987  0.0  0.1 224052  2952 ?        S    23:16   0:00 /usr/sbin/httpd -DFOREGROUND
apache    17988  0.0  0.1 224052  2952 ?        S    23:16   0:00 /usr/sbin/httpd -DFOREGROUND
apache    17989  0.0  0.1 224052  2952 ?        S    23:16   0:00 /usr/sbin/httpd -DFOREGROUND
root      18017  0.0  0.0 112720   984 pts/0    S+   23:17   0:00 grep --color=auto httpd

#Ansible文档的使用
[root@minglinux-01 ~] ansible-doc -l  #列出所有的模块
[root@minglinux-01 ~] ansible-doc cron #查看指定模块的文档
[root@minglinux-01 ~] ansible-doc shell

二十二、使用ansible playbook

相当于把模块写入到配置文件里面,例:
vi /etc/ansible/test.yml //加入如下内容
---
- hosts: minglinux-02
remote_user: root
tasks:
- name: test_playbook
shell: touch /tmp/hello.txt
说明: 第一行需要有三个杠,hosts参数指定了对哪些主机进行参作,如果是多台机器可以用逗号作为分隔,也可以使用主机组,在/etc/ansible/hosts里定义;
user参数指定了使用什么用户登录远程主机操作;
tasks指定了一个任务,其下面的name参数同样是对任务的描述,在执行过程中会打印出来,shell是ansible模块名字
执行:ansible-playbook test.yml

[root@minglinux-01 ~] vim /etc/ansible/test.yml

  1 ---
  2 - hosts: minglinux-02
  3   remote_user: root
  4   tasks:
  5     - name: test_playbook
  6       shell: touch /tmp/hello.txt

#执行
[root@minglinux-01 ~] ansible-playbook /etc/ansible/test.yml

 _____________________
< PLAY [minglinux-02] >
 ---------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ________________________
< TASK [Gathering Facts] >
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02]
 ______________________
< TASK [test_playbook] >
 ----------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 [WARNING]: Consider using the file module with state=touch rather than running 'touch'.  If you need
to use command because file 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.

changed: [minglinux-02]
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=2    changed=1    unreachable=0    failed=0   

[root@minglinux-02 ~] ls /tmp/hello.txt 
/tmp/hello.txt    #有了
[root@minglinux-02 ~] ll !$
ll /tmp/hello.txt
-rw-r--r-- 1 root root 0 3月  12 23:36 /tmp/hello.txt

二十三、playbook里的变量

再来一个创建用户的例子:
vi /etc/ansible/create_user.yml //加入如下内容
---
- name: create_user
hosts: minglinux-02
user: root
gather_facts: false
vars:
- user: "test"
tasks:
- name: create user
user: name="{{ user }}"
说明:name参数对该playbook实现的功能做一个概述,后面执行过程中,会打印 name变量的值 ,可以省略;gather_facts参数指定了在以下任务部分执行前,是否先执行setup模块获取主机相关信息,这在后面的task会使用到setup获取的信息时用到;vars参数,指定了变量,这里指字一个user变量,其值为test ,需要注意的是,变量值一定要用引号引住;user提定了调用user模块,name是user模块里的一个参数,而增加的用户名字调用了上面user变量的值。

[root@minglinux-01 ~] vim /etc/ansible/create_user.yml
#加入如下内容
  1 ---
  2 - name: create_user
  3   hosts: minglinux-02
  4   user: root
  5   gather_facts: false
  6   vars:
  7     - user: "test"
  8   tasks:
  9     - name: create user
 10       user: name="{{ user }}"

[root@minglinux-01 ~] ansible-playbook /etc/ansible/create_user.yml
 ____________________
< PLAY [create_user] >
 --------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ____________________
< TASK [create user] >
 --------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=1    changed=1    unreachable=0    failed=0   
#查看创建的用户
[root@minglinux-02 ~] id test
uid=1002(test) gid=1002(test) 组=1002(test)
#如果用户已创建,运行该操作是changed=0
[root@minglinux-01 ~] ansible-playbook /etc/ansible/create_user.yml
···
minglinux-02               : ok=1    changed=0    unreachable=0    failed=0  

二十四、playbook循环

vi /etc/ansible/while.yml //加入如下内容
---
- hosts: testhost
user: root
tasks:
- name: change mode for files
file: path=/tmp/{{ item }} mode=600
with_items:
- 1.txt
- 2.txt
- 3.txt
说明: with_items为循环的对象
执行 ansible-playbook while.yml

[root@minglinux-01 ~] vim /etc/ansible/while.yml 
#加入如下内容,创建文件并改权限,循环三次
  1 ---
  2 - hosts: minglinux-02
  3   user: root
  4   tasks:
  5     - name: change mode for files
  6       file: path=/tmp/{{ item }} state=touch mode=600
  7       with_items:
  8         - 1.txt
  9         - 2.txt
 10         - 3.txt

#执行
[root@minglinux-01 ~] ansible-playbook /etc/ansible/while.yml
 _____________________
< PLAY [minglinux-02] >
 ---------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ________________________
< TASK [Gathering Facts] >
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02]
 ______________________________
< TASK [change mode for files] >
 ------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02] => (item=1.txt)
changed: [minglinux-02] => (item=2.txt)
changed: [minglinux-02] => (item=3.txt)
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=2    changed=1    unreachable=0    failed=0   
#禁用Gathering Facts效率更高

[root@minglinux-02 ~] ll /tmp/*.txt
-rw-r--r-- 1 root root    0 3月  12 23:55 /tmp/111.txt
-rw-r--r-- 1 root root 1754 3月  12 23:47 /tmp/123.txt
-rw------- 1 root root    0 3月  13 00:17 /tmp/1.txt
-rw------- 1 root root    0 3月  13 00:17 /tmp/2.txt
-rw------- 1 root root    0 3月  13 00:17 /tmp/3.txt
-rw-r--r-- 1 root root   43 3月  12 22:32 /tmp/ansible_test.txt
-rw-r--r-- 1 root root    0 3月  12 23:36 /tmp/hello.txt

二十五、playbook中的条件判断

vi /etc/ansible/when.yml //加入如下内容
---
- hosts: minglinux-02
user: root
gather_facts: True
tasks:
- name: use when
shell: touch /tmp/when.txt
when: ansible_ens33.ipv4.address == "192.168.162.132“
说明:ansible aming-02 -m setup 可以查看到所有的facter信息

[root@minglinux-01 ~] vim /etc/ansible/when.yml

  1 ---
  2 - hosts: minglinux-02
  3   user: root
  4   gather_facts: True
  5   tasks:
  6     - name: use when
  7       shell: touch /tmp/when.txt
  8       when: ansible_ens33.ipv4.address == "192.168.162.132"  #条件选择,只有02机器才会执行

#执行
[root@minglinux-01 ~] ansible minglinux-02 -m setup #可以查看到所有的facter信息
[root@minglinux-01 ~] ansible-playbook /etc/ansible/when.yml
 _____________________
< PLAY [minglinux-02] >
 ---------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ________________________
< TASK [Gathering Facts] >
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02]
 _________________
< TASK [use when] >
 -----------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 [WARNING]: Consider using the file module with state=touch rather than running 'touch'.  If you need
to use command because file 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.

changed: [minglinux-02]
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=2    changed=1    unreachable=0    failed=0   

#查看文件
[root@minglinux-02 ~] ls /tmp/when.txt 
/tmp/when.txt
[root@minglinux-02 ~] ll !$
ll /tmp/when.txt
-rw-r--r-- 1 root root 0 3月  13 00:38 /tmp/when.txt

二十六、playbook中的handlers

执行task之后,服务器发生变化之后要执行的一些操作,比如我们修改了配置文件后,需要重启一下服务
vi /etc/ansible/handlers.yml//加入如下内容
---
- name: handlers test
hosts: minglinux-02
user: root
tasks:
- name: copy file
copy: src=/etc/passwd dest=/tmp/aaa.txt
notify: test handlers
handlers:
- name: test handlers
shell: echo "111111" >> /tmp/aaa.txt
说明,只有copy模块真正执行后,才会去调用下面的handlers相关的操作。这种比较适合配置文件发生更改后,重启服务的操作。

[root@minglinux-01 ~] vim /etc/ansible/handlers.yml
#写入以下内容
  1 ---
  2 - name: handlers test
  3   hosts: minglinux-02
  4   user: root
  5   tasks:
  6     - name: copy file
  7       copy: src=/etc/passwd dest=/tmp/aaa.txt
  8       notify: test handlers
  9   handlers:
 10     - name: test handlers
 11       shell: echo "111111" >> /tmp/aaa.txt
#执行
[root@minglinux-01 ~] ansible-playbook /etc/ansible/handlers.yml
 ______________________
< PLAY [handlers test] >
 ----------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ________________________
< TASK [Gathering Facts] >
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02]
 __________________
< TASK [copy file] >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 _________________________________
< RUNNING HANDLER [test handlers] >
 ---------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=3    changed=2    unreachable=0    failed=0   

#查看执行后效果
[root@minglinux-02 ~] ls /tmp/aaa.txt 
/tmp/aaa.txt
[root@minglinux-02 ~] cat /tmp/aaa.txt | tail -5
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
zabbix:x:998:995:Zabbix Monitoring System:/var/lib/zabbix:/sbin/nologin
memcached:x:997:994:Memcached daemon:/run/memcached:/sbin/nologin
mongod:x:996:993:mongod:/var/lib/mongo:/bin/false
111111

二十七、用playbook安装nginx

  • playbook实战-nginx安装1

思路:先在一台机器上编译安装好nginx、打包,然后再用ansible去下发
cd /etc/ansible 进入ansible配置文件目录
mkdir nginx_install 创建一个nginx_install的目录,方便管理
cd nginx_install
mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
说明:roles目录下有两个角色,common为一些准备操作,install为安装nginx的操作。每个角色下面又有几个目录,handlers下面是当发生改变时要执行的操作,通常用在配置文件发生改变,重启服务。files为安装时用到的一些文件,meta为说明信息,说明角色依赖等信息,tasks里面是核心的配置文件,templates通常存一些配置文件,启动脚本等模板文件,vars下为定义的变量

[root@minglinux-01 ~] cd /etc/ansible
[root@minglinux-01 /etc/ansible] mkdir nginx_install
[root@minglinux-01 /etc/ansible] cd nginx_install/
[root@minglinux-01 /etc/ansible/nginx_install] mkdir -p roles/{common,install}/{handlers,files,meta,tasks,templates,vars}
[root@minglinux-01 /etc/ansible/nginx_install] ls
roles
[root@minglinux-01 /etc/ansible/nginx_install] ls roles/
common  install
[root@minglinux-01 /etc/ansible/nginx_install] ls roles/common/
files  handlers  meta  tasks  templates  vars
[root@minglinux-01 /etc/ansible/nginx_install] ls roles/install/
files  handlers  meta  tasks  templates  vars

  • playbook实战-nginx安装2

需要事先准备好安装用到的文件,具体如下:
在一台机器上事先编译安装好nginx,配置好启动脚本,配置好配置文件
安装好后,我们需要把nginx目录打包,并放到/etc/ansible/nginx_install/roles/install/files/下面,名字为nginx.tar.gz
启动脚本、配置文件都要放到/etc/ansible/nginx_install/roles/install/templates下面
cd /etc/ansible/nginx_install/roles
定义common的tasks,nginx是需要一些依赖包的
vim ./common/tasks/main.yml //内容如下
- name: Install initializtion require software
yum: name={{ item }} state=installed
with_items:
- zlib-devel
- pcre-devel

[root@minglinux-01 /etc/ansible/nginx_install] ls /usr/local/nginx/  #nginx目录
client_body_temp  conf  fastcgi_temp  html  logs  proxy_temp  sbin  scgi_temp  uwsgi_temp
[root@minglinux-01 /etc/ansible/nginx_install] ls /etc/init.d/nginx  #启动脚本
/etc/init.d/nginx
[root@minglinux-01 /etc/ansible/nginx_install] ls  /usr/local/nginx/conf/nginx.conf  #配置文件
/usr/local/nginx/conf/nginx.conf

#把nginx目录打包
[root@minglinux-01 /usr/local] tar czvf nginx.tar.gz --exclude "nginx.conf" --exclude "vhost" nginx/
[root@minglinux-01 /usr/local] mv nginx.tar.gz /etc/ansible/nginx_install/roles/install/files/ 
[root@minglinux-01 /usr/local] cp nginx/conf/nginx.conf /etc/ansible/nginx_install/roles/install/templates/
[root@minglinux-01 /usr/local] cp /etc/init.d/nginx /etc/ansible/nginx_install/roles/install/templates/

#定义common的tasks,安装nginx需要的一些依赖包
[root@minglinux-01 /usr/local] cd  /etc/ansible/nginx_install/roles
[root@minglinux-01 ~] vim /etc/ansible/nginx_install/roles/common/tasks/main.yml 
#写入以下内容
  1 - name: Install initializtion require software
  2   yum: name={{ item }} state=installed
  3   with_items:
  4     - zlib-devel
  5     - pcre-devel

  • playbook实战-nginx安装3

定义变量
vim /etc/ansible/nginx_install/roles/install/vars/main.yml //内容如下
nginx_user: www
nginx_port: 80
nginx_basedir: /usr/local/nginx
首先要把所有用到的文档拷贝到目标机器
vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml //内容如下
- name: Copy Nginx Software
copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root
- name: Uncompression Nginx Software
shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/
- name: Copy Nginx Start Script
template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
- name: Copy Nginx Config
template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=0644

#定义一些变量
[root@minglinux-01 ~] vim /etc/ansible/nginx_install/roles/install/vars/main.yml
#内容如下
  1 nginx_user: www
  2 nginx_port: 80
  3 nginx_basedir: /usr/local/nginx

#创建配置文件用于拷贝文件到目标机器
[root@minglinux-01 ~] vim /etc/ansible/nginx_install/roles/install/tasks/copy.yml
#内容如下
  1 - name: Copy Nginx Software
  2   copy: src=nginx.tar.gz dest=/tmp/nginx.tar.gz owner=root group=root
  3 - name: Uncompression Nginx Software
  4   shell: tar zxf /tmp/nginx.tar.gz -C /usr/local/
  5 - name: Copy Nginx Start Script
  6   template: src=nginx dest=/etc/init.d/nginx owner=root group=root mode=0755
  7 - name: Copy Nginx Config
  8   template: src=nginx.conf dest={{ nginx_basedir }}/conf/ owner=root group=root mode=0644
#src=nginx和src=nginx.conf去template里找文件
  • playbook实战-nginx安装4

接下来会建立用户,启动服务,删除压缩包
vim /etc/ansible/nginx_install/roles/install/tasks/install.yml //内容如下
- name: Create Nginx User
user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin
- name: Start Nginx Service
shell: /etc/init.d/nginx start
- name: Add Boot Start Nginx Service
shell: chkconfig --level 345 nginx on
- name: Delete Nginx compression files
shell: rm -rf /tmp/nginx.tar.gz

#用于建立用户,启动服务,删除压缩包的配置文件
[root@minglinux-01 ~] vim /etc/ansible/nginx_install/roles/install/tasks/install.yml 
#内容如下
  1 - name: Create Nginx User
  2   user: name={{ nginx_user }} state=present createhome=no shell=/sbin/nologin
  3 - name: Start Nginx Service
  4   shell: /etc/init.d/nginx start
  5 - name: Add Boot Start Nginx Service
  6   shell: chkconfig --level 345 nginx on
  7 - name: Delete Nginx compression files
  8   shell: rm -rf /tmp/nginx.tar.gz
  • playbook实战-nginx安装5

再创建main.yml把copy和install调用
vim /etc/ansible/nginx_install/roles/install/tasks/main.yml //内容如下
- include: copy.yml
- include: install.yml
到此两个roles:common和install就定义完成了,接下来要定义一个入口配置文件
vim /etc/ansible/nginx_install/install.yml //内容如下
---
- hosts: minglinux-02
remote_user: root
gather_facts: True
roles:
- common
- install
执行: ansible-playbook /etc/ansible/nginx_install/install.yml

#创建main.yml把copy和install调用
[root@minglinux-01 ~] ls /etc/ansible/nginx_install/roles/install/tasks
copy.yml  install.yml
[root@minglinux-01 ~] vim /etc/ansible/nginx_install/roles/install/tasks/main.yml 
#内容如下
  1 - include: copy.yml
  2 - include: install.yml

#定义总入口配置文件
[root@minglinux-01 ~] vim /etc/ansible/nginx_install/install.yml
#内容如下
  1 ---
  2 - hosts: minglinux-02
  3   remote_user: root
  4   gather_facts: True
  5   roles:
  6     - common
  7     - install
#执行,目标机器上先yum remove nginx
[root@minglinux-02 /usr/share/nginx/html] yum remove nginx

[root@minglinux-01 ~] ansible-playbook /etc/ansible/nginx_install/install.yml
 _____________________
< PLAY [minglinux-02] >
 ---------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ________________________
< TASK [Gathering Facts] >
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02]
 ________________________________________________________
< TASK [common : Install initializtion require software] >
 --------------------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

[DEPRECATION WARNING]: Invoking "yum" only once while using a loop via squash_actions is deprecated. 
Instead of using a loop to supply multiple items and specifying `name: "{{ item }}"`, please use `name:
 ['zlib-devel', 'pcre-devel']` and remove the loop. This feature will be removed in version 2.11. 
Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg.
ok: [minglinux-02] => (item=[u'zlib-devel', u'pcre-devel'])
 ______________________________________
< TASK [install : Copy Nginx Software] >
 --------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 _______________________________________________
< TASK [install : Uncompression Nginx Software] >
 -----------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 [WARNING]: Consider using the unarchive module rather than running 'tar'.  If you need to use command
because unarchive 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.

changed: [minglinux-02]
 __________________________________________
< TASK [install : Copy Nginx Start Script] >
 ------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 ____________________________________
< TASK [install : Copy Nginx Config] >
 ------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 ____________________________________
< TASK [install : Create Nginx User] >
 ------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 ______________________________________
< TASK [install : Start Nginx Service] >
 --------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 _______________________________________________
< TASK [install : Add Boot Start Nginx Service] >
 -----------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 _________________________________________________
< TASK [install : Delete Nginx compression files] >
 -------------------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 [WARNING]: Consider using the file module with state=absent rather than running 'rm'.  If you need to
use command because file 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.

changed: [minglinux-02]
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=10   changed=8    unreachable=0    failed=0   

#minglinux-02上查看进程
[root@minglinux-02 /usr/share/nginx/html] ps aux|grep nginx
root       6729  0.0  0.0  45928  1096 ?        Ss   03:19   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
nobody     6730  0.0  0.2  48416  3740 ?        S    03:19   0:00 nginx: worker process
nobody     6731  0.0  0.2  48416  3740 ?        S    03:19   0:00 nginx: worker process
root       7051  0.0  0.0 112720   980 pts/0    S+   03:22   0:00 grep --color=auto nginx

二十八、playbook管理配置文件

  • playbook管理配置文件1

生产环境中大多时候是需要管理配置文件的,安装软件包只是在初始化环境的时候用一下。下面我们来写个管理nginx配置文件的playbook
mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}
其中new为更新时用到的,old为回滚时用到的,files下面为nginx.conf和vhosts目录,handlers为重启nginx服务的命令
关于回滚,需要在执行playbook之前先备份一下旧的配置,所以对于老配置文件的管理一定要严格,千万不能随便去修改线上机器的配置,并且要保证new/files下面的配置和线上的配置一致
先把nginx.conf和vhosts目录放到files目录下面
cd /usr/local/nginx/conf/
cp -r nginx.conf vhost /etc/ansible/nginx_config/roles/new/files/

[root@minglinux-01 ~] mkdir -p /etc/ansible/nginx_config/roles/{new,old}/{files,handlers,vars,tasks}
[root@minglinux-01 ~] cd /etc/ansible/nginx_config/
[root@minglinux-01 /etc/ansible/nginx_config] ls
roles
[root@minglinux-01 /etc/ansible/nginx_config] ls roles/
new  old

#把nginx.conf和vhosts目录放到files目录下面
[root@minglinux-01 /etc/ansible/nginx_config] cd /usr/local/nginx/conf/
[root@minglinux-01 /usr/local/nginx/conf] cp -r nginx.conf vhost  /etc/ansible/nginx_config/roles/new/files/
[root@minglinux-01 /usr/local/nginx/conf] ls /etc/ansible/nginx_config/roles/new/files/
nginx.conf  vhost

  • playbook管理配置文件2

vim /etc/ansible/nginx_config/roles/new/vars/main.yml //定义变量
nginx_basedir: /usr/local/nginx
vim /etc/ansible/nginx_config/roles/new/handlers/main.yml //定义重新加载nginx服务
- name: restart nginx
shell: /etc/init.d/nginx reload
vim /etc/ansible/nginx_config/roles/new/tasks/main.yml //这是核心的任务
- name: copy conf file
copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=root group=root mode=0644
with_items:
- { src: nginx.conf, dest: conf/nginx.conf }
- { src: vhosts, dest: conf/ }
notify: restart nginx

#定义变量
[root@minglinux-01 ~] vim /etc/ansible/nginx_config/roles/new/vars/main.yml 
#内容如下
  1 nginx_basedir: /usr/local/nginx

#定义重新加载nginx服务
[root@minglinux-01 ~] vim /etc/ansible/nginx_config/roles/new/handlers/main.yml
#内容如下
  1 - name: restart nginx
  2   shell: /etc/init.d/nginx reload

#核心任务
[root@minglinux-01 ~] vim /etc/ansible/nginx_config/roles/new/tasks/main.yml 
#内容如下
  1 - name: copy conf file
  2   copy: src={{ item.src }} dest={{ nginx_basedir }}/{{ item.dest }} backup=yes owner=root group=root     mode=0644
  3   with_items:
  4     - { src: nginx.conf, dest: conf/nginx.conf }
  5     - { src: vhost, dest: conf/ }
  6   notify: restart nginx

  • playbook管理配置文件3

vim /etc/ansible/nginx_config/update.yml // 最后是定义总入口配置
---
- hosts: testhost
user: root
roles:
- new
执行: ansible-playbook /etc/ansible/nginx_config/update.yml
而回滚的backup.yml对应的roles为old
rsync -av /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/
回滚操作就是把旧的配置覆盖,然后重新加载nginx服务, 每次改动nginx配置文件之前先备份到old里,对应目录为/etc/ansible/nginx_config/roles/old/files
vim /etc/ansible/nginx_config/rollback.yml // 最后是定义总入口配置
---
- hosts: testhost
user: root
roles:
- old

#定义总入口配置
[root@minglinux-01 ~] vim /etc/ansible/nginx_config/update.yml 
#内容如下
  1 ---
  2 - hosts: minglinux-02
  3   user: root
  4   roles:
  5   - new

#执行
[root@minglinux-01 ~] ansible-playbook /etc/ansible/nginx_config/update.yml
 _____________________
< PLAY [minglinux-02] >
 ---------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

 ________________________
< TASK [Gathering Facts] >
 ------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02]
 _____________________________
< TASK [new : copy conf file] >
 -----------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

ok: [minglinux-02] => (item={u'dest': u'conf/nginx.conf', u'src': u'nginx.conf'})
changed: [minglinux-02] => (item={u'dest': u'conf/', u'src': u'vhost'})
 _______________________________________
< RUNNING HANDLER [new : restart nginx] >
 ---------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

changed: [minglinux-02]
 ____________
< PLAY RECAP >
 ------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

minglinux-02               : ok=3    changed=2    unreachable=0    failed=0   

#查看目标机器是否重新加载
[root@minglinux-02 ~] ps aux|grep nginx
root       3868  0.0  0.1  46200  2936 ?        Ss   03:32   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/localnginx/conf/nginx.conf
nobody     6307  0.0  0.2  48688  4024 ?        S    04:24   0:00 nginx: worker process
nobody     6308  0.0  0.2  48688  4024 ?        S    04:24   0:00 nginx: worker process
root       6322  0.0  0.0 112720   984 pts/0    S+   04:24   0:00 grep --color=auto nginx
[root@minglinux-02 ~] date
2019年 03月 14日 星期四 04:24:59 CST

#对/etc/ansible/nginx_config/roles/new/files/nginx.conf做变更再执行
[root@minglinux-01 ~] vim /etc/ansible/nginx_config/roles/new/files/nginx.conf 
[root@minglinux-01 ~] cat /etc/ansible/nginx_config/roles/new/files/nginx.conf |grep vhost
    #include vhost/*.conf;
[root@minglinux-01 ~] ansible-playbook /etc/ansible/nginx_config/update.yml
[root@minglinux-02 ~] cat /usr/local/nginx/conf/nginx.conf |grep vhost
    #include vhost/*.conf;

#回滚
#old和new保持一致,相当于把当前nginx配置文件备份到old里,如需回滚就将备份还原
#每次改动nginx配置文件之前先备份到old里,目录是/etc/ansible/nginx_config/roles/old/files 
[root@minglinux-01 ~] rsync -av  /etc/ansible/nginx_config/roles/new/ /etc/ansible/nginx_config/roles/old/
sending incremental file list
files/
files/nginx.conf
files/vhost/
files/vhost/aaa.com.conf
files/vhost/load.conf
files/vhost/proxy.conf
files/vhost/ssl.conf
files/vhost/test.com.conf
handlers/
handlers/main.yml
tasks/
tasks/main.yml
vars/
vars/main.yml

sent 5,233 bytes  received 207 bytes  10,880.00 bytes/sec
total size is 4,409  speedup is 0.81

#定义一个总入口配置
[root@minglinux-01 ~] vim /etc/ansible/nginx_config/rollback.yml 
#内容如下
  1 ---
  2 - hosts: minglinux-02
  3   user: root
  4   roles:
  5   - old 

#执行回滚
[root@minglinux-01 ~] ansible-playbook /etc/ansible/nginx_config/rollback.yml

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

推荐阅读更多精彩内容