一,工具与环境介绍

 

1.1 ansible简介

批量管理服务器的工具
无需部署agent,通过ssh进行管理
流行的自动化运维工具:https://github.com/ansible/ansible

 

1.2 jenkins简介

可视化运维(主要用在可视化部署)
持续构建,可以和git,svn结合
可结合ssh实现可视化运维
可结合ansible实现可视化运维

 

1.3 环境说明

Centos7.3(yum -y install net-tools vim)
关闭防火墙(systemctl stop firewalld,systemctl disable firewalld)
关闭selinux

 

二,Python3与ansible的安装

 

2.1 使用源码安装Python3.5

 
  1. #安装支持包
  2. [root@ansible ~]# yum -y install lrzsz vim net-tools gcc gcc-c++ ncurses ncurses-devel unzip zlib-devel zlib openssl-devel openssl
  3. #源码编译Python3.5
  4. [root@ansible Python-3.5.2]# tar xf Python-3.5.2.tgz -C /usr/src/
  5. [root@ansible Python-3.5.2]# cd /usr/src/Python-3.5.2/
  6. [root@ansible Python-3.5.2]# ./configure --prefix=/usr/local/python/
  7. [root@ansible Python-3.5.2]# make && make install
  8. [root@ansible Python-3.5.2]# ln -s /usr/local/python/bin/python3 /usr/bin/python3
  9. [root@ansible Python-3.5.2]# which python3
  10. /usr/bin/python3
  11. [root@ansible Python-3.5.2]# python3 -V
  12. Python 3.5.2
 

