Ansible自动化管理

1 基础介绍

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

2 为什么使用Ansible?

简单、方便、容易学习、 register。
Ansible有配置文件,可以多线程直接实现。不需要写脚本,类似实时复制的sersync。

3 什么是Ansible

Ansible是一个用来批量部署远程主机上服务的工具。这里“远程主机”是指任何可以通过SSH登录的主机,所以他即可以是远程虚拟机或物理机,也可以是本地主机。
Ansible通过SSH协议实现管理节点与远程节点之间的通信。理论上来说,只要能通过SSH登录到远程主机来完成的操作,都可以通过Ansible实现批量自动化操作。
涉及命令管理操作:复制文件、安装服务、服务启动停止管理、配置管理等等。

4 Ansible特点

Ansible基于Python语言实现,由Paramiko和PyYAML两个关键模块构建。

  • 安装部署过程特别简单,学习曲线很平坦。
  • 不需要单独安装客户端,只是利用现有的SSHD服务即可。
  • 不需要服务端
  • Ansible playbook,采用yaml配置,提前编排自动化任务。
  • Ansible功能模块较多,对于自动化的场景支持丰富。
  • 幂等性:一个任务执行1遍和执行N遍效果一样,不因重复执行带来意外情况

5 Ansible架构介绍

  • 连接插件connectior plugins用于连接主机,用来连接被管理端
  • 核心模块core modules 连接主机实现操作,它依赖于具体的模块来做具体的事情
  • 插件plugins,完成模块功能的补充。
  • 剧本 playbooks,Ansible的配置文件,将多个任务定义在剧本中,由Ansible自动执行
  • 主机清单inventor,定义Ansible需要操作主机的范围

最重要的一点是Ansible是模块化的,它所有的操作都依赖于模块

6 安装并配置Ansible

  1. #1、安装Ansible
  2. [root@jumpserver-10 ~]# yum install epel-release -y
  3. [root@jumpserver-10 ~]# yum install ansible -y
  4. [root@jumpserver-10 ~]# rpm -qa|grep libselinux-python #确定服务端和客户端是否安装
  5. libselinux-python-2.5-14.1.el7.x86_64
  6. #ansible配置文件介绍
  7. /etc/ansible/ansible.cfg 主配置文件,配置ansible工作特性
  8. /etc/ansible/hosts 主机清单
  9. /etc/ansible/roles/ 存放角色的目录
  10. #2、配置Ansible hosts文件
  11. [root@jumpserver-10 ~]# cp /etc/ansible/hosts{,.bak} #先备份hosts文件
  12. [root@jumpserver-10 ~]# tail /etc/ansible/hosts
  13. [NFS] #模块名称,可以自定义
  14. 192.168.89.31 #需要批量部署的IP地址
  15. [BACKUP]
  16. 192.168.89.41
  17. #/etc/ansible/hosts #主机列表的配置文件,用于定义被管理主机的认证信息,列如ssh登录用户名、密码以及key相关信息
  18. #/etc/ansible/ansible.cfg #ansible的配置文件
  19. #3、基于密码的批量操作
  20. [root@jumpserver-10 ~]# vim /etc/ansible/hosts
  21. [NFS_pass]
  22. 192.168.89.31 ansible_ssh_user=root ansible_ssh_pass=123456 ansible_ssh_port=1314
  23. [root@jumpserver-10 ~]# ansible NFS_pass -m command -a "free -m"
  24. 192.168.89.31 | CHANGED | rc=0 >>
  25. total used free shared buff/cache available
  26. Mem: 976 130 305 7 540 643
  27. Swap: 2047 0 2047
  28. #基于这种方式,/etc/ssh/sshd_config配置文件里的PasswordAuthentication必须为yes,否则无法通过密码的方式批量执行
  29. #要想执行上面命令成功,要先解决yes/no的问题
  30. #4、基于SSH秘钥的认证(企业一般使用这种)
  31. [root@jumpserver-10 .ssh]# vim /etc/ansible/hosts #只需添加IP地址
  32. [NFS]
  33. 192.168.89.31
  34. [root@jumpserver-10 ~]# ssh-keygen #生成公钥和私钥
  35. [root@jumpserver-10 ~]# cd .ssh/
  36. #以下两种发送私钥方法都可以,但是推荐第二种
  37. [root@jumpserver-10 .ssh]# ssh-copy-id -i id_rsa.pub root@192.168.89.31
  38. [root@jumpserver-10 .ssh]# sshpass -p123456 ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.89.31
  39. [root@jumpserver-10 .ssh]# cat /root/.ssh/known_hosts #查看是否有31的秘钥认证信息
  40. 192.168.89.31 ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMRZn7E3MOkCDmhaTDyK+MBBqMwTbsq5Ik+9jEf4/y2qGuIz5+wTEtjqQy62eEaihrNcvpZ2tgZ5ic/t4kevr7c=
  41. [root@jumpserver-10 ~]# ansible NFS -m command -a "free -m" #然后根据NFS模块执行
  42. 192.168.89.31 | CHANGED | rc=0 >>
  43. total used free shared buff/cache available
  44. Mem: 976 130 305 7 540 643
  45. Swap: 2047 0 2047
  46. #问题一:
  47. [root@jumpserver-10 ~]# > .ssh/known_hosts #清空known_hosts文件
  48. [root@jumpserver-10 ~]# ansible NFS -m command -a "free -m" #执行ansible
  49. 192.168.89.31 | FAILED | rc=-1 >>
  50. 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.
  51. 以上错误就是因为known_hosts没有相对应主机的ssh缓存地址,解决问题如下:
  52. [root@jumpserver-10 ~]# vim /etc/ansible/ansible.cfg
  53. host_key_checking = False #取消注释
  54. [root@jumpserver-10 ~]# > .ssh/known_hosts
  55. [root@jumpserver-10 ~]# ansible NFS -m command -a "free -m"
  56. 192.168.89.31 | CHANGED | rc=0 >>
  57. total used free shared buff/cache available
  58. Mem: 976 130 305 7 540 643
  59. Swap: 2047 0 2047

6.1 Ansible相关工具

  • /usr/bin/ansible:主程序,临时命令执行工具
  • /usr/bin/ansible-doc:模块功能查看工具,相当于man
  • /usr/bin/ansible-playbook:定制自动化任务,编排剧本工具,相当于脚本
  • /usr/bin/ansible-pull:远程执行命令的工具
  • /usr/bin/ansible-vault:文件加密工具
  • /usr/bin/ansible-console:基于Console界面与用户交互的执行工具
  • /usr/bin/ansible-galaxy:下载/上传优秀代码或Roles模块的官网平台

6.1.1 ansible-doc

此工具用来显示模块帮助,相当于man

  1. ansible-doc -l #列出可用模块
  2. ansible-doc -s 模块 #显示指定模块的帮助文档

6.1.2 ansible

  1. #ansible选项说明
  2. --version #显示版本
  3. -m module #指定模块,默认为command
  4. -v #详细过程
  5. --list-hosts #显示主机列表
  6. -k #提示输入ssh连接密码,默认key验证
  7. -C #检查,并不执行
  8. -T #执行命令的超时时间,默认10s
  9. -u #执行远程执行的用户
  10. -b #代替旧版的sudo切换
  11. --become-user=USERNAME #指定sudo的runas用户,默认为root
  12. -K #提示输入sudo时的口令

6.1.3 ansible-playbook

此工具用于执行编写好的playbook任务

  1. ansible-playbook -C hello.yml #检查yml文件中的语法
  2. ansible-playbook hello.yml #执行playbook

