最近接触了ansible工具,查找了一些资料,也做了一些总结。希望能给刚接触的新手带来一些帮助。

此总结有实际例子,大部分也是从实践中用到才逐一总结的。

当然可能肯定一定会存在一些错误和纰漏,还望大家具体实践时进一步熟悉了解。

ansible本身的模块有几百个,按照官网的建议来说,不建议一次性学完。

我们需要一边学习一边实践一边总结。要经常查找官方文档。

官方文档如下:

https://docs.ansible.com/ansible/latest/index.html

  1. Ansible学习
  2. 安装:
  3. pip install ansible==2.4.1.0
  4. 为什么要指定版本是:2.4.1.0
  5. 1、因为最新版本2.7.1在导入时,报错:
  6. root@ubuntu:/etc/ansible# ansible --version
  7. Traceback (most recent call last):
  8. File "/usr/bin/ansible", line 41, in <module>
  9. from ansible.utils.unicode import to_unicode
  10. ImportError: cannot import name to_unicode
  11. 暂时解决办法:将ansible版本降低到2.4.1.0问题解决
  12. 2、一些新特性只能在更高的ansible版本中使用,比如:include_tasks
  13. 在低版本中使用时会报错:
  14. ERROR! no action detected in task
  15.  
  16. The error appears to have been in '/etc/ansible/roles/newone/tasks/main.yml': line 8, column 4, but may
  17. be elsewhere in the file depending on the exact syntax problem.
  18.  
  19. The offending line appears to be:
  20.  
  21. - include_tasks: lala.yml
  22. ^ here
  23.  
  24. 依赖包如下:
  25. jinja2 Jinja2 2.10
  26. PyYAML PyYAML 3.11
  27. paramiko paramiko 2.4.2
  28. cryptography cryptography 2.3.1
  29. setuptools setuptools 20.7.0
  30. MarkupSafe>=0.23 MarkupSafe 0.23
  31. pyasn1>=0.1.7 pyasn1 0.4.4
  32. bcrypt>=3.1.3 bcrypt 3.1.4
  33. pynacl>=1.0.1 PyNaCl 1.3.0
  34. enum34; python_version < "" enum34 1.1.6
  35. asn1crypto>=0.21.0 asn1crypto 0.24.0
  36. cffi!=1.11.3,>=1.7 cffi 1.11.5
  37. idna>=2.1 idna 2.7
  38. six>=1.4.1 six 1.10.0
  39. ipaddress; python_version < "" ipaddress 1.0.22
  40. pycparser pycparser 2.19
  41.  
  42. ansible -h 参数解析
  43. Usage: ansible <host-pattern> [options]
  44.  
  45. Options:
  46. -a MODULE_ARGS, --args=MODULE_ARGS 模块的参数,如果执行默认COMMAND的模块,即是命令参数,如:“date”,"pwd"等等
  47. module arguments 模块参数
  48. -k, --ask-pass ask for SSH password 登录密码,提示输入SSH密码而不是假设基于密钥的验证
  49. --ask-su-pass ask for su password su切换密码
  50. -K, --ask-sudo-pass ask for sudo password 提示密码使用sudo,sudo表示提权操作
  51. --ask-vault-pass ask for vault password
  52. -B SECONDS, --background=SECONDS 后台运行超时时间
  53. run asynchronously, failing after X seconds
  54. (default=N/A)
  55. -C, --check don't make any changes; instead, try to predict some
                  只是测试一下会改变什么内容,不会真正去执行;相反,试图预测一些可能发生的变化
  56. of the changes that may occur
  57. -c CONNECTION, --connection=CONNECTION 连接类型使用。可能的选项是paramiko(SSH),SSH和地方。当地主要是用于crontab或启动。
  58. connection type to use (default=smart)
  59. -f FORKS, --forks=FORKS 并行任务数。NUM被指定为一个整数,默认是5
  60. specify number of parallel processes to use
  61. (default=5)
  62. -h, --help show this help message and exit 打开帮助文档API
  63. -i INVENTORY, --inventory-file=INVENTORY 指定库存主机文件的路径,默认为/etc/ansible/hosts
  64. specify inventory host file
  65. (default=/etc/ansible/hosts)
  66. -l SUBSET, --limit=SUBSET 进一步限制所选主机/组模式 --limit=192.168.91.135 只对这个ip执行
  67. further limit selected hosts to an additional pattern
  68. --list-hosts outputs a list of matching hosts; does not execute
  69. anything else
  70. -m MODULE_NAME, --module-name=MODULE_NAME 执行模块的名字,默认使用 command 模块,所以如果是只执行单一命令可以不用 -m参数
  71. module name to execute (default=command)
  72. -M MODULE_PATH, --module-path=MODULE_PATH 要执行的模块的路径,默认为/usr/share/ansible/
  73. specify path(s) to module library
  74. (default=/usr/share/ansible/)
  75. -o, --one-line condense output 压缩输出,摘要输出.尝试一切都在一行上输出。
  76. -P POLL_INTERVAL, --poll=POLL_INTERVAL 调查背景工作每隔数秒。需要- b
  77. set the poll interval if using -B (default=15)
  78. --private-key=PRIVATE_KEY_FILE 私钥路径,使用这个文件来验证连接
  79. use this file to authenticate the connection
  80. -S, --su run operations with su 用 su 命令
  81. -R SU_USER, --su-user=SU_USER 指定SU的用户,默认是root用户
  82. run operations with su as this user (default=root)
  83. -s, --sudo run operations with sudo (nopasswd)
  84. -U SUDO_USER, --sudo-user=SUDO_USER sudo到哪个用户,默认为 root
  85. desired sudo user (default=root)
  86. -T TIMEOUT, --timeout=TIMEOUT 指定SSH默认超时时间, 默认是10S
  87. override the SSH timeout in seconds (default=10)
  88. -t TREE, --tree=TREE log output to this directory 将日志内容保存在该输出目录,结果保存在一个文件中在每台主机上。
  89. -u REMOTE_USER, --user=REMOTE_USER 远程用户, 默认是root用户
  90. connect as this user (default=root)
  91. --vault-password-file=VAULT_PASSWORD_FILE
  92. vault password file
  93. -v, --verbose verbose mode (-vvv for more, -vvvv to enable 如果命令执行成功,输出详细的结果
  94. connection debugging)(-vv –vvv -vvvv)
  95. --version show program's version number and exit 输出ansible的版本
  96.  
  97. ansible-playbook参数解析:
  98. Options:
  99. --ask-vault-pass
  100. #加密playbook文件时提示输入密码
  101. -C, --check
  102. #模拟执行,不会真正在机器上执行(查看执行会产生什么变化)
  103. -D, --diff
  104. #当更新的文件数及内容较少时,该选项可显示这些文件不同的地方,该选项结合-C用会有较好的效果
  105. -e EXTRA_VARS, --extra-vars=EXTRA_VARS
  106. #在Playbook中引入外部参数变量
  107. --flush-cache
  108. #将fact清除到的远程主机缓存
  109. --force-handlers
  110. #强制运行handlers的任务,即使在任务失败的情况下
  111. -f FORKS, --forks=FORKS
  112. #并行任务数。FORKS被指定为一个整数,默认是5
  113. -h, --help
  114. #打开帮助文档API
  115. -i INVENTORY, --inventory-file=INVENTORY
  116. #specify inventory host path (default=/etc/ansible/hosts) or comma separated host list.
  117. #指定要读取的Inventory文件
  118. -l SUBSET, --limit=SUBSET
  119. #further limit selected hosts to an additional pattern
  120. #限定执行的主机范围
  121. --list-hosts
  122. #outputs a list of matching hosts; does not execute anything else
  123. #列出执行匹配到的主机,但并不会执行
  124. --list-tags
  125. #list all available tags
  126. #列出所有可用的tags
  127. --list-tasks
  128. #list all tasks that would be executed
  129. #列出所有即将被执行的任务
  130. -M MODULE_PATH, --module-path=MODULE_PATH
  131. #specify path(s) to module library (default=None)
  132. #要执行的模块的路径
  133. --new-vault-password-file=NEW_VAULT_PASSWORD_FILE
  134. #new vault password file for rekey
  135. #
  136. --output=OUTPUT_FILE
  137. #output file name for encrypt or decrypt; use - for stdout
  138. #
  139. --skip-tags=SKIP_TAGS
  140. #only run plays and tasks whose tags do not match these values
  141. #跳过指定的tags任务
  142. --start-at-task=START_AT_TASK
  143. #start the playbook at the task matching this name
  144. #从第几条任务(START_AT_TASK)开始执行
  145. --step
  146. #one-step-at-a-time: confirm each task before running
  147. #逐步执行Playbook定义的任务,并经人工确认后继续执行下一步任务
  148. --syntax-check
  149. #perform a syntax check on the playbook, but do not execute it
  150. #检查Playbook中的语法书写,并不实际执行
  151. -t TAGS, --tags=TAGS
  152. #only run plays and tasks tagged with these values
  153. #指定执行该tags的任务
  154. --vault-password-file=VAULT_PASSWORD_FILE
  155. #vault password file
  156. #
  157. -v, --verbose
  158. #verbose mode (-vvv for more, -vvvv to enable connection debugging)
  159. #执行详细输出
  160. --version
  161. #show program's version number and exit
  162. #显示版本
  163.  
  164. Connection Options:
  165. control as whom and how to connect to hosts
  166.  
  167. -k, --ask-pass
  168. #ask for connection password
  169. #
  170. --private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE
  171. #use this file to authenticate the connection
  172. #
  173. -u REMOTE_USER, --user=REMOTE_USER
  174. #connect as this user (default=None)
  175. #指定远程主机以USERNAME运行命令
  176. -c CONNECTION, --connection=CONNECTION
  177. #connection type to use (default=smart)
  178. #指定连接方式,可用选项paramiko (SSH)、ssh、local,local方式常用于crontab和kickstarts
  179. -T TIMEOUT, --timeout=TIMEOUT
  180. #override the connection timeout in seconds(default=10)
  181. #SSH连接超时时间设定,默认10s
  182. --ssh-common-args=SSH_COMMON_ARGS
  183. #specify common arguments to pass to sftp/scp/ssh (e.g.ProxyCommand)
  184. #
  185. --sftp-extra-args=SFTP_EXTRA_ARGS
  186. #specify extra arguments to pass to sftp only (e.g. -f, -l)
  187. #
  188. --scp-extra-args=SCP_EXTRA_ARGS
  189. #specify extra arguments to pass to scp only (e.g. -l)
  190. #
  191. --ssh-extra-args=SSH_EXTRA_ARGS
  192. #specify extra arguments to pass to ssh only (e.g. -R)
  193. #
  194.  
  195. Privilege Escalation Options:
  196. control how and which user you become as on target hosts
  197.  
  198. -s, --sudo
  199. #run operations with sudo (nopasswd) (deprecated, use become)
  200. #相当于Linux系统下的sudo命令
  201. -U SUDO_USER, --sudo-user=SUDO_USER
  202. #desired sudo user (default=root) (deprecated, use become)
  203. #使用sudo,相当于Linux下的sudo命令
  204. -S, --su
  205. #run operations with su (deprecated, use become)
  206. #
  207. -R SU_USER, --su-user=SU_USER
  208. #run operations with su as this user (default=root)(deprecated, use become)
  209. -b, --become
  210. #run operations with become (does not imply password prompting)
  211. #
  212. --become-method=BECOME_METHOD
  213. #privilege escalation method to use (default=sudo),valid choices:
            [ sudo | su | pbrun | pfexec | doas |dzdo | ksu | runas ]
  214. #
  215. --become-user=BECOME_USER
  216. #run operations as this user (default=root)
  217. #
  218. --ask-sudo-pass
  219. #ask for sudo password (deprecated, use become)
  220. #传递sudo密码到远程主机,来保证sudo命令的正常运行
  221. --ask-su-pass
  222. #ask for su password (deprecated, use become)
  223. #
  224. -K, --ask-become-pass
  225. #ask for privilege escalation password
  226. #
  227.  
  228. 当然,我们对于一些具体的学习还要参考一些文档
  229. https://docs.ansible.com/ansible/2.4/intro_installation.html
  230.  
  231. Ansible学习实践:
  232. 1.A主机上创建密钥对,实现对其他主机无密码访问,执行:
  233. # ssh-keygen -t rsa -f ~/.ssh/id_rsa.pub -P ""
  234. # ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.18.19.188
  235. 此时会在远程机的/root/.ssh/authorized_keys文件中,生成id_rsa.pub文件的内容。
  236.  
  237. 执行具体回显
  238. root@docker-02:~# ssh-copy-id -i /root/.ssh/id_rsa.pub root@172.18.19.188
  239. /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
  240. The authenticity of host '172.18.19.188 (172.18.19.188)' can't be established.
  241. ECDSA key fingerprint is SHA256:BLDdJTy5lNOuopbtXDVojySMfc1y2lmJSPwvKIyvSVM.
  242. Are you sure you want to continue connecting (yes/no)? yes
  243. /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
  244. /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
  245. root@172.18.19.188's password:
  246.  
  247. Number of key(s) added: 1
  248.  
  249. Now try logging into the machine, with: "ssh 'root@172.18.19.188'"
  250. and check to make sure that only the key(s) you wanted were added.
  251.  
  252. root@docker-02:~# ssh 'root@172.18.19.188'
  253. Welcome to Ubuntu 16.04 LTS (GNU/Linux 4.4.0-21-generic x86_64)
  254.  
  255. * Documentation: https://help.ubuntu.com/
  256.  
  257. 177 packages can be updated.
  258. 24 updates are security updates.
  259.  
  260. *** System restart required ***
  261. Last login: Wed Nov 22 19:39:52 2017 from 172.18.19.94
  262. root@docker-01:~# exit
  263. logout
  264. Connection to 172.18.19.188 closed.
  265.  
  266. 2.A主机管理清单的配置
  267.     # cd /etc/ansible
  268.     # cp hosts{,.bak}
  269.     # vim hosts
  270. 添加如下内容:
  271. [remote]
  272. 172.18.19.188
  273. 测试执行是否成功:
  274. # ansible remote -m command -a "ls"
  275. 172.18.19.188 | SUCCESS | rc=0 >>
  276. # ansible all -m command -a "ls"
  277. 172.18.19.188 | SUCCESS | rc=0 >>
  278. 两种方法都可以解决执行问题。
  279.  
  280. 3.常用模块
  281.  
  282.   1.command模块:在远程主机上执行的命令
  283.     相关选项:
  284.       creates:一个文件名,当该文件存在,则该命令不执行
  285.       free_form:要执行的linux指令
  286.       chdir:在执行指令之前,先切换到该目录
  287.       removes:一个文件名,当该文件不存在,则该选项不执行
  288.       executable:切换shell来执行指令,该执行路径必须是一个绝对路径
  289. /*示例*/
  290. ansible remote -m command -a "ls"
  291.  
  292. 值得留意的时,command模块执行的命令是获取不到$HOME这样的环境变量的,
  293. 一些运算符,例如”<“ 、”>“ command模块上也是不能使用的。
  294.  
  295.   2.setup模块:查看远程主机的相关facts变量信息
  296. /*示例*/
  297. ansible all -m setup
  298. ansible 192.168.43.130 -m setup
  299.  
  300.   3.shell模块:让远程主机在shell进程下执行命令,从而支持shell的特性,如管道等
  301. /*示例*/
  302. ansible all -m shell -a "echo "test" | passwd --stdin test1"
  303. 相当于增强版的command
  304.  
  305.   4.copy模块:复制本地文件至远程主机上
  306.     相关选项:
  307.       backup:在覆盖之前,将源文件备份,备份文件包含时间信息。有两个选项:yes|no
  308.       content:用于替代“src”,可以直接设定指定文件的值
  309.       dest:必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
  310.       directory_mode:递归设定目录的权限,默认为系统默认权限
  311.       force:如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的
              目标位置不存在该文件时,才复制。默认为yes
  312.       others:所有的file模块里的选项都可以在这里使用
  313.       src:被复制到远程主机的本地文件,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。
              在这种情况下,如果路径使用“/”来结尾,则只复制目录里的内容,如果没有使用“/”来结尾,
              则包含目录在内的整个内容全部复制,类似于rsync
  314.       owner,group,mode...
  315. /*示例*/
  316. ansible remote -m copy -a "src=/etc/fstab dest=/root/ owner=root group=root mode=0644"
  317.  
  318.   5.file模块:设置文件属性
  319.     相关选项:
  320.       force:需要在两种情况下强制创建软链接,一种是源文件不存在,但之后会建立的情况下;另一种是目标软链接已存在,
              需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
  321.       group:定义文件/目录的属组
  322.       mode:定义文件/目录的权限
  323.       owner:定义文件/目录的属主
  324.       path:必选项,定义文件/目录的路径
  325.       recurse:递归设置文件的属性,只对目录有效
  326.       src:被链接的源文件路径,只应用于state=link的情况
  327.       dest:被链接到的路径,只应用于state=link的情况
  328.       state
  329.        directory:如果目录不存在,就创建目录
  330.        file:即使文件不存在,也不会被创建
  331.        link:创建软链接
  332.       hard:创建硬链接
  333.       touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
  334.        absent:删除目录、文件或者取消链接文件
  335. /*示例*/
  336. ansible remote -m file -a "path=/root/fstab owner=root group=root mode=600"
  337. ansible storm_cluster -m file -a "src=/etc/resolv.conf dest=/tmp/resolv.conf state=link"创建链接文件
  338. ansible storm_cluster -m file -a "path=/tmp/resolv.conf state=absent" 删除链接文件
  339.  
  340.   6.cron模块:计划任务的实现
  341.     相关选项:
  342.       minute=/hour=/day=/month=/weekday= 某个值不写,默认就是*
  343.       name:必选项,任务描述信息
  344.       job:执行的任务,要加引号
  345.       state:present(创建)/absent(删除)
  346. /*示例*/
  347. ansible remote -m cron -a "minute=*/1 job='/usr/bin/echo 'hello'' name=hello"
  348.  
  349.   7.yum模块:管理安装相关程序包
  350.     相关选项:
  351.       name:程序包名称,可带版本号
  352.       state:presentinstalledlatest(安装)/absentremoved(删除)
  353.  
  354.   8.service模块:管理服务
  355.     相关选项:
  356.       name:服务名称
  357.       state:started/stopped/restarted
  358.       enabled:true/false
  359.       runlevel:运行级别
  360.  
  361. 9.group模块:管理用户组模块
  362.     相关选项:
  363.       name:组名称
  364.       gid:指定GID
  365.       state:present/absent
  366.       system:yes/no
  367. /*示例*/
  368. ansible all -m group -a "name=test_grp state=present"
  369.  
  370.   10.user模块:管理用户模块
  371.     相关选项:
  372.       由于user模块的选项众多,这里只介绍一些常用的选项:
  373.       name:用户名
  374.       password:为用户设置登陆密码,此密码是明文密码加密后的密码
  375.       update_password:always/on_create
  376.        always:只有当密码不相同时才会更新密码(默认)
  377.         on_create:只为新用户设置密码
  378.       shell:用户的shell设定
  379.       groups:用户组设定
  380.       home:指定用户的家目录
  381.       state:present/absent
  382.       append:yes/no
  383.         yes:增量添加group
  384.         no:全量变更group,只设置groups指定的group组(默认)
  385.       remove:配合state=absent使用,删除用户的家目录->remove=yes
  386.       expires:设置用户的过期时间,值是一个时间戳
  387. /*示例*/
  388. ansible all -m user -a "name=test2 state=present groups=test2,test_grp shell=/bin/bash append=yes"
  389. 11.ping 用来测试远程主机的运行状态
  390. /*示例*/
  391. ansible all -m ping
  392. 172.18.19.188 | SUCCESS => {
  393. "changed": false,
  394. "ping": "pong"
  395. }
  396.  
  397. ansible-doc
  398. Usage: ansible-doc [-l|-s] [options] [-t <plugin type] [plugin]
  399.  
  400. plugin documentation tool
  401.  
  402. Options:
  403. -a, --all **For internal testing only** Show documentation for
  404. all plugins.
  405. -h, --help show this help message and exit
  406. -l, --list List available plugins
  407. -M MODULE_PATH, --module-path=MODULE_PATH
  408. prepend colon-separated path(s) to module library
  409. (default=[u'/root/.ansible/plugins/modules',
  410. u'/usr/share/ansible/plugins/modules'])
  411. -s, --snippet Show playbook snippet for specified plugin(s)
  412. -t TYPE, --type=TYPE Choose which plugin type (defaults to "module")
  413. -v, --verbose verbose mode (-vvv for more, -vvvv to enable
  414. connection debugging)
  415. --version show program's version number and exit
  416.  
  417. ansible-doc command ===>会打印出command模块的使用帮助
  418.  
  419. 4.Playbook
  420. playbook是由一个或多个“play”组成的列表,可以让它们联同起来按事先编排的机制执行;所谓task无非是调用ansible的
      一个module,而在模块参数中可以使用变量;模块执行是幂等的,这意味着多次执行是安全的,因为其结果均一致。
  421. 执行模型:task list中的各任务按次序逐个在hosts中指定的所有主机上执行,即在所有主机上完成第一个任务后再开始第二个。
      在顺序运行某playbook时,如果中途发生错误,所有已执行任务都将回滚,因此,在修改playbook后重新执行一次即可;
  422. task组成:每个task都应该有其name,用于playbook的执行结果输出,建议其内容尽可能清晰地描述任务执行步骤。
    如果未提供name,则action的结果将用于输出;
  423. notify指定handler的执行机制:“notify”这个action可用于在每个play的最后被触发,在notify中列出的操作称为handler,
    仅在所有的变化发生完成后一次性地执行指定操作。
  424. 5.实践ansible自动化安装nginx
  425. 首先、配置 /etc/hosts:
  426. IP test
  427. 第二、配置 /etc/ansible/hosts:
  428. [hadoop]
  429. test
  430.  
  431. 第三、创建目录
  432. mkdir -p /ansible/roles/nginx/{defaults,files,handlers,meta,tasks,templates,vars}
  433.  
  434. 第四、编辑文件
  435. 在files目录下创建shell安装脚本,并将nginx的压缩包也放到files下面
  436. install_nginx.sh:
  437.  
  438. #!/bin/bash
  439. yum -y install zlib zlib-devel openssl openssl-devel pcre-devel
  440. groupadd -r nginx
  441. useradd -s /sbin/nologin -g nginx -r nginx
  442. cd /tmp
  443. tar xf nginx-1.9.9.tar.gz;cd nginx-1.9.9
  444. mkdir /var/run/nginx/;chown nginx.nginx /var/run/nginx/
  445. ./configure \
  446. --prefix=/usr \
  447. --sbin-path=/usr/sbin/nginx \
  448. --conf-path=/etc/nginx/nginx.conf \
  449. --error-log-path=/var/log/nginx/error.log \
  450. --pid-path=/var/run/nginx/nginx.pid \
  451. --user=nginx \
  452. --group=nginx \
  453. --with-http_ssl_module
  454. make && make install
  455. sed "/^\s*index / i proxy_pass http://localhost:8080;" /etc/nginx/nginx.conf
  456. /usr/sbin/nginx
  457.  
  458. 在tasks目录中放置main.yml文件
  459. main.yml:
  460.  
  461. - name: copy nginx_tar_gz to client
  462. copy: src=nginx-1.9.9.tar.gz dest=/tmp/nginx-1.9.9.tar.gz
  463. - name: copy install_shell to client
  464. copy: src=install_nginx.sh dest=/tmp/install_nginx.sh
  465. - name: install nginx
  466. shell: /bin/bash /tmp/install_nginx.sh
  467.  
  468. 在ansible目录下放置webservice.yml文件
  469. webservice.yml:
  470.  
  471. - hosts: hadoop
  472. remote_user: root
  473. roles:
  474. - nginx
  475.  
  476. 第五、执行
  477. cd /ansible
  478. ansible-playbook webservice.yml
  479.  
  480. 目录结构解析如下:
  481. roles/ \\ ansible所有的信息都放到此目录下面对应的目录中
  482. └── nginx \\ 角色名称
  483. ├── default \\ 为当前角色设定默认变量时使用此目录,应当包含一个main.yml文件;
  484. ├── files \\ 存放有copy或script等模块调用的文件
  485. ├── handlers \\ 此目录应当包含一个main.yml文件,用于定义各角色用到的各handler
  486. ├── meta \\ 应当包含一个main.yml,用于定义角色的特殊设定及其依赖关系;1.3及以后版本支持
  487. ├── tasks \\ 至少包含一个名为main.yml的文件,定义了此角色的任务列表,可使用include指令
  488. ├── templates \\ template模块会自动在此目录中寻找Jinja2模板文件
  489. └── vars \\ 应当包含一个main.yml文件,用于定义此角色用到的变量
  490. ├───────────├──────────────────────────────────────────────────────────────────│
  491. │ 目录名 │ 说明 │
  492. ├───────────├──────────────────────────────────────────────────────────────────│
  493. ├defaults │ 为当前角色设定默认变量时使用此目录,应当包含一个main.yml文件 │
  494. ├───────────├──────────────────────────────────────────────────────────────────│
  495. ├handlers │此目录中应当包含一个main.yml文件,用于定义此角色用到的各handler, │
  496. │ │ 在handler中使用include包含的其它的handler文件也应该位于此目录中 │
  497. ├───────────├──────────────────────────────────────────────────────────────────│
  498. ├meta │ 应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系 │
  499. ├───────────├──────────────────────────────────────────────────────────────────│
  500. ├tasks │ 至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表, │
  501. │ │ 此文件可以使用include包含其它的位于此目录中的task文件 │
  502. ├───────────├──────────────────────────────────────────────────────────────────│
  503. ├templates │ template模块会自动在此目录中寻找Jinja2模板文件 │
  504. ├───────────├──────────────────────────────────────────────────────────────────│
  505. ├vars │ 定义当前角色使用的变量 │
  506. ├───────────├──────────────────────────────────────────────────────────────────│
  507. ├files │ 存放由copy或script等模块调用的文件 │
  508. ├───────────├──────────────────────────────────────────────────────────────────│
  509. ├tests │ 在playbook中角色的使用样例 │
  510. ├───────────├──────────────────────────────────────────────────────────────────│
  511.  
  512. ---
  513. - name: create user
  514. hosts: remote
  515. remote_user: root
  516. gather_facts: false
  517. vars:
  518. - say: "tiger"
  519. tasks:
  520. - name: Copy file to client
  521. # copy: src=/tmp/tiger dest=/tmp/tigress
  522. template: src=/tmp/tiger dest=/tmp/{{ say }}
  523.  
  524. ansible-playbook -i /root/xxx.cfg /root/app/main.yml --limit "lala_xxx" -e "user=wawo"
  525.  
  526. 解析:
  527. -i 指定要运行的配置文件
  528. --limit 指定运行的ip地址
  529. -e 指定运行的外部参数
  530. 运行的控制 YAML 文件为: /root/app/main.yml
  531. ---
  532. - hosts: all
  533. roles:
  534. - xxx
  535.  
  536. hosts指定所有(all)的主机,但是由于在外部已经指定了主机的配置,所以all由外部指定参数来进行
  537. roles指定要执行的具体剧本
  538. roles的任务执行顺序
  539. ### 首先执行meta下的main.yml文件内容 可以设置该role和其它role之前的关联关系。 dependencies
  540. ### 然后执行tasks下的main.yml文件内容
  541. ### 用到的变量,会直接加载defaults/vars目录下的main.yml文件
  542. ### 用到的需要拷贝到远程机器的文件,会放到files目录下
  543. ### 用到模板文件,会放到 templates 目录下
  544. ### 在执行的task中,使用了notify后,会调用 handlers 目录下的main.yml文件

  545. 记录一些基本的使用模块
  546. 1、ansible中的include, include_tasks 和 import_tasks 的差别
  547. include 被 deprecated(不建议使用)了. 建议使用 include_tasks 和 import_tasks
  548.  
  549. include_tasks
  550. 是动态的: 在运行时展开. when只应用一次. 被include的文件名可以使用变量.
  551.  
  552. import_tasks
  553. 是静态的: 在加载时展开. when在被import的文件里的每个task, 都会重新检查一次. 因为是加载时展开的,
    文件名的变量不能是动态设定的.
  554. 请确保文件名中使用到的变量被定义在vars中、vars_files中、或者extra-vars中,静态的import不支持其他方式传入的变量。
  555.  
  556. When using static includes, ensure that any variables used in their names are defined in
    vars/vars_files or extra-vars passed in from the command line. Static includes cannot use
    variables from inventory sources like group or host vars.
  557. 除了上述不同之处,在使用"循环操作"和"条件判断"时,"include_tasks"和"import_tasks"也有很多不同点需要注意,注意点如下。
  558. 如果想要对包含的任务列表进行循环操作,则只能使用"include_tasks"关键字,不能使用"import_tasks"关键字,
    "import_tasks"并不支持循环操作,
  559. 也就是说,使用"loop"关键字或"with_items"关键字对include文件进行循环操作时,只能配合"include_tasks"才能正常运行。
  560. when关键字对"include_tasks"和"import_tasks"的实际操作有着本质区别,区别如下:
  561. 当对"include_tasks"使用when进行条件判断时,when对应的条件只会应用于"include_tasks"任务本身,
    当执行被包含的任务时,不会对这些被包含的任务重新进行条件判断。
  562. 当对"import_tasks"使用when进行条件判断时,when对应的条件会应用于被include的文件中的每一个任务,当执行被包含的任务时,
    会对每一个被包含的任务进行同样的条件判断。
  563. 对于tags和handler
  564. 与"include_tasks"不同,当为"import_tasks"添加标签时,tags是针对被包含文件中的所有任务生效的,与"include"关键字的效果相同。
  565. "include_tasks"与"import_tasks"都可以在handlers中使用,并没有什么不同,不过在当前2.7.0版本中,如果在handlers
    中使用"import_tasks"引用任务列表,会出现bug,期待修复。
  566.  
  567. tasks:
  568. - include_tasks:
  569. file: in.yml
  570. apply:
  571. tags:
  572. - t1
  573. tags: always
  574.  
  575. 2、setup模块用于收集远程主机的一些基本信息。而在playbook中,默认参数 ” gather_facts: True ” 的含义就是在远程主机
    运行setup模块,并将收集的信息记录起来。
  576. gather_facts: False 不使用远程主机的setup模块,
  577. tasks:
  578. - set_fact: mode=1 设置远程主机的参数 mode=1
  579.  
  580. 3、一点疑惑
  581. ---
  582. - hosts: webserver
  583. vars:
  584. logserver: 10.127.2.170
  585. gather_facts: True
  586. tasks:
  587. - name: add conf to config files to CentOS6
  588. lineinfile: dest=/etc/rsyslog.conf line="*.* @{{ logserver }}"
  589. when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == ""
  590. - name: restart syslog @CentOS6
  591. when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == ""
  592. service: name=rsyslog state=restarted
  593. - name: add conf to config files to RedHat 5
  594. lineinfile: dest=/etc/syslog.conf line="*.* @{{ logserver }}"
  595. when: ansible_distribution == 'RedHat' and ansible_distribution_major_version == ""
  596. - name: restart syslog @RedHat 5
  597. when: ansible_distribution == 'RedHat' and ansible_distribution_major_version == ""
  598. service: name=syslog state=restarted
  599. 有同学要问,为什么要进行四次when判断,两次不就够了,写成这样
  600.  
  601. - name: restart syslog @CentOS6
  602. when: ansible_distribution == 'CentOS' and ansible_distribution_major_version == ""
  603. lineinfile: dest=/etc/rsyslog.conf line="*.* @{{ logserver }}"
  604. service: name=rsyslog state=restarted
  605. 这是不行的,ansible要求每一个play里面只能使用一个模块,使用多个会报错
  606. ERROR: multiple actions specified in task
  607.  
  608. 4、tasks/main.yml 里面有如下行:
  609. - name: Configure Tomcat server
  610. template: src=server.xml dest=/usr/share/tomcat/conf/
  611. notify: restart tomcat
  612.  
  613. - name: Configure Tomcat user
  614. template: src=tomcat-users.xml dest=/usr/share/tomcat/conf/
  615. notify: restart tomcat
  616.  
  617. template模块官方的解释为: Templates a file out to a remote server. 大概意思就是当 src=config_file
    这些文件发生变化的时候,触发notify的动作
  618. templates目录就是存放这些文件用的(一般都是一些配置文件)
  619.  
  620. handlers目录里有一个main.yml文件,就是用来执行notify动作的
  621.  
  622. 大概的流程为:
  623. templates/config_file 发生变化 --> 触发notify: action --> action定义在 handlers/main.yml 中
  624. notify后面的动作名字必须与handlers/main.yml里面的name后面的名字一致,例:
  625. - name: Configure Tomcat user
  626. template: src=tomcat-users.xml dest=/usr/share/tomcat/conf/
  627. notify: restart tomcat
  628.  
  629. handlers:
  630. - name: restart tomcat
  631. service: name=tomcat state=restart
  632.  
  633. 而files目录下存放的是一些脚本, 通过copy模块可以transport到remote hosts上的,而后触发notify动作之后执行的脚本
  634.  
  635. 5、语法验证
  636. ● 在执行playbook之前,最后好进行验证,确保内容无误
  637.  
  638. $ ansible-playbook --syntax-check site.yml
  639.  
  640. playbook: site.yml
  641. ● 语法失败时将会报告错误(无法坚持模块内参数是否正确)
  642.  
  643. 6、执行空运行
  644. ● -C选项。这会使ansible报告在执行该playbook时将会发生什么更改,但不会对受管主机进行任何实际更改
  645.  
  646. $ ansible-playbook -C site.yml
  647.  
  648. 7、特权升级属性:
  649. ● 特提供额外的属性,从而在playbook内定义特权升级参数。
  650. become布尔值参数可用于启动或禁用特权升级,无论在ansible配置文件如何定义
  651.  
  652. become: Ture/False
  653.  
  654. ● 如果启用了特权升级,可以使用become_method属性来定义play期间所要使用的特权升级的方法sudo
  655.  
  656. become_method: sudo
  657.  
  658. 此外,启用特权升级时,become_user属性可以定义play上下文内用于特权升级的用户
  659. become_user: root
  660.  
  661. 8、用户属性:
  662. ● playbook中的任务通常通过网络连接多受管主机执行。与临时命令相同,用于这些任务执行的用户账号取决于ansible配置文件
    /etc/ansible/ansible.cfg中的参数。执行任务的用户可以通过remote_user参数定义,不过,如果启用了特权升级,
    become_user等其他参数也会发生作用
  663. ● 如果用于任务执行的Ansible配置中定义的远程用户不合适,可以通过在play中使用remote_user属性覆盖
  664.  
  665. remote_user: devops
  666.  
  667. 9、修改文件
  668. lineinfile
  669. 用于检测文件是否存在特殊行或者使用后端正则表达式来替换匹配到的特殊行
  670.  
  671. 10、replace
  672. lineinfile的多行匹配版本,此模块会在文件中插入一段内容,并在内容开始和结束位置设置标签,后续可以使用标签可以
    对此块内容进行操作
  673. path参数:必须参数,指定要操作的文件,2.3版本之前,只能使用dest, destfile, name指定要操作的文件,2.4版本中,
    仍然可以使用这些参数名,这些参数名作为path参数的别名使用。
  674. regexp参数:必须参数,指定一个python正则表达式,文件中与正则匹配的字符串将会被替换。
  675. replace参数: 指定最终要替换成的字符串。
  676. backup参数:是否在修改文件之前对文件进行备份,最好设置为yes。
  677.  
  678. ### 在ml2_conf.ini文件的[ml2]和[ml2_type_vlan]字段之间插入一段内容
  679. - name: Enable ovn in neutron-server
  680. replace:
  681. dest: "{{ node_config_directory }}/neutron-server/ml2_conf.ini"
  682. regexp: '\[ml2\][\S\s]*(?=\[ml2_type_vlan\])'
  683. replace: |+
  684. [ml2]
  685. type_drivers = local,flat,vlan,geneve
  686. tenant_network_types = geneve
  687. mechanism_drivers = ovn
  688. extension_drivers = port_security
  689. overlay_ip_version = 4
  690.  
  691. [ml2_type_geneve]
  692. vni_ranges = 1:65536
  693. max_header_size = 38
  694.  
  695. [ovn]
  696. ovn_nb_connection = tcp:{{ api_interface_address }}:{{ ovn_northdb_port }}
  697. ovn_sb_connection = tcp:{{ api_interface_address }}:{{ ovn_sourthdb_port }}
  698. ovn_l3_mode = False
  699. ovn_l3_scheduler = chance
  700. ovn_native_dhcp = True
  701. neutron_sync_mode = repair
  702. backup: yes
  703. when:
  704. - action == "deploy"
  705. - inventory_hostname in groups['network']
  706. notify:
  707. - Restart neutron-server container
  708.  
  709. 11、ini_file
  710. ini后缀格式文件修改
  711. ini文件是十分常见的一种配置文件,ansible内置了ini配置文件的管理模块,用于对文件进行配置项的管理。
  712. Ø 修改配置文件/root/demo.ini,selection为cron的选项组的crontime选项,把cron的值修改为10。
  713. ansible all –m ini_file –a “dest=/root/demo.ini section=cron option=crontime value=10”
  714.  
  715. ### 设置l3_agent.ini文件[DEFAULT]字段的external_network_bridge选项值为br-ex
  716. - name: Set the external network bridge
  717. vars:
  718. agent: "{{ 'neutron-vpnaas-agent' if enable_neutron_vpnaas | bool else 'neutron-l3-agent' }}"
  719. ini_file:
  720. dest: "{{ node_config_directory }}/{{ agent }}/l3_agent.ini"
  721. section: "DEFAULT"
  722. option: "external_network_bridge"
  723. value: "{{ neutron_bridge_name | default('br-ex') }}"
  724. backup: yes
  725. when:
  726. - action == "deploy"
  727. - inventory_hostname in ovn_central_address
  728. delegate_to: "{{ item }}"
  729. with_items: "{{ groups['neutron-server'] }}"
  730. notify:
  731. - Restart {{ agent }} container
  732.  
  733. 12、循环控制
  734. with_items
  735. 标准循环,用于执行重复任务,{{ item }}类似宏展开
  736.  
  737. - name: add several users
  738. user:
  739. name: "{{ item.name }}"
  740. state: present
  741. groups: "{{ item.groups }}"
  742. with_items:
  743. - { name: 'testuser1', groups: 'wheel' }
  744. - { name: 'testuser2', groups: 'root' }
  745. with_nested
  746. 嵌套循环
  747.  
  748. ### 修改neutron-server组所有主机的ml2_conf.ini文件的对应字段值
  749. - name: Enable ovn in neutron-server
  750. vars:
  751. params:
  752. - { section: 'ml2', option: 'type_drivers', value: 'local,flat,vlan,geneve' }
  753. - { section: 'ml2', option: 'tenant_network_types', value: 'geneve' }
  754. - { section: 'ml2', option: 'mechanism_drivers', value: 'ovn' }
  755. - { section: 'ml2', option: 'extension_drivers', value: 'port_security' }
  756. - { section: 'ml2', option: 'overlay_ip_version', value: '' }
  757. - { section: 'securitygroup', option: 'enable_security_group', value: 'True' }
  758. ini_file:
  759. dest: "{{ node_config_directory }}/neutron-server/ml2_conf.ini"
  760. section: "{{ item[0].section }}"
  761. option: "{{ item[0].option }}"
  762. value: "{{ item[0].value }}"
  763. backup: yes
  764. when:
  765. - action == "deploy"
  766. - inventory_hostname in ovn_central_address
  767. delegate_to: "{{ item[1] }}"
  768. with_nested:
  769. - "{{ params }}"
  770. - "{{ groups['neutron-server'] }}"
  771. notify:
  772. - Restart neutron-server container
  773.  
  774. 13、流程控制
  775. tags
  776. 设置任务标签
  777.  
  778. tasks:
  779. - yum: name={{ item }} state=installed
  780. with_items:
  781. - httpd
  782. - memcached
  783. tags:
  784. - packages
  785.  
  786. - template: src=templates/src.j2 dest=/etc/foo.conf
  787. tags:
  788. - configuration
  789.  
  790. ### 执行playbook可以指定只执行标签对应任务或跳过标签对应任务
  791. # ansible-playbook example.yml --tags "configuration,packages"
  792. # ansible-playbook example.yml --skip-tags "notification"
  793.  
  794. 14、failed_when
  795. 用来控制playbook退出
  796.  
  797. - name: Check if firewalld is installed
  798. command: rpm -q firewalld
  799. register: firewalld_check
  800. failed_when: firewalld_check.rc > 1
  801. when: ansible_os_family == 'RedHat'
  802. 15、pre_tasks/post_tasks
  803. 用来设置在执行roles模块之前和之后需要执行的任务
  804.  
  805. 16、wait_for
  806. 等待一个端口变得可用或者等待一个文件变得可用
  807.  
  808. - local_action: wait_for port=22 host="{{ ansible_ssh_host | default(inventory_hostname) }}" search_regex=OpenSSH delay=10
    #等待openssh启动,10s检查一次
  809.  
  810. - name: Wait for container ssh
  811. wait_for:
  812. port: ""
  813. delay: "{{ ssh_delay }}"
  814. search_regex: "OpenSSH"
  815. host: "{{ ansible_host }}"
  816. delegate_to: "{{ physical_host }}"
  817. register: ssh_wait_check
  818. until: ssh_wait_check | success
  819. retries: 3
  820. when:
  821. - (_mc is defined and _mc | changed) or (_ec is defined and _ec | changed)
  822. - not is_metal | bool
  823. tags:
  824. - common-lxc
  825.  
  826. 17、执行shell命令
  827. ### ignore_errors为true表示命令执行出错也不会退出playbook
  828. - name: Check if clean is needed
  829. command: docker exec openvswitch_vswitchd ovs-vsctl br-exists br-tun
  830. register: result
  831. ignore_errors: True
  832.  
  833. 18、切换用户
  834. ### 使用become会先切换成apache用户,再执行command命令,默认become_user用户为root
  835. ### (如果你ansible配置的就是root用户的免密码登入那就不需要become了)
  836. - name: Run a command as the apache user
  837. command: somecommand
  838. become: true
  839. become_user: apache
  840. 检测链表是否为空
  841.  
  842. ### pip_wheel_install为链表变量
  843. - name: Install wheel packages
  844. shell: cd /tmp/wheels && pip install {{ item }}*
  845. with_items:
  846. - "{{ pip_wheel_install | default([]) }}"
  847. when: pip_wheel_install > 0
  848.  
  849. 19、when中使用jinja2
  850. when表达式中不建议直接使用{{}}的方式来获取变量值,如果变量是字符串可以使用管道操作| string来获取变量值
  851.  
  852. - name: Checking free port for OVN
  853. vars:
  854. service: "{{ neutron_services[item.name] }}"
  855. wait_for:
  856. host: "{{ hostvars[inventory_hostname]['ansible_' + api_interface]['ipv4']['address'] }}"
  857. port: "{{ item.port }}"
  858. connect_timeout: 1
  859. state: stopped
  860. when:
  861. - container_facts[ item.facts | string ] is not defined
  862. - service.enabled | bool
  863. - service.host_in_groups | bool
  864. with_items:
  865. - { name: "ovn-nb-db-server", port: "{{ ovn_northdb_port }}", facts: "ovn_nb_db" }
  866. - { name: "ovn-sb-db-server", port: "{{ ovn_sourthdb_port }}", facts: "ovn_sb_db" }
  867.  
  868. 20、uri web访问,类似执行curl命令
  869. uri模块主要用于发送HTTP协议,通过使用uri模块,可以让目标主机向指定的网站发送如Get、Post这样的HTTP请求,
    并且能得到返回的状态码。
  870.  
  871. - name: test proxy URL for connectivity
  872. uri:
  873. url: "{{ repo_pkg_cache_url }}/acng-report.html"
  874. method: "HEAD"
  875. register: proxy_check
  876. failed_when: false
  877. tags:
  878. - common-proxy
  879.  
  880. 21、local_action 将任务放在ansible控制主机(运行ansible-playbook的主机)上执行
  881.  
  882. - name: Check if the git cache exists on deployment host
  883. local_action:
  884. module: stat
  885. path: "{{ repo_build_git_cache }}"
  886. register: _local_git_cache
  887. when: repo_build_git_cache is defined
  888.  
  889. 22、When语句官方文档
  890.  
  891. 在有的时候play的结果依赖于变量、fact或者是前一个任务的执行结果,从而需要使用到条件语句。
  892.  
  893. 有的时候在特定的主机需要跳过特定的步骤,例如在安装包的时候,需要指定主机的操作系统类型,
    或者是当操作系统的硬盘满了之后,需要清空文件等
  894.  
  895. 在ansible中,我们可以使用如下比较运算符:
  896. == :比较两个对象是否相等,相等为真
  897. != :比较两个对象是否不等,不等为真
  898. > :比较两个值的大小,如果左边的值大于右边的值,则为真
  899. < :比较两个值的大小,如果左边的值小于右边的值,则为真
  900. >= :比较两个值的大小,如果左边的值大于右边的值或左右相等,则为真
  901. <= :比较两个值的大小,如果左边的值小于右边的值或左右相等,则为真
  902. 逻辑运算符:
  903. and :逻辑与,当左边与右边同时为真,则返回真
  904. or :逻辑或,当左边与右边有任意一个为真,则返回真
  905. not :取反,对一个操作体取反
  906. ( ) :组合,将一组操作体包装在一起,形成一个较大的操作体
  907.  
  908. 判断变量
  909. defined :判断变量是否已经定义,已经定义则返回真
  910. undefind :判断变量是否已经定义,未定义则返回真
  911. none :判断变量值是否为空,如果变量已经定义,但是变量值为空,则返回真
  912. 判断执行结果
  913. success 或 succeeded:通过任务的返回信息判断任务的执行状态,任务执行成功则返回真
  914. failure 或 failed:通过任务的返回信息判断任务的执行状态,任务执行失败则返回真
  915. change 或 changed:通过任务的返回信息判断任务的执行状态,任务执行状态为changed则返回真
  916. skip 或 skipped:通过任务的返回信息判断任务的执行状态,当任务没有满足条件,而被跳过执行时,则返回真
  917. 判断路径的使用方式:
  918. file : 判断路径是否是一个文件,如果路径是一个文件则返回真
  919. directory :判断路径是否是一个目录,如果路径是一个目录则返回真
  920. link :判断路径是否是一个软链接,如果路径是一个软链接则返回真
  921. mount:判断路径是否是一个挂载点,如果路径是一个挂载点则返回真
  922. exists:判断路径是否存在,如果路径存在则返回真
  923. 在2.6及以后的版本,支持直接写下面的关键字;2.5之前的版本需要在前面加 is 或 is not
  924. 判断字符串:
  925. lower:判断包含字母的字符串中的字母是否是纯小写,字符串中的字母全部为小写则返回真
  926. upper:判断包含字母的字符串中的字母是否是纯大写,字符串中的字母全部为大写则返回真
  927. 判断整除
  928. even :判断数值是否是偶数,是偶数则返回真
  929. odd :判断数值是否是奇数,是奇数则返回真
  930. divisibleby(num) :判断是否可以整除指定的数值,如果除以指定的值以后余数为0,则返回真
  931.  
  932. subset:判断一个list是不是另一个list的子集,是另一个list的子集时返回真
  933. superset: 判断一个list是不是另一个list的父集,是另一个list的父集时返回真
  934.  
  935. string:判断对象是否是一个字符串,是字符串则返回真
  936. number:判断对象是否是一个数字,是数字则返回真
  937.  
  938. 下面的例子表示为使用when语句,如下:
  939.  
  940. tasks:
  941. - name: "shutdown Debian flavored systems"
  942. command: /sbin/shutdown -t now
  943. when: ansible_os_family == "Debian"
  944.  
  945. 也可以使用括号来表示一组条件,如下所示:
  946. tasks:
  947. - name: "shutdownCentOS6andDebian7systems"
  948. command: /sbin/shutdown -t now
  949. when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "") or
  950. (ansible_distribution == "Debian" and ansible_distribution_major_version == "")
  951.  
  952. 假设需要忽略一个语句的错误,根据执行的结果是成功还是失败从而执行不同的命令,如下(使用的是jinja2的过滤):
  953.  
  954. tasks:
  955. - command: /bin/false 没有 - name 时,此行将被默认成为标题-- TASK: [command: /bin/false]
  956. register: result
  957. ignore_errors: True
  958. - command: /bin/something
  959. when: result|failed
  960. - command: /bin/something_else
  961. when: result|succeeded
  962. - command: /bin/still/something_else
  963. when: result|skipped
  964.  
  965. 当接收到一个变量是一个字符串的时候,然后想做一个数字的比较,那么可以使用如下的方式
    (在这个例子中远程主机上需要有lsb_package包):
  966.  
  967. tasks:
  968. - shell: echo "only on Red Hat 6, derivatives, and later"
  969. when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
  970.  
  971. 在playbooks中或者inventory清单中定义的变量也是可以使用,假设任务的执行依赖于一个布尔变量,如下:
  972. vars:
  973. epic: true
  974.  
  975. 条件执行如下所示:
  976. tasks:
  977. - shell: echo "This certainly is epic!"
  978. when: epic
  979.  
  980. 或者使用如下形式:
  981. tasks:
  982. - shell: echo "This certainly isn't epic!"
  983. when: not epic
  984.  
  985. 如果需要的变量没有定义,那么可以skip或者使用jinja2的defined如下所示:
  986.  
  987. tasks:
  988. - shell: echo "I've got '{{ foo }}' and am not afraid to use it!"
  989. when: foo is defined
  990.  
  991. - fail: msg="Bailing out. this play requires 'bar'"
  992. when: bar is undefined
  993.  
  994. 当结合使用when和with_items的时候,需要注意的是when语句会对每个item进行单独的处理,如下所示:
  995.  
  996. tasks:
  997. - command: echo {{ item }}
  998. with_items: [ 0,2,4,6,8,10 ]
  999. when: item > 5
  1000.  
  1001. 3、在roles中和include中使用when
  1002. 当几个任务都是使用相同的条件的时候,那么可以将条件写在include之中,那么当写在include的时候,
    每个任务都会去判断条件,如下所示:
  1003.  
  1004. - include: tasks/sometasks.yml
  1005. when: "'reticulatingsplines'inoutput"
  1006.  
  1007. 或者在roles中使用,如下:
  1008.  
  1009. - hosts: webservers
  1010. roles:
  1011. - { role:debian_stock_config,when:ansible_os_family == 'Debian' }
  1012.  
  1013. 4、条件导入
  1014. 在playbook中可能会根据一些特定的标准从而做不同的事情,在一个playbook中工作在不同的平台和os版本是最好的例子
  1015.  
  1016. 如下的例子表示,在centos和debian中apache的包是不同的,从而可以使用以下:
  1017.  
  1018. ---
  1019. - hosts: all
  1020. remote_user: root
  1021. vars_files:
  1022. - "vars/common.yml"
  1023. - [ "vars/{{ansible_os_family}}.yml","vars/os_defaults.yml" ]
  1024. tasks:
  1025. - name: make sure apache is running
  1026. service: name={{ apache }} state=running
  1027.  
  1028. 另外,在变量文件中只包含key和values,如下:
  1029.  
  1030. ---
  1031. # for vars/CentOS.yml
  1032. apache: httpd
  1033. somethingelse: 42
  1034.  
  1035. 如何工作的呢?
  1036. 当操作系统为centos的时候,那么会加载变量/vars/centos.yml,当文件不存在的时候,那么会加载defaults.yml,
    当没有找到任何文件的时候,那么就会出错。当操作系统为debian的时候,那么就会加载变量/vars/debian.yml,
    没有就加载defaults.yml
  1037.  
  1038. 当使用整个功能的时候,在运行playbook之前必须先安装facter或者ohai,也可以直接在playbook中使用如下所示:
  1039.  
  1040. # for facter
  1041. ansible -m yum -a "pkg=facter state=present"
  1042. ansible -m yum -a "pkg=ruby-json state=present"
  1043.  
  1044. # for ohai
  1045. ansible -m yum -a "pkg=ohai state=present"
  1046.  
  1047. 5、基于变量选择文件和模板
  1048. 在有的时候,配置文件使用copy或者是template的时候,可能会依赖于变量。
  1049. 下面的例子中表示使用template输出一个配置文件,在centos和debian中不同,如下:
  1050. - name: template a file
  1051. template: src={{ item }} dest=/etc/myapp/foo.conf
  1052. with_first_found:
  1053. - files:
  1054. - {{ ansible_distribution }}.conf
  1055. - default.conf
  1056. paths:
  1057. - search_location_one/somedir/
  1058. - /opt/other_location/somedir/
  1059.  
  1060. 6、注册变量
  1061. 在playbook中可以使用变量的值便于其他的任务用到。
  1062. 关键字register用来保存变量值,整个变量可以使用在template中,动作行中,或者是when语句中,如下所示:
  1063.  
  1064. - name: test play
  1065. hosts: all
  1066. tasks:
  1067. - shell: cat /etc/motd
  1068. register: motd_contents
  1069.  
  1070. - shell: echo "motd contains the word hi"
  1071. when: motd_contents.stdout.find('hi') != -1
  1072.  
  1073. 注册的变量值可以用stdout得到,或者用with_items得到,也可以使用stdout_lines得到,
  1074. 如下所示:
  1075.  
  1076. - name: registered variable usage as a with_items list
  1077. hosts: all
  1078. tasks:
  1079. - name: retrieve the list of home directories
  1080. command: ls /home
  1081. register: home_dirs
  1082.  
  1083. - name: add home dirs to the backup spooler
  1084. file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
  1085. with_items: home_dirs.stdout_lines
  1086. # same as with_items: home_dirs.stdout.split()
  1087.  
  1088. 23、文件组装模块——assemble(主要用于把多份配置文件片段组装成一个配置文件)
  1089. Ø 将/root/demo下的片段组装后放到/root/target目录下
  1090. ansible all –m assemble –a “dest=/root/demo src=/root/target”
  1091.  
  1092. 24、文件拉取模块——fetch
  1093. Ø 将远端主机的/etc/salt/minion文件收集回服务器/root/demo目录下
  1094. ansible all –m fetch –a “dest=/root/demo src=/etc/salt/minion “
  1095.  
  1096. 25、文件管理模块——file
  1097. file 如果是directory,那么则会创建文件夹
  1098. link 如果是file,则会创建文件
  1099. state 默认值:file directory 如果是link,则会创建链接
  1100. hard 如果是hard,则会创建硬链接
  1101. touch 如果是touch,则会创建文件
  1102. absent 如果是absent,则会删除文件
  1103.  
  1104. 26、unarchive模块
  1105. 用于解压文件,模块包含如下选项:
  1106. copy:在解压文件之前,是否先将文件复制到远程主机,默认为yes。若为no,则要求目标主机上压缩包必须存在。
  1107. creates:指定一个文件名,当该文件存在时,则解压指令不执行
  1108. dest:远程主机上的一个路径,即文件解压的路径
  1109. grop:解压后的目录或文件的属组
  1110. list_files:如果为yes,则会列出压缩包里的文件,默认为no,2.0版本新增的选项
  1111. mode:解决后文件的权限
  1112. src:如果copy为yes,则需要指定压缩文件的源路径
  1113. owner:解压后文件或目录的属主
  1114. 示例如下:
  1115. - unarchive: src=foo.tgz dest=/var/lib/foo
  1116. - unarchive: src=/tmp/foo.zip dest=/usr/local/bin copy=no
  1117. - unarchive: src=https://example.com/example.zip dest=/usr/local/bin copy=no
  1118.  
  1119. 27、fail
  1120. 用于终止当前playbook的执行,通常与条件语句组合使用,当满足条件时,终止当前play的运行。可以直接由failed_when取代。
  1121. 'changed_when'关键字的作用是在条件成立时,将对应任务的执行状态设置为changed
  1122. 选项只有一个:
  1123. msg:终止前打印出信息
  1124. 示例:
  1125. - fail: msg="The system may not be provisioned according to the CMDB status."
  1126. when: cmdb_status != "to-be-staged"
  1127.  
  1128. 28、pause
  1129. 在playbook执行的过程中暂停一定时间或者提示用户进行某些操作
  1130. 常用参数:
  1131. minutes:暂停多少分钟
  1132. seconds:暂停多少秒
  1133. prompt:打印一串信息提示用户操作
  1134. 示例:
  1135. - name: wait on user input
  1136. pause: prompt="Warning! Detected slight issue. ENTER to continue CTRL-C a to quit"
  1137. - name: timed wait
  1138. pause: seconds=30
  1139.  
  1140. 29、关于 async 和 poll
  1141. 有的任务执行起来却不那么直接,可能会花比较长的时间,甚至可能会比ssh的超时时间还要长。这种情况任务是不是没法执行了?
  1142. ansible考虑到了这种情况,官方文档介绍了这个问题的解决方法,就是让下发的任务执行的连接变为异步:任务下发之后,
    长连接不再保持,而是每隔一段时间轮询结果,直到任务结束。
  1143. 他们在playbook的任务中加入两个参数:
  1144.  
  1145. async和poll
  1146. async参数值代表了这个任务执行时间的上限值。即任务执行所用时间如果超出这个时间,则认为任务失败。
    此参数若未设置,则为同步执行。
  1147. poll参数值代表了任务异步执行时轮询的时间间隔。如果poll为0,就相当于一个不关心结果的任务。
  1148.  
  1149. 官方给出例子:
  1150. ----
  1151. hosts: all
  1152. remote_user: root
  1153. tasks:
  1154. - name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec
  1155. command: /bin/sleep 15
  1156. async: 45
  1157. poll: 5
  1158.  
  1159. 如果还想要更方便地看轮询结果,ansible还提供了这个模块async_status。
  1160.  
  1161. ---
  1162. # Requires ansible 1.8+
  1163. - name: 'YUM - fire and forget task'
  1164. yum: name=docker-io state=installed
  1165. async: 1000
  1166. poll: 0
  1167. register: yum_sleeper
  1168.  
  1169. - name: 'YUM - check on fire and forget task'
  1170. async_status: jid={{ yum_sleeper.ansible_job_id }}
  1171. register: job_result
  1172. until: job_result.finished
  1173. retries: 30
  1174. 第一个job执行异步任务,并且注册了一个名字叫yum_sleeper,用于提供给第二个job作为轮询对象,并且poll设为0,它自己不再轮询。
  1175. 第二个job使用async_status模块,进行轮询并返回轮询结果。准备检查30次。结果如下:
  1176.  
  1177. PLAY [all] *********************************************************************
  1178.  
  1179. TASK [setup] *******************************************************************
  1180. ok: [cloudlab001]
  1181.  
  1182. TASK [YUM - fire and forget task] **********************************************
  1183. ok: [cloudlab001]
  1184.  
  1185. TASK [YUM - check on fire and forget task] *************************************
  1186. FAILED - RETRYING: TASK: YUM - check on fire and forget task (29 retries left).
  1187. FAILED - RETRYING: TASK: YUM - check on fire and forget task (28 retries left).
  1188. FAILED - RETRYING: TASK: YUM - check on fire and forget task (27 retries left).
  1189. FAILED - RETRYING: TASK: YUM - check on fire and forget task (26 retries left).
  1190. FAILED - RETRYING: TASK: YUM - check on fire and forget task (25 retries left).
  1191. FAILED - RETRYING: TASK: YUM - check on fire and forget task (24 retries left).
  1192. changed: [cloudlab001]
  1193.  
  1194. PLAY RECAP *********************************************************************
  1195. cloudlab001 : ok=3 changed=1 unreachable=0 failed=0
  1196.  
  1197. ---
  1198. - hosts: all
  1199. gather_facts: no
  1200. tasks:
  1201. - shell: "ls /opt"
  1202. register: returnvalue
  1203. - debug:
  1204. var: returnvalue
  1205.  
  1206. 30、debug 调试模块,用于在调试中输出信息
  1207. 常用参数:
  1208. msg:调试输出的消息,不能与var同时使用
  1209. var:将某个任务执行的输出作为变量传递给debug模块,debug会直接将其打印输出,不能与msg同时使用
  1210. verbosity:debug的级别(默认是0级,全部显示,如果设置为3时,会在 -vvv 时打印出信息)
  1211.  
  1212. 31、内置变量 groups
  1213. 配置文件 justtest 如下:
  1214.  
  1215. 10.1.1.60
  1216. justtest.zsythink.net ansible_host=10.1.1.70
  1217. test71 anisble_host=10.1.1.71
  1218.  
  1219. [testA]
  1220. test60 ansible_host=10.1.1.60
  1221. test61 ansible_host=10.1.1.61
  1222.  
  1223. [testB]
  1224. justtest ansible_host=10.1.1.70
  1225.  
  1226. [test:children]
  1227. testA
  1228. testB
  1229. 上述清单中,显式的指定了三个组,testA组、testB组、test组,其中,testA组与testB组是test组的子组,
    除了组中的主机,还有三台主机没有任何分组,直接写在了清单中。
  1230. 现在,我们获取一下groups变量的值,看看会返回哪些信息,随便操作清单中的任意一台主机即可,示例如下
  1231. # ansible justtest -m debug -a "msg={{groups}}"
  1232. justtest | SUCCESS => {
  1233. "changed": false,
  1234. "msg": {
  1235. "all": [
  1236. "10.1.1.60",
  1237. "justtest.zsythink.net",
  1238. "test71",
  1239. "test60",
  1240. "test61",
  1241. "justtest"
  1242. ],
  1243. "test": [
  1244. "test60",
  1245. "test61",
  1246. "justtest"
  1247. ],
  1248. "testA": [
  1249. "test60",
  1250. "test61"
  1251. ],
  1252. "testB": [
  1253. "justtest"
  1254. ],
  1255. "ungrouped": [
  1256. "10.1.1.60",
  1257. "justtest.zsythink.net",
  1258. "test71"
  1259. ]
  1260. }
  1261. }
  1262. 从上述返回信息可以看出,所有主机默认被分成了组名为"all"的组,testA组中有两台主机,testB组中有一台主机,
    由于testA组和testB组都属于test组的子组,所以testA组与testB组中的主机都属于test组,
    由于有三台主机在清单中并未分组,所以,ansible自动将没有分组的主机分到了名为"ungrouped"的组中,即组名为"未分组"的组。
  1263. 我们还能够通过组名,获取到指定组的分组信息,假设,我想要获取到上例中test组中的主机名称,则可以使用如下方法。
  1264. # ansible justtest -m debug -a "msg={{groups.test}}"
  1265. # ansible justtest -m debug -a "msg={{groups['test']}}"
  1266. # ansible justtest -m debug -a "msg={{groups.ungrouped}}"
  1267.  
  1268. 32、handlers模块 之 meta模块
  1269. ---
  1270. - hosts: justtest
  1271. remote_user: root
  1272. tasks:
  1273. - name: task1
  1274. file: path=/testdir/testfile
  1275. state=touch
  1276. notify: handler1
  1277. - name: task2
  1278. file: path=/testdir/testfile2
  1279. state=touch
  1280. notify: handler2
  1281.  
  1282. - meta: flush_handlers
  1283.  
  1284. - name: task3
  1285. file: path=/testdir/testfile3
  1286. state=touch
  1287. notify: handler3
  1288.  
  1289. handlers:
  1290. - name: handler1
  1291. file: path=/testdir/ht1
  1292. state=touch
  1293. - name: handler2
  1294. file: path=/testdir/ht2
  1295. state=touch
  1296. - name: handler3
  1297. file: path=/testdir/ht3
  1298. state=touch
  1299. 如上例所示,我在task1与task2之后写入了一个任务,我并没有为这个任务指定name属性,这个任务使用meta模块,
    meta任务是一种特殊的任务,meta任务可以影响ansible的内部运行方式,上例中,meta任务的参数值为flush_handlers,
  1300. "meta: flush_handlers"表示立即执行之前的task所对应handler,什么意思呢?
  1301. 意思就是,在当前meta任务之前,一共有两个任务,task1与task2,它们都有对应的handler,
    当执行完task1与task2以后,立即执行对应的handler,而不是像默认情况那样在所有任务都执行完毕以后
    才能执行各个handler,那么我们来实际运行一下上述剧本,运行结果如下
  1302.  
  1303. 33、handlers模块 之 立即执行
  1304. 我们还可以在一个task中一次性notify多个handler,怎样才能一次性notify多个handler呢?
  1305. 你可能会尝试将多个handler使用相同的name,但是这样并不可行,因为当多个handler的name相同时,只有一个handler会被执行。
  1306. 所以,我们并不能通过这种方式notify多个handler,如果想要一次notify多个handler,则需要借助另一个关键字,它就是'listen'。
  1307. 你可以把listen理解成"组名",我们可以把多个handler分成"组",当我们需要一次性notify多个handler时,
    只要将多个handler分为"一组",使用相同的"组名"即可,当notify对应的值为"组名"时,"组"内的所有handler都会被notify,
    这样说可能还是不容易理解,我们来看个小示例,示例如下
  1308. ---
  1309. - hosts: justtest
  1310. remote_user: root
  1311. tasks:
  1312. - name: task1
  1313. file: path=/testdir/testfile
  1314. state=touch
  1315. notify: handler group1
  1316.  
  1317. handlers:
  1318. - name: handler1
  1319. listen: handler group1
  1320. file: path=/testdir/ht1
  1321. state=touch
  1322. - name: handler2
  1323. listen: handler group1
  1324. file: path=/testdir/ht2
  1325. state=touch
  1326.  
  1327. 34、tags模块
  1328. ---
  1329. - hosts: justtest
  1330. remote_user: root
  1331. tags: httpd
  1332. tasks:
  1333. - name: install httpd package
  1334. tags: ['package']
  1335. yum:
  1336. name=httpd
  1337. state=latest
  1338.  
  1339. - name: start up httpd service
  1340. tags:
  1341. - service
  1342. - always # 意思是service的tag总会被执行
  1343. service:
  1344. name: httpd
  1345. state: started
  1346. 当tags写在play中而非task中时,play中的所有task会继承当前play中的tags,而上例中,两个任务都会继承httpd标签,
    同时还有拥有自己的标签。
  1347.  
  1348. ansible-playbook --tags package,service testhttpd.yml
  1349. 或者 ansible-playbook --tags httpd testhttpd.yml
  1350. 执行的结果是一样的,都会将两个标签进行执行
  1351. 其实,ansible还预置了5个特殊tag,这5个特殊tag分别为:
  1352. always
  1353. never(2.5后的版本才有)
  1354. tagged
  1355. untagged
  1356. all
  1357.  
  1358. always:当我们把任务的tags的值指定为always时,那么这个任务就总是会被执行,除非你使用'--skip-tags'
    选项明确指定不执行对应的任务, --skip-tags always 如果存在多个tag标记了 always,我们只想跳过某一个,
  1359. 那么可以使用 --skip-tags service
  1360.  
  1361. never:在2.5版本的ansible中,引入了新的特殊标签 'never',
  1362. 从字面上理解,never的作用应该与always正好相反,由于我当前使用的ansible版本为2.4(还没有引入never标签),
    所以当指定任务的标签为never时,貌似被ansible当做了自定义标签,所以如果你安装了2.5版本的ansible,
    可以尝试一下never标签的作用,由于还没有实际使用过2.5版本,所以此处暂时不进行示例。
  1363.  
  1364. ansible-playbook --tags tagged testtag.yml
  1365. 上述命令表示只执行有标签的任务,没有任何标签的任务不会被执行。
  1366.  
  1367. ansible-playbook --skip-tags tagged testtag.yml
  1368. 上述命令表示跳过包含标签的任务,即使对应的任务包含always标签,也会被跳过。
  1369.  
  1370. ansible-playbook --tags untagged testtag.yml
  1371. 上述命令表示只执行没有标签的任务,但是如果某些任务包含always标签,那么这些任务也会被执行。
  1372.  
  1373. 特殊标签all表示所有任务会被执行,不用指定,默认情况下就是使用这个标签。
  1374.  
  1375. 35、变量-vars
  1376. 使用 vars 可以在当前的play中设置变量
  1377. ---
  1378. - hosts: all
  1379. vars:
  1380. v: wawo
  1381.  
  1382. tasks:
  1383. - name invoke v
  1384. file:
  1385. path: /home/{{ v }}
  1386. state: touch
  1387.  
  1388. 也可以定义属性:
  1389. ---
  1390. - hosts: all
  1391. vars:
  1392. nginx:
  1393. conf80: /etc/nginx/conf.d/80.conf
  1394. conf8080: /etc/nginx/conf.d/8080.conf
  1395.  
  1396. tasks:
  1397. - name invoke v
  1398. file:
  1399. path: "{{ nginx.conf80 }}" == "{{ nginx['conf80'] }}" 两个方式等价
  1400. state: touch
  1401. 此处的变量增加了 " 引号,原因是使用变量是出于开头的位置。
  1402. 在playbook中参数赋值,可以使用 : 也可以使用 = 。当使用 = 进行赋值时,就不需要考虑使用 " 引号了。
  1403. 但是要使用 : 冒号时,就需要在紧邻参数的那个变量处添加 " 引号。
  1404. path={{ nginx.conf80 }}
  1405. path: /home/{{ v }}
  1406. 在实际使用中,我们提倡"变量文件分离",可以通过 vars_files 关键字引入文件
  1407. vars_files:
  1408. - /testdir/ansible/nginx_vars.yml
  1409. - yaml_file_path
  1410.  
  1411. - include_vars:
  1412. file: /testdir/ansible/testfile
  1413. name: get_var 将文件中的所有变量赋值给get_var
  1414. extensions: [yaml,yml,json,varfile] 指定包含的文件
  1415. depth: 1 指定目录深度
  1416. files_matching: "^var_.*" 指定过滤条件
  1417. ignore_files: ["^var_.*",varintest.yaml] 忽略过滤条件
  1418.  
  1419. 36、变量-注册变量 register
  1420. ---
  1421. - hosts: justtest
  1422. remote_user: root
  1423. tasks:
  1424. - name: test shell
  1425. shell: "echo test > /var/testshellfile"
  1426. register: testvar
  1427. - name: shell module return values
  1428. debug:
  1429. var: testvar
  1430. testvar会将shell执行的结果进行保存
  1431. 37、提示用户操作-交互操作
  1432. ---
  1433. - hosts: 192.168.43.130
  1434. vars_prompt:
  1435. - name: "your_name"
  1436. prompt: "What is your name"
  1437. private: no # 可以让输入可见,不加此属性看不到对应的输入信息,适用于密码
  1438. - name: "your_age"
  1439. prompt: "How old are you"
  1440. tasks:
  1441. - name: output vars
  1442. debug:
  1443. msg: Your name is {{your_name}},You are {{your_age}} years old.
  1444. 还可以使用选择的形式的如下:
  1445. vars_prompt:
  1446. - name: "solution"
  1447. prompt: "Choose the solution you want \n
  1448. A: solutionA\n
  1449. B: solutionB\n
  1450. C: solutionC\n"
  1451. private: no
  1452. default: A
  1453. 38、外部设置变量-通过 -e 和 --extra-vars
  1454. 通过对应的文件设置变量,调用时,需要使用 @file_path 进行引用
  1455. ansible-playbook cmdvar.yml -e "@/testdir/ansible/testvar.yml"
  1456.  
  1457. 39、set_fact 定义变量
  1458. ---
  1459. - hosts: justtest
  1460. remote_user: root
  1461. tasks:
  1462. - set_fact:
  1463. testvar: "testtest"
  1464. - debug:
  1465. msg: "{{testvar}}"
  1466.  
  1467. 40、循环 with_list、with_items、with_flattened、with_together、with_cartesian
  1468. ---
  1469. - hosts: justtest
  1470. remote_user: root
  1471. gather_facts: no
  1472. vars:
  1473. dirs:
  1474. - "/opt/a"
  1475. - "/opt/b"
  1476. - "/opt/c"
  1477. - "/opt/d"
  1478. tasks:
  1479. - file:
  1480. path: "{{item}}"
  1481. state: touch
  1482. with_items: "{{dirs}}"
  1483.  
  1484. ---
  1485. - hosts: justtest
  1486. remote_user: root
  1487. gather_facts: no
  1488. tasks:
  1489. - debug:
  1490. msg: "{{item}}"
  1491. with_items: [ 1, 2, 3 ]
  1492. ||
  1493. with_items:
  1494. - 1
  1495. - 2
  1496. - 3
  1497. with_list
  1498. 经过with_list处理后,每个嵌套在大列表中的小列表都被当做一个整体存放在item变量中,最终被debug作为一个
    小整体输出了,而不会像with_items一样将小列表"展开拉平"后一并将小列表中的元素循环输出。
  1499. with_flattened
  1500. 拉平展开,与with_list基本一致
  1501. with_together
  1502. with_together可以将两个列表中的元素"对齐合并",单单用语言来描述,不是特别容易理解,不如来看一个小示例,
    示例playbook如下:
  1503.  
  1504. ---
  1505. - hosts: justtest
  1506. remote_user: root
  1507. gather_facts: no
  1508. tasks:
  1509. - debug:
  1510. msg: "{{ item }}"
  1511. with_together:
  1512. - [ 1, 2, 3 ]
  1513. - [ a, b, c ]
  1514. 结果:
  1515. TASK [debug] ******************************
  1516. ok: [justtest] => (item=[1, u'a']) => {
  1517. "changed": false,
  1518. "item": [
  1519. 1,
  1520. "a"
  1521. ],
  1522. "msg": [
  1523. 1,
  1524. "a"
  1525. ]
  1526. }
  1527. ok: [justtest] => (item=[2, u'b']) => {
  1528. "changed": false,
  1529. "item": [
  1530. 2,
  1531. "b"
  1532. ],
  1533. "msg": [
  1534. 2,
  1535. "b"
  1536. ]
  1537. }
  1538. ok: [justtest] => (item=[3, u'c']) => {
  1539. "changed": false,
  1540. "item": [
  1541. 3,
  1542. "c"
  1543. ],
  1544. "msg": [
  1545. 3,
  1546. "c"
  1547. ]
  1548. }
  1549. with_cartesian 是将两个列表进行笛卡尔积组合 与 with_nested 使用一致
  1550. ---
  1551. - hosts: justtest
  1552. remote_user: root
  1553. gather_facts: no
  1554. tasks:
  1555. - file:
  1556. state: directory
  1557. path: "/testdir/testdir/{{ item.0 }}/{{ item.1 }}"
  1558. with_cartesian:
  1559. - [ a, b, c ]
  1560. - [ test1, test2 ]
  1561.  
  1562. "with_indexed_items"应该与"索引"有关,没错,"with_indexed_items"的作用就是在循环处理列表时为
    列表中的每一项添加"数字索引","索引"从0开始
  1563.  
  1564. with_sequence start=1 end=5 stride=1 从1到5,每次增加1
  1565. ---
  1566. - hosts: justtest
  1567. remote_user: root
  1568. gather_facts: no
  1569. tasks:
  1570. - debug:
  1571. msg: "{{ item }}"
  1572. with_sequence: start=1 end=5 stride=1
  1573.  
  1574. with_file 获取主机文件的内容的
  1575.  
  1576. 41、有几种分隔符。默认的Jinja分隔符配置如下:
  1577. {% ... %} 对于声明 可以直接将 for等语句放到里面执行
  1578. {{ ... }} 对于表达式打印到模板输出
  1579. {# ... #} for Comments不包含在模板输出中
  1580. # ... ## 对于行语句
  1581.  
  1582. 42、过滤器
  1583. 变量可以通过过滤器修改。过滤器通过管道符号(|)与变量分隔,并且在括号中可以包含可选参数。可以链接
    多个过滤器。一个过滤器的输出应用于下一个过滤器。
  1584. abs 绝对值
  1585. capitalize 首字母大写
  1586. center 将值集中在给定宽度的字段中
  1587. default 设置默认值
  1588. first 返回序列中第一项
  1589. float 转化成浮点型的数据
  1590. join {{ [1, 2, 3]|join('|') }} -> 1|2|3 {{ [1, 2, 3]|join }} -> 123
  1591. last 返回序列中最后一项
  1592. length == count 返回长度
  1593. max {{ [1, 2, 3]|max }}
  1594. min {{ [1, 2, 3]|min }}
  1595. pprint 优雅打印
  1596. replace(s, old, new, count=None) {{ "Hello World"|replace("Hello", "Goodbye") }}
  1597. reverse 反向打印
  1598. round round(value,precision = 0,method ='common' )
  1599. 将数字四舍五入到给定的精度。
  1600. 第一个参数指定精度(默认为0),第二个参数指定舍入方法:
  1601. 'common' 向上或向下舍入
  1602. 'ceil' 总是围捕
  1603. 'floor' 总是四舍五入
  1604. safe(值) 将值标记为安全,这意味着在启用了自动转义的环境中,此变量不会被转义。
  1605. sort 对可迭代进行排序。
  1606. 默认情况下,它会按升序排序,如果您将其作为第一个参数传递,它将反转排序。
  1607. string 如果尚未创建字符串unicode。这样,标记字符串不会转换回unicode。
  1608. striptags(值) 剥离SGML / XML标记并将相邻的空格替换为一个空格。
  1609. sum 返回数字序列的总和加上参数'start'的值(默认为0)。当序列为空时,它返回start。
  1610. title 返回值的标题版本。即单词将以大写字母开头,所有剩余字符均为小写。
  1611. trim #将字符串开头和结尾的空格去除
  1612. truncate 返回字符串的截断副本。
  1613. unique 去重
  1614. upper #将字符串转换成纯大写
  1615. wordcount 计算该字符串中的单词。
  1616.  
  1617. ---
  1618. - hosts: justtest
  1619. remote_user: root
  1620. vars:
  1621. testvar: "abc123ABC 666"
  1622. testvar1: " abc "
  1623. testvar2: ''
  1624. testvar3: "1a2b,@#$%^&"
  1625. tasks:
  1626. - debug:
  1627. #将字符串转换成纯大写
  1628. msg: "{{ testvar | upper }}"
  1629. - debug:
  1630. #将字符串转换成纯小写
  1631. msg: "{{ testvar | lower }}"
  1632. - debug:
  1633. #将字符串变成首字母大写,之后所有字母纯小写
  1634. msg: "{{ testvar | capitalize }}"
  1635. - debug:
  1636. #将字符串反转
  1637. msg: "{{ testvar | reverse }}"
  1638. - debug:
  1639. #返回字符串的第一个字符
  1640. msg: "{{ testvar | first }}"
  1641. - debug:
  1642. #返回字符串的最后一个字符
  1643. msg: "{{ testvar | last }}"
  1644. - debug:
  1645. #将字符串开头和结尾的空格去除
  1646. msg: "{{ testvar1 | trim }}"
  1647. - debug:
  1648. #将字符串放在中间,并且设置字符串的长度为30,字符串两边用空格补齐30位长
  1649. msg: "{{ testvar1 | center(width=30) }}"
  1650. - debug:
  1651. #返回字符串长度,length与count等效,可以写为count
  1652. msg: "{{ testvar2 | length }}"
  1653. - debug:
  1654. #将字符串转换成列表,每个字符作为一个元素
  1655. msg: "{{ testvar3 | list }}"
  1656. - debug:
  1657. #将字符串转换成列表,每个字符作为一个元素,并且随机打乱顺序
  1658. #shuffle的字面意思为洗牌
  1659. msg: "{{ testvar3 | shuffle }}"
  1660. - debug:
  1661. #将字符串转换成列表,每个字符作为一个元素,并且随机打乱顺序
  1662. #在随机打乱顺序时,将ansible_date_time.epoch的值设置为随机种子
  1663. #也可以使用其他值作为随机种子,ansible_date_time.epoch是facts信息
  1664. msg: "{{ testvar3 | shuffle(seed=(ansible_date_time.epoch)) }}"
  1665.  
  1666. 43、lookup 模块
  1667. 从2.5版本开始,官方加入了 loop 关键字进行循环操作,来代替 with_xxx 的风格
  1668. 而实际上内部的操作,就是 loop + lookup 的操作
  1669.  
  1670. 在说循环和lookup插件之间的关系,需要注意,不要错误的以为lookup插件只能实现循环操作,
  1671. lookup插件有很多,有的lookup插件与"循环操作"完全没有关系,
  1672. lookup类型的插件的主要作用是访问外部的数据源,
  1673. 比如,获取到外部数据并赋值给某个变量,以便之后使用这些数据,lookup插件的操作都是在ansible主机中进行的,
    与目标主机没有关系。
  1674.  
  1675. 以"with_"开头的循环实际上就是"with_"和"lookup()"的组合,lookup插件可以作为循环的数据源,通过以上描述,
    应该已经明白了我们之前总结的循环与各种lookup插件之间的关系了吧。
  1676.  
  1677. ---
  1678. - hosts: justtest
  1679. remote_user: root
  1680. gather_facts: no
  1681. tasks:
  1682. - debug:
  1683. msg: "{{ lookup('file','/testdir/testfile') }}" 获得/testdir/testfile文件的内容
  1684.  
  1685. - debug: 可以获得多个文件的内容
  1686. msg: "{{ lookup('file','/testdir/testfile','/testdir/testfile1') }}"
  1687.  
  1688. - debug: 对每个文件内容单独放在一个列表中 2.5 版本中添加的
  1689. msg: "{{ lookup('file','/testdir/testfile','/testdir/testfile1',wantlist=true) }}"
  1690.  
  1691. - debug: 2.6版本中引入的错误判读
  1692. msg: "{{ lookup('file','/testdir/testfile',errors='ignore') }}"
  1693. #errors的值需要使用引号引起,errors的值可以设置为ignore、warn或者strict,缺省值为strict
  1694. 通过ansible-doc -t lookup -l命令查看到如下列表,
  1695. 我们可以通过使用lookup + 下面的列表信息进行组合使用。
  1696. cartesian 返回列表的笛卡尔积
  1697. chef_databag 从Chef的databag获取数据
  1698. consul_kv 从consul键值存储中获取元数据。
  1699. credstash 在AWS上检索信用卡的秘密
  1700. csvfile 从TSV或CSV文件读取数据
  1701. cyberarkpassword 从CyberArk AIM获得秘密
  1702. dict 从字典返回键/值对项
  1703. dig 使用DNSPython库查询DNS
  1704. dnstxt 查询域的DNS TXT字段
  1705. env 读取环境变量的值
  1706. etcd 从ETCD服务器获取信息
  1707. file 读取文件内容
  1708. fileglob 与模式匹配的列表文件
  1709. filetree 递归地匹配目录树中的所有文件
  1710. first_found 返回从列表中找到的第一个文件
  1711. flattened 返回完全展开的单个列表
  1712. hashi_vault 从HasiHCORP拱顶中找回秘密
  1713. hiera 从HIELA数据获取信息
  1714. indexed_items 重写列表以返回“索引项目”
  1715. ini 从INI文件读取数据
  1716. inventory_hostnames 与主机模式匹配的库存主机列表
  1717. items 项目清单
  1718. keyring 从操作系统钥匙抓取秘密
  1719. lastpass 从LASTPASS获取数据
  1720. lines 从命令读取行
  1721. list 简单地返回它所给予的。
  1722. mongodb 从MangGDB查找信息
  1723. nested 用其他列表的嵌套元素编写列表
  1724. password 检索或生成随机密码,存储在文件中
  1725. passwordstore 使用passwordstore.org的通行工具管理密码
  1726. pipe 从命令读取输出
  1727. random_choice 从列表返回随机元素
  1728. redis_kv 从ReDIS获取数据
  1729. sequence 基于数字序列生成列表
  1730. shelvefile 从Python搁置文件读取密钥
  1731. subelements 从字典列表中遍历嵌套密钥
  1732. template 用Jinja2 检索模板后的文件内容
  1733. together 将列表合并为同步化列表
  1734. url 从URL返回内容
  1735.  
  1736. 44、block rescue always的使用
  1737. block 块,可以将多个任务整合到一起执行,可以添加条件判断 when 进行判断执行
  1738. ---
  1739. - hosts: justtest
  1740. remote_user: root
  1741. tasks:
  1742. - debug:
  1743. msg: "task1 not in block"
  1744. - block:
  1745. - debug:
  1746. msg: "task2 in block1"
  1747. - debug:
  1748. msg: "task3 in block1"
  1749. when: 2 > 1
  1750. rescue 捕获 block 的执行失败任务(任意一个失败都会触发rescue)
  1751. 执行block成功不会触发rescue
  1752. --- 不使用 rescue ---
  1753. - hosts: justtest - hosts: justtest
  1754. remote_user: root remote_user: root
  1755. tasks: tasks:
  1756. - block: - shell: 'ls /ooo'
  1757. - shell: 'ls /ooo' register: return_value
  1758. rescue: ignore_errors: true
  1759. - debug: - debug:
  1760. msg: 'I caught an error' msg: "I caught an error"
  1761. when: return_value is failed
  1762.  
  1763. 我们能从中看到,使用这种方式的便捷性
  1764.  
  1765. always 不管怎么样都要执行的一部分
  1766. 说到这里是不是感觉到了,有一种 try{}catch{}finally{} 的感觉了?
  1767.  
  1768. ---
  1769. - hosts: justtest
  1770. remote_user: root
  1771. tasks:
  1772. - block:
  1773. - debug:
  1774. msg: 'I execute normally'
  1775. - command: /bin/false
  1776. - debug:
  1777. msg: 'I never execute, due to the above task failing'
  1778. rescue:
  1779. - debug:
  1780. msg: 'I caught an error'
  1781. - command: /bin/false
  1782. - debug:
  1783. msg: 'I also never execute'
  1784. always:
  1785. - debug:
  1786. msg: "This always executes"
  1787.  
  1788. 44、关于使用Jinja2 template 模块
  1789. 为什么要用到 Jinja2 主要是为了根据变量动态生成适合的模板
  1790. 比如多机器下的模板,可以根据不同的机器设置变量来生成对应的模板,并推送到对应的机器上。
  1791. 就是为了方便快捷。
  1792. Jinja2的语法是由 variables (变量)和 statement (语句)组成,如下:
  1793. 1、variables:可以输出数据
  1794. ` my_variables `
  1795. {{ some_dudes_name | capitalize }} 可以使用过滤器进行变量使用
  1796. 2、statements: 可以用来创建条件和循环等
  1797. if语句:
  1798. {% if my_conditional %} 进行语句判断
  1799. ...
  1800. {% endif %}
  1801. for 语句:
  1802. {% for item in all_items %}
  1803. `item`
  1804. ……
  1805. {% endfor %}
  1806. 生成文件内容
  1807. # cat test.j2 # cat test
  1808. jinja2 test jinja2 test
  1809. {{ 3 + 2 }} 5
  1810. {{ 3 - 4 }} -1
  1811. {{ 3 * 5 }} 15
  1812. {{ 2 ** 3 }} 8
  1813. {{ 7 / 5 }} 1.4
  1814. {{ 7 // 5 }} 1
  1815. {{ 17 % 5 }} 2
  1816. 生成文件内容
  1817. # cat test.j2 # cat test
  1818. jinja2 test jinja2 test
  1819. {{ 1 in [1,2,3,4] }} True
  1820. {{ 1 not in [1,2,3,4] }} False
  1821.  
  1822. 条件:
  1823. {% if 条件一 %}
  1824. ...
  1825. {% elif 条件N %}
  1826. ...
  1827. {% else %}
  1828. ...
  1829. {% endif %}
  1830.  
  1831. 设置值:
  1832. {% set teststr='abc' %}
  1833. {{ teststr }}
  1834.  
  1835. 循环:
  1836. {% for 迭代变量 in 可迭代对象 %}
  1837. {{ 迭代变量 }}
  1838. {% endfor %} # cat test.j2
  1839. jinja2 test
  1840. {% for i in [3,1,7,8,2] %} {% for i in [3,1,7,8,2] -%} 在for结束前加 -
  1841. {{ i }} {{ i }}{{ ' ' }}
  1842. {% endfor %} {%- endfor %} endfor开始前加 - 可以避免换行
  1843.  
  1844. # cat test.j2 # cat test.j2
  1845. jinja2 test jinja2 test
  1846. {% for i in [3,1,7,8,2] -%} {% for key,val in {'name':'bob','age':18}.iteritems() %}
  1847. {{ i~' ' }} ~ 就是字符串连接符 {{ key ~ ':' ~ val }}
  1848. {%- endfor %} {% endfor %}
  1849.  
  1850. loop.index 当前循环操作为整个循环的第几次循环,序号从1开始
  1851. loop.index0 当前循环操作为整个循环的第几次循环,序号从0开始
  1852. loop.revindex 当前循环操作距离整个循环结束还有几次,序号到1结束
  1853. loop.revindex0 当前循环操作距离整个循环结束还有几次,序号到0结束
  1854. loop.first 当操作可迭代对象中的第一个元素时,此变量的值为true
  1855. loop.last 当操作可迭代对象中的最后一个元素时,此变量的值为true
  1856. loop.length 可迭代对象的长度
  1857. loop.depth 当使用递归的循环时,当前迭代所在的递归中的层级,层级序号从1开始
  1858. loop.depth0 当使用递归的循环时,当前迭代所在的递归中的层级,层级序号从0开始
  1859. loop.cycle() 这是一个辅助函数,通过这个函数我们可以在指定的一些值中进行轮询取值,具体参考之后的示例
  1860.  
  1861. {% for i in [7,1,5,3,9] if i>3 %} {% for i in [7,1,5,3,9] %}
  1862. {{ i ~'----'~ loop.index }} {% if loop.index is even %}
  1863. {% endfor %} {%continue%}
  1864. {%endif%}
  1865. {% for i in [7,1,5,3,9] %} {{ i ~'----'~ loop.index }}
  1866. {% if i>3 %} {% endfor %}
  1867. {{ i ~'----'~ loop.index}}
  1868. {% endif %}
  1869. {% endfor %}
  1870.  
  1871. ansible all -m template -a "src=test.j2 dest=/opt/test"
  1872. 可以在结果:cat /opt/test
  1873. jinja2 test
  1874. False
  1875. True
  1876. abc
  1877. 3
  1878. 1
  1879. 7
  1880. 8
  1881. 2

参考的网站较多,不一一列举了,但有一个重要的参考是下面的这位的。

http://www.zsythink.net/archives/category/%e8%bf%90%e7%bb%b4%e7%9b%b8%e5%85%b3/ansible/

===========================END===========================

Ansible学习实战手记-你想要知道的可能都在这里了的更多相关文章

  1. Linux.NET实战手记—自己动手改泥鳅(上)

    各位读者大家好,不知各位读者有否阅读在下的前一个系列<Linux.NET 学习手记>,在前一个系列中,我们从Linux中Mono的编译安装开始,到Jexus服务器的介绍,以及如何在Linu ...

  2. artTemplate模板引擎学习实战

    在我的一篇关于智能搜索框异步加载数据的文章中,有博友给我留言,认为我手写字符串拼接效率过低,容易出错.在经过一段时间的摸索和学习之后,发现现在拼接字符串的方法都不在是自己去书写了,而是使用Javasc ...

  3. ansible 学习与实践

    title: ansible 学习与实践 date: 2016-05-06 16:17:28 tags: --- ansible 学习与实践 一 介绍 ansible是新出现的运维工具是基于Pytho ...

  4. 『深度应用』NLP机器翻译深度学习实战课程·零(基础概念)

    0.前言 深度学习用的有一年多了,最近开始NLP自然处理方面的研发.刚好趁着这个机会写一系列NLP机器翻译深度学习实战课程. 本系列课程将从原理讲解与数据处理深入到如何动手实践与应用部署,将包括以下内 ...

  5. 『深度应用』NLP机器翻译深度学习实战课程·壹(RNN base)

    深度学习用的有一年多了,最近开始NLP自然处理方面的研发.刚好趁着这个机会写一系列NLP机器翻译深度学习实战课程. 本系列课程将从原理讲解与数据处理深入到如何动手实践与应用部署,将包括以下内容:(更新 ...

  6. 强化学习实战 | 自定义Gym环境之井字棋

    在文章 强化学习实战 | 自定义Gym环境 中 ,我们了解了一个简单的环境应该如何定义,并使用 print 简单地呈现了环境.在本文中,我们将学习自定义一个稍微复杂一点的环境--井字棋.回想一下井字棋 ...

  7. 强化学习实战 | 表格型Q-Learning玩井子棋(三)优化,优化

    在 强化学习实战 | 表格型Q-Learning玩井字棋(二)开始训练!中,我们让agent"简陋地"训练了起来,经过了耗费时间的10万局游戏过后,却效果平平,尤其是初始状态的数值 ...

  8. RPC之Thrift学习实战

    关于Thrift的学习实战请参考:http://blog.csdn.net/column/details/slimina-thrift.html

  9. ansible学习笔记一

    ansible学习笔记一 参考博客: ansible学习 - 51CTO博客 一.安装 1 .下载epel源 wget -O /etc/yum.repos.d/epel.repo http://mir ...

随机推荐

  1. AI人工智能顶级实战工程师 课程大纲

    课程名称    内容    阶段一.人工智能基础 — 高等数学必知必会     1.数据分析    "a. 常数eb. 导数c. 梯度d. Taylore. gini系数f. 信息熵与组合数 ...

  2. List接口:(介绍其下的两个实现类:ArrayList和LinkedList)

    以下介绍接口: List接口:(介绍其下的两个实现类:ArrayList和LinkedList) ArrayList和数组非常类似,其底层①也用数组组织数据,ArrayList是动态可变数组. ①  ...

  3. R options scipen 控制科学计数法的显示

    当数字过长,R语言会自动采用科学计数法显示,测试如下 > a <- > a [] > a <- > a <- > a [] > a <- & ...

  4. Android利用Mediapalyer播放本地资源文件声音

    首先在res下创建raw,然后将mp3音乐拷贝到raw下 直接贴代码吧 //开始播放声音 public class PlayVoice { private static MediaPlayer med ...

  5. iview表单验证不生效问题注意点

    按照iview官网介绍写的form表单验证,但是无论填写与否都不进行校验,找了很久的原因,突然才发现一个关键的地方,一定要加props!!! https://blog.csdn.net/xuaner8 ...

  6. MapReduce原理

    MapReduce原理 WordCount例子 用mapreduce计算wordcount的例子: package org.apache.hadoop.examples; import java.io ...

  7. 从0移植uboot(六) _实现网络功能

    为uboot添加网卡功能可以让uboot通过tftp下载内核, 方便我们的开发, 对于网卡功能的移植,我们依然在在一遍又一遍的实践这个uboot改造的套路. 找运行逻辑,即插入代码的位置. 根据运行逻 ...

  8. js库 - 浅拷贝 & 深拷贝

    学了堆栈内存空间,应该就理解了什么叫简单数据类型存在栈内存,复杂数据类型存在堆内存了. 然后面试中经常会问.业务中也经常会遇到的问题就是深浅拷贝的问题了. 栈内存中简单数据类型直接拷贝就能得到一个副本 ...

  9. java中的动态代理Proxy

    动态代理是java语言的一个神奇的地方,不是很好理解,下面来看看关键的地方. InvocationHandler 是一个接口,官方文档解释说,每个代理的实例都有一个与之关联的 InvocationHa ...

  10. MySQL查询表与表字段的信息

    环境: Mysql数据库 库名:db_name 表名: table_name1 table_name2 查询一个里面所有表的信息: use information_scheam; select * f ...