2.2 使用pip3安装ansible

 
  1. #安装ansible最新版本
  2. [root@ansible Python-3.5.2]# /usr/local/python/bin/pip3 install ansible
  3. #静心等待ansible安装完毕后
  4. [root@ansible python]# ln -s /usr/local/python/bin/ansible /usr/local/bin/
  5. [root@ansible python]# which ansible
  6. /usr/local/bin/ansible
  7. [root@ansible python]# ansible --version
  8. ansible 2.5.4
  9. config file = None
  10. configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  11. ansible python module location = /usr/local/python/lib/python3.5/site-packages/ansible
  12. executable location = /usr/local/bin/ansible
  13. python version = 3.5.2 (default, Jun 13 2018, 09:13:32) [GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
 

2.3 ansible查看帮助

[root@ansible ~]# /usr/local/python/bin/ansible-doc -l 查看总帮助
[root@ansible ~]# /usr/local/python/bin/ansible-doc -s shell 查看shell模块的帮助
[root@ansible ~]# /usr/local/python/bin/ansible-doc -s raw

 

三,使用公私钥实现ssh无密码登陆

ansible是无agent的,无agent是怎么批量管理服务器的?主要是借用ssh来批量管理服务器。
ssh默认登陆是需要密码的,所以管理起来比较麻烦,这节课主要是介绍ssh的无密码登陆。
ssh无密码登陆实现以后,使用ansible批量管理服务器就变得简单了。

Host IP
ansible 192.168.200.137
webA 192.168.200.132
webB 192.168.200.138
 
  1. #生成密钥对
  2. [root@ansible python]# ssh-keygen -t rsa -f ~/.ssh/id_rsa -P ""
  3. #分发密钥
  4. [root@ansible python]# ssh-copy-id -i ~/.ssh/id_rsa.pub "-o StrictHostKeyChecking=no" 192.168.200.132
  5. #进行免密码登陆测试
  6. [root@ansible python]# ssh 192.168.200.132
  7. Last login: Wed Jun 13 11:01:10 2018 from 192.168.200.137
  8. [root@webA ~]# hostname -I
  9. 192.168.200.132
  10. [root@webA ~]# exit
  11. logout
  12. Connection to 192.168.200.132 closed.
  13. [root@ansible python]# hostname -I
  14. 192.168.200.137
 

四,ansible的简单配置和ping模块

 

4.1 ansible的配置文件

通过pip安装的ansible是没有配置文件的。我们需要创建一个

 
  1. [root@ansible python]# mkdir -p /etc/ansible
  2. [root@ansible python]# vim /etc/ansible/hosts
  3. [root@ansible python]# cat /etc/ansible/hosts #ansible主机管理配置文件
  4. [nginx] #被管理的主机组名称
  5. webA ansible_ssh_host=192.168.200.132 ansible_ssh_port=22 ansible_ssh_user=root #第一台主机
  6. webB ansible_ssh_host=192.168.200.138 ansible_ssh_port=22 ansible_ssh_user=root ansible_ssh_pass=666666 #第二台主机
  7. 特别提示:
  8. WebA ===> 主机名
  9. ansible_ssh_host ===>主机IP
  10. ansible_ssh_port ===>ssh的默认端口
  11. ansible_ssh_user ===>ssh的用户名
  12. ansible_ssh_pass ===>ssh的用户的连接密码

如果我们已经设置了ssh免密钥了。那么就不需要写密码了。例如:webA
我们要是没有设置免密钥,那么就需要安装sshpass工具,并在/etc/ansible/hosts文件里写上主机的连接密码。例如webB

 
  1. #下载epel源安装sshpass
  2. [root@ansible python]# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
  3. [root@ansible python]# yum -y install sshpass
  4. [root@ansible python]# which sshpass
  5. /usr/bin/sshpass
 

4.2 进行ansible远程执行命令测试

语法:

ansible chensiqi -m command -a 'uptime'
ansible 主机组 -m ansible内置功能模块名 -a 命令

进行命令测试:

 
  1. #进行ping模块的连接测试
  2. [root@ansible python]# ansible nginx -m ping
  3. webB | FAILED! => { #我们发现webB还是没链接成功,这是因为本机的known_hosts文件还没有记录对方主机的信息。
  4. "msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add this host's fingerprint to your known_hosts file to manage this host."
  5. }
  6. webA | SUCCESS => { #webA成功
  7. "changed": false,
  8. "ping": "pong"
  9. }

想要解决known_hosts的问题,只需要修改ssh的配置文件/etc/ssh/ssh_config即可

 
  1. #修改ssh配置文件
  2. [root@ansible .ssh]# sed -n '35p' /etc/ssh/ssh_config
  3. # StrictHostKeyChecking ask
  4. [root@ansible .ssh]# vim /etc/ssh/ssh_config
  5. [root@ansible .ssh]# sed -n '35p' /etc/ssh/ssh_config
  6. StrictHostKeyChecking no #去掉注释,修改成这样
  7. #重启ssh服务
  8. [root@ansible .ssh]# systemctl reload sshd.service
  9. #再次进行ansible连接测试
  10. [root@ansible .ssh]# ansible nginx -m ping
  11. webA | SUCCESS => {
  12. "changed": false,
  13. "ping": "pong"
  14. }
  15. webB | SUCCESS => {
  16. "changed": false,
  17. "ping": "pong"
  18. }
 

4.3 ansible的简单使用方式

ansible -i /etc/ansible/hosts 主机或主机组 -m 指定模块 -a 命令

不用-i指定配置文件默认为/etc/ansible/hosts

 

4.4 使用ping模块用来查看服务器是否连接正常,ping模块不需要-a指定参数

ansible all -m ping

主机组,主机,all代表所有

主机和主机组注意事项:

主机组范围 解释
all 代表所有主机
webA:webB 可以指定多台主机
all:\!webA 指定all但不包含webB,注意!前需要加转意符号\
 
  1. #操作测试
  2. [root@ansible .ssh]# ansible webA -m ping
  3. webA | SUCCESS => {
  4. "changed": false,
  5. "ping": "pong"
  6. }
  7. [root@ansible .ssh]# ansible all -m ping
  8. webA | SUCCESS => {
  9. "changed": false,
  10. "ping": "pong"
  11. }
  12. webB | SUCCESS => {
  13. "changed": false,
  14. "ping": "pong"
  15. }
  16. [root@ansible .ssh]# ansible webA:webB -m ping
  17. webA | SUCCESS => {
  18. "changed": false,
  19. "ping": "pong"
  20. }
  21. webB | SUCCESS => {
  22. "changed": false,
  23. "ping": "pong"
  24. }
  25. [root@ansible .ssh]# ansible all:\!webA -m ping
  26. webB | SUCCESS => {
  27. "changed": false,
  28. "ping": "pong"
  29. }
  30. [root@ansible .ssh]# ansible webA:webB -m command -a 'uptime'
  31. webA | SUCCESS | rc=0 >>
  32. 12:29:05 up 2:43, 3 users, load average: 0.00, 0.01, 0.05
  33. webB | SUCCESS | rc=0 >>
  34. 12:29:05 up 1:03, 2 users, load average: 0.01, 0.02, 0.02
 

五,ansible的三个命令模块

 

5.1 ansible模块command(不支持管道,不建议使用)

 
  1. #command支持直接回显命令的执行结果
  2. [root@ansible ~]# ansible all -m command -a "pwd"
  3. webA | SUCCESS | rc=0 >>
  4. /root
  5. webB | SUCCESS | rc=0 >>
  6. /root
  7. #command模块不支持管道符操作
  8. [root@ansible ~]# ansible all -m command -a "echo test | grep t"
  9. webA | SUCCESS | rc=0 >>
  10. test | grep t
  11. webB | SUCCESS | rc=0 >>
  12. test | grep t
  13. #command模块不支持重定向操作
  14. [root@ansible ~]# ansible all -m command -a "echo bb >> /tmp/testansible"
  15. webA | SUCCESS | rc=0 >>
  16. bb >> /tmp/testansible
  17. webB | SUCCESS | rc=0 >>
  18. bb >> /tmp/testansible
 

5.2 ansible模块shell(支持管道,支持重定向)

 
  1. #shell模块支持管道符
  2. [root@ansible ~]# ansible all -m shell -a "echo testansible | grep a"
  3. webA | SUCCESS | rc=0 >>
  4. testansible
  5. webB | SUCCESS | rc=0 >>
  6. testansible
  7. #shell支持重定向
  8. [root@ansible ~]# ansible all -m shell -a "echo bb >> /tmp/testansible"
  9. webA | SUCCESS | rc=0 >>
  10. webB | SUCCESS | rc=0 >>
  11. #如果遇到特殊符号需要加入\转义,这样子ansible才能正常运行
  12. [root@ansible ~]# ansible all -m shell -a "cat /etc/passwd | awk -F":" '{print \$1}'"
  13. webB | SUCCESS | rc=0 >>
  14. root
  15. bin
  16. daemon
  17. adm
  18. lp
  19. sync
  20. shutdown
  21. halt
  22. mail
  23. operator
  24. games
  25. ftp
  26. nobody
  27. systemd-bus-proxy
  28. systemd-network
  29. dbus
  30. polkitd
  31. tss
  32. postfix
  33. sshd
  34. chrony
  35. webA | SUCCESS | rc=0 >>
  36. root
  37. bin
  38. daemon
  39. adm
  40. lp
  41. sync
  42. shutdown
  43. halt
  44. mail
  45. operator
  46. games
  47. ftp
  48. nobody
  49. systemd-bus-proxy
  50. systemd-network
  51. dbus
  52. polkitd
  53. tss
  54. postfix
  55. sshd
  56. chrony
 

5.3 ansible模块raw,最原始的方式运行命令(不依赖python,仅通过ssh实现)

 
  1. #清除yum缓存
  2. [root@ansible ~]# ansible all -m raw -a "yum -y clean all"
  3. webB | SUCCESS | rc=0 >>
  4. Loaded plugins: fastestmirror
  5. Cleaning repos: c7-media
  6. Cleaning up everything
  7. Shared connection to 192.168.200.138 closed.
  8. webA | SUCCESS | rc=0 >>
  9. Loaded plugins: fastestmirror
  10. Cleaning repos: c7-media epel
  11. Cleaning up everything
  12. Cleaning up list of fastest mirrors
  13. Shared connection to 192.168.200.132 closed.
  14. #建立yum缓存
  15. [root@ansible ~]# ansible all -m raw -a "yum makecache"
  16. webA | SUCCESS | rc=0 >>
  17. Loaded plugins: fastestmirror
  18. c7-media | 3.6 kB 00:00
  19. Loading mirror speeds from cached hostfile
  20. * c7-media:
  21. Metadata Cache Created
  22. Shared connection to 192.168.200.132 closed.
  23. webB | SUCCESS | rc=0 >>
  24. Loaded plugins: fastestmirror
  25. c7-media | 3.6 kB 00:00
  26. Loading mirror speeds from cached hostfile
  27. * c7-media:
  28. Metadata Cache Created
  29. Shared connection to 192.168.200.138 closed.
  30. #yum装nmap包
  31. ansible all -m raw -a "yum -y install nmap"
 

六,ansible的copy模块批量下发文件或文件夹

 

6.1 copy模块概述

  • copy模块的参数,ansible 主机组 -m 模块 -a 命令

    • src:指定源文件或目录
    • dest:指定目标服务器的文件或目录
    • backup:是否要备份
    • owner:拷贝到目标服务器后,文件或目录的所属用户
    • group:拷贝到目标服务器后,文件或目录的所属群组
    • mode:文件或目录的权限
  • 准备工作

    • [root@ansible ~]# mkdir -p /service/scripts
    • [root@ansible ~]# echo "aaa" > /service/scripts/test.txt
    • [root@ansible ~]# echo "bbb" > /service/scripts/test2.txt
  • 所有被管理端节点必须安装libselinux-python包

    • yum -y install libselinux-python
 

6.2 copy模块拷贝文件

特别提示:如果目标路径不存在会自动创建
src===>源文件路径 dest=目标路径位置

 
  1. [root@ansible ~]# ansible all -m copy -a "src=/service/scripts/test.txt dest=/service/scripts/"
  2. webB | FAILED! => { #节点未安装libselinux-python
  3. "changed": false,
  4. "checksum": "972a1a11f19934401291cc99117ec614933374ce",
  5. "msg": "Aborting, target uses selinux but python bindings (libselinux-python) aren't installed!"
  6. }
  7. webA | SUCCESS => {
  8. "changed": true,
  9. "checksum": "972a1a11f19934401291cc99117ec614933374ce",
  10. "dest": "/service/scripts/test.txt",
  11. "gid": 0,
  12. "group": "root",
  13. "md5sum": "5c9597f3c8245907ea71a89d9d39d08e",
  14. "mode": "0644",
  15. "owner": "root",
  16. "secontext": "system_u:object_r:svc_svc_t:s0",
  17. "size": 4,
  18. "src": "/root/.ansible/tmp/ansible-tmp-1529035954.8010113-22928023490467/source",
  19. "state": "file",
  20. "uid": 0
  21. }
  22. #节点安装libselinux-python后在进行发送测试
  23. [root@ansible ~]# ansible webB -m copy -a "src=/service/scripts/test.txt dest=/service/scripts/"
  24. webB | SUCCESS => { #发送成功
  25. "changed": true,
  26. "checksum": "972a1a11f19934401291cc99117ec614933374ce",
  27. "dest": "/service/scripts/test.txt",
  28. "gid": 0,
  29. "group": "root",
  30. "md5sum": "5c9597f3c8245907ea71a89d9d39d08e",
  31. "mode": "0644",
  32. "owner": "root",
  33. "secontext": "system_u:object_r:svc_svc_t:s0",
  34. "size": 4,
  35. "src": "/root/.ansible/tmp/ansible-tmp-1529036146.1609693-94270890826089/source",
  36. "state": "file",
  37. "uid": 0
  38. }
 

6.3 copy模块拷贝文件夹

特别提示:
如果目标路径里有与我拷贝的文件同名文件的话,会直接覆盖目标路径下的文件

 
  1. #拷贝/service/scripts/ 目录下所有内容到dest的路径下(注意两条命令的对比)
  2. [root@ansible ~]# ansible webA -m copy -a "src=/service/scripts/ dest=/service/scripts/"
  3. webA | SUCCESS => {
  4. "changed": true,
  5. "dest": "/service/scripts/",
  6. "src": "/service/scripts/"
  7. }
  8. #拷贝/service/scripts目录本身及其内部的所有内容到dest的路径下(注意两条命令的对比)
  9. [root@ansible ~]# ansible webA -m copy -a "src=/service/scripts dest=/service/scripts/"
  10. webA | SUCCESS => {
  11. "changed": true,
  12. "dest": "/service/scripts/",
  13. "src": "/service/scripts"
  14. }
 

6.4 copy模块自动备份

特别提示:
参数:backup=yes ===>意思是,如果目标路径下,有与我同名但不同内容的文件时,在覆盖前,对目标文件先进行备份。

 
  1. [root@ansible ~]# ansible webB -m copy -a "src=/service/scripts/ dest=/service/scripts/ backup=yes"
  2. webB | SUCCESS => {
  3. "changed": true,
  4. "dest": "/service/scripts/",
  5. "src": "/service/scripts/"
  6. }
 

6.5 copy模块指定用户和属主

 
  1. [root@ansible ~]# ansible webA -m copy -a "src=/service/scripts/ dest=/service/scripts/ owner=nobody group=nobody mode=0600"
  2. webA | SUCCESS => {
  3. "changed": true,
  4. "dest": "/service/scripts/",
  5. "src": "/service/scripts/"
  6. }
 

七,ansible的script模块批量运行脚本

ansible的script模块能够实现远程服务器批量运行本地的shell脚本。

 
  1. #操作示例-->远程批量分发并自动部署nginx
  2. #所有被管理端需要挂载光盘,并创建本地yum配置文件
  3. [root@ansible scripts]# pwd
  4. /service/scripts
  5. [root@ansible scripts]# ls | xargs -n1
  6. auto_nginx.sh #自动安装nginx脚本
  7. fenfa.sh #批量分发脚本
  8. nginx-1.10.2.tar.gz #nginx源码包
  9. [root@ansible scripts]# cat auto_nginx.sh #nginx安装脚本
  10. #!/bin/sh
  11. #nginx install shell scripts
  12. test -d /media/cdrom || mkdir -p /media/cdrom
  13. mount /dev/sr0 /media/cdrom &>/dev/null
  14. yum -y install gcc gcc-c++ make pcre pcre-devel zlib zlib-devel openssl openssl-devel &>/dev/null
  15. test -d /service/scripts || exit 3
  16. cd /service/scripts/
  17. tar xf nginx-1.10.2.tar.gz -C /usr/src/
  18. cd /usr/src/nginx-1.10.2/
  19. ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_stub_status_module &>/dev/null
  20. make &>/dev/null
  21. make install &>/dev/null
  22. exit 0
  23. [root@ansible scripts]# cat fenfa.sh #源码包和安装脚本的批量分发脚本
  24. #!/bin/sh
  25. #批量分发脚本
  26. Group=$1
  27. ansible $Group -m copy -a "src=/service/scripts/ dest=/service/scripts/"
  28. ansible $Group -m script -a "/service/scripts/auto_nginx.sh"
  29. [root@ansible scripts]# sh fenfa.sh all #激活脚本

此脚本只是个演示示例,工作中需要写的尽量严谨一些。

 

八,ansible-playbook的初步使用

playbook的使用,playbook可以把ansible的模块进行组合

ln -s /usr/local/python/bin/ansible-playbook /usr/local/bin/

 

8.1 playbook的简单shell模块的使用

 
  1. [root@ansible scripts]# cat test_shell.yaml #playbook的执行模板
  2. --- #开头三个小-开头
  3. - hosts: webB
  4. tasks:
  5. - name: test
  6. shell: echo "welcome to yunjisaun" >> /tmp/username
  7. - name: test2
  8. shell: echo "welcome to yunjisuan" >> /tmp/username
  9. 模板说明:
  10. --- #开头必须有三个小-,顶格写
  11. - hosts: #正文配置代码的第一级,必须有两个空格(-占一个空格位)
  12. - host: webB #webB是host参数的值,值和hosts:之间要有一个空格
  13. tasks: #tasks:表示接下来要执行的具体任务
  14. - name: #相对于tasks再多缩进两个格(-占一个空格位),表示属于tasks的下一级
  15. - name: test #test只是要执行的具体命令的名字可以随便写。name:后还是有一个空格要注意
  16. shell: #表示调用shell模块执行命令相对于tasks仍旧要多缩进两个空格
  17. shell: echo "xxx" >> xxx #shell:后边还是要有个空格,需要注意。

执行playbook配置文件

 
  1. [root@ansible scripts]# ansible-playbook test_shell.yaml #执行playbook配置文件
  2. PLAY [webB] ********************************************************************************************************
  3. TASK [Gathering Facts] *********************************************************************************************
  4. ok: [webB]
  5. TASK [test] ********************************************************************************************************
  6. changed: [webB]
  7. TASK [test2] *******************************************************************************************************
  8. changed: [webB]
  9. PLAY RECAP *********************************************************************************************************
  10. webB : ok=3 changed=2 unreachable=0 failed=0
 

8.2 playbook的简单copy模块的使用

 
  1. [root@ansible scripts]# echo "welcom to yunjisuan" >> /tmp/test_copy
  2. [root@ansible scripts]# cat test_copy.yaml
  3. ---
  4. - hosts: all
  5. tasks:
  6. - name: test copy
  7. copy: src=/tmp/copy_test dest=/tmp/
  8. [root@ansible scripts]# ansible-playbook /service/scripts/test_copy.yaml
  9. PLAY [all] *********************************************************************************************************
  10. TASK [Gathering Facts] *********************************************************************************************
  11. ok: [webA]
  12. ok: [webB]
  13. TASK [test copy] ***************************************************************************************************
  14. changed: [webA]
  15. changed: [webB]
  16. PLAY RECAP *********************************************************************************************************
  17. webA : ok=2 changed=1 unreachable=0 failed=0
  18. webB : ok=2 changed=1 unreachable=0 failed=0
 

8.3 playbook使用register输出命令运行结果

我们在用playbook进行ansible模块操作的时候,并没有命令的执行结果输出,默认被隐藏了。
我们可以通过register模块最加输出命令的执行结果

 
  1. [root@ansible scripts]# cat test_register.yaml
  2. ---
  3. - hosts: all
  4. tasks:
  5. - name: test register
  6. shell: echo "welcome to yunjisuan"
  7. register: print_result #将之前命令的输出结果保存在变量print_result里
  8. - debug: var=print_result #将变量的值作为debug输出出来。
  9. [root@ansible scripts]# ansible-playbook test_register.yaml
  10. PLAY [all] *********************************************************************************************************
  11. TASK [Gathering Facts] *********************************************************************************************
  12. ok: [webA]
  13. ok: [webB]
  14. TASK [test register] ***********************************************************************************************
  15. changed: [webA]
  16. changed: [webB]
  17. TASK [debug] *******************************************************************************************************
  18. ok: [webA] => { #命令的执行结果有输出了
  19. "print_result": {
  20. "changed": true,
  21. "cmd": "echo \"welcome to yunjisuan\"",
  22. "delta": "0:00:00.002269",
  23. "end": "2018-06-15 10:28:14.693883",
  24. "failed": false,
  25. "rc": 0,
  26. "start": "2018-06-15 10:28:14.691614",
  27. "stderr": "",
  28. "stderr_lines": [],
  29. "stdout": "welcome to yunjisuan",
  30. "stdout_lines": [
  31. "welcome to yunjisuan"
  32. ]
  33. }
  34. }
  35. ok: [webB] => {
  36. "print_result": {
  37. "changed": true,
  38. "cmd": "echo \"welcome to yunjisuan\"",
  39. "delta": "0:00:00.002633",
  40. "end": "2018-06-15 10:28:14.710242",
  41. "failed": false,
  42. "rc": 0,
  43. "start": "2018-06-15 10:28:14.707609",
  44. "stderr": "",
  45. "stderr_lines": [],
  46. "stdout": "welcome to yunjisuan",
  47. "stdout_lines": [
  48. "welcome to yunjisuan"
  49. ]
  50. }
  51. }
  52. PLAY RECAP *********************************************************************************************************
  53. webA : ok=3 changed=1 unreachable=0 failed=0
  54. webB : ok=3 changed=1 unreachable=0 failed=0
 

8.4 nginx配置下发并检测

 
  1. [root@ansible scripts]# cat test_nginx_conf.yaml
  2. ---
  3. - hosts: all
  4. tasks:
  5. - name: copy nginx.conf
  6. copy: src=/tmp/nginx.conf dest=/usr/local/nginx/conf/ backup=yes
  7. - name:
  8. shell: /usr/local/nginx/sbin/nginx -t
  9. register: nginx_result
  10. - debug: var=nginx_result
 

九,playbook的自定义变量和内置变量

 

9.1 在Playbook中使用自定义变量

 
  1. [root@localhost scripts]# cat test_vars.yaml
  2. ---
  3. - hosts: all
  4. vars: #定义变量
  5. - name: "yunjisuan" #第一个name变量
  6. age: "3" #第二个age变量
  7. tasks:
  8. - name: "{{ name }}" #{{}}两对大括号引用变量,变量名两头空格
  9. shell: echo "myname {{ name }},myage {{ age }}"
  10. register: var_result
  11. - debug: var=var_result
  12. 特别提示:
  13. 引用变量需要在双引号中引用。
  14. [root@localhost scripts]# ansible-playbook /service/scripts/test_vars.yaml
  15. [WARNING]: Found variable using reserved name: name #这里提示,name是一个保留的内置变量,我们在自定义时不能用
  16. PLAY [all] *********************************************************************************************************
  17. TASK [Gathering Facts] *********************************************************************************************
  18. ok: [webA]
  19. ok: [webB]
  20. TASK [yunjisuan] ***************************************************************************************************
  21. changed: [webA]
  22. changed: [webB]
  23. TASK [debug] *******************************************************************************************************
  24. ok: [webA] => {
  25. "var_result": {
  26. "changed": true,
  27. "cmd": "echo \"myname yunjisuan,myage 3\"",
  28. "delta": "0:00:00.002320",
  29. "end": "2018-06-19 10:45:16.175728",
  30. "failed": false,
  31. "rc": 0,
  32. "start": "2018-06-19 10:45:16.173408",
  33. "stderr": "",
  34. "stderr_lines": [],
  35. "stdout": "myname yunjisuan,myage 3",
  36. "stdout_lines": [
  37. "myname yunjisuan,myage 3"
  38. ]
  39. }
  40. }
  41. ok: [webB] => {
  42. "var_result": {
  43. "changed": true,
  44. "cmd": "echo \"myname yunjisuan,myage 3\"",
  45. "delta": "0:00:00.002518",
  46. "end": "2018-06-19 10:45:10.552331",
  47. "failed": false,
  48. "rc": 0,
  49. "start": "2018-06-19 10:45:10.549813",
  50. "stderr": "",
  51. "stderr_lines": [],
  52. "stdout": "myname yunjisuan,myage 3",
  53. "stdout_lines": [
  54. "myname yunjisuan,myage 3"
  55. ]
  56. }
  57. }
  58. PLAY RECAP *********************************************************************************************************
  59. webA : ok=3 changed=1 unreachable=0 failed=0
  60. webB : ok=3 changed=1 unreachable=0 failed=0
  61. #我们修改一下name这个变量再发送,就不会出警告了
  62. [root@localhost scripts]# cat test_vars.yaml
  63. ---
  64. - hosts: all
  65. vars:
  66. - names: "yunjisuan"
  67. age: "3"
  68. tasks:
  69. - name: "{{ names }}"
  70. shell: echo "myname {{ names }},myage {{ age }}"
  71. register: var_result
  72. - debug: var=var_result

在使用自定义变量时,我们要特别注意不要和系统的内置保留变量同名,容易引发问题。

 

9.2 在playbook中使用ansible内置变量

我们可以使用ansible all -m setup | less查看ansible内置变量

 
  1. [root@localhost scripts]# cat test_setupvars.yaml
  2. ---
  3. - hosts: all
  4. gather_facts: True #使用ansible内置变量
  5. tasks:
  6. - name: setup var
  7. shell: echo "ip {{ ansible_all_ipv4_addresses[0] }} cpu {{ ansible_processor_count }}"
  8. register: var_result
  9. - debug: var=var_result
  10. [root@localhost scripts]#
  11. [root@localhost scripts]# ansible-playbook test_setupvars.yaml
  12. PLAY [all] *********************************************************************************************************
  13. TASK [Gathering Facts] *********************************************************************************************
  14. ok: [webA]
  15. ok: [webB]
  16. TASK [setup var] ***************************************************************************************************
  17. changed: [webA]
  18. changed: [webB]
  19. TASK [debug] *******************************************************************************************************
  20. ok: [webA] => {
  21. "var_result": {
  22. "changed": true,
  23. "cmd": "echo \"ip 192.168.200.132 cpu 1\"",
  24. "delta": "0:00:00.002408",
  25. "end": "2018-06-19 11:32:44.540658",
  26. "failed": false,
  27. "rc": 0,
  28. "start": "2018-06-19 11:32:44.538250",
  29. "stderr": "",
  30. "stderr_lines": [],
  31. "stdout": "ip 192.168.200.132 cpu 1",
  32. "stdout_lines": [
  33. "ip 192.168.200.132 cpu 1"
  34. ]
  35. }
  36. }
  37. ok: [webB] => {
  38. "var_result": {
  39. "changed": true,
  40. "cmd": "echo \"ip 192.168.200.138 cpu 1\"",
  41. "delta": "0:00:00.002102",
  42. "end": "2018-06-19 11:32:44.526875",
  43. "failed": false,
  44. "rc": 0,
  45. "start": "2018-06-19 11:32:44.524773",
  46. "stderr": "",
  47. "stderr_lines": [],
  48. "stdout": "ip 192.168.200.138 cpu 1",
  49. "stdout_lines": [
  50. "ip 192.168.200.138 cpu 1"
  51. ]
  52. }
  53. }
  54. PLAY RECAP *********************************************************************************************************
  55. webA : ok=3 changed=1 unreachable=0 failed=0
  56. webB : ok=3 changed=1 unreachable=0 failed=0

简单演示一下ansible内置变量的取用方法ansible all -m setup | less

 
  1. [root@localhost scripts]# cat test_setupvars.yaml
  2. ---
  3. - hosts: all
  4. gather_facts: True
  5. tasks:
  6. - name: setup var
  7. shell: echo "ip {{ ansible_all_ipv4_addresses[0] }} cpu {{ ansible_processor_count }}" >> /tmp/test
  8. - name: setup var2
  9. shell: echo "time {{ ansible_date_time["date"] }}" >> /tmp/test
  10. register: var_result
  11. - debug: var=var_result
 

十,Playbook下发可变配置文件

配置文件如果使用copy模块去下发的话,那配置都是一样的;
如果下发的配置文件里有可变的配置,需要用到template模块。

 

10.1 利用template模块下发可变的配置文件

 
  1. [root@localhost scripts]# cat /tmp/test
  2. my name is {{ myname }} #自定义变量
  3. my name is {{ ansible_all_ipv4_addresses[0] }} #系统变量
  4. [root@localhost scripts]# cat test_filevars.yaml
  5. ---
  6. - hosts: all
  7. gather_facts: True #开启系统变量
  8. vars:
  9. - myname: "yunjisuan" #自定义变量
  10. tasks:
  11. - name: template test
  12. template: src=/tmp/test dest=/root/test #使用template下发可变配置文件
  13. [root@localhost scripts]# ansible-playbook test_filevars.yaml
 

10.2 下发配置文件里面使用判断语法

 
  1. [root@localhost scripts]# cat /tmp/if.j2
  2. {% if PORT %} #if PORT存在
  3. ip=0.0.0.0:{{ PORT }}
  4. {% else %} #否则的话
  5. ip=0.0.0.0:80
  6. {% endif %} #结尾
  7. [root@localhost scripts]# cat test_ifvars.yaml
  8. ---
  9. - hosts: all
  10. gather_facts: True #开启系统内置变量
  11. vars:
  12. - PORT: 90 #自定义变量
  13. tasks:
  14. - name: jinja2 if test
  15. template: src=/tmp/if.j2 dest=/root/test
  16. [root@localhost scripts]# ansible-playbook test_ifvars.yaml

如果我们将变量PORT值为空的话,就会是另外的结果

 
  1. [root@localhost scripts]# cat test_ifvars.yaml
  2. ---
  3. - hosts: all
  4. gather_facts: True
  5. vars:
  6. - PORT: #置空
  7. tasks:
  8. - name: jinja2 if test
  9. template: src=/tmp/if.j2 dest=/root/test
  10. [root@localhost scripts]# ansible-playbook test_ifvars.yaml
 

十一,Playbook的notify通知和下发nginx配置

 
    1. #实战下发可执行动作的可变的nginx配置文件
    2. [root@localhost scripts]# head -1 /tmp/nginx.j2
    3. worker_processes {{ ansible_processor_count }}; #可变的参数
    4. [root@localhost scripts]# cat test_nginxvars.yaml
    5. ---
    6. - hosts: all
    7. gather_facts: True #开启系统内置变量
    8. tasks:
    9. - name: nginx conf
    10. template: src=/tmp/nginx.j2 dest=/usr/local/nginx/conf/nginx.conf
    11. notify:
    12. - reload nginx #下发通知给handlers模块执行名字叫做reload nginx的动作
    13. handlers: #定义动作
    14. - name: reload nginx #动作的名字
    15. shell: /usr/local/nginx/sbin/nginx -s reload
    16. [root@localhost scripts]# ansible-playbook test_nginxvars.yaml

十二,使用roles标准化Playbook

roles功能可以用来规范playbook的编写

 

12.1 创建所需要的roles原型目录结构

 
  1. #创建roles基本原型的目录结构
  2. [root@ansible myroles]# tree /myroles/
  3. /myroles/
  4. ├── nginx.yaml #入口触发配置文件
  5. └── roles #playbook的原型配置目录
  6. └── nginx #nginx相关模组配置目录
  7. ├── files #copy模块和script模块的参数src默认会从这个文件夹查找
  8. ├── handlers #用来存放notify的
  9. ├── tasks #用来存放ansible模块任务的
  10. ├── templates #用来存放j2的
  11. └── vars #用来存放变量的
  12. 7 directories, 1 file
  13. #入口触发配置文件
  14. [root@ansible myroles]# cat /myroles/nginx.yaml
  15. ---
  16. - hosts: all #执行的主机范围
  17. gather_facts: True #开启系统内置变量
  18. roles: #启用roles原型配置
  19. - nginx #执行nginx原型模组
 

12.2 roles中tasks任务编排模组的使用

 
  1. #在nginx模组添加tasks任务配置文件
  2. [root@ansible myroles]# cat roles/nginx/tasks/main.yaml
  3. ---
  4. - name: check alived #任务1的名字
  5. ping: #执行ping模块
  6. - name: #任务2的名字
  7. shell: ls / #执行shell模块
  8. register: ls_result #将执行结果保存给变量
  9. - debug: var=ls_result #变量的值赋值给debug进行输出
  10. #完成后的目录结构如下所示
  11. [root@ansible myroles]# tree /myroles/
  12. /myroles/
  13. ├── nginx.yaml #nginx模组入口配置文件
  14. └── roles
  15. └── nginx #nginx原型模组目录
  16. ├── files
  17. ├── handlers
  18. ├── tasks
  19. │   └── main.yaml #nginx模组的tasks任务配置文件
  20. ├── templates
  21. └── vars
  22. 7 directories, 2 files
 

12.3 执行简单的roles任务模型

 
  1. #执行nginx入口配置文件
  2. [root@ansible myroles]# ansible-playbook nginx.yaml
  3. PLAY [all] ****************************************************************************************************
  4. TASK [Gathering Facts] ****************************************************************************************
  5. ok: [webA]
  6. ok: [webB]
  7. TASK [nginx : check alived] ***********************************************************************************
  8. ok: [webA]
  9. ok: [webB]
  10. TASK [nginx : shell] ******************************************************************************************
  11. changed: [webA]
  12. changed: [webB]
  13. TASK [nginx : debug] ******************************************************************************************
  14. ok: [webA] => {
  15. "ls_result": {
  16. "changed": true,
  17. "cmd": "ls /",
  18. "delta": "0:00:00.002805",
  19. "end": "2018-06-21 11:52:29.343592",
  20. "failed": false,
  21. "rc": 0,
  22. "start": "2018-06-21 11:52:29.340787",
  23. "stderr": "",
  24. "stderr_lines": [],
  25. "stdout": "bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroo\nroot\nrun\nsbin\nservice\nsrv\nsys\ntmp\nusr\nvar",
  26. "stdout_lines": [
  27. "bin",
  28. "boot",
  29. "dev",
  30. "etc",
  31. "home",
  32. "lib",
  33. "lib64",
  34. "media",
  35. "mnt",
  36. "opt",
  37. "proc",
  38. "roo",
  39. "root",
  40. "run",
  41. "sbin",
  42. "service",
  43. "srv",
  44. "sys",
  45. "tmp",
  46. "usr",
  47. "var"
  48. ]
  49. }
  50. }
  51. ok: [webB] => {
  52. "ls_result": {
  53. "changed": true,
  54. "cmd": "ls /",
  55. "delta": "0:00:00.002708",
  56. "end": "2018-06-21 11:52:29.359754",
  57. "failed": false,
  58. "rc": 0,
  59. "start": "2018-06-21 11:52:29.357046",
  60. "stderr": "",
  61. "stderr_lines": [],
  62. "stdout": "bin\nboot\ndev\netc\nhome\nlib\nlib64\nmedia\nmnt\nopt\nproc\nroo\nroot\nrun\nsbin\nservice\nsrv\nsys\ntmp\nusr\nvar",
  63. "stdout_lines": [
  64. "bin",
  65. "boot",
  66. "dev",
  67. "etc",
  68. "home",
  69. "lib",
  70. "lib64",
  71. "media",
  72. "mnt",
  73. "opt",
  74. "proc",
  75. "roo",
  76. "root",
  77. "run",
  78. "sbin",
  79. "service",
  80. "srv",
  81. "sys",
  82. "tmp",
  83. "usr",
  84. "var"
  85. ]
  86. }
  87. }
  88. PLAY RECAP ****************************************************************************************************
  89. webA : ok=4 changed=1 unreachable=0 failed=0
  90. webB : ok=4 changed=1 unreachable=0 failed=0
  • ansible-playbook执行入口配置文件nginx.yaml后,它会自动在roles目录下查找nginx目录并进入后查找tasks任务目录并执行main.yaml的任务配置文件。
  • 其实,这个roles的操作等效于以下配置
 
  1. #本配置和之前的roles配置等效
  2. [root@ansible myroles]# cat /service/scripts/test.yaml
  3. ---
  4. - hosts: all
  5. gather_facts: True
  6. tasks: #其实roles的本质就是将tasks任务单独写了。
  7. - name: check alived #并在入口文件里追加了roles去查找tasks配置文件路径
  8. ping:
  9. - name:
  10. shell: ls /
  11. register: ls_result
  12. - debug: var=ls_result
 

12.4 roles中vars自定义变量模组的使用

 
  1. #创建自定义变量vars模组的配置文件
  2. [root@ansible myroles]# cat roles/nginx/vars/main.yaml
  3. ---
  4. my_name: yunjisuan
  5. phone: 1800000000
  6. [root@ansible myroles]# cat roles/nginx/tasks/main.yaml
  7. ---
  8. - name: check alived
  9. ping:
  10. - name:
  11. shell: ls /
  12. register: ls_result
  13. - debug: var=ls_result
  14. - name: #添加对变量引用的任务编排
  15. shell: echo my phone is {{ phone }}
  16. register: echo_result
  17. - debug: var=echo_result
  18. [root@ansible myroles]# ansible-playbook nginx.yaml #执行入口配置文件
 

12.5 使用copy,script模块的标准化

roles模型里使用copy,script模块,默认从roles/nginx/files这里面找

 
  1. [root@ansible myroles]# cat roles/nginx/files/test
  2. welcome to yunjisuan
  3. [root@ansible myroles]# cat roles/nginx/files/test.sh
  4. echo "aaa" >> /tmp/test
  5. [root@ansible myroles]# chmod +x roles/nginx/files/test.sh
  6. [root@ansible myroles]# cat roles/nginx/tasks/main.yaml
  7. ---
  8. - name: check alived
  9. ping:
  10. - name:
  11. shell: ls /
  12. register: ls_result
  13. - debug: var=ls_result
  14. - name:
  15. shell: echo my phone is {{ phone }}
  16. register: echo_result
  17. - debug: var=echo_result
  18. - name: #添加copy模块
  19. copy: src=test dest=/root/
  20. - name: #添加script模块(自动在目标IP机器上执行脚本)
  21. script: test.sh
  22. [root@ansible myroles]# ansible-playbook nginx.yaml
 

12.6 roles中template模块的使用

roles模型里使用template模块,默认从roles/nginx/template里面找

 
  1. [root@ansible myroles]# cat roles/nginx/templates/test.j2
  2. myname is {{ my_name }},my phone is {{ phone }} #引用自定义变量
  3. my ipaddress is {{ansible_all_ipv4_addresses[0]}} #引用内置变量
  4. [root@ansible myroles]# cat roles/nginx/tasks/main.yaml
  5. ---
  6. - name: check alived
  7. ping:
  8. - name:
  9. shell: ls /
  10. register: ls_result
  11. - debug: var=ls_result
  12. - name:
  13. shell: echo my phone is {{ phone }}
  14. register: echo_result
  15. - debug: var=echo_result
  16. - name:
  17. copy: src=test dest=/root/
  18. - name:
  19. script: test.sh
  20. - name:
  21. template: src=test.j2 dest=/root/test2 #下发可变配置文件
  22. [root@ansible myroles]# ansible-playbook nginx.yaml
 

12.7 roles中notify模块的使用

roles使用notify模块,默认从roles/nginx/handles里面找

 
  1. [root@ansible myroles]# cat roles/nginx/handlers/main.yaml
  2. ---
  3. - name: start_nginx #定义handlers的动作类型
  4. shell: /usr/local/nginx/sbin/nginx
  5. - name: stop_nginx #定义handlers的动作类型
  6. shell: /usr/local/nginx/sbin/nginx -s stop
  7. - name: reload_nginx #定义handlers的动作类型
  8. shell: /usr/local/nginx/sbin/nginx -s reload
  9. [root@ansible myroles]# cat roles/nginx/tasks/main.yaml
  10. ---
  11. - name: check alived
  12. ping:
  13. - name:
  14. shell: ls /
  15. register: ls_result
  16. - debug: var=ls_result
  17. - name:
  18. shell: echo my phone is {{ phone }}
  19. register: echo_result
  20. - debug: var=echo_result
  21. - name:
  22. copy: src=test dest=/root/
  23. - name:
  24. script: test.sh
  25. - name:
  26. template: src=test.j2 dest=/root/test2
  27. notify: start_nginx #执行template任务后下发通知给handlers执行start_nginx
  28. [root@ansible myroles]# ansible-playbook nginx.yaml

特别提示:
notify下发通知只有当之前的任务造成了变化那么才会被执行,如果没有发生任何改变,则notify不会被执行。例如:

 
    1. #tasks任务造成改变,触发notify
    2. [root@ansible myroles]# cat /tmp/test.yaml
    3. ---
    4. - hosts: webA
    5. gather_facts: True
    6. tasks:
    7. - name:
    8. copy: src=/tmp/test dest=/root/ #这步造成目标改变才能出发notify
    9. notify: start_nginx
    10. handlers:
    11. - name: start_nginx
    12. shell: /usr/local/nginx/sbin/nginx
    13. [root@ansible myroles]# ansible-playbook /tmp/test.yaml
    14. PLAY [webA] ***************************************************************************************************
    15. TASK [Gathering Facts] ****************************************************************************************
    16. ok: [webA]
    17. TASK [copy] ***************************************************************************************************
    18. changed: [webA] #发生了改变
    19. RUNNING HANDLER [start_nginx] #触发notify *********************************************************************************
    20. changed: [webA]
    21. PLAY RECAP ****************************************************************************************************
    22. webA : ok=3 changed=2 unreachable=0 failed=0
    23. #我们再次执行/tmp/test.yaml
    24. [root@ansible myroles]# ansible-playbook /tmp/test.yaml
    25. PLAY [webA] ***************************************************************************************************
    26. TASK [Gathering Facts] ****************************************************************************************
    27. ok: [webA]
    28. TASK [copy] ***************************************************************************************************
    29. ok: [webA] #没有造成任务改变,未触发notify通知
    30. PLAY RECAP ****************************************************************************************************
    31. webA : ok=2 changed=0 unreachable=0 failed=0

ansible自动化的更多相关文章

  1. Ansible自动化运维工具-上

    [Ansible特点] 1)Ansible与saltstack均是基于Python语言开发的 2)安装使用简单,基于不同插件和模块实现各种软件,平台,版本的管理以及支持虚拟容器多层级的部署 3)不需要 ...

  2. CentOS7系统 ansible自动化部署多台服务器部署

    CentOS7系统 ansible自动化部署多台服务器部署   Ansible工作机制  从图中可以看出ansible分为以下几个部份: 1> Control Node:控制机器2> In ...

  3. ansible 自动化运维

    Ansible 自动化运维 ansible安装epel #yum list all *ansible*#yum install *ansible*#yum info ansible#rpm -ql a ...

  4. ansible自动化工具安装和简单使用

    ansible自动化工具安装和简单使用 1.安装 ansible依赖于Python 2.6或更高的版本.paramiko.PyYAML及Jinja2. 2.1 编译安装 解决依赖关系 # yum -y ...

  5. Jenkins +svn +maven +tomcat+ ansible 自动化批量部署

    Jenkins +svn +maven +tomcat+ ansible 自动化批量部署 一.部署svn yum install subversion 先创建目录 mkdir /home/svn 创建 ...

  6. [k8s]kubespray(ansible)自动化安装k8s集群

    kubespray(ansible)自动化安装k8s集群 https://github.com/kubernetes-incubator/kubespray https://kubernetes.io ...

  7. Jenkins+Gitlab+Ansible自动化部署(五)

    Freestyle Job实现静态网站部署交付(接Jenkins+Gitlab+Ansible自动化部署(四)https://www.cnblogs.com/zd520pyx1314/p/102445 ...

  8. Jenkins+Gitlab+Ansible自动化部署(六)

    Pipeline Job实现Nginix+MySQL+PHP+Wordpress实现自动化部署交付(Jenkins+Gitlab+Ansible自动化部署(五)https://www.cnblogs. ...

  9. Jenkins+Gitlab+Ansible自动化部署(三)

    接Jenkins+Gitlab+Ansible自动化部署(一)https://www.cnblogs.com/zd520pyx1314/p/10210727.html 和(二)https://www. ...

  10. Jenkins+Gitlab+Ansible自动化部署(一)

    首先准备实验环境 虚拟机 主机名 IP地址 服务 系统版本 内核版本 Vmware Workstation 14 gitlab.example.com 192.168.244.130 gitlab  ...

随机推荐

  1. qt5程序打包含qml

    Qt 官方开发环境使用的动态链接库方式,在发布生成的exe程序时,需要复制一大堆 dll,如果自己去复制dll,很可能丢三落四,导致exe在别的电脑里无法正常运行. 因此 Qt 官方开发环境里自带了一 ...

  2. 如何重置Gitlab root用户密码

    一.切换到root用户 sudo su 二.进入gitlab控制台 gitlab-rails console production 三.查找用户对象 user = User.).first 四.重置密 ...

  3. json2.js JSON解析程序

    源码: /* http://www.JSON.org/json2.js 2010-03-20 Public Domain. NO WARRANTY EXPRESSED OR IMPLIED. USE ...

  4. Centos 7环境下安装配置Hadoop 3.0 Beta1简记

    前言 由于以前已经写过一篇Centos 7环境下安装配置2.8的随笔,因此这篇写得精简些,只挑选一些重要环节记录一下. 安装环境为:两台主机均为Centos 7.*操作系统,两台机器配置分别为: 主机 ...

  5. Java解析XML之Dom4j

    Java解析XML文件的方法有多种,个人感觉最常用的是使用Dom4j来解析XML文件.下面就简单介绍下Dom4j的基础使用. Dom4j需要jar包的支持,大家可以从网络上下载,如dom4j-1.6. ...

  6. 有什么学习MySQL的好教程吗?

      有什么学习Mysql的好教程吗? 文档是最好的,现整理如下: [mysql教程]MySQL 教程 [MySQL教程]MySQL 安装 [MySQL教程]MySQL 管理 [MySQL教程]MySQ ...

  7. 通过nginx日志,统计最近两天的交易笔数

    #!/bin/bash yesterday=`date -d last-day +%Y-%m-%d` dayago=`date -d '2 days ago' +%Y-%m-%d` #echo $ye ...

  8. HTML5 full-screen全屏API

    这篇文章纯属记录,非常感谢张鑫旭大神的demo 原文地址: http://www.zhangxinxu.com/study/201210/html5-full-screen-api.html 代码 C ...

  9. MAIL服务器搭建

    一,邮件服务: 优    点 缺   点 应 用 sendmail 有点年代久远,稳定功能多 太过于臃肿,配置文件多且繁琐 6以前默认 postfix 优点更稳定,且交轻便 发布年限较短,市场占有率低 ...

  10. C#对象与XMl文件之间的相互转换(转)

    本文是对C#中对象与XMl文件之间的相互转换进行了详细的介绍,需要的朋友可以过来参考下,希望对大家有所帮助 C#提供三种序列化方式,分别为:1.是使用BinaryFormatter进行串行化: 2.使 ...