7 Ansible 主机清单详解

  1. #1、基于IP的方式
  2. [root@iflytek-m01 ~]# vim /etc/ansible/hosts
  3. 10.0.0.41
  4. 10.0.0.31
  5. #2、基于主机组的方式
  6. [web]
  7. 10.0.0.41
  8. 10.0.0.31
  9. #3、基于主机名符号匹配设置
  10. [web]
  11. 10.0.0.[7:9] #表示10.0.0.7到10.0.0.9
  12. #4、基于非标准远程端口的方式
  13. [web]
  14. 10.0.0.41:1314
  15. 10.0.0.31:1314
  16. #5、基于变量的方式
  17. [web]
  18. 10.0.0.41 ansible_ssh_port=1314 ansible_ssh_user=root ansible_ssh-pass=iflytek
  19. 10.0.0.31 ansible_ssh_port=1314 ansible_ssh_user=root ansible_ssh-pass=iflytek
  20. [nfs]
  21. iflytek-41 ansible_ssh_host=10.0.0.41 ansible_ssh_port=1314
  22. 注释:
  23. ansible_ssh_port=1314 #定义被远程主机的端口
  24. ansible_ssh_user=root #定义被远程主机的用户名
  25. ansible_ssh-pass=iflytek #定义被远程主机的密码
  26. ansible_ssh_host=10.0.0.41 #定义被远程主机的主机映射关系
  27. #6、主机组名嵌入式配置
  28. [backup]
  29. 10.0.0.31
  30. [nfs]
  31. iflytek-41 ansible_ssh_host=10.0.0.41 ansible_ssh_port=1314
  32. [rsync:children] #把两个主机名一起配置到一个模块里
  33. backup
  34. nfs
  35. #7、嵌入式变量信息
  36. [web:vars]
  37. ansible_ssh_port=1314
  38. ansible_ssh_user=root
  39. ansible_ssh-pass=iflytek
  40. ansible_ssh_host=10.0.0.41
  41. [web]
  42. web01

8 Ansible配置文件

image.png

  1. #module_name = command #默认模块command,可以修改为shell模块

8.1 Ansible配置文件的优先级

  1. 优先级如下:
  2. 1.首先找执行ansible命令的当前目录中,是否有 ansible.cfg文件
  3. ./ansible.cfg
  4. 2.如果找不到,再找当前用户的家目录下是否有 .ansible.cfg
  5. ~/.ansible.cfg
  6. 3.如果还找不到,就找 /etc/ansible/ansible.cfg
  7. /etc/ansible/ansible.cfg
  8. 要检查当前使用的是哪个配置文件。
  9. ansible --version 命令中,会显示
  10. config file = /etc/ansible/ansible.cfg

9 Ansible语法格式

image.png

  1. #ansible的主机列表格式:
  2. 匹配主机的列表:
  3. ALL:表示所有Inventory中的所有主机
  4. --- absible all -m ping
  5. *:通配符
  6. --- ansible "*" -m ping
  7. --- ansible 10.0.0.* -m ping
  8. --- absible "*servers*" -m ping
  9. 或关系
  10. --- ansible "webserver:appservers" -m ping
  11. --- ansible "10.0.0.10:10.0.0.20" -m ping
  12. 逻辑与
  13. --- ansible "webserver:&dbserver" -m ping #在webserver组并且在dbserver组中的主机
  14. 逻辑非
  15. --- ansible 'webserver:!dbserver' -m ping #在webserver组,但不在dbserver组中的主机。注意:此处为单引号
  16. 综合逻辑
  17. --- ansible 'webserver:dbserver:&appserver:!ftpserver' -m ping
  18. 正则表达式
  19. --- ansible "webserver:&dbserver" -m ping
  20. --- absible "~(web|db).*\.magedu\.com" -m ping

10 Ansible命令执行过程

  • ansible命令执行过程
    1、加载自己的配置文件,默认/etc/ansible/ansible.cfg
    2、加载自己对应的模块文件,如command
    3、通过ansible将模块或命令生成对应的临时py文件,并将该文件传输至远程服务器的对应执行用户$HOME/.ansible/tmp/ansible-tmp-数字/XXX.PY文件
    4、给文件+x执行
    5、执行并返回结果
    6、删除临时py文件,sleep 0退出
  • 执行状态:
    1、绿色:执行成功并且不需要做改变的操作
    2、黄色:执行成功并且对目标主机做变更
    3、红色:执行失败

11 Ansible主要模块详解

11.1 command模块

  1. #第一个模块:command(默认模块)
  2. command - Executes a command on a remote node #在一个远程主机上执行一个命令
  3. [root@m01-201 ansible]# ansible 10.0.0.41 -m command -a "hostname"
  4. 10.0.0.41 | CHANGED | rc=0 >>
  5. nfs-41
  6. #command扩展应用:
  7. chdir:在执行命令之前,对目录进行切换
  8. [root@m01-201 ansible]# ansible 10.0.0.41 -m command -a "chdir=/tmp touch xujun.txt"
  9. creates:如果文件存在,则不执行后面的命令
  10. [root@m01-201 ansible]# ansible 10.0.0.41 -m command -a "creates=/tmp/xujun.txt touch /tmp/oldboy.txt"
  11. 10.0.0.41 | SUCCESS | rc=0 >>
  12. skipped, since /tmp/xujun.txt exists
  13. removes:如果文件存在,则执行后面的命令
  14. [root@m01-201 ansible]# ansible 10.0.0.41 -m command -a "removes=/tmp/xujun.txt touch /tmp/oldboy.txt"
  15. 10.0.0.41 | CHANGED | rc=0 >>
  16. command注意事项:
  17. 不能使用特殊符号:"<", ">", "|", ";" and "&"
  18. 不能使用变量:$HOME
  19. 如果需要这些功能,请使用shell模块

11.2 shell模块

  1. #第二个模块:shell
  2. shell:在节点上执行命令操作,包括可以执行特殊符号
  3. [root@m01-201 ansible]# ansible 10.0.0.41 -m shell -a "cd /etc;pwd"
  4. 10.0.0.41 | CHANGED | rc=0 >>
  5. /etc
  6. #shell扩展应用:
  7. chdir:在执行命令之前,对目录进行切换
  8. [root@m01-201 ansible]# ansible 10.0.0.41 -m shell -a "chdir=/tmp touch xujun.txt"
  9. creates:如果文件存在,则不执行后面的命令
  10. [root@m01-201 ansible]# ansible 10.0.0.41 -m shell -a "creates=/tmp/xujun.txt touch /tmp/oldboy.txt"
  11. 10.0.0.41 | SUCCESS | rc=0 >>
  12. skipped, since /tmp/xujun.txt exists
  13. removes:如果文件存在,则执行后面的命令
  14. [root@m01-201 ansible]# ansible 10.0.0.41 -m shell -a "removes=/tmp/xujun.txt touch /tmp/oldboy.txt"
  15. 10.0.0.41 | CHANGED | rc=0 >>
  16. 注意:要查看变量名,需要使用单引号
  17. [root@iflytek-18 ~]# ansible mysql -m shell -a 'echo $HOSTNAME'
  18. 192.168.1.65 | CHANGED | rc=0 >>
  19. mysql-65

11.3 script模块

  1. #第三个模块:script
  2. script:在远程节点上运行一个脚本
  3. #第一步:创建脚本
  4. [root@iflytek-m01 scripts]# cat /scripts/htop.sh
  5. #!/bin/bash
  6. yum install htop -y
  7. #第二步:执行ansible命令
  8. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m script -a "/scripts/htop.sh"
  9. 10.0.0.41 | CHANGED => {
  10. "changed": true,
  11. "rc": 0,
  12. "stderr": "Shared connection to 10.0.0.41 closed.\r\n",
  13. "stderr_lines": [
  14. "Shared connection to 10.0.0.41 closed."
  15. ],
  16. "正在解决依赖关系",
  17. "--> 正在检查事务",
  18. "---> 软件包 htop.x86_64.0.2.2.0-3.el7 将被 安装",
  19. "--> 解决依赖关系完成",
  20. "",
  21. "依赖关系解决",
  22. "",
  23. "================================================================================",
  24. " Package 架构 版本 源 大小",
  25. "================================================================================",
  26. "正在安装:",
  27. " htop x86_64 2.2.0-3.el7 epel 103 k",
  28. "",
  29. "事务概要",
  30. "================================================================================",
  31. "安装 1 软件包",
  32. "",
  33. "总下载量:103 k",
  34. "安装大小:218 k",
  35. "Downloading packages:",
  36. "",
  37. "htop-2.2.0-3.el7.x86_64.rp 0% [ ] 0.0 B/s | 0 B --:-- ETA ",
  38. "警告:/var/cache/yum/x86_64/7/epel/packages/htop-2.2.0-3.el7.x86_64.rpm: 头V3 RSA/SHA256 Signature, 密钥 ID 352c64e5: NOKEY",
  39. "htop-2.2.0-3.el7.x86_64.rpm 的公钥尚未安装",
  40. "",
  41. "htop-2.2.0-3.el7.x86_64.rpm | 103 kB 00:00 ",
  42. "从 file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7 检索密钥",
  43. "导入 GPG key 0x352C64E5:",
  44. " 用户ID : \"Fedora EPEL (7) <epel@fedoraproject.org>\"",
  45. " 指纹 : 91e9 7d7c 4a5e 96f1 7f3e 888f 6a2f aea2 352c 64e5",
  46. " 软件包 : epel-release-7-11.noarch (@extras)",
  47. " 来自 : /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7",
  48. "Running transaction check",
  49. "Running transaction test",
  50. "Transaction test succeeded",
  51. "Running transaction",
  52. "",
  53. " 正在安装 : htop-2.2.0-3.el7.x86_64 [ ] 1/1",
  54. " 正在安装 : htop-2.2.0-3.el7.x86_64 [######### ] 1/1",
  55. " 正在安装 : htop-2.2.0-3.el7.x86_64 [################### ] 1/1",
  56. " 正在安装 : htop-2.2.0-3.el7.x86_64 [######################## ] 1/1",
  57. " 正在安装 : htop-2.2.0-3.el7.x86_64 [######################### ] 1/1",
  58. " 正在安装 : htop-2.2.0-3.el7.x86_64 [############################ ] 1/1",
  59. " 正在安装 : htop-2.2.0-3.el7.x86_64 [############################### ] 1/1",
  60. " 正在安装 : htop-2.2.0-3.el7.x86_64 [################################ ] 1/1",
  61. " 正在安装 : htop-2.2.0-3.el7.x86_64 1/1 ",
  62. "",
  63. " 验证中 : htop-2.2.0-3.el7.x86_64 1/1 ",
  64. "",
  65. "已安装:",
  66. " htop.x86_64 0:2.2.0-3.el7 ",
  67. "",
  68. "完毕!"
  69. ]
  70. }
  71. 说明:scriptcommand模块参数一致

11.4 copy模块

  1. #第四个模块:copy
  2. copy:将文件或者数据信息进行批量分发
  3. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "src=/scripts/htop.sh dest=/scripts/"
  4. copy扩展参数:
  5. #第一个扩展参数
  6. owner:指定文件的属主
  7. group:指定文件的属组
  8. 注意:指定文件的属主和属组之前,被管理端需要有对应的属主和属组
  9. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "src=/scripts/htop.sh dest=/scripts/ owner=xujun group=xujun"
  10. #第二个扩展参数
  11. mode:指定传输文件的权限
  12. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "src=/scripts/htop.sh dest=/scripts/ mode=600"
  13. #第三个扩展参数
  14. backup:在传输文件时,对远程主机源文件进行备份
  15. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "src=/scripts/htop.sh dest=/scripts/ backup=yes"
  16. #第四个扩展参数
  17. content:传输文件并直接编辑文件的信息
  18. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "content='yum install htop -y' dest=/scripts/htop.sh"
  19. 注意:copy模块复制目录信息
  20. src后面目录没有/:将目录本身以及目录下面的内容都进行远程传输复制
  21. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "src=/scripts dest=/scripts"
  22. src后面目录有/:只将目录下面的内容都进行远程传输复制
  23. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m copy -a "src=/scripts/ dest=/scripts"

11.5 file模块

  1. #第五个模块:file
  2. file:设置文件属性信息
  3. 基本用法:
  4. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m file -a "dest=/scripts/htop.sh owner=xujun group=xujun mode=600"
  5. #第一个扩展参数:
  6. state:利用模块创建数据信息(文件、目录、链接文件)
  7. =absent --->删除数据信息 ansible 10.0.0.41 -m file -a "dest=/oldboy/xujun_link.txt state=absent"
  8. =directory ---> 创建目录 ansible 10.0.0.41 -m file -a "dest=/oldboy state=directory"
  9. =hard --->创建一个硬链接信息 ansible 10.0.0.41 -m file -a "src=/oldboy/xujun.txt dest=/oldboy/xujun_hard.txt state=hard"
  10. =link --->创建一个软链接信息 ansible 10.0.0.41 -m file -a "src=/oldboy/xujun.txt dest=/oldboy/xujun_link.txt state=link"
  11. =touch --->创建一个文件信息 ansible 10.0.0.41 -m file -a "dest=/oldboy/xujun.txt state=touch"
  12. #第二个扩展参数:
  13. recurse:权限信息递归创建。默认是no,如果需要递归创建选择yes
  14. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m file -a "dest=/oldboy/ owner=xujun group=xujun mode=700 recurse=yes"

11.6 fetch模块

  1. #第六个模块:fetch
  2. fetch:批量拉取数据
  3. 基本用法:
  4. [root@iflytek-m01 ~]# ansible 10.0.0.41 -m fetch -a "src=/scripts/oldboy.txt dest=/scripts/"
  5. [root@iflytek-m01 scripts]# ls
  6. oldboy.txt
  7. [root@iflytek-m01 scripts]# pwd #会在要被拉取的目录下,创建一个拉取端的IP目录
  8. /scripts/10.0.0.41/scripts

11.7 yum模块

  1. #第七个模块:yum
  2. yum:批量安装软件
  3. name --- 指定安装软件名称
  4. state --- 指定是否安装软件
  5. installed --- 安装软件
  6. removed --- 卸载软件
  7. 基本用法:
  8. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m yum -a "name=iotop state=installed"
  9. #示列一:安装当前最新的Apache软件,如果存在则更新
  10. ansible oldboy -m yum -a "name=httpd state=latest"
  11. #示例二、安装当前最新的Apache软件,通过epel仓库安装
  12. ansible oldboy -m yum -a "name=httpd state=latest enablerepo=epel"
  13. #示例三、通过公网URL安装rpm软件
  14. ansible oldboy -m yum -a "name=https://mirrors.aliyun.com/zabbix/zabbix/4.2/rhel/7/x86_64/zabbix-agent-4.2.3-2.el7.x86_64.rpm state=latest"
  15. #示例四、更新所有的软件包,但排除和kernel相关的
  16. ansible oldboy -m yum -a "name=* state=latest exclude=kernel*,foo*"
  17. #示例五、删除Apache软件
  18. ansible oldboy -m yum -a "name=httpd state=absent"

11.8 service模块

  1. #第八个模块:service
  2. service:管理服务的运行状态
  3. name --- 指定服务的服务名称
  4. state --- 指定服务状态
  5. started 启动
  6. restarted 重启
  7. stopped 停止
  8. enabled --- 指定服务是否开启自启动
  9. yes 开启自启动
  10. no 不开启自启动
  11. 基本用法:
  12. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m service -a "name=firewalld state=started"
  13. #示例一、启动Httpd服务
  14. [root@ansible ~]# ansible oldboy -m service -a "name=httpd state=started"
  15. #示例二、重载Httpd服务
  16. [root@ansible ~]# ansible oldboy -m service -a "name=httpd state=reloaded"
  17. #示例三、重启Httpd服务
  18. [root@ansible ~]# ansible oldboy -m service -a "name=httpd state=restarted"
  19. #示例四、停止Httpd服务
  20. [root@ansible ~]# ansible oldboy -m service -a "name=httpd state=stopped"
  21. #示例五、启动Httpd服务,并加入开机自启
  22. [root@ansible ~]# ansible oldboy -m service -a "name=httpd state=started enabled=yes"

11.9 cron模块

  1. #第九个模块:cron
  2. cron:批量设置多个主机的定时任务信息
  3. minute:设置分钟信息(0-59,*,*/2
  4. hour:设置小时信息(0-23,*,*/2
  5. day:设置日期信息(1-31,*,*/2
  6. month:设置月份信息(1-12,*,*/2
  7. weekday:设置周信息(0-60表示星期天)
  8. job:用于定义定时任务需要干的事情
  9. name:设置定时任务的注释信息
  10. 基本用法:
  11. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m cron -a "name='time sync' minute=5 job='/usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1'"
  12. 扩展用法:
  13. 1state:批量删除定时任务
  14. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m cron -a "name='date sync' state=absent" #批量删除定时任务
  15. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "crontab -l" #查看是否还有定时任务
  16. 10.0.0.41 | CHANGED | rc=0 >>
  17. 注意:ansible可以删除的定时任务,只能是ansible设置好的定时任务
  18. 2disabled:注释定时任务
  19. ---yes 开启注释
  20. ---no 关闭注释
  21. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m cron -a "name='date sync' job='/usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1' disabled=yes"
  22. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "crontab -l"
  23. 10.0.0.41 | CHANGED | rc=0 >>
  24. #Ansible: date sync
  25. #* * * * * /usr/sbin/ntpdate ntp1.aliyun.com >/dev/null 2>&1

11.10 mount模块

  1. #第十个模块:mount
  2. mount:批量进行挂载操作
  3. 常用参数:src --- 需要挂载的存储设备或文件信息
  4. 常用参数:path --- 指定目标挂载点目录
  5. 常用参数:fstype --- 指定挂载时的文件系统类型
  6. 常用参数:state
  7. 参数选项:present/mounted --- 进行挂载
  8. present:不会实现立即挂载,修改fstab文件,实现开机自动挂载
  9. mounted:会实现立即挂载,并且会修改fstab文件,实现开机自动挂载
  10. 参数选项:absent/unmounted --- 进行卸载
  11. absent:会实现立即卸载,并且会删除fstab文件信息,禁止开机自动挂载
  12. unmounted:会实现立即卸载,但是不会删除fstab文件信息
  13. 基本用法:
  14. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m mount -a "src=/dev/sdb path=/iflytek fstype=xfs state=present"

11.11 user模块

  1. #第十一个模块:user
  2. user:实现批量创建用户
  3. 基本用法:
  4. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m user -a "name=oldboy"
  5. 10.0.0.41 | CHANGED => {
  6. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "id oldboy"
  7. 10.0.0.41 | CHANGED | rc=0 >>
  8. uid=1001(oldboy) gid=1001(oldboy) 组=1001(oldboy)
  9. 扩展用法:
  10. 1uid:指定用户uid信息
  11. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m user -a "name=oldboy01 uid=1314"
  12. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "id oldboy01"
  13. 10.0.0.41 | CHANGED | rc=0 >>
  14. uid=1314(oldboy01) gid=1314(oldboy01) 组=1314(oldboy01)
  15. 2group:指定用户组信息
  16. groups:指定多个用户组信息
  17. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m user -a "name=oldboy02 group=oldboy01"
  18. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "id oldboy02"
  19. 10.0.0.41 | CHANGED | rc=0 >>
  20. uid=1315(oldboy02) gid=1314(oldboy01) 组=1314(oldboy01)
  21. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m user -a "name=oldboy03 groups=oldboy01"
  22. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "id oldboy03"
  23. 10.0.0.41 | CHANGED | rc=0 >>
  24. uid=1316(oldboy03) gid=1316(oldboy03) 组=1316(oldboy03),1314(oldboy01)
  25. 3、批量创建虚拟用户
  26. create_home:是否创建家目录
  27. shell:指定创建的shell
  28. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m user -a "name=rsync create_home=no shell=/sbin/nologin"
  29. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -a "tail -1 /etc/passwd"
  30. 10.0.0.41 | CHANGED | rc=0 >>
  31. rsync:x:1317:1317::/home/rsync:/sbin/nologin
  32. 4、给指定用户创建密码
  33. password:给用户指定密码,但是这个指定是明文的,所以指定密码之前,要把密码变成密文的
  34. [root@iflytek-m01 scripts]# ansible all -i localhost, -m debug -a "msg={{ '123456' | password_hash('sha512','oldboy') }}" #指定密码为密文
  35. localhost | SUCCESS => {
  36. "msg": "$6$oldboy$MVd3DevkLcimrBLdMICrBY8HF82Wtau5cI8D2w4Zs6P1cCfMTcnnyAmmJc7mQaE9zuHxk8JFTRgYMGv9uKW7j1"
  37. }
  38. [root@iflytek-m01 scripts]# ansible 10.0.0.41 -m user -a 'name=oldboy05 password=$6$oldboy$MVd3DevkLcimrBLdMICrBY8HF82Wtau5cI8D2w4Zs6P1cCfMTcnnyAmmJc7mQaE9zuHxk8JFTRgYMGv9uKW7j1'
  39. 5、删除指定用户
  40. ansible oldboy -m user -a 'name=oldboy05 state=absent remove=yes'
  41. #remove:把指定用户对应的家目录删除

11.12 ping模块

  1. #第十二个模块:ping
  2. ping:用于判断远程主机是否在线
  3. 基础用法:
  4. [root@m01-201 ~]# ansible all -m ping
  5. 10.0.0.41 | SUCCESS => {
  6. "ansible_facts": {
  7. "discovered_interpreter_python": "/usr/bin/python"
  8. },
  9. "changed": false,
  10. "ping": "pong" #返回pong,说明成功
  11. }

11.13 get_url模块

  1. #第十三个模块:get_url 用于将文件或软件从http、https或ftp下载到本地节点上
  2. 常用参数:
  3. dest 指定将文件下载的绝对路径---必须
  4. url 文件的下载地址(网址)---必须
  5. url_username: 用于http基本认证的用户名
  6. url_password 用于http基本认证的密码
  7. validate_certs 如果否,SSL证书将不会验证。这只应在使用自签名证书的个人控制站点上使用
  8. owner 指定属主
  9. group 指定属组
  10. mode 指定权限
  11. [admin@node1 ~]$ ansible NFS -m get_url -a "url=http://nginx.org/download/nginx-1.12.2.tar.gz dest=/tmp/"
  12. 192.168.20.136 | SUCCESS => {
  13. "changed": true,
  14. "checksum_dest": null,
  15. "checksum_src": "6b41d63befa4f52b0724b533e6292a6671b71fdc",
  16. "dest": "/tmp/nginx-1.12.2.tar.gz",
  17. "gid": 1010,
  18. "group": "admin",
  19. "md5sum": "4d2fc76211435f029271f1cf6d7eeae3",
  20. "mode": "0664",
  21. "msg": "OK (981687 bytes)",
  22. "owner": "admin",
  23. "secontext": "unconfined_u:object_r:user_tmp_t:s0",
  24. "size": 981687,
  25. "src": "/tmp/tmpk78fBY",
  26. "state": "file",
  27. "status_code": 200,
  28. "uid": 1010,
  29. "url": "http://nginx.org/download/nginx-1.12.2.tar.gz"
  30. }

11.14 group模块

  1. #第十四个模块:group 管理远程主机上的组
  2. name参数:必须参数,用于指定要操作的组名称
  3. state参数:用于指定组的状态,两个值可选,presentabsent,默认为present,设置为absent,表示删除组
  4. gid参数:用于指定组的gid
  5. 示列:
  6. #1、创建news基本组,指定uid为9999
  7. ansible oldboy -m group -a "name=news gid=9999 state=present"
  8. #2、创建http系统组,指定uid为8888
  9. ansible oldboy -m group -a "name=http gid=8888 system=yes state=present"
  10. #3、删除news基本组
  11. ansible oldboy -m group -a "name=http state=absent"

11.15 selinux模块

  1. #第十五个模块:selinux 配置selinux模式和策略
  2. conf参数:默认值/etc/selinux/config
  3. policy参数:默认值null 设置selinux的策略
  4. state参数:选项 enforcingpermissivedisabled
  5. 示列:
  6. ansible oldboy -m selinux -a "state=disabled" -i hosts

11.16 firewalld模块

  1. #第十六个模块:firewalld 配置防火墙模式和策略
  2. 示例一 永久放行https的流量,只有重启才会生效
  3. ansible oldboy -m firewalld -a "zone=public service=https permanent=yes state=enabled"
  4. 示例二 永久放行8081端口的流量,只有重启才会生效
  5. ansible oldboy -m firewalld -a "zone=public port=8080/tcp permanent=yes state=enabled"
  6. 示例三 放行8080-8090的所有tcp端口流量,临时和永久都生效.
  7. ansible oldboy -m firewalld -a "zone=public port=8080-8090/tcp permanent=yes immediate=yes state=enabled"

11.17 unarchive模块

  1. #第十七个模块:unarchive模块
  2. 功能:解包解压缩
  3. 实现有两种用法:
  4. 1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes
  5. 2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
  6. copy:默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no,会在远程主机上寻找src源文件
  7. src:源路径,可以使ansible主机上路径,也可以是远程主机上的路径,如果是远程主机上的路径,则需要设置copy=no
  8. dest:远程主机上的目标路径
  9. mode:设置解压缩后的文件权限
  10. 案例一:把ansible主机上的tar包传至远程主机上,并解压至/root目录下
  11. [root@iflytek-18 ~]# ansible mysql -m unarchive -a "src=/root/192.168.1.65.tar.gz dest=/root"
  12. 案例二:下载互联网的压缩包,并解压在远端服务器上
  13. [root@iflytek-18 ~]# ansible mysql -m unarchive -a "src=https://example.com/example.zip dest=/data copy=no"

11.18 archive模块

  1. #第十八个模块:archive模块
  2. 功能:打包压缩
  3. path:要压缩的文件或目录
  4. dest:压缩后的文件
  5. formatbz2,gz,tar,xz,zip 指定打包的类型
  6. 案例一:
  7. [root@iflytek-18 ~]# ansible mysql -m archive -a "path=/root/192.168.1.65 dest=/tmp/192.168.1.65.tar.gz"

12 Ansible playbook的编写

Playbook英文翻译过来就是剧本的意思。

12.1 Playbook的组成部分

play:定义的是主机的角色

hosts:执行的远程主机列表

tasks:定义的是具体执行的任务

variables:内置变量或自定义变量在playbook中调用

handlers和notify结合使用,由特定条件触发的操作,满足条件方才执行,否则不执行

tags标签:指定某条任务执行,用于选择运行playbook中的部分代码。ansible具有幂等性,因此会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常的长。此时,如果确信其没有变化,就可以通过tags跳过此些代码片段。

playbook:由一个或多个play组成,一个play可以包含多个task任务

简单理解为:使用不同的模块完成一件事情

image.png

12.2 Playbook编写规范

再说Playbook编写规范之前,我们要说一下YAML语言

12.2.1 YMAL语言介绍

YAML:YAML通俗来理解,就是一种标记语言。YAML是一个可读性高的用来表达资料序列的格式。YAML参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822等。Clark Evans在2001年首次发表了这种语言,目前很多最新的软件比较流行采用此格式的文件存放配置信息,如:Ubuntu、Ansible、Docker等。

12.2.2 YAML语言特性

  • YAML的可读性好
  • YAML和脚本语言的交互性好
  • YAML使用实现语言的数据类型
  • YAML有一个一致的信息模型
  • YAML易于实现
  • YAML可以基于流来处理
  • YAML表达能力强,扩展性好

12.2.3 Playbook语言规范

1.合理的缩进,两个空格表示一个缩进

  1. 标题一
  2. 标题二

注意:在ansible中一定不能用tab进行缩进

2.冒号的使用方法
hosts: 172.16.1.41
tasks:
注意:使用冒号时后面要有空格,以冒号结尾,冒号出现在注释说明中,后面不需要加上空格

3.短横线应用 - (列表功能)

  1. - 张三
  2. - 打游戏
  3. - 运动
  4. - 李四
  5. 学习
  6. 湖南
  7. 注意:使用短横线构成列表信息,短横线后面需要有空格

4.剧本中一个name标识下面只能写一个模块任务信息,如果写一个以上,会有报错

5.剧本中尽量不要大量使用shell模块

12.2.4 playbook命令

  1. ansible-playbook file.yml
  2. #主要选项:
  3. -C #检测语法,不执行任务
  4. --list-hosts #列出执行任务的主机
  5. --list-tags #列出tag
  6. --list-tasks #列出task
  7. --limit 主机列表 #只针对主机列表中的特定主机执行
  8. -v -vv -vvv #显示过程

12.3 playbook实战

剧本一键安装rsnync

  1. 管理端:
  2. 1、创建剧本目录
  3. [root@iflytek-m01 ~]# mkdir /etc/ansible/ansible-playbook
  4. 2、创建剧本
  5. [root@iflytek-m01 ~]# cd /etc/ansible/ansible-playbook
  6. [root@iflytek-m01 ansible-playbook]# vim rsync_server.yaml
  7. #说明:剧本文件扩展名尽量写为yaml
  8. #1.方便识别文件是一个剧本文件
  9. #2.文件编写时会有颜色提示
  10. [root@iflytek-m01 ansible-playbook]# cat rsync_server.yaml
  11. - hosts: 10.0.0.31
  12. tasks:
  13. - name: 01-install rsync
  14. yum: name=rsync state=installed
  15. - name: 02-copy rsyncd.conf
  16. copy: src=/playbook/rsyncd.conf dest=/etc/
  17. - name: 03-useradd name
  18. user: name=rsync create_home=no shell=/sbin/nologin
  19. - name: 04-systemctl start rsyncd
  20. service: name=rsyncd state=started enabled=yes
  21. - name: 05-mkdir /backup
  22. file: dest=/backup state=directory owner=rsync group=rsync recurse=yes
  23. - name: 06-touch rsync.password
  24. copy: src=/playbook/rsync.password dest=/etc/ mode=600
  25. - hosts: 10.0.0.41
  26. tasks:
  27. - name: 01-install rsync
  28. yum: name=rsync state=installed
  29. - name: 02-copy rsyncd.conf
  30. copy: content=oldboy dest=/etc/rsync.password mode=600
  31. - name: 03-mkdir /backup
  32. file: dest=/backup
  33. 3、执行剧本之前,先检查语法格式
  34. [root@iflytek-m01 ansible-playbook]# ansible-playbook --syntax-check rsync_server.yaml #检测语法格式
  35. playbook: rsync_server.yaml
  36. [root@iflytek-m01 ansible-playbook]# ansible-playbook -C rsync_server.yaml #模拟运行剧本,查看剧本是否运行正常
  37. PLAY [10.0.0.41] ****************************************************************************************************************************************************************************
  38. TASK [Gathering Facts] **********************************************************************************************************************************************************************
  39. ok: [10.0.0.41]
  40. TASK [yum] **********************************************************************************************************************************************************************************
  41. changed: [10.0.0.41]
  42. TASK [copy] *********************************************************************************************************************************************************************************
  43. changed: [10.0.0.41]
  44. PLAY RECAP **********************************************************************************************************************************************************************************
  45. 10.0.0.41 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
  46. 4、运行剧本
  47. [root@iflytek-m01 ansible-playbook]# ansible-playbook rsync_server.yaml

剧本一键安装nfs

  1. [root@md-68 playbook]# cd /etc/ansible/playbook/
  2. [root@md-68 playbook]# ls
  3. exports.j2 nfs.yaml
  4. [root@md-68 playbook]# cat nfs.yaml
  5. - hosts: 192.168.1.31
  6. tasks:
  7. - name: install rpcbind
  8. yum:
  9. name: rpcbind
  10. state: installed
  11. - name: install nfs-utils
  12. yum:
  13. name: nfs-utils
  14. state: installed
  15. - name: copy configure exports
  16. copy:
  17. src: ./exports.j2
  18. dest: /etc/exports
  19. backup: yes
  20. - name: make dir
  21. file:
  22. dest: /data
  23. state: directory
  24. owner: nfsnobody
  25. group: nfsnobody
  26. recurse: yes
  27. - name: start service rbcbind
  28. service:
  29. name: rpcbind
  30. state: started
  31. enabled: yes
  32. - name: start service nfs
  33. service:
  34. name: nfs
  35. state: started
  36. enabled: yes
  37. - hosts: 192.168.1.41
  38. tasks:
  39. - name: install rpcbind
  40. yum:
  41. name: rpcbind
  42. state: installed
  43. - name: install nfs-utils
  44. yum:
  45. name: nfs-utils
  46. state: installed
  47. - name: start service rbcbind
  48. service:
  49. name: rpcbind
  50. state: started
  51. enabled: yes
  52. - name: start service nfs
  53. service:
  54. name: nfs
  55. state: started
  56. enabled: yes
  57. - name: mount nfs
  58. mount:
  59. src: 192.168.1.31:/data
  60. path: /data
  61. fstype: nfs
  62. opts: defaults
  63. state: mounted
  64. [root@md-68 playbook]# ansible-playbook --syntax-check nfs.yaml
  65. playbook: nfs.yaml
  66. [root@md-68 playbook]# ansible-playbook nfs.yaml

剧本一键安装nginx

  1. [root@md-68 playbook]# cat nginx.yaml
  2. - hosts: 192.168.1.7
  3. tasks:
  4. - name: Install nginx
  5. yum:
  6. name: nginx
  7. state: installed
  8. - name: service nginx start
  9. service:
  10. name: nginx
  11. state: started
  12. enabled: yes
  13. [root@md-68 playbook]# ansible-playbook --syntax-check nfs.yaml
  14. playbook: nfs.yaml
  15. [root@md-68 playbook]# ansible-playbook nfs.yaml

12.4 playbook中使用handler和notify

12.4.1 handlers和notify结合触发条件

  • handlers(触发器):定义一些task列表,与之前剧本中task没有关系,只有资源发生变化才会采取一定的操作
  • notify:notify中调用handler中定义的操作

12.4.2 案例

  1. 1yum安装nginx
  2. [root@iflytek-18 playbook]# tree
  3. .
  4. ├── files
  5. └── nginx.conf
  6. └── nginx.yaml
  7. [root@iflytek-18 playbook]# cat nginx.yaml
  8. - hosts: mysql
  9. tasks:
  10. - name: install nginx package
  11. yum: name=nginx
  12. - name: copy conf file
  13. copy: src=files/nginx.conf dest=/etc/nginx/nginx.conf
  14. - name: start service
  15. service: name=nginx state=started enabled=yes
  16. [root@iflytek-18 playbook]# ansible-playbook nginx.yaml #运行playbook
  17. #这时候nginx 80端口是起来的
  18. [root@iflytek-18 files]# ansible mysql -m shell -a "ss -lntp|grep 80"
  19. 192.168.1.65 | CHANGED | rc=0 >>
  20. LISTEN 0 128 *:80 *:* users:(("nginx",pid=14010,fd=6),("nginx",pid=14009,fd=6))
  21. 2、我们修改nginx配置文件,只修改端口
  22. [root@iflytek-18 files]# grep listen nginx.conf
  23. listen 81 default_server;
  24. [root@iflytek-18 playbook]# ansible-playbook nginx.yaml
  25. 3、然后我们查看远端的nginx服务器
  26. [root@mysql-65 ~]# grep "listen" /etc/nginx/nginx.conf
  27. listen 81 default_server; #说明配置文件的确是修改了
  28. [root@mysql-65 ~]# ss -lntp|grep nginx #但是nginx并没有重启,这个是因为ansible的幂等性导致的
  29. LISTEN 0 128 *:80 *:* users:(("nginx",pid=14010,fd=6),("nginx",pid=14009,fd=6))
  30. 所以为了解决这个问题,我们需要引入handlersnotify
  31. #####################################################################################################
  32. [root@iflytek-18 playbook]# cat nginx.yaml
  33. - hosts: mysql
  34. tasks:
  35. - name: install nginx package
  36. yum: name=nginx
  37. - name: copy conf file
  38. copy: src=files/nginx.conf dest=/etc/nginx/nginx.conf
  39. notify: restart service #这边的值必须和下面handlers中的name相匹配
  40. - name: start service
  41. service: name=nginx state=started enabled=yes
  42. handlers:
  43. - name: restart service
  44. service: name=nginx state=restarted
  45. [root@iflytek-18 playbook]# ansible-playbook nginx.yaml
  46. 最后的结果:
  47. [root@mysql-65 nginx]# ss -lntp|grep nginx
  48. LISTEN 0 128 *:82 *:* users:(("nginx",pid=15210,fd=6),("nginx",pid=15208,fd=6))
  49. 我们可以看到端口的确是更改了。所以只要碰到修改配置文件操作的,需要重启服务的,一般都需要使用handlersnotify

12.5 playbook中使用tags组件

在playbook文件中,可以利用tags组件,为特定task指定标签,当在执行playbook时,可以只执行tags的task,而非整个playbook文件

  1. 1、修改nginx配置文件
  2. [root@iflytek-18 files]# grep listen nginx.conf
  3. listen 8080 default_server;
  4. 2、修改playbook文件
  5. [root@iflytek-18 playbook]# cat nginx.yaml
  6. - hosts: mysql
  7. tasks:
  8. - name: install nginx package
  9. yum: name=nginx
  10. - name: copy conf file
  11. copy: src=files/nginx.conf dest=/etc/nginx/nginx.conf
  12. tags: conf #定义一个conf标签
  13. - name: start service
  14. tags: service #定义一个service标签
  15. service: name=nginx state=started enabled=yes
  16. 3、执行playbook
  17. [root@iflytek-18 playbook]# ansible-playbook -t conf,service nginx.yaml

12.6 playbook中使用变量

12.6.1 变量的定义

仅能由字母、数字和下划线组成,且只能以字母开头

variable=value

范列:

http_port=80

12.6.2 变量的调用方式

通过{{ variable_name }} 调用变量,且变量名前后建议加空格,有时用“{{ variable_name }}”才生效

12.6.3 变量来源

使用setup模块中变量

注意:本模块自动在playbook调用,不要用ansible命令调用

#案例:使用setup中的变量
[root@iflytek-18 playbook]# cat var.yaml 
- hosts: mysql

  tasks:
    - name: create log file
      file: name=/data/{{ ansible_nodename }}.log state=touch mode=600

[root@iflytek-18 playbook]# ansible-playbook var.yaml

通过命令行指定变量,优先级最高

[root@iflytek-18 playbook]# vim var2.yml 
- hosts: webserver
  remote_user: root
  tasks:
    - name: install packages
      yum: name={{ pkname }} state=present

]# ansible-playbook -e pkname="nginx" var2.yml

在playbook文件中定义变量

]# vim var3.yml 
- hosts: webserver
  remote_user: root
  vars:
    - username: user1
    - groupname: group1

  tasks:
    - name: create group
      group: name={{ groupname }} state=present
    - name: create user
      user: name={{ username }} group={{ groupname }} state=present

]# ansible-playbook var3.yml

使用变量文件

可以在一个独立的playbook文件中定义变量,在另一个playbook文件中引用变量文件中的变量,比playbook中定义的变量优化级高

]# vim vars.yml 
package_name: mariadb-server
service_name: mariadb


]# vim var4.yml 
- hosts: webserver
  remote_user: root
  vars_files:
    - /etc/ansible/test/playbook/vars.yml

  tasks:
    - name: install packages
      yum: name={{ package_name }}
    - name: start service
      service: name={{ service_name }} state=started enabled=yes

通过inventory主机清单进行变量定义

============================== group vars ==============================
在项目目录下创建两个变量的目录,host_vars group_vars
#1)在当前的项目目录中创建两个变量的目录
[root@ansible project1]# mkdir host_vars
[root@ansible project1]# mkdir group_vars

#2)在group_vars目录中创建一个文件,文件名与inventory清单中的组名称要保持完全一致。
[root@ansible project1]# cat group_vars/oldboy
web_packages: wget
ftp_packages: tree

#3)编写playbook,只需在playbook文件中使用变量即可。
[root@ansible project1]# cat f4.yml 
- hosts: oldboy
  tasks:
    - name: Install Rpm Packages "{{ web_packages }}" "{{ ftp_packages }}"
      yum: 
        name: 
          - "{{ web_packages }}"
          - "{{ ftp_packages }}"
        state: present

注意必须在group_vars目录之外创建yml文件,这样才能识别group_vars/oldboy文件中的变量名

注意: 默认情况下,group_vars目录中文件名与hosts清单中的组名保持一致.
     比如在group_vars目录中创建了oldboy组的变量,其他组是无法使用oldboy组的变量
     系统提供了一个特殊组,all,只需要在group_vars目录下建立一个all文件,编写好变量,所有组都可使用.

============================== host vars ==============================
#1)在host_vars目录中创建一个文件,文件名与inventory清单中的主机名称要保持完全一致
[root@ansible project1]# cat hosts 
[oldboy]
10.0.0.64
10.0.0.68

#2)在host_vars目录中创建文件,给10.0.0.64主机定义变量
[root@ansible project1]# cat host_vars/10.0.0.64
web_packages: wget
ftp_packages: tree

#3)准备一个playbook文件调用host主机变量
[root@ansible project1]# cat f4.yml 
- hosts: 10.0.0.64
  tasks:
    - name: Install Rpm Packages "{{ web_packages }}" "{{ ftp_packages }}"
      yum: 
        name: 
          - "{{ web_packages }}"
          - "{{ ftp_packages }}"
        state: present

- hosts: 10.0.0.68
  tasks:
    - name: Install Rpm Packages "{{ web_packages }}" "{{ ftp_packages }}"
      yum: 
        name: 
          - "{{ web_packages }}"
          - "{{ ftp_packages }}"
        state: present

注意必须在host_vars目录之外创建yml文件,这样才能识别host_vars/10.0.0.64文件中的变量名    
host_vars 特殊的变量目录,针对单个主机进行变量.
group_vars 特殊的变量目录,针对inventory主机清单中的组进行变量定义. 对A组定义的变量 B组无法调用
group_vars/all 特殊的变量文件,可以针对所有的主机组定义变量.

12.6.4 变量的优先级

外置传参 ---> playbook(vars_files ---> vars) ---> inventory(host_vars --> group_vars/group_name ---> group_vars-all)

12.7 ansible变量注册

[root@m01 project1]# cat vars_9.yml 
- hosts: oldboy

  tasks:
    - name: Installed Httpd Server
      yum: name=httpd state=present

    - name: Service Httpd Server
      service: name=httpd state=started

    - name: Check Httpd Server
      shell: ps aux|grep httpd
      register: check_httpd  #把上面的ps aux|grep httpd写进check_httpd变量中

    - name: OutPut Variables
      debug:
        msg: "{{ check_httpd.stdout_lines }}" #通过debug模块中的msg方法输出变量的所有内容

12.8 Facts概述

Ansible Facts 是 Ansible 在被托管主机上自动收集的变量。它是通过在执行 Ad-Hoc 以及 Playbook 时使用 setup 模块进行收集的,并且这个操作是默认的。

因为这个收集托管主机上的 Facts 比较耗费时间,所以可以在不需要的时候关闭 setup 模块。收集的 Facts 中包含了托管主机特有的信息,这些信息可以像变量一样在 Playbook 中使用。

收集的 Facts 中包含了以下常用的信息:

主机名、内核版本、网卡接口、IP 地址、操作系统版本、环境变量、CPU 核数、可用内存、可用磁盘 等等……。

使用场景

  1. 通过 facts 检查 CPU,生成对应的 Nginx 配置文件
  2. 通过 facts 检查内存情况,定义不同的 MySQL 配置文件或 Redis 配置文件
  3. 通过 facts 检查主机 hostname,生成不同的 zabbix 配置文件

12.8.1 获取指定受控端的facts信息

[root@es-161 roles]# ansible all -m setup
10.0.0.64 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.0.0.64"
        ], 
        "ansible_all_ipv6_addresses": [
            "fe80::63af:74b9:89f6:61a7"
        ], 
        "ansible_apparmor": {
            "status": "disabled"
        }, 
.......

12.8.2 如何在playbook中关闭facts

[yun@ansi-manager object03]$ cat test_facts.yml 
---
# facts 使用
- hosts: proxyservers
  # 关闭 facts 变量
  gather_facts: no

  # 这时就不能取到 ansible_hostname、ansible_eth0.ipv4.address、ansible_eth1 ['ipv4']['address'] 变量信息
  tasks:
    - name: "get ansible facts var"
      debug:
        msg: "This host name is {{ ansible_hostname }} ,eth0: {{ ansible_eth0.ipv4.address }}, eth1: {{ ansible_eth1['ipv4']['address'] }}"

12.8.3 案列:获取主机名和网卡信息

#获取受控端的主机名、外网地址
[root@es-161 roles]# cat vars10.yml 
- hosts: oldboy
  tasks:
    - name: "get ansible facts var"
      debug:
        msg: "This host name is {{ ansible_hostname }} ,ens33: {{ ansible_ens33.ipv4.address }}"

[root@es-161 roles]# ansible-playbook vars10.yml 
PLAY [oldboy] *******************************************************************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************************************************************
ok: [10.0.0.64]

TASK [get ansible facts var] ****************************************************************************************************************************************************************
ok: [10.0.0.64] => {
    "msg": "This host name is mysql-64 ,ens33: 10.0.0.64"
}

PLAY RECAP **********************************************************************************************************************************************************************************
10.0.0.64                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

12.9 template模板

12.9.1 template模板作用

template模块使用了[Jinjia2](http://jinja.pocoo.org/docs/)模版语言,进行文档内变量的替换的模块。

template模块用法和copy模块用法基本一致,它主要用于复制配置文件。可以按需求修改配置文件内容来复制模板到被控主机上。

template功能:可以根据和参考模块文件,动态生成相类似的配置文件
template文件必须存放于templates目录下,且命名为 .j2 结尾
yaml/yml 文件需和templates目录平级,目录结构如下示例:
./
├── temnginx.yml
└── templates
└── nginx.conf.j2

12.9.2 范例

#修改文件nginx.conf.j2 
mkdir templates
vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};

vim temnginx2.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf 
    - name: start service
      service: name=nginx state=started enable=yes

ansible-playbook temnginx2.yml


#范例2 template算术运算
[root@ansible ansible]#vim templates/nginx.conf.j2
worker_processes {{ ansible_processor_vcpus**3 }};

[root@ansible ansible]#cat templnginx.yml
---
- hosts: websrvs
  remote_user: root

  tasks:
    - name: install nginx
      yum: name=nginx
    - name: template config to remote hosts
      template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
      notify: restart nginx
    - name: start service
      service: name=nginx state=started enabled=yes

  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

ansible-playbook  templnginx.yml --limit 10.0.0.8

12.10 roles角色

12.10.1 roles角色简介

角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用include指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,并可以便捷地include它们的一种机制。角色一般用于基于主机构建服务的场景中,但也可以是用于构建守护进程等场景中。

运维复杂的场景:建议使用roles,代码复用度高。

roles:多个角色的集合, 可以将多个的role,分别放至roles目录下的独立子目录中

roles/
mysql/
httpd/
nginx/
redis/

12.10.2 Ansible Roles目录结构

image.png

Roles各目录作用

roles/project/ :项目名称,有以下子目录

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

12.10.3 创建role

创建role的步骤:

(1) 创建以roles命名的目录

(2) 在roles目录中分别创建以各角色名称命名的目录,如webservers等

(3) 在每个角色命名的目录中分别创建files、handlers、meta、tasks、templates和vars目录;用不到的目录可以创建为空目录,也可以不创建

(4) 在playbook文件中,调用各角色

针对大型项目使用Roles进行编排,范例:roles的目录结构:

nginx-role.yml 
roles/
└── nginx 
     ├── files
     │    └── main.yml 
     ├── tasks
     │    ├── groupadd.yml 
     │    ├── install.yml 
     │    ├── main.yml 
     │    ├── restart.yml 
     │    └── useradd.yml 
     └── vars 
          └── main.yml

12.10.4 playbook调用角色

调用方法1:

---
- hosts: websrvs
  remote_user: root
  roles:
    - mysql
    - memcached
    - nginx

调用方法2:

键role用于指定角色名称,后续的k/v用于传递变量给角色

---
- hosts: all
  remote_user: root
  roles:
    - mysql
    - { role: nginx, username: nginx }

调用方法3:

还可基于条件测试实现角色调用

---
- hosts: all
  remote_user: root
  roles:
    - { role: nginx, username: nginx, when: ansible_distribution_major_version == ‘7’  }

12.10.5 企业实战案例

12.10.5.1 案例1:实现Nginx角色
mkdir -pv  /data/ansible/roles/nginx/{tasks,handlers,templates,vars}

#创建task文件
cd /data/ansible/roles/nginx/

vim tasks/main.yml 
- include: install.yml
- include: config.yml
- include: index.yml
- include: service.yml

vim  tasks/install.yml 
- name: install
  yum: name=nginx 

vim tasks/config.yml 
- name: config file for centos7
  template: src=nginx7.conf.j2 dest=/etc/nginx/nginx.conf
  when: ansible_distribution_major_version=="7"
  notify: restart
- name: config file for centos8
  template: src=nginx8.conf.j2 dest=/etc/nginx/nginx.conf
  when: ansible_distribution_major_version=="8"
  notify: restart

vim  tasks/index.yml 
- name: index.html
  copy: src=roles/httpd/files/index.html dest=/usr/share/nginx/html/

vim tasks/service.yml 
- name: start service
  service: name=nginx state=started enabled=yes

#创建handler文件
cat handlers/main.yml 
- name: restart
  service: name=nginx state=restarted

#创建两个template文件
cat templates/nginx7.conf.j2
...省略...
user {{user}};
worker_processes {{ansible_processor_vcpus+3}};   #修改此行
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...

cat templates/nginx8.conf.j2
...省略...
user nginx;
worker_processes {{ansible_processor_vcpus**3}};  #修改此行
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
...省略...

#创建变量文件
vim vars/main.yml 
user: daemon

#目录结构如下

tree /data/ansible/roles/nginx/
/data/ansible/roles/nginx/
├── handlers
│   └── main.yml
├── tasks
│   ├── config.yml
│   ├── file.yml
│   ├── install.yml
│   ├── main.yml
│   └── service.yml
├── templates
│   ├── nginx7.conf.j2
│   └── nginx8.conf.j2
└── vars
    └── main.yml

4 directories, 9 files

#在playbook中调用角色
vim /data/ansible/role_nginx.yml 
---
#nginx role 
- hosts: websrvs

  roles:
    - role: nginx

#运行playbook
ansible-playbook  /data/ansible/role_nginx.yml

12.10.5.2 案例2:实现mysql5.6
[root@ansible ~]#cat /data/ansible/roles/mysql/files/my.cnf 
[mysqld]
socket=/tmp/mysql.sock
user=mysql
symbolic-links=0
datadir=/data/mysql
innodb_file_per_table=1
log-bin
pid-file=/data/mysql/mysqld.pid

[client]
port=3306
socket=/tmp/mysql.sock

[mysqld_safe]
log-error=/var/log/mysqld.log

[root@ansible ~]#cat /data/ansible/roles/mysql/files/secure_mysql.sh 
#!/bin/bash
/usr/local/mysql/bin/mysql_secure_installation <<EOF

y
magedu
magedu
y
y
y
y
EOF

[root@ansible ~]#chmod +x  /data/ansible/roles/mysql/files/secure_mysql.sh

[root@ansible ~]#ls /data/ansible/roles/mysql/files/
my.cnf  mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz  secure_mysql.sh

[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/main.yml
- include: install.yml
- include: group.yml
- include: user.yml
- include: unarchive.yml
- include: link.yml
- include: data.yml
- include: config.yml
- include: service.yml
- include: path.yml
- include: secure.yml

[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/install.yml 
- name: install packages                                            
  yum: name=libaio,perl-Data-Dumper,perl-Getopt-Long
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/group.yml 
- name: create mysql group
  group: name=mysql gid=306
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/user.yml 
- name: create mysql user
  user: name=mysql uid=306 group=mysql shell=/sbin/nologin system=yes create_home=no home=/data/mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/unarchive.yml 
- name: copy tar to remote host and file mode 
  unarchive: src=mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz dest=/usr/local/ owner=root group=root
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/link.yml 
- name: mkdir /usr/local/mysql 
  file: src=/usr/local/mysql-5.6.46-linux-glibc2.12-x86_64 dest=/usr/local/mysql state=link
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/data.yml 
- name: data dir
  shell: chdir=/usr/local/mysql/  ./scripts/mysql_install_db --datadir=/data/mysql --user=mysql
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/config.yml 
- name: config my.cnf
  copy: src=my.cnf  dest=/etc/my.cnf 
[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/service.yml 
- name: service script
  shell: /bin/cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld;chkconfig --add mysqld;chkconfig mysqld on;/etc/init.d/mysqld start

[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/path.yml 
- name: PATH variable
  copy: content='PATH=/usr/local/mysql/bin:$PATH' dest=/etc/profile.d/mysql.sh  

[root@ansible ~]#cat /data/ansible/roles/mysql/tasks/secure.yml 
- name: secure script
  script: secure_mysql.sh

[root@ansible ~]#tree /data/ansible/roles/mysql/
/data/ansible/roles/mysql/
├── files
│   ├── my.cnf
│   ├── mysql-5.6.46-linux-glibc2.12-x86_64.tar.gz
│   └── secure_mysql.sh
└── tasks
    ├── config.yml
    ├── data.yml
    ├── group.yml
    ├── install.yml
    ├── link.yml
    ├── main.yml
    ├── path.yml
    ├── secure.yml
    ├── service.yml
    ├── unarchive.yml
    └── user.yml

2 directories, 14 files

[root@ansible ~]#cat /data/ansible/mysql_roles.yml
- hosts: dbsrvs
  remote_user: root

  roles:
    - {role: mysql,tags: ["mysql","db"]}
    - {role: nginx,tage: ["nginx","web"]}

[root@ansible ~]#ansible-playbook -t mysql /data/ansible/mysql_roles.yml