ansible-playbook 运维

为何引入playbook?
通常运维人员完成一个任务, 好比安装部署一个httpd服务会须要多个模块(一个模块也能够称之为task)提供功能来完成。而playbook就是组织多个task的容器,它的实质就是一个文件,有着特定的组织格式,它采用的语法格式是YAML(Yet Another Markup Language)。YAML语法可以简单的表示散列表,字典等数据结构。简单来讲, playbook是由一个或多个模块组成的,使用多个不一样的模块,完成一件事情。 
php

Ansible核心功能
-  pyYAML用于ansible编写剧本所使用的语言格式(saltstack---python);
-  rsync-ini语法, sersync-xml语法, nsible-pyYAML语法;
-  paramiko远程链接与数据传输;
-  Jinja2用于编写ansible的模板信息;



html

YAML三板斧
缩进: YAML使用一个固定的缩进风格表示层级结构,每一个缩进由两个空格组成, 不能使用tabs;
冒号: 以冒号结尾的除外,其余全部冒号后面全部必须有空格;
短横线: 表示列表项,使用一个短横杠加一个空格。多个项使用一样的缩进级别做为同一列表;


java

YAML基本语法
Ansible-playbook采用YAML语法编写。连续的项目(即列表)用 -减号来表示,key/value(字典)用冒号:分隔。
node

列表:每个列表成员前面都要有一个短横线和一个空格python

1mysql

2linux

3nginx

4web

5redis

6

7

8

fruits:

    - Apple

    - Orange

    - Strawberry

    - Mango

 

或者:

fruits: ['Apple''Orange''Strawberry''Mango']

字典:每个成员由键值对组成,注意冒号后面要有空格

1

2

3

4

5

6

martin:

    name: Martin D'vloper

    job: Developer

    skill: Elite

或者

martin: {name: Martin D'vloper, job: Developer, skill: Elite}

列表和字典能够混合使用

1

2

3

4

5

6

7

8

9

10

11

12

13

14

-  martin:

    name: Martin D'vloper

    job: Developer

    skills:

      - python

      - perl

      - pascal

-  tabitha:

    name: Tabitha Bitumen

    job: Developer

    skills:

      - lisp

      - fortran

      - erlang

示例以下:
[root@localhost ~]# cat httpd.yaml

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

---

- hosts: control-node    #将要执行任务的主机,已经在hosts文件中定义好了,但是单个主机或主机组

  remote_user: root      #在目标主机上执行任务时的用户身份

  vars:

    - pkg: httpd

  tasks:

    - name: "install httpd package."

      yum: name={{ pkg }}  state=installed

    - name: "copy httpd configure file to remote host."

      copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf

      notify: restart httpd     #当这个任务执行状态发生改变时,触发handlers执行.

    - name: "boot httpd service."

      service: name=httpd state=started

  handlers:                     #handlers与tasks是同一级别

    - name: restart httpd

      service: name=httpd state=restarted

playbook语法特性
1.  以 --- (三个减号)开始,必须顶行写;
2. 次行开始写Playbook的内容,可是通常要求写明该playbook的功能;
3. 严格缩进,而且不能用Tab键缩进;
4. 缩进级别必须是一致的,一样的缩进表明一样的级别,程序判别配置的级别是经过缩进结合换行来实现的;
5. K/V的值可同行写,也可换行写。同行使用 :分隔,换行写须要以 - 分隔;




playbook基础组件
Hosts:运行执行任务(task)的目标主机
remote_user:在远程主机上执行任务的用户
tasks:任务列表
handlers:任务,与tasks不一样的是只有在接受到通知时才会被触发
templates:使用模板语言的文本文件,使用jinja2语法。
variables:变量,变量替换{{ variable_name }}





整个playbook是以task为中心,代表要执行的任务。hosts和remote_user代表在远程主机以何种身份执行,其余组件让其可以更加灵活。下面介绍插件:

1.  variable
变量定义在资产 (inventory) 中, 默认就是/etc/ansible/hosts文件中

1

2

3

4

5

6

7

8

9

10

11

12

主机变量:

192.168.200.136 http_port=808 maxRequestsPerChild=808

192.168.200.137 http_port=8080 maxRequestsPerChild=909

 

主机组变量:

[websers]

192.168.200.136

192.168.200.137

 

[websers:vars] 

ntp_server=ntp.exampl.com

proxy=proxy.exampl.com

变量定义在playbook中

1

2

3

- hosts: webservers

  vars:

    http_port: 80

使用facts变量

1

2

3

4

facts变量是由setup模块获取远程主机的信息。

 

用法:

# ansible 192.168.200.136 -m setup

在roles中定义变量, 这个后面会介绍到.

ansible-playbook 命令中传入参数

1

2

使用 -e选项传入参数

# ansible-playbook 192.168.200.136 -e "httpd_port=808" httpd04.yml

变量的引用

1

{{ var_name }}

2.  templates
它是一个模块功能,与copy不一样的是他的文本文件采用了jinga2语法,jinga2基本语法以下:

1

2

3

4

5

6

7

8

9

10

11

12

字面量:

  字符串:使用单引号或双引号

  数字:整型,浮点数

  列表:{item1,item2,...}

  字典:{key1:value1,key2:value2,...}

  布尔型:true/false

算术运算:

  +,-,*,/,//,%,**

比较运算:

  ==,!=,>,>=,<,<=

逻辑运算:

  and,or,not

注意:template只能在palybook中使用。

3.  tasks
执行的模块命令

1

2

3

4

5

6

7

8

9

10

11

12

13

格式:

  action:模块参数(此种方式只在较新的版本中出现)

  module:参数(已键值对的形式出现)

 

每个task都有一个名称,用于标记此任务。任务示例:

  name: install httpd

  yum: name=httpd state=present

 

注意:shell和command没有参数,可在后面直接跟命令

  shell: ss -tnl | grep :80

 

1)某任务的运行状态为changed后,可经过相应的notify通知相应的handlers

2)任务能够经过tags打标签,而后经过palybook命令-t选项调用.

playbook命令及调用方式

用法:
ansible-playbook  <filename.yml> ... [options]

<filename.yml>: yaml格式的playbook文件路径,必须指明
[options]: 选项

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

Options:

--ask-vault-pass    

             #ask for vault password

             #加密playbook文件时提示输入密码

  -C, --check         

             #don't make any changes; instead, try to predict some of the changes that may occur

             #模拟执行,不会真正在机器上执行(查看执行会产生什么变化)。即并不在远程主机上执行,只是测试。

  -D, --diff          

             #when changing (small) files and templates, show the differences in those files; works great with --check

             #当更新的文件数及内容较少时,该选项可显示这些文件不一样的地方,该选项结合-C用会有较好的效果

  -e EXTRA_VARS, --extra-vars=EXTRA_VARS

             #set additional variables as key=value or YAML/JSON

             #在Playbook中引入外部参数变量

  --flush-cache       

             #clear the fact cache

             #清理fact缓存,将fact清除到的远程主机缓存

  --force-handlers    

             #run handlers even if a task fails

             #强制运行handlers的任务,即便在任务失败的状况下

  -f FORKS, --forks=FORKS

             #specify number of parallel processes to use(default=5)

             #并行任务数。FORKS被指定为一个整数,默认是5

  -h, --help          

             #show this help message and exit

             #打开帮助文档API

  -i INVENTORY, --inventory-file=INVENTORY

             #specify inventory host path (default=/etc/ansible/hosts) or comma separated host list.

             #指定要读取的Inventory清单文件

  -l SUBSET, --limit=SUBSET

             #further limit selected hosts to an additional pattern

             #限定执行的主机范围

  --list-hosts        

             #outputs a list of matching hosts; does not execute anything else

             #列出执行匹配到的主机,但并不会执行任何动做。

  --list-tags         

             #list all available tags

             #列出全部可用的tags

  --list-tasks        

             #list all tasks that would be executed

             #列出全部即将被执行的任务

  -M MODULE_PATH, --module-path=MODULE_PATH

             #specify path(s) to module library (default=None)

             #要执行的模块的路径

  --new-vault-password-file=NEW_VAULT_PASSWORD_FILE

             #new vault password file for rekey

             #

  --output=OUTPUT_FILE

             #output file name for encrypt or decrypt; use - for stdout

             #

  --skip-tags=SKIP_TAGS

             #only run plays and tasks whose tags do not match these values

             #跳过指定的tags任务

  --start-at-task=START_AT_TASK

             #start the playbook at the task matching this name

             #从第几条任务(START_AT_TASK)开始执行

  --step              

             #one-step-at-a-time: confirm each task before running

             #逐步执行Playbook定义的任务,并经人工确认后继续执行下一步任务

  --syntax-check      

             #perform a syntax check on the playbook, but do not execute it

             #检查Playbook中的语法书写,并不实际执行

  -t TAGS, --tags=TAGS

             #only run plays and tasks tagged with these values

             #指定执行该tags的任务

  --vault-password-file=VAULT_PASSWORD_FILE

             #vault password file

             #

  -v, --verbose       

             #verbose mode (-vvv for more, -vvvv to enable connection debugging)

             #执行详细输出

  --version           

             #show program's version number and exit

             #显示版本

  

  ############Connection Options,即下面时链接权限############

    control as whom and how to connect to hosts

  

    -k, --ask-pass    

             #ask for connection password

             #

    --private-key=PRIVATE_KEY_FILE, --key-file=PRIVATE_KEY_FILE

             #use this file to authenticate the connection

             #

    -u REMOTE_USER, --user=REMOTE_USER

             #connect as this user (default=None)

             #指定远程主机以USERNAME运行命令

    -c CONNECTION, --connection=CONNECTION

             #connection type to use (default=smart)

             #指定链接方式,可用选项paramiko (SSH)、ssh、local,local方式经常使用于crontab和kickstarts

    -T TIMEOUT, --timeout=TIMEOUT

             #override the connection timeout in seconds(default=10)

             #SSH链接超时时间设定,默认10s

    --ssh-common-args=SSH_COMMON_ARGS

             #specify common arguments to pass to sftp/scp/ssh (e.g.ProxyCommand)

             #

    --sftp-extra-args=SFTP_EXTRA_ARGS

             #specify extra arguments to pass to sftp only (e.g. -f, -l)

             #

    --scp-extra-args=SCP_EXTRA_ARGS

             #specify extra arguments to pass to scp only (e.g. -l)

             #

    --ssh-extra-args=SSH_EXTRA_ARGS

             #specify extra arguments to pass to ssh only (e.g. -R)

             #

  

  ############Privilege Escalation Options, 即下面时权限提高权限############

    control how and which user you become as on target hosts

  

    -s, --sudo        

             #run operations with sudo (nopasswd) (deprecated, use become)

             #至关于Linux系统下的sudo命令

    -U SUDO_USER, --sudo-user=SUDO_USER

             #desired sudo user (default=root) (deprecated, use become)

             #使用sudo,至关于Linux下的sudo命令

    -S, --su          

             #run operations with su (deprecated, use become)

             #

    -R SU_USER, --su-user=SU_USER

             #run operations with su as this user (default=root)(deprecated, use become)

    -b, --become      

             #run operations with become (does not imply password prompting)

             #

    --become-method=BECOME_METHOD

             #privilege escalation method to use (default=sudo),valid choices: [ sudo | su | pbrun | pfexec | doas |dzdo | ksu | runas ]

             #

    --become-user=BECOME_USER

             #run operations as this user (default=root)

             #

    --ask-sudo-pass   

             #ask for sudo password (deprecated, use become)

             #传递sudo密码到远程主机,来保证sudo命令的正常运行

    --ask-su-pass     

             #ask for su password (deprecated, use become)

             #

    -K, --ask-become-pass

             #ask for privilege escalation password

             #

ansible-playbook须要注意的两个命令
1)检查语法,只检查是不是yaml语法格式。并不作逻辑校验。(记住这个要常用, 它是判断语法是否正确!!!)
# ansible-playbook --syntax-check kevin.yml
2)模拟执行(不是真的执行)
# ansible-playbook -C kevin.yml



关闭Facts
若是不须要使用主机的任何fact数据,能够选择关闭fact数据的获取,这样有利于加强Ansible面对大量系统的push模块。
在playbook中关闭Facts方法(gather_facts: no):

1

2

3

---

- hosts: webserver

  gather_facts: no

palybook书写格式

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

---                                   # 也能够不使用这一行。能够省略。

- hosts: 172.16.60.211                #处理指定服务器.   - (空格)hosts:(空格)172.16.20.211

  task:                               #剧本所要干的事情; (空格)(空格)task:

  - name:                             #(两个空格)-(空格)name。

    commandecho hello clsn linux    #(四个空格)command:(空格)

 

须要注意:

Task任务里的name能够省略不写,将-(空格)放到下一行模块墙面。例如:

---                                  

- hosts: 172.16.60.211              

  task:                            

  commandecho hello clsn linux

 

小示例:

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  gather_facts: no

  tasks:

     file: path=/opt/task1.txt state=touch

palybook格式示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

[root@ansible-server ~]# vim /etc/ansible/test.yaml

- hosts: 172.16.60.213

  tasks:

    - name: Install Rsync

      yum: name=rsync state=installed

 

playbook检查方法

[root@ansible-server ~]# ansible-playbook --syntax-check /etc/ansible/test.yaml

 

playbook: /etc/ansible/test.yaml

[root@ansible-server ~]# ansible-playbook -C /etc/ansible/test.yaml

 

PLAY [172.16.60.213] *******************************************************************************************************************

 

TASK [Gathering Facts] *****************************************************************************************************************

ok: [172.16.60.213]

 

TASK [Install Rsync] *******************************************************************************************************************

ok: [172.16.60.213]

 

PLAY RECAP *****************************************************************************************************************************

172.16.60.213              : ok=2    changed=0    unreachable=0    failed=0 

 

上面两个检查命令, 第一个是进行playbook剧本配置信息语法检查; 第二个是模拟playbook剧本执行(彩排)

palybook剧本文件示例

ansible-playbook编写内容扩展剧本任务编写多个任务

1

2

3

4

5

6

- hosts: all

  tasks:

    - name: restart-network

      cron: name='restart network' minute=00 hour=00 job='/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1'

    - name: sync time

      cron: name='sync time' minute=*/5 job="/usr/sbin/ntpdate pool.ntp.com >/dev/null 2>&1"

剧本编写内容扩展:剧本任务编写多个主机

1

2

3

4

5

6

7

8

9

10

11

- hosts: 172.16.60.7

  tasks:

    - name: restart-network

      cron: name='restart network' minute=00 hour=00 job='/usr/sbin/ntpdate time.nist.gov >/dev/null 2>&1'

    - name: sync time

      cron: name='sync time' minute=*/5 job="/usr/sbin/ntpdate pool.ntp.com >/dev/null 2>&1"

 

- hosts: 172.16.60.31

  tasks:

    - name: show ip addr to file

      shell: echo $(hostname -i) >> /tmp/ip.txt

playbook剧本编写方式
-  多主机单任务编写方式
-  多主机多任务编写方式
-  不一样主机多任务编写方式


来看一个比较完整的ansible的yml文件写法:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

---

- host: webservers       ###要管理的远程服务器组名称, 服务器地址维护在/etc/ansible/hosts 里, 也能够直接写地址

  vars:

    port: 8081           ###定义了一个变量 端口号

  remote_user: root      ###远程登陆后用什么用户执行

  

  pre_tasks:             ###执行正式 task 以前执行的任务

  - name: pre task       ###任务名称

    shell: echo 'execute pre task'      ###执行一行 shell 命令, 支持 >> 等符号

  

  roles:            ###引入 roles, 能够理解为引用了一个其余项目 ansible 包, 引用的 roles 能够是另外一个完整的 ansible 脚本

  - role: my_role   ###要引用的 role 名称

    when: "ansible_os_family == 'RedHat'"   ###判断条件, ansible_os_family 是一个内置变量, 可直接使用

  

  tasks:           ###按顺序执行如下 task

  - include: my_tasks/some_task.yml       ###能够引入其余 yml 文件

  - name: get hostname        ###这是一个 task, 名称

    commandcat log.log      ###执行一行 command , 和 shell 相似, 可是不支持 >> 等操做符

    register: result          ###执行的结果, 设到 result 这个变量中, 后面可使用

  - name: set hostname

    shell: cat {{result.stdout}} >> host.text

  - name: task1

    commandecho 'execute task1'

  - name: task2 start apache

    service:             ###启动 httpd 服务器, service 是一个 ansible 内置模块, 读者能够自行查看更多模块, 包括下载复制等等

      name: httpd

      state: started

      tags:

        - apache        ###这是一个标签, 能够用 ansible-playbook main.yml --tags "apache" 指定只执行这个任务

  - name: copy and set value of index.html

    template:           ###这是一个复制方法, 也叫模块, 而且.j2文件中可使用{{}}来设置须要替换的变量

      src: templates/index.html.j2

      dest: /etc/httpd/index.html

    notify:             ###唤醒执行后面的 handlers 中名字叫 restart apache 的任务

    - restart apache

  

  post_tasks:           ###最后须要执行的任务

  - name: posy task

    shell: echo 'execute post task'

  

  handlers:

  - name: restart apache

    debug:              ###这是一个打印模块

      msg: start restart apche

palybook剧本中的方法

1.  handlers 任务触发
在须要被监控的任务(tasks)中定义一个notify,只有当这个任务被执行时,才会触发notify对应的handlers去执行相应操做。例如配置文件被修改后,有可能须要重启程序,此时咱们能够配置一个handlers,相似触发器。注意:handlers下的name名称必需要和它对应的notify名称相同!不然不会执行!!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

[root@localhost ~]# cat httpd.yaml

---

- hosts: control-node

  remote_user: root

  vars:

    - pkg: httpd

  tasks:

    - name: "install httpd package."

      yum: name={{ pkg }}  state=installed

    - name: "copy httpd configure file to remote host."

      copy: src=/root/conf/httpd.conf dest=/etc/httpd/conf/httpd.conf

      notify: restart httpd

    - name: "boot httpd service."

      service: name=httpd state=started

  handlers:

    - name: restart httpd

      service: name=httpd state=restarted

########  在使用handlers的过程当中,须要注意下面几点  ########
1. handlers只有在其所在的任务被执行完时,它才会被运行;若是一个任务中定义了notify调用Handlers,但因为条件判断等缘由,该任务未被执行,则Handlers一样不会被执行。
2. handlers只会在Play的末尾运行一次;若是想在一个Playbook的中间运行handlers,则须要使用meta模块来实现,例如:-meta: flush_handlers。
3. 能够直接在Handlers中使用notify选项,实现Handlers调用Handlers。
4. 可使用listen关键字,在一个tasks任务中一次性notify多个handler。即将多个handler分为"一组",使用相同的"组名"便可,当notify对应的值为"组名"时,"组"内的全部handler都会被notify。
5. 若是一个Play在运行到调用handlers的语句以前失败了,那么这个handlers将不会被执行。可是可使用mega模块的--force-handlers选项来强制执行handlers,即便在handlers所在Play中途运行失败也能执行。须要注意:--force-handlers参数主要针对即便playbook执行失败,也要执行代码块成功了的handlers(即执行成功的task任务), 若是代码块自己执行失败(即执行失败的task任务),那么它所对应的handlers应当不会被执行!




handlers能够理解成另外一种tasks,handlers是另外一种"任务列表",能够理解handlers和tasks是"平级关系",因此他们的缩进相同。handlers的任务会被tasks中的任务进行"调用",可是,被"调用"并不意味着必定会执行,只有当tasks中的任务"真正执行"之后,handlers中被调用的任务才会执行,若是tasks中的任务并无作出任何实际的操做,那么handlers中的任务即便被"调用",也并不会执行。handlers中能够有多个任务,被tasks中不一样的任务notify。

场景1:headlers在全部tasks任务被执行完时才执行。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  become: yes

  become_method: sudo

  tasks:

    - name: make file task1

      file: path=/opt/task1.txt state=touch

      notify: task1

    - name: make file task2

      file: path=/opt/task2.txt state=touch

      notify: task2

  handlers:

    - name: task1

      file: path=/opt/task1.txt mode=777 owner=root group=root

    - name: task2

      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes

 

执行结果:

[root@localhost ansible]# ansible-playbook haha.yaml

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.233]

ok: [172.16.60.234]

 

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

TASK [make file task2] ***************************************************************************************************************************

changed: [172.16.60.233]

changed: [172.16.60.234]

 

RUNNING HANDLER [task1] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task2] **************************************************************************************************************************

changed: [172.16.60.233]

changed: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=5    changed=4    unreachable=0    failed=0  

172.16.60.234              : ok=5    changed=4    unreachable=0    failed=0

从上面运行结果看出,Handlers执行的顺序与Handlers在playbook中定义的顺序是相同的,与"handler"被notify的顺序无关。

场景2:使用meta模块,headlers会在它所对应的task任务执行完后当即被触发并执行,即在playbook的中间环节运行。
默认状况下,全部的task执行完毕后,才会执行各个handles,并非执行完某个task后,当即执行相应的handler,若是想要在执行完某些task之后当即执行对应的handlre,那么须要使用meta模块。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  become: yes

  become_method: sudo

  tasks:

    - name: make file task1

      file: path=/opt/task1.txt state=touch

      notify: task1

    - meta: flush_handlers

    - name: make file task2

      file: path=/opt/task2.txt state=touch

      notify: task2

  handlers:

    - name: task1

      file: path=/opt/task1.txt mode=777 owner=root group=root

    - name: task2

      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes

 

执行结果:

[root@localhost ansible]# ansible-playbook haha.yaml

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.234]

ok: [172.16.60.233]

 

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task1] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

TASK [make file task2] ***************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task2] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=5    changed=4    unreachable=0    failed=0  

172.16.60.234              : ok=5    changed=4    unreachable=0    failed=0

上面使用了meta模块后,注意它的执行顺序于场景1作下对比!

场景3:Handlers调用Handlers
若实现Handlers调用Handlers,则直接在Handlers中使用notify选项便可以。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  become: yes

  become_method: sudo

  tasks:

    - name: make file task1

      file: path=/opt/task1.txt state=touch

      notify: task1

    - name: make file task2

      file: path=/opt/task2.txt state=touch

        

  handlers:

    - name: task1

      file: path=/opt/task1.txt mode=777 owner=root group=root

      notify: task2

    - name: task2

      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes

  

执行结果:

[root@localhost ansible]# ansible-playbook haha.yaml            

  

PLAY [test_host] *********************************************************************************************************************************

  

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.234]

ok: [172.16.60.233]

  

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.233]

changed: [172.16.60.234]

  

TASK [make file task2] ***************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

  

RUNNING HANDLER [task1] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

  

RUNNING HANDLER [task2] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=5    changed=4    unreachable=0    failed=0 

172.16.60.234              : ok=5    changed=4    unreachable=0    failed=0

 

 

注意:上面执行的顺序是:make file task1 > make file task2 > task1 > task2

 

====================================================================

也能够改为下面的方式:实现Handlers调用Handlers

 

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  become: yes

  become_method: sudo

  tasks:

    - name: make file task1

      file: path=/opt/task1.txt state=touch

      notify: task1

 

  handlers:

    - name: task1

      file: path=/opt/task1.txt mode=777 owner=root group=root

      notify: task2

    - name: task2

      file: path=/opt/task2.txt state=touch

      notify: task3

    - name: task3

      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes

 

执行结果:

[root@localhost ansible]# ansible-playbook haha.yaml

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.233]

ok: [172.16.60.234]

 

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.233]

changed: [172.16.60.234]

 

RUNNING HANDLER [task1] **************************************************************************************************************************

changed: [172.16.60.233]

changed: [172.16.60.234]

 

RUNNING HANDLER [task2] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task3] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=5    changed=4    unreachable=0    failed=0  

172.16.60.234              : ok=5    changed=4    unreachable=0    failed=0 

 

注意:上面的执行顺序是:make file task1 > task1 > task2 > task3

场景4:使用listen关键字,在一个tasks任务中一次性notify多个handler
怎么才能一次性notify多个handler呢?若是尝试将多个handler使用相同的name呢?其实这样并不可行!由于当多个handler的name相同时,只有一个handler会被执行。要想实现一次notify多个handler,须要借助一个关键字,它就是"listen",能够把listen理解成"组名",能够把多个handler分红"组",当须要一次性notify多个handler时,只要将多个handler分为"一组",使用相同的"组名"便可,当notify对应的值为"组名"时,"组"内的全部handler都会被notify。须要注意:listen的名称要和notify名称保持一致!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  become: yes

  become_method: sudo

  tasks:

    - name: make file task1

      file: path=/opt/task1.txt state=touch

      notify: group1_handler

  handlers:

    - name: task1

      listen: group1_handler

      file: path=/opt/task1.txt mode=777 owner=root group=root

    - name: task2

      listen: group1_handler

      file: path=/opt/task1.txt src=/opt/task1.txt dest=/opt/heihei state=link force=yes

    - name: task3

      listen: group1_handler

      shell: echo "this is test,haha...." >> /opt/task1.txt

 

执行结果:

[root@localhost ansible]# ansible-playbook haha.yaml

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.233]

ok: [172.16.60.234]

 

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task1] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task2] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

RUNNING HANDLER [task3] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=5    changed=4    unreachable=0    failed=0  

172.16.60.234              : ok=5    changed=4    unreachable=0    failed=0

场景5:使用--force-handlers选项来强制执行handlers
当playbook剧本执行失败之后,handlers可能并无被触发,也就不会执行了!若是想无论task任务是否成功执行,都强制执行handlers。在这个时候,能够在执行playbook的时候,添加--force-handlers来强制执行handlers!可是必需要注意的是:--force-handlers参数主要针对即便playbook执行失败,也要执行代码块成功了的handlers(即执行成功的task任务), 若是代码块自己执行失败(即执行失败的task任务),那么它所对应的handlers应当不会被执行!

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  become: yes

  become_method: sudo

  tasks:

    - name: make file task1

      file: path=/opt/task1.txt state=touch

      notify: task1

    - name: make file task2

      file: path=/opt/kevin/task2.txt state=touch

      notify: task2

  handlers:

    - name: task1

      file: path=/opt/task1.txt mode=777 owner=root group=root

    - name: task2

      shell: ln -s /opt/task1.txt /opt/task2.txt

 

执行结果:

[root@localhost ansible]# ansible-playbook haha.yaml

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.234]

ok: [172.16.60.233]

 

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.233]

changed: [172.16.60.234]

 

TASK [make file task2] ***************************************************************************************************************************

fatal: [172.16.60.234]: FAILED! => {"changed"false"module_stderr""""module_stdout""Traceback (most recent call last):\r\n  File \"/tmp/ansible_iNMDpU/ansible_module_file.py\", line 474, in <module>\r\n    main()\r\n  File \"/tmp/ansible_iNMDpU/ansible_module_file.py\", line 448, in main\r\n    open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n""msg""MODULE FAILURE""rc": 0}

fatal: [172.16.60.233]: FAILED! => {"changed"false"module_stderr""""module_stdout""Traceback (most recent call last):\r\n  File \"/tmp/ansible_OvTacW/ansible_module_file.py\", line 474, in <module>\r\n    main()\r\n  File \"/tmp/ansible_OvTacW/ansible_module_file.py\", line 448, in main\r\n    open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n""msg""MODULE FAILURE""rc": 0}

 

RUNNING HANDLER [task1] **************************************************************************************************************************

        to retry, use: --limit @/etc/ansible/haha.retry

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=2    changed=1    unreachable=0    failed=1  

172.16.60.234              : ok=2    changed=1    unreachable=0    failed=1

 

如上执行结果,因为/opt/kevin目录不存在,致使task的第二个任务执行失败,这个时候handler根本没有被触发,也就不会执行。

即便第一个任务执行成功,可是它对应的第一个handler也不会被执行!!

 

###################################################################################

接下来使用--force-handlers选项来强制执行handlers(强制执行的是:成功执行的task对应的handler)

[root@localhost ansible]# ansible-playbook haha.yaml --force-handlers

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.234]

ok: [172.16.60.233]

 

TASK [make file task1] ***************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

 

TASK [make file task2] ***************************************************************************************************************************

fatal: [172.16.60.233]: FAILED! => {"changed"false"module_stderr""""module_stdout""Traceback (most recent call last):\r\n  File \"/tmp/ansible_rEJQHm/ansible_module_file.py\", line 474, in <module>\r\n    main()\r\n  File \"/tmp/ansible_rEJQHm/ansible_module_file.py\", line 448, in main\r\n    open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n""msg""MODULE FAILURE""rc": 0}

fatal: [172.16.60.234]: FAILED! => {"changed"false"module_stderr""""module_stdout""Traceback (most recent call last):\r\n  File \"/tmp/ansible_7CDxpp/ansible_module_file.py\", line 474, in <module>\r\n    main()\r\n  File \"/tmp/ansible_7CDxpp/ansible_module_file.py\", line 448, in main\r\n    open(b_path, 'wb').close()\r\nIOError: [Errno 2] No such file or directory: '/opt/kevin/task2.txt'\r\n""msg""MODULE FAILURE""rc": 0}

 

RUNNING HANDLER [task1] **************************************************************************************************************************

changed: [172.16.60.234]

changed: [172.16.60.233]

        to retry, use: --limit @/etc/ansible/haha.retry

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.233              : ok=3    changed=2    unreachable=0    failed=1  

172.16.60.234              : ok=3    changed=2    unreachable=0    failed=1

 

如上执行结果,即便playbook执行中有task任务执行失败,可是执行成功的task任务所调用的handler依然会被强制触发并执行!可是执行失败的task任务所调用的handler依然不会被执行。

即handlers中的task1会被执行,task2不会被执行!

2.  tags任务标签
tags用于让用户选择运行playbook中的部分代码。ansible具备幂等性,所以会自动跳过没有变化的部分,即使如此,有些代码为测试其确实没有发生变化的时间依然会很是地长。此时若是确信其没有变化,就能够经过tags跳过此些代码片段。tags能够看做是ansible的任务控制!

ansible的标签(Tags)功能能够给角色(Roles)、文件、单独的任务,甚至整个Playbook打上标签,而后利用这些标签来指定要运行Playbook中的个别任务,或不执行指定的任务。若是有一个很大的playbook剧本,而只想运行playbook其中的某个或部分task任务,而不是运行playbook中全部的任务,这个时候tags是你的最佳选择。

2.1  ansible支持"tags:"属性,执行playbook时,能够经过两种方式根据"tags"过滤任务:
1. 在命令行上,使用或选项"--tags或 --skip-tags",后面使用空格或"="均可以。
2. 在ansible配置设置中,使用和选项"TAGS_RUN或TAGS_SKIP";
3. 可使用"--list-tags"查看playbook中有哪些tags会被执行;


2.2  ansible系统中内置的特殊tags(目前有5个特殊的tags)
到ansible 2.5版本之后,目前系统内置的tags有如下几个:
always: 除非--skip-tags指定这个标签,不然该标记为always的task一直都会执行。"--tags always"只执行标记了always的tasks;
never: 除非--tags指定了这个标签,不然该标记为never的task一直都不会执行。"--tags never"执行标记了always和never的tasks;
tagged: --tags tagged表示执行全部有tags标签的tasks任务,但不包括tags标签是never的tasks任务;--skip-tags tagged表示全部有tags标签的tasks任务都跳过,即不会执行。
untagged: --tags untagged表示执行全部没有tags标签的tasks任务和tags标签为always的tasks任务;--skip-tags untagged效果相反!
all:--tags all表示执行全部的tags标签为非never的task,包括有tags标签和无tags标签的tasks。





执行ansible-playbook命令时,使用下面两个参数的含义(自定义的tags能够是单个,也能够是多个,多个之间使用逗号隔开):
"--tags 自定义的tag" 表示执行tags为指定的标签名的tasks和tags为always的tasks。若是执行命令ansible-playbook site.yml 时不指定tags,则会执行全部tags为非never的tasks
"--skip-tags 自定义tag" 表示执行全部非指定tag和非never的tasks

2.3  tags标签配置语法有下面三种:

1

2

3

4

5

6

7

8

9

语法一:

tags:

  - tag_test

  

语法二:

tags: tag_test

  

语法三:

tags: ['tag_test']

2.3  ansible的tags使用
1)最多见的使用形式。一个task任务添加一个tags标签。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

官方示例以下:

[root@localhost ansible]# vim example.yml

---

- hosts: all

  remote_user: root

  gather_facts: no

  tasks:

    - yum: name={{ item }} state=installed

      with_items:

         - httpd

         - memcached

      tags:

         - packages

    - template: src=templates/src.j2 dest=/etc/foo.conf

      tags:

         - configuration

此时若是但愿只run其中的某个task,则run的时候指定tags便可。能够运行多个tags,中间使用逗号隔开;也能够运行单个tags。

1

2

3

4

5

6

7

[root@localhost ansible]# ansible-playbook example.yml --tags "configuration,packages"  

[root@localhost ansible]# ansible-playbook example.yml --tags configuration  

[root@localhost ansible]# ansible-playbook example.yml --tags packages

或者

[root@localhost ansible]# ansible-playbook example.yml --tags="configuration,packages"  

[root@localhost ansible]# ansible-playbook example.yml --tags=configuration  

[root@localhost ansible]# ansible-playbook example.yml --tags=packages

相反,也可使用--skip-tags跳过某个task任务。

1

2

3

[root@localhost ansible]# ansible-playbook example.yml --skip-tags configuration

或者

[root@localhost ansible]# ansible-playbook example.yml --skip-tags=configuration

具体看下面示例(tags三种语法都用上):

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  gather_facts: no

  tasks:

    - name: task1

      file: path=/opt/task1.txt state=touch

      tags: make_task1

    - name: task2

      file: path=/opt/task2.txt state=touch

      tags:

         - make_task2

    - name: task3

      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes

      tags: ['link_task3']

 

只运行make_task1标签的task任务

[root@localhost ansible]# ansible-playbook haha.yaml --tags make_task1

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [task1] *************************************************************************************************************************************

changed: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.234              : ok=1    changed=1    unreachable=0    failed=0  

 

运行多个tags

[root@localhost ansible]# ansible-playbook haha.yaml --tags make_task1,make_task2

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [task1] *************************************************************************************************************************************

changed: [172.16.60.234]

 

TASK [task2] *************************************************************************************************************************************

changed: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.234              : ok=2    changed=2    unreachable=0    failed=0

 

跳过make_task2标签的任务,其余任务正常执行

[root@localhost ansible]# ansible-playbook haha.yaml --skip-tags make_task2

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [task1] *************************************************************************************************************************************

changed: [172.16.60.234]

 

TASK [task3] *************************************************************************************************************************************

changed: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.234              : ok=2    changed=2    unreachable=0    failed=0

2)一个task任务添加多个tags标签。
上面是一个task任务添加一个tags标签,其实一个task任务能够添加多个标签,并且不一样的task任务可使用相同的tags标签。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

一个任务添加多个tags标签的语法仍然也有三种:

语法1:

tags:

  - tag1

  - tag2

 

语法2:

tags: tag1,tag2

 

语法3:

tags: ['tag1,tag2']

 

========================================================

具体示例以下:

[root@localhost ansible]# vim https.yml

---

- hosts: test_host

  remote_user: root

  tasks:

     - name: install httpd package

       tags: 

         - httpd

         - package

       yum:

         name=httpd

         state=latest

  

     - name: start up httpd service

       tags: httpd,service

       service:

         name: httpd

         state: started

 

 

上面例子中每一个任务都有多个标签,并且上例中两个任务都有一个共同的标签,就是httpd标签。

因此当执行"ansible-playbook httpd.yml --tags=httpd"时,上面两个task任务都会被执行。

 

因为上面例子中的全部任务都有共同的httpd标签,因此像这种状况,能够把httpd标签提取出来并写在play剧本中,示例以下:

[root@localhost ansible]# vim https.yml

---

- hosts: test_host

  remote_user: root

  tags:httpd

  tasks:

     - name: install httpd package

       tags: 

          - package

       yum:

         name=httpd

         state=latest

  

     - name: start up httpd service

       tags: ['service']

       service:

         name: httpd

         state: started

须要注意:当tags写在play剧本中而非写在task任务中时,play中的全部task任务都会继续当前paly中的tags,就像上例中,两个任务都会继承httpds的tag标签,同时还拥有本身的tag标签。

3)内置的特殊tags的用法
上面已经介绍了5个内置的特殊的tags,每一个都有其自身的用意。以下以always关键字的tags为例:若是把任务的tags值指定为always时,那么这个任务就老是被执行,除非使用"--skip-tags"选项明确指定不执行对应任务的tags标签。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

[root@localhost ansible]# cat haha.yaml

---

- hosts: test_host

  remote_user: root

  gather_facts: no

  tasks:

    - name: task1

      file: path=/opt/task1.txt state=touch

      tags: make_task1

    - name: task2

      file: path=/opt/task2.txt state=touch

      tags:

         - always

    - name: task3

      file: path=/opt/task2.txt src=/opt/task2.txt dest=/opt/heihei state=link force=yes

      tags: ['link_task3']

 

执行1:以下,虽然tags指定了执行标签为make_task1的任务,可是因为任务2的标签有关键字always,因此任务2也会被执行,这就是always的做用!

[root@localhost ansible]# ansible-playbook haha.yaml --tags=make_task1

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [task1] *************************************************************************************************************************************

changed: [172.16.60.234]

 

TASK [task2] *************************************************************************************************************************************

changed: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.234              : ok=2    changed=2    unreachable=0    failed=0 

 

执行2: 只执行标签为always的任务

[root@localhost ansible]# ansible-playbook haha.yaml --tags always

或者

[root@localhost ansible]# ansible-playbook haha.yaml --tags=always

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [task2] *************************************************************************************************************************************

changed: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.234              : ok=1    changed=1    unreachable=0    failed=0

 

执行3: 跳过标签为always关键字的任务,这里明确指出跳过执行always标签。

[root@localhost ansible]# ansible-playbook haha.yaml --skip-tags always   

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [task1] *************************************************************************************************************************************

changed: [172.16.60.234]

 

TASK [task3] *************************************************************************************************************************************

ok: [172.16.60.234]

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.234              : ok=2    changed=1    unreachable=0    failed=0  

 

其余四个特殊的tags标签在这里就不作示例说明了。特殊tags标签能够在ansible-playbook命令执行时直接使用。

4)tags标签能够和role 结合使用

1

2

3

4

[root@localhost ansible]# cat test.yml

---

roles:

  - { role: webserver, port: 5000, tags: [ 'web''foo' ] }

5)tags和include结合使用。

1

2

3

[root@localhost ansible]# cat test.yml

---

- include: kevin.yml tags=web,foo

如上,对一个include任务打了两个tags标签,直接执行"ansible_playbook test.yml" 或 "ansible_playbook test.yml --tags=web" 或 "ansible_playbook test.yml --tags=foo" 命令则会将kevin.yml文件中全部task任务都执行。

再来看看一个include结合tags的示例:经过指定标签(tags),来讲明是安装tomcat7仍是tomcat8

tomcat.yml文件

1

2

3

4

5

---

- include: install_tomcat7.yml

  tags: tomcat7

- include: install_tomcat8.yml

  tags: tomcat8

install_tomcat7.yml文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

---

- name: "复制文件到远程主机"

  copy:

    src={{ item.src }}

    dest={{ item.dest }}

  with_items:

    - src: jdk-7u79-linux-x64.rpm

      dest: /usr/local/src/

    - src: java17.sh

      dest: /etc/profile.d/

- name: "安装jdk"

  yum:

    name: /usr/local/src/jdk-7u79-linux-x64.rpm

    state: present

- name: "从新加载环境变量"

  shell: "source /etc/profile.d/java17.sh"

- name: "复制tomcat文件到远程服务器并解压"

  unarchive:

    src=apache-tomcat-7.0.64.zip

    dest=/data/

    copy=yes

    owner=staplesapp

    group=admin

- name: "对解压后的文件重命名"

  shell: mv /data/apache-tomcat-7.0.64 /data/tomcat7

- name: "对tomcat进行相关配置"

  shell: find /data/tomcat7/bin -name "*.sh" xargs chmod +x

- name: "启动tomcat"

  shell: 'nohup /data/tomcat7/bin/startup.sh &'

install_tomcat8.yml文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

---

- name: "复制文件到远程主机"

  copy:

    src={{ item.src }}

    dest={{ item.dest }}

  with_items:

    - src: jdk-8u111-linux-x64.rpm

      dest: /usr/local/src/

    - src: java18.sh

      dest: /etc/profile.d/

- name: "安装jdk"

  yum:

    name: /usr/local/src/jdk-8u111-linux-x64.rpm

    state: present

- name: "配置java环境变量"

  shell: "source /etc/profile.d/java18.sh"

- name: "安装tomcat"

  unarchive:

      src=apache-tomcat-8.0.30.tar.gz

      dest=/data/

      copy=yes

      owner=staplesapp

      group=admin

- name: "对解压后的文件重命名"

  shell: mv /data/apache-tomcat-8.0.30 /data/tomcat8

- name: "启动tomcat"

  shell: 'nohup /data/tomcat8/bin/startup.sh &'

下面开始执行命令:

1

2

3

4

5

安装tomcat7:

[root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat7

 

安装tomcat8:

[root@localhost ansible]# ansible-playbook tomcat.yml --tags tomcat8

这里须要特别注意:
在以前ansible版本中使用include 整合多个roles至统一入口结合tags标签来管理roles剧本,但在ansible2.8版本以后将会删除include语法,更改成import_playbook。若是还使用include语法也能够,只不过ansible-playbook执行结果中会有告警信息:"DEPRECATION WARNING]:'include' for playbook includes. You should use 'import_playbook' instead. This feature will be removed in version 2.8. Deprecation warnings can be disabled by setting deprecation_warnings=False in ansible.cfg."。因此,最好将上面tomcat.yml文件中的include语法改为import_playbook,以下:

1

2

3

4

5

6

[root@localhost ansible]# cat tomcat.yml

---

- import_playbook: install_tomcat7.yml

  tags: tomcat7

- import_playbook: install_tomcat8.yml

  tags: tomcat8

3.  include用法
若是想在playbook中重复使用任务列表,则可使用include文件来执行此操做。 使用include的任务列表是定义系统将要实现的角色的好方法。主要清楚:ansible2.8版本以后include语法变成了import_playbook。若是仍是使用include,则不会影响执行结果,只不过是有告警信息。ansible也能够将变量传递给include。示例以下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

示例1: 经过Include,能够在playbook中引用另外一个playbook或者tasks

==============================================================

[root@localhost ansible]# cat install_MysqlAndPhp.yml

- yum:

    name: mysql

    state: present

- yum:

    name: php-fpm

    state: present

 

[root@localhost ansible]# cat lamp.yml

---

- hosts: test_host

  remote_user: root

  gather_facts: no

  tasks:

  - include: install_MysqlAndPhp.yml

  - yum:

      name: httpd

      state: present

  

[root@localhost ansible]# cat lnmp.yml

---

- hosts: test_host

  remote_user: root

  gather_facts: no

  tasks:

    - include: install_MysqlAndPhp.yml

    - yum:

        name: nginx

        state: present

 

 

示例2: 能够在handler中引用include

==============================================================

[root@localhost ansible]# cat test_include.yml

---

- hosts: test_host

  remote_user: root

  gather_facts: no

  tasks:

    file:

        path: /opt/ttt

        state: touch

      notify: test include handlers

  

  handlers:

    - name: test include handlers

      include: include_handler.yml

  

[root@localhost ansible]# cat include_handler.yml

- debug:

    msg: "task1 of handlers"

- debug:

    msg: "task2 of handlers"

- debug:

    msg: "task3 of handlers"

 

示例3: when在include中使用

==============================================================

[root@localhost ansible]# cat /etc/ansible/hosts

[db]

192.168.24.10

[app]

192.168.24.11

 

[root@localhost ansible]# cat install_client.yml

---

- hosts: '` hosts `'

  user: ansible

  sudoyes

  sudo_user:root

  roles:

    - install_client

 

[root@localhost ansible]# cat roles/install_client/tasks/main.yml 

---

- include: db.yml

  when: "hosts == 'db'"

- include: app.yml

  when: "hosts == 'app'"

 

[root@localhost ansible]# cat roles/install_client/tasks/db.yml

---

  - name: Touchdb file

    shell: touch /tmp/db.txt

 

[root@localhost ansible]# cat roles/install_client/tasks/app.yml

---

  - name: Touchdb file

    shell: touch /tmp/db.txt

 

执行命令:

[root@localhost ansible]# ansible-playbook -i hosts install_client.yml --extra-vars "hosts=db"

[root@localhost ansible]# ansible-playbook -i hosts install_client.yml --extra-vars "hosts=app"

 

示例4: 能够在include中使用tags标签,这个在上面已经介绍过了

==============================================================

4.  role用法
角色(roles)是ansible自1.2版本开始引入的新特性,用于层次性,结构化地组织playbook。roles可以根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只须要在playbook中使用include指令便可。简单的说,roles就是经过分别将变量、文件、任务、模块及处理器放置于单独的目录中、并能够便捷地include他们的一种机制。角色通常用于基于主机构建服务的场景中、但也能够是用于构建守护进程等场景中。role主要做用是重用playbook,例如不管安装什么软件都会安装时间同步服务,那么每一个playbook都要编写ntp task,能够将ntp task写好,等到用的时候再调用就好了。ansible中将其组织成role,它有着固定的组织格式,以便playbook调用。

4.1  role层级目录结构
role以特定的层级目录结构进行组织的tasks、variables、handlers、templates、files等;至关于函数的调用把各个功能切割成片断来执行。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

roles/

    role_name/:定义的role的名字

    file/:     用于存放copy或script等模块调用的函数

    tasks/:     用于定义各类task,此目录必定要有main.yml;其余文件须要main.yml包含调用

    handlers/: 用于定义各类handlers,此目录必定要有main.yml;其余文件须要main.yml包含调用

    vars/:      用于定义variables,此目录必定要有main.yml;其余文件须要main.yml包含调用

    templates/:存储由template模块调用的模板文本;

    meta/:     定义当前角色的特殊设定及其依赖关系,此目录中至少应该有一个名为main.yml的文件;其它的文件须要由main.yml进行"包含"调用;

    default/:  此目录中至少应该有一个名为main.yml的文件,用于设定默认变量;

 

[root@localhost ansible]# ll roles/

total 40

drwkebor-kebor-kebo 8 root root 4096 Jul 29 22:13 web_Deploy

drwkebor-kebor-kebo 8 root root 4096 May  7  2019 web_Deploy_af

 

[root@localhost ansible]# ll roles/web_Deploy                  

total 25

-rw-r--r-- 1 root root   45 May  7  2019 web_Deploy.yml

drwkebor-kebor-kebo 2 root root 4096 Jul 10 19:09 defaults

drwkebor-kebor-kebo 2 root root 4096 May  7  2019 handlers

drwkebor-kebor-kebo 2 root root 4096 May  7  2019 meta

drwkebor-kebor-kebo 2 root root 4096 Dec 26 19:42 tasks

drwkebor-kebor-kebo 2 root root 4096 May  7  2019 templates

drwkebor-kebor-kebo 2 root root 4096 May  7  2019 vars

 

[root@localhost ansible]# ll roles/web_Deploy/tasks/

total 35

-rwkebor-kebor-kebo 1 root root 1542 Jun 24  2019 Auth.yml

-rwkebor-kebor-kebo 1 root root 1482 Oct 11 16:13 StartService.yml

-rwkebor-kebor-kebo 1 root root  963 Jun 18  2019 main.yml

-rwkebor-kebor-kebo 1 root root 1415 May  7  2019 StopService.yml

 

[root@localhost ansible]# cat roles/web_Deploy/tasks/main.yml

---

- include_tasks: Auth.yml

  tags: userauth

   

- include_tasks: StopService.yml

  tags: stopservice

- include_tasks: StartService.yml

  tags: startservice

 

[root@localhost ansible]# cat roles/web_Deploy/web_Deploy.yml

---

- hosts: all

  roles:

    - web_Deploy

 

===================================================================================

再以下一个项目的role目录结构:

site.yml

webservers.yml

fooservers.yml

roles/

   common/

     files/

     templates/

     tasks/

     handlers/

     vars/

     defaults/

     meta/

   webservers/

     files/

     templates/

     tasks/

     handlers/

     vars/

     defaults/

     meta/

 

 

再看下目录解释:

yml文件:用于定义此角色用到的各handler:在handler中使用include包含的其余的handler文件也应该位于此目录中;

files目录:存放由copy或script等模块调用的文件;

templates目录:templates模块会自动在此目录中寻找Jinja2模板文件;

tasks目录:至少应该包含一个名为main.yml的文件,其定义了此角色的任务列表;此文件可使用include包含其余的位于此目录中的task文件;

handlers目录:此目录中应当包含一个main;

vars目录:应当包含一个main.yml文件,用于定义此角色用到的变量;

meta目录:应当包含一个main.yml文件,用于定义此角色的特殊设定及其依赖关系;ansible 1.3及其之后的版本才支持

default目录:为当前角色设定默认变量时使用此目录;应当包含一个main.yml文件;

 

 

那么一个playbook就能够这样写:

---

 - hosts: webservers

  roles:

     - common

     - webservers

 

这个playbook为一个角色"kebo"指定了以下的行为:

若是 roles/kebo/tasks/main.yml 存在, 其中列出的tasks将被添加到play中

若是roles/kebo/handlers/main.yml 存在, 其中列出的handlers将被添加到play中

若是roles/kebo/vars/main.yml 存在, 其中列出的variables将被添加到play中

若是roles/kebo/meta/main.yml 存在, 其中列出的 "角色依赖"将被添加到roles列表中 (1.3 andlater)

全部 copy tasks 能够引用 roles/kebo/files/ 中的文件,不须要指明文件的路径。

全部 scripttasks 能够引用 roles/kebo/files/ 中的脚本,不须要指明文件的路径。

全部 template tasks 能够引用roles/kebo/templates/ 中的文件,不须要指明文件的路径。

全部 include tasks 能够引用roles/kebo/tasks/ 中的文件,不须要指明文件的路径。

 

若是roles目录下有文件不存在,这些文件将被忽略。好比 roles目录下面缺乏了"vars/"目录,这也不要紧。

 

须要注意:

仍然能够在playbook中松散地列出tasks,vars_files 以及 handlers,这种方式仍然可用,可是roles是一种很好的具备组织性的功能特性,强烈建议使用它。

若是在playbook中同时使用roles和tasks,vars_files 或者 handlers,roles 将优先执行。

 

并且也可使用参数化的roles,这种方式经过添加变量来实现,好比:

--

- hosts: webservers

  roles:

    - common

    - { role: foo_app_instance, dir'/opt/a',  port: 5000 }

    - { role: foo_app_instance, dir'/opt/b',  port: 5001 }

 

当一些事情不须要频繁去作时,也能够为 roles 设置触发条件,像这样:

---

- hosts: webservers

  roles:

    - { role: some_role, when: "ansible_os_family == 'RedHat'" }

它的工做方式是:将条件子句应用到 role 中的每个 task 上。

 

也能够给role分配指定的标签,好比:

---

- hosts: webservers

  roles:

    - { role: foo, tags: ["bar""baz"] }

 

若是play仍然包含有 "tasks" section,这些 tasks 将在全部 roles 应用完成以后才被执行。也可定义一些tasks,让它们在roles以前以及以后执行,能够这样作:

---

- hosts: webservers

  pre_tasks:

    - shell: echo 'hello'

  roles:

    - { role: some_role }

  tasks:

    - shell: echo 'still busy'

  post_tasks:

    - shell: echo 'goodbye'

 

注意:

pre_tasks: 执行正式 task 以前执行的任务

post_tasks:最后须要执行的任务

4.2  在playbook中调用role

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

role存放的路径在配置文件/etc/ansible/ansible.cfg中定义。以下,发现ansible的roles目录定义到/root/app/script/ansible/roles路径下了!!

[root@localhost ansible]# cat /etc/ansible/ansible.cfg |grep roles_path

roles_path    = /etc/ansible/roles:/root/app/script/ansible/roles

 

在playbook中调用role的方式有三种,以下:

第一种:

- hosts: HOSTS

  remote_user: root

  roles:

    - ROLE_NAME1

    - ROLE_NAME2

 

第二种:除了字典第一个元素指明调用的role,后面是传递给role的变量

- hosts: HOSTS

  remote_user: root

  roles:

  - { role: ROLE_NAME1, VARIABLE1: VALUE1, ... }

 

第三种:when指明role调用的条件

- hosts: HOSTS

  remote_user: root

  roles:

  - { role: ROLE_NAME1, when: CONDITIONS }

4.3  调用role示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

0) 先来看看role的路径定义

[root@localhost ansible]# cat /etc/ansible/ansible.cfg|grep roles_path

roles_path    = /etc/ansible/roles:/etc/ansible/roles

 

1)目录结构

[root@localhost ansible]# tree /etc/ansible/roles

/etc/ansible/roles

└── httpd                   #palybook调用时role的名称

    ├── defaults

    ├── files

    └── handlers

    │   └── main.yml       #全部的目录文件,并不必定要有,用时才建立

    └── mata

    └── tasks

    │   └── main.yml

    └── tamplates

        └── httpd.conf.c6.j2  #centos6,centos7的配置文件

        └── httpd.conf.c7.j2

 

2)tasks文件

[root@localhost ansible]# cat /etc/ansible/roles/httpd/tasks/main.yml

- name: install httpd package

  yum: name=httpd state=present

- name: install configure file

  template: src=httpd.conf.c{{ ansible_distribution_major_version }}.j2 dest=/etc/httpd/conf/httpd.conf

  tags: instconf

  notify: restart httpd service

- name: start httpd service

  service: name=httpd state=started enabled=true

 

3) handlers文件

[root@localhost ansible]# cat /etc/ansible/roles/httpd/handlers/main.yml

- name: restart httpd service

  service: name=httpd state=restarted

 

4) 模板文件

[root@localhost ansible]# grep ^Listen /etc/ansible/roles/httpd/templates/httpd.conf.c6.j2

Lister {{ httpd_port }}

 

5) 变量

[root@localhost ansible]# cat /etc/ansible/roles/httpd/vars/main.yml

httpd_port: 8088

 

6) playbook文件

[root@localhost ansible]# cat /etc/ansible/httpd_conf.yml

---

- hosts: webservers

  remote_user: root

  roles:

  - { role: httpd }

 

7) 执行playbook文件,并查看httpd端口

[root@localhost ansible]# ansible-playbook -i /etc/ansible/hosts /etc/ansible/httpd_conf.yml

[root@localhost ansible]# ansible -i /etc/ansible/hosts webservers -m shell -a "ss -tnlp|grep :80"

 

========================================================================================================

再来看一例:

1.group: 建立用户组nginx

2.user: 建立用户nginx

3.yum: 安装nginx

4.template: 配置文件更新nginx.conf

5.service: 启动nginx

 

[root@localhost ~]# cat /etc/ansible/ansible.cfg|grep roles_path

roles_path    = /etc/ansible/roles:/root/ansible/roles

 

[root@localhost ~]# cd /root/ansible/roles/nginx

[root@localhost nginx]# mkdir tasks templates

[root@localhost nginx]# cd tasks

 

[root@localhost tasks]# vim group.yml

- name: create group nginx

    group: name=nginx gid=80

 

[root@localhost tasks]# vim user.yml

-name: create user nginx

    user: name=nginx uid=80 group=nginx system=yes shell=/sbi/nologin

 

[root@localhost tasks]# vim install.yml

- name: install package

    yum: name=nginx

    

[root@localhost tasks]# vim start.yml

- name: start service

    service: name=nginx state=started enabled=yes

     

[root@localhost tasks]# vim restart.yml

- name: restart service

    service: name=nginx state=restarted

     

[root@localhost tasks]# vim templ.yml

- name: copy conf

    template: src=nginx.conf.j2 dest=/etc/nginx/conf/nginx.conf

     

[root@localhost tasks]# vim main.yml

- include: group.yml

- include: user.yml

- include: install.yml

- include: templ.yml

- include: start.yml

       

[root@localhost tasks]# cd ../templates  && ls

nginx.conf.j2

 

[root@localhost tasks]# cd /root/ansible

[root@localhost ansible]# vim nginx_role.yml

- hosts: websrvs

  remote_user: root

  roles:

    - role: nginx

 

执行命令:

[root@localhost ansible]# ansible-playbook nginx_role.yml

5. loop列表循环用法
在ansible 2.5版本以前,大多数人习惯使用"with_X"风格的关键字操做循环,从ansible 2.6版本开始,官方开始推荐使用"loop"关键字代替"with_X"风格关键字。下面经过一些小示例来讲明使用loop关键字进行的列表循环操做。[loop、with_items、with_list 三者等同,效果是同样的!]。ansible的循环使用,能够参考下面"循环变量"以及参考这里

playbook中的变量设置

########   变量的优先级   ########
1.  extra vars变量(在命令行中使用 -e);优先级最高
2.  在inventory中定义的链接变量(好比ansible_ssh_user);优先级第二
3.  大多数的其余变量(命令行转换,play中的变量,include的变量,role的变量等);优先级第三
4.  在inventory定义的其余变量;优先级第四
5.  有系统发现的facts;优先级第五
6.  "role默认变量",这个是最默认的值,很容易丧失优先权。优先级最小。





另外:在inventory清单列表里定义的变量:单个主机定义的变量优先级高于主机组定义的变量
通过实验,ansible使用inventory定义变量的优先级顺序从高到低为:
1. host_vars下定义变量
2. inventory中单个主机定义变量
3. group_vars下定义变量
4. inventory中组定义变量




playbook中定义变量,以下:

1

2

3

- hosts: webservers

  vars:

    http_port: 80

YAML陷阱
YAML语法要求若是值以{{ foo }}开头的话,那么就须要将整行用双引号包起来,这是为了确认你不是想声明一个YAML字典。
以下面配置是不行的!!!

1

2

3

4

---

- hosts: app_servers

  vars:

    app_path: {{ base_path }}/data/web

应该改为下面这样:

1

2

3

4

---

- hosts: app_servers

  vars:

    app_path: "{{ base_path }}/data/web"

########   Ansbile-playbook变量配置方法   ########

1.  在inventory主机清单文件中定义变量
能够直接定义在主机清单文件/etc/ansible/hosts中,代表该变量只对对应的主机或者组有效,对其他的主机和组无效。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

有针对单个主机定义变量和组定义变量两种方式。

1)向不一样的单个主机传递不一样的变量;

IP/HOSTNAME  var1=value1 var2=value2

 

2)向组中的主机传递相同的变量;

[groupname:vars]

var1=value1

var2=value2

 

可是注意:

组定义变量的做用范围是组下的全部主机。

当两种定义方式同时存在时,ansible会优先采用单个主机定义的变量值!

 

[root@ss-server ansible]# pwd

/etc/ansible

[root@ss-server ansible]# cat hosts|egrep -v "^#|^$"

[kevin]

172.16.60.20 key=20180101

172.16.60.22 ansible_ssh_port=22288 key="niubility"

  

[root@ss-server ansible]# cat ansi.yml

---

- hosts: kevin

  gather_facts: False

  tasks:

    - name: haha

      debug: msg="the {{ inventory_hostname }} value is {{ key }}"

  

执行结果(注意inventory_hostname表明inventory列表列表里被控节点的主机名):

[root@ss-server ansible]# ansible-playbook ansi.yml

  

PLAY [kevin] *************************************************************************************************************************************

  

TASK [haha] **************************************************************************************************************************************

ok: [172.16.60.20] => {

    "msg""the 172.16.60.20 value is 20180101"

}

ok: [172.16.60.22] => {

    "msg""the 172.16.60.22 value is niubility"

}

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

172.16.60.22             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

 

再看下面一示例

[root@ss-server ansible]# tail -n 10 /etc/ansible/hosts

[webserver]

172.16.60.51 dir=/root/node2

172.16.60.80 dir=/root/node1

 

[node1]

172.16.60.80

 

[webserver:vars]

file=hostname.txt

 

[root@ss-server ansible]# cat playbook.yml

---

- hosts: webserver

  remote_user: root

  tasks:

    - name: Create New Folder

      file: name={{ dir }} state=directory

    - name: Create New Folder

      shell: echo `hostname` > {{dir}}/{{ file }}

 

执行结果:

[root@ss-server ansible]# ansible-playbook playbook.yml   

 

PLAY [webserver] ************************************************************************

 

TASK [Gathering Facts] ***************************************************************

ok: [172.16.60.80]

ok: [172.16.60.51]

 

TASK [Create New Folder] *************************************************************

changed: [172.16.60.51]

changed: [172.16.60.80]

 

TASK [Create New Folder] *************************************************************

changed: [172.16.60.51]

changed: [172.16.60.80]

 

PLAY RECAP ***************************************************************************

172.16.60.51              : ok=3    changed=2    unreachable=0    failed=0  

172.16.60.80              : ok=3    changed=2    unreachable=0    failed=0

此外:ansible还内置了一些固定的主机变量名,在inventory中定义其值, 在另外一篇文章中介绍过。

2.  经过host_vars和group_vars目录来定义变量
/etc/ansible/目录是linux系统上ansible默认的配置文件目录(Mac系统上的话,其默认配置目录是在/usr/local/etc/ansible/),在该目录下建立host_vars和group_vars两个目录用来存放定义变量的文件。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

1)针对单个主机的变量 

[root@ss-server ansible]# pwd

/etc/ansible

[root@ss-server ansible]# cat host_vars/172.16.60.20

---

user: root

pass: root@123

 

2)针对test组的变量

[root@ss-server ansible]# cat group_vars/kevin

---

user: work

pass: work@123

 

############ 在inventory清单列表文件里,单个主机定义的变量优先级高于主机组定义的变量 ############

############ 通过实验,ansible使用变量的优先级顺序从高到低为 #############

1. host_vars下定义变量

2. inventory中单个主机定义变量

3. group_vars下定义变量

4. inventory中组定义变量

 

示例以下:

[root@ss-server ~]# cat /root/ansible/hosts

[kevin]

172.16.60.20 ansible_ssh_port=22222

172.16.60.21 ansible_ssh_port=22288

 

[root@ss-server ~]# cat /root/ansible/group_vars/kevin

key=20191010

 

[root@ss-server ~]# cat /root/ansible/bo.yml

---

- hosts: kevin

  remote_user: root

  tasks:

    - debug: msg='The key is {{key}} '

 

[root@ss-server ~]# ansible-playbook /root/ansible/bo.yml

  

PLAY [kevin] *************************************************************************************************************************************

  

TASK [haha] **************************************************************************************************************************************

ok: [172.16.60.20] => {

    "msg""The key is 20191010"

}

ok: [172.16.60.22] => {

    "msg""The key is 20191010"

}

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

172.16.60.22             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

3.  经过var_files定义变量

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

[root@ss-server ansible]# cat laoji.yml

---

key: jiayou

 

[root@ss-server ansible]# cat bo.yml

---

- hosts: kevin

  gather_facts: False

  vars_files:

      - laoji.yml

  tasks:

    - name: display

      debug: msg="the {{ inventory_hostname }} valus is {{ key }}"

  

执行结果:

[root@ss-server ansible]# ansible-playbook bo.yml

PALY [kevin] ****************************************************

  

TASK [display] ****************************************************

ok: [172.16.60.20] => {

    "changed"false

    "msg":"the 172.16.60.20 value is jiayou"

}

  

PLAY RECAP ****************************************************

172.16.60.20         : ok=1  changed=0  unreachable=0  failed=0

4.  经过vars_prompt交互式传入变量
在playbook中定义vars_prompt的变量名和交互式提示信息,就能够实如今运行playbook时,经过交互的传入变量值。
private字段:用来定义交互时是否回显输入的值,默认private为yes;
default字段:用来定义变量的默认值。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

[root@ss-server ansible]#  cat prom.yml

---

- hosts: kevin

  remote_user: root

  vars_prompt:

      - name: "var1"

        prompt: "please input you name"

        private: no

      - name: "var2"

        prompt: "please input you age"

        private: yes

        default: 'kevin var'

  tasks:

      - name: display var1

        debug: msg="your name of var1 is {{ var1 }}"

      - name: display var2

        debug: msg="you age of var2 is {{ var2 }}"

  

执行结果:

[root@ss-server ansible]# ansible-playbook prom.yml

your name of var1: wangzhaojun       #把输入的内容传递给变量var1。输入的值显示出来!!

you age of var2 [kevin var]:         #把输入的内容传递给默认变量kevin var。可是输入的值不显示出来!! 好比这里输入的30

  

PALY [kevin] ****************************************************

  

TASK [Gathering Facts] ****************************************************

OK: [172.16.60.20]

  

TASK [display var1] ****************************************************

ok: [172.16.60.20] =>{

    "msg""youn name of var1 is wangzhaojun"

}

  

TASK [display var2] ****************************************************

ok: [172.16.60.20] =>{

    "msg""youn name of var2 is 30"

}

  

PLAY RECAP ****************************************************

172.16.60.20         : ok=3  changed=0  unreachable=0  failed=0

  

接下来再来看一个"ansible 中prompt 交互变量的使用"的示例

[root@ss-server ansible]# cat haha.yml

---

- hosts: kevin

  remote_user: root

  vars_prompt:

     - name: "your_name"

       prompt: "what is your name"

       private: no

     - name: "your_age"

       prompt: "how old are you"

       private: no

     - name: "solution"

       prompt: "Choose the solution you want \n

       A: solutionA\n

       B: solutionB\n

       C: solutionC\n"

       private: no

       default: A

     - name: "user_name"

       prompt: "Enter user name"

       private: no

     - name: "user_password"

       prompt: "Enter user password"

       private: no

       encrypt: "sha512_crypt"

       confirm: yes

  tasks:

     - name: "output vars"

       debug: msg="your name is {{ your_name }},you are {{ your_age }} years old"

     - name: "output solution"

       debug: msg="the final solution is {{solution}}"

     - name: "create_user"

       user:

         name: "{{user_name}}"

         password: "{{user_password}}"

     - name: "debug_create user"

       debug: msg="create user {{user_name}} in"

  

执行结果为:

[root@ss-server ansible]# ansible-playbook haha.yml

what is your name: wangshibo

how old are you: 29

Choose the solution you want

 A: solutionA

 B: solutionB

 C: solutionC

 [A]: C

Enter user name: bobo

Enter user password: bobo123

confirm Enter user password: bobo123

  

PLAY [kevin] *************************************************************************************************************************************

  

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.20]

  

TASK [output vars] *******************************************************************************************************************************

ok: [172.16.60.20] => {

    "msg""your name is wangshibo,you are 29 years old"

}

  

TASK [output solution] ***************************************************************************************************************************

ok: [172.16.60.20] => {

    "msg""the final solution is C"

}

  

TASK [create_user] *******************************************************************************************************************************

changed: [172.16.60.20]

  

TASK [debug_create user] *************************************************************************************************************************

ok: [172.16.60.20] => {

    "msg""create user bobo in"

}

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20                  : ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

5.  经过ansible-playbook命令行定义变量!即参数传入变量
除了"vars_prompt"和"vars_files",也能够经过Ansible命令行发送变量。若是想要编写一个通用的发布playbook时则特别有用!你能够传递应用的版本以便部署。例以下面命令(注意: --extra-vars 相等于 -e)

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

[root@ss-server ~]# ansible-playbook release.yml --extra-vars "version=1.78.34 other_variable=fos"

  

其余场景中,经过参数传入变量也是颇有用的。好比为playbook设置主机群组或用户。以下:

[root@ss-server ~]# vim exap.yml

---

- hosts: '{{hosts}}'

  remote_user: '{{user}}'

  tasks:

    - name: "一个测试"

      debug: msg="your hosts is {{hosts}}, user is {{user}}"

  

执行的时候,经过参数传入变量(-e)。变量{{hosts}}能够是主机群组名称,也能够是主机ip。

[root@ss-server ansible]# ansible-playbook exap.yml -e "hosts=kevin user=root"  

[WARNING]: Found variable using reserved name: hosts

  

  

PLAY [kevin] *************************************************************************************************************************************

  

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.20]

  

TASK [一个测试] **************************************************************************************************************************************

ok: [172.16.60.20] => {

    "msg""your hosts is kevin, user is root"

}

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

  

在命令行里面传值的方法:

[root@ss-server ansible]# ansible-playbook amp.yml --extra-vars "hosts=webserver user=root"

  

还可使用json格式传递参数:

[root@ss-server ansible]# ansible-playbook amp.yml --extra-vars "{'hosts':'webserver', 'user':'root'}"

  

还能够将参数放在文件里面进行传递(注意命令行里要是用"@文件名"):

[root@ss-server ansible]# ansible-playbook amp.yml --extra-vars "@anhui.yml"

[root@ss-server ansible]# cat anhui.yml

---

hosts: webserver

user: root

 

例以下面这个添加用户的plakbook剧本配置,用传递了json文件:

[root@ss-server ansible]# cat useradd.yml

---

- hosts: "{{ host }}"

    gather_facts: no

    remote_user: root

    vars:

      UserName: "{{ user }}"

      UserPassword: "{{ pass }}"

    tasks:

      - name: create new user {{ UserName }}

        user: name={{ UserName }} shell=/bin/bash  password={{ UserPassword |password_hash('sha512') }} update_password=always append=yes

      - name: Config /etc/sudoers

        lineinfile: dest=/etc/sudoers state=present  line='{{ item }}' validate='visudo -cf %s'

        with_items:

          "{{ user }} ALL=(ALL) NOPASSWD:ALL,!/bin/rm,!/bin/su,!/usr/bin/passwd,!/usr/sbin/visudo,!/sbin/shutdown,!/sbin/reboot,!/sbin/halt"

          "Defaults: {{ user }}  !requiretty"

 

[root@ss-server ansible]# ansible-playbook useradd.yml -e "host=172.16.60.20 user=kevin_bo pass=kevin@bo123"

 

在上例中,变量pass是密码,若是变量pass里有特殊的字符,或者变量pass是一串数组的话,它将被转义。若不想被转义,可使用以下方法:

[root@ss-server ansible]# cat user.json

host: webserver                     #ansible里面定义的主机组或者直接配置主机ip,如172.16.60.20

user: kevin_bo                      #添加的用户名

pass: 'Fxx6unM$R%I$Jna&'            #添加的用户的密码,能够用百度上随机密码生成器生成

 

指定user,json文件执行剧本 (使用JSON格式的文件便可,-e 传递变量,优先级最高)

[root@ss-server ansible]# ansible-playbook useradd.yml -e "@user.json"       

 

删除web组中全部用户

[root@ss-server ansible]# ansible webserver -m user -a 'name=zhangsan state=absent remove=yes'

6.  在playbook剧本中定义变量

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

在playbook中定义变量须要用到Ansible的vars模块,能够将全部须要用到的变量统一在vars模块下定义,定义格式须要遵循YAML语言格式:

vars:

  - var1: value1

  - var2: value2

  - var3: value3

  - ....: .....

 

示例以下:

[root@ss-server ansible]# cat playbook.yml

---

- hosts: kevin

  remote_user: root

  vars:

    - dir1: /root/Ansible

    - dir2: /root/Ansible/test1

    - dir3: /root/Ansible/test2

  tasks:

    - name: Create New Folder

      file: name={{ dir1 }} state=directory

    - name: Create New Folder

      file: name={{ dir2 }} state=directory

    - name: Create New Folder

      file: name={{ dir3 }} state=directory

 

[root@ss-server ansible]# ansible-playbook playbook.yml   

 

PLAY [kevin] *************************************************************************

 

TASK [Gathering Facts] ***************************************************************

ok: [172.16.60.20]

 

TASK [Create New Folder] *************************************************************

changed: [172.16.60.20]

 

TASK [Create New Folder] *************************************************************

changed: [172.16.60.20]

 

TASK [Create New Folder] *************************************************************

changed: [172.16.60.20]

 

PLAY RECAP ***************************************************************************

[172.16.60.20]              : ok=4    changed=3    unreachable=0    failed=0

7.  经过roles角色定义变量

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

在Ansible的roles中定义变量,须要将变量及值的键值对形式写到roles的vars目录下的main.yml文件中,一样适用YAML语言格式,格式以下:

var1: value1

var2: value2

var3: value3

 

可是请注意:

经过Roles定义的变量只适用于当前roles。以下是roles文件组织结构:

[root@ss-server roles]# tree test/                 

test/

├── files

├── handlers

├── playbook.retry

├── playbook.yml

├── tasks

│   └── main.yml

├── templates

└── vars

    └── main.yml

5 directories, 4 files

 

[root@ss-server roles]# cat test/tasks/main.yml         #任务文件

- name: Get IP Address

  shell: echo `{{ cmd }}` >> {{ dir }}/{{ file }}

 

[root@ss-server roles]# cat test/vars/main.yml          #定义变量cmd

cmd: hostname -I

 

[root@ss-server roles]# cat test/playbook.yml

---

- hosts: webserver

  remote_user: root

  roles:

    test

 

hosts清单列表里定义的变量,适用于全部roles。

[root@ss-server roles]# cat /etc/ansible/hosts

[webserver]

172.16.60.51 dir=/root/node2

172.16.60.80 dir=/root/node1

 

[node1]

172.16.60.80

 

[webserver:vars]

file=hostname.txt

 

playbook调用Roles,执行结果为:

[root@Centos7T test]#ansible-playbook playbook.yml   

 

PLAY [websvr] ************************************************************************

 

TASK [Gathering Facts] ***************************************************************

ok: [172.16.60.80]

ok: [172.16.60.51]

 

TASK [test : Get IP Address] *********************************************************

changed: [172.16.60.51]

changed: [172.16.60.80]

 

PLAY RECAP ***************************************************************************

172.16.60.51              : ok=2    changed=1    unreachable=0    failed=0  

172.16.60.80              : ok=2    changed=1    unreachable=0    failed=0

8.  使用Facts获取的信息
还有其它地方能够获取变量, 这些变量是自动发现的,而不是用户本身设置的。Facts经过访问远程系统获取相应的信息,一个很好的例子就是远程主机的IP地址或者操做系统是什么。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

使用如下命令能够查看哪些信息是可用的(kevin是上面在/etc/ansible/hosts列表文件中配置的主机群组):

[root@ss-server ansible]# ansible kevin -m setup

  

[root@ss-server ansible]# ansible kevin -m setup|grep "ansible_python_version"

        "ansible_python_version""2.7.5",

能够在playbook中这样引用上面被控制主机的python版本: {{ ansible_python_version }}

  

[root@ss-server ansible]# ansible kevin -m setup|grep "ansible_nodename"

        "ansible_nodename""ss-server",

能够在playbook中这样引用上面被控制主机的主机名: {{ ansible_nodename }}

  

[root@ss-server ansible]# ansible kevin -m setup|grep "ansible_hostname"

        "ansible_hostname""ss-server",

被控制主机的主机名变量还能够是: {{ ansible_hostname }}

 

访问复杂变量数据

有些提供的facts, 好比网络信息等, 是一个嵌套的数据结构。访问它们使用简单的 {{ foo }} 语法并不够用,

可是也仍然很容易.以下所示:

{{ ansible_eth0["ipv4"]["address"] }}

 

或者这样写:

{{ ansible_eth0.ipv4.address }}

  

############ 若是关闭Facts,能够大大提升ansible的执行速度 ###########

关闭方法以下:

[root@ss-server ansible]# cat anhui.yml

---

- hosts: kevin

  gather_facts: no

9.  register注册变量
变量的另外一个主要用途是在运行命令时,把命令结果存储到一个变量中,不一样模块的执行结果是不一样的。运行playbook时使用-v选项能够看到可能的结果值,ansible执行任务的结果值能够保存在变量中,以便稍后使用它。register方式主要用于在task之间传递变量。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

示例以下:

[root@ss-server ansible]# cat /etc/ansible/hosts

[kevin]

172.16.60.237

172.16.60.238

  

[root@ss-server ansible]# cat /root/register.yml

---

- hosts: kevin

  remote_user: root

  tasks:

      - name: register bo_test

        shell: hostname -I

        register: info

      - name: display info

        debug: msg="this host ip is {{ info }}"

  

[root@ss-server ansible]# ansible-playbook /root/register.yml

  

PLAY [kevin] *************************************************************************************************************************************

  

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.238]

ok: [172.16.60.237]

  

TASK [register bo_test] **************************************************************************************************************************

changed: [172.16.60.238]

changed: [172.16.60.237]

  

TASK [display info] ******************************************************************************************************************************

ok: [172.16.60.237] => {

    "msg""this host ip is {'stderr_lines': [], u'changed': True, u'end': u'2019-12-15 22:07:18.431549', 'failed': False, u'stdout': u'172.16.60.237 ', u'cmd': u'hostname -I', u'rc': 0, u'start': u'2019-12-15 22:07:18.408235', u'stderr': u'', u'delta': u'0:00:00.023314', 'stdout_lines': [u'172.16.60.237 ']}"

}

ok: [172.16.60.238] => {

    "msg""this host ip is {'stderr_lines': [], u'changed': True, u'end': u'2019-12-15 22:07:18.430108', 'failed': False, u'stdout': u'172.16.60.238 ', u'cmd': u'hostname -I', u'rc': 0, u'start': u'2019-12-15 22:07:18.407184', u'stderr': u'', u'delta': u'0:00:00.022924', 'stdout_lines': [u'172.16.60.238 ']}"

}

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.237              : ok=3    changed=1    unreachable=0    failed=0 

172.16.60.238              : ok=3    changed=1    unreachable=0    failed=0

  

这里注意下:

register定义的info变量在第二个task中用来查看前一个task中执行的hostname命令的结果。

能够看到playbook运行后的结果中,info返回的是一段python字典数据,若是只想看到stdout部分的信息的话,能够经过info[‘stdout’]来引用。

  

[root@ss-server ansible]# cat /root/register.yml

---

- hosts: kevin

  remote_user: root

  tasks:

      - name: register bo_test

        shell: hostname -I

        register: info

      - name: display info

        debug: msg="this host ip is {{ info['stdout'] }}"

  

[root@ss-server ansible]# ansible-playbook /root/register.yml

  

PLAY [kevin] *************************************************************************************************************************************

  

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.238]

ok: [172.16.60.237]

  

TASK [register bo_test] **************************************************************************************************************************

changed: [172.16.60.237]

changed: [172.16.60.238]

  

TASK [display info] ******************************************************************************************************************************

ok: [172.16.60.237] => {

    "msg""this host ip is 172.16.60.237 "

}

ok: [172.16.60.238] => {

    "msg""this host ip is 172.16.60.238 "

}

  

PLAY RECAP ***************************************************************************************************************************************

172.16.60.237              : ok=3    changed=1    unreachable=0    failed=0 

172.16.60.238              : ok=3    changed=1    unreachable=0    failed=0

10.  hostvars 变量
该变量用于引用其余主机上收集的facts中的数据,或者引用其余主机的主机变量、主机组变量。即从一台远程主机获取另外一台远程主机的变量。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

以下示例:

[root@ss-server ansible]# cat /etc/ansible/hosts

[kevin]

172.16.60.237 addr=beijing

172.16.60.238 user=shibo age=39

 

[root@ss-server ansible]# cat test.yml

---

- hosts: kevin

  remote_user: root

  gather_facts: False

  tasks:

    - name: this is test1

      debug: msg="She is come from {{ hostvars['172.16.60.237']['addr'] }}"

    - name: this is test2

      debug: msg="I am {{ hostvars['172.16.60.238']['user'] }}, and age is {{ hostvars['172.16.60.238']['age'] }}"

 

或者将test.yml文件配置以下,即由 "[变量]"" 改成 ".变量"

两种配置的执行结果都是同样的!

[root@ss-server ansible]# cat test.yml

---

- hosts: kevin

  remote_user: root

  gather_facts: False

  tasks:

    - name: this is test1

      debug: msg="She is come from {{ hostvars['172.16.60.237'].addr }}"

    - name: this is test2

      debug: msg="I am {{ hostvars['172.16.60.238'].user }}, and age is {{ hostvars['172.16.60.238'].age }}"

 

执行结果为:

[root@ss-server ansible]# ansible-playbook test.yml            

 

PLAY [kevin] *************************************************************************************************************************************

 

TASK [this is test1] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "msg""She is come from beijing"

}

ok: [172.16.60.238] => {

    "msg""She is come from beijing"

}

 

TASK [this is test2] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "msg""I am shibo, and age is 39"

}

ok: [172.16.60.238] => {

    "msg""I am shibo, and age is 39"

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.237              : ok=2    changed=0    unreachable=0    failed=0  

172.16.60.238              : ok=2    changed=0    unreachable=0    failed=0 

 

 

############################# 这里须要注意下 ###########################

除了上面的配置,还能够以下配置,可是请注意:

1)debug后面必须使用"var"字段,即hostvar变量传递给var字段的变量。

2)var=hostvars[....],等于两边不能有空格!

 

[root@ss-server ansible]# cat test.yml

---

- hosts: kevin

  remote_user: root

  gather_facts: False

  tasks:

    - name: this is test1

      debug: var=hostvars['172.16.60.237']['addr']

    - name: this is test2

      debug: var=hostvars['172.16.60.238']['user']

 

或者将test.yml文件配置以下,这两个配置方法的执行结果是同样的!

[root@ss-server ansible]# cat test.yml

---

- hosts: kevin

  remote_user: root

  gather_facts: False

  tasks:

    - name: this is test1

      debug: var=hostvars['172.16.60.237'].addr

    - name: this is test2

      debug: var=hostvars['172.16.60.238'].user

 

执行结果为:

[root@ss-server ansible]# ansible-playbook test.yml

 

PLAY [kevin] *************************************************************************************************************************************

 

TASK [this is test1] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "hostvars['172.16.60.237']['addr']""beijing"

}

ok: [172.16.60.238] => {

    "hostvars['172.16.60.237']['addr']""beijing"

}

 

TASK [this is test2] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "hostvars['172.16.60.238']['user']""shibo"

}

ok: [172.16.60.238] => {

    "hostvars['172.16.60.238']['user']""shibo"

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.237              : ok=2    changed=0    unreachable=0    failed=0  

172.16.60.238              : ok=2    changed=0    unreachable=0    failed=0

 

注意:若是同一个name里配置了多个debug,则默认执行最后一个debug内容! (多个task的话,也是执行最后一个task)

[root@ss-server ansible]# cat test.yml

---

- hosts: kevin

  remote_user: root

  gather_facts: False

  tasks:

    - name: this is test1

      debug: var=hostvars['172.16.60.237']['addr']

    - name: this is test2

      debug: var=hostvars['172.16.60.238']['user']

      debug: var=hostvars['172.16.60.238']['age']

 

执行结果:

[root@ss-server ansible]# ansible-playbook test.yml

 [WARNING]: While constructing a mapping from /etc/ansible/test.yml, line 8, column 7, found a duplicate dict key (debug). Using last defined

value only.

 

 

PLAY [kevin] *************************************************************************************************************************************

 

TASK [this is test1] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "hostvars['172.16.60.237']['addr']""beijing"

}

ok: [172.16.60.238] => {

    "hostvars['172.16.60.237']['addr']""beijing"

}

 

TASK [this is test2] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "hostvars['172.16.60.238']['age']""39"

}

ok: [172.16.60.238] => {

    "hostvars['172.16.60.238']['age']""39"

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.237              : ok=2    changed=0    unreachable=0    failed=0  

172.16.60.238              : ok=2    changed=0    unreachable=0    failed=0

11. 列表变量、循环变量、字典变量

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

1)ansible的变量不只能够是单个的值,也能够为列表,即ansible传列表做为变量。以下示例:

#################################################################################################################

[root@ss-server ansible]# vim test.yml

---

- hosts: test_host

  gather_facts: no

  vars:

    - list: [1,2,3]

  tasks:

    - name: echo

      debug: msg="{{ list }}"

 

执行结果:

[root@ss-server ansible]# ansible-palybook test.yml

TASK [echo] ********************************************************************

ok: [172.16.60.220] => {

    "msg": [

        1,

        2,

        3

    ]

}

 

再来看一例:

linux建立用户,须要获取的变量有用户名,用户密码,用户组,有时候须要建立多个用户,那么传递给ansible的用户确定是列表,但每一组又有用户名、密码、组这些变量值。

作法以下:

[root@ss-server ~]# cat /etc/ansible/test.yml

---

- hosts: test_host

  gather_facts: no

  tasks:

   - name: create or update account

     user: name={{ item.user }} password={{ item.password }} groups={{ item.group }} system=no

     with_items:

       -  '{{ user_list }}'

 

执行结果:

[root@ss-server ansible]# ansible-playbook /etc/ansible/test.yml -e '{"user_list":[{"user":"user1","password":"*******","group":"user1"}]}'

 

#################################################################################################################

2)循环列表

结合循环,这个特性就变得颇有用;以参数传递列表给playbook,不用在playbook中固定循环的次数与内容。以下示例:

[root@ss-server ansible]# vim test.yml

---

- hosts: test_host

  gather_facts: no

  vars:

    - list: [1,2,3]

  tasks:

    - name: this is loop

      debug: msg="{{ item }}"

      with_items: '{{list}}'

 

执行结果:

[root@ss-server ansible]# ansible-palybook test.yml

TASK [this is loop] ********************************************************************

ok: [172.16.60.220] => (item=1) => {

    "item": 1,

    "msg": 1

}

ok: [localhost] => (item=2) => {

    "item": 2,

    "msg": 2

}

ok: [localhost] => (item=3) => {

    "item": 3,

    "msg": 3

}

 

接着看下面一例:

loop 关键字表示循环,去读循环体里的变量固定使用{{item}},item是个字典对象item.key=value。

须要注意:下面test.yml文件中的"loop"关键字 改成 "with_items"关键字,效果是同样的!

ansible的循环用法:在ansible 2.5版本以前,大多数人习惯使用"with_X"风格的关键字操做循环,

从ansible 2.6版本开始,官方开始推荐使用"loop"关键字代替"with_X"风格关键字。

[root@ss-server ~]# cat /etc/ansible/test.yml

---

- name: this is test

  hosts: test_host

  connection: local

  gather_facts: no

 

  tasks:

    - name: debug loop

      debug:

        msg: "{{item.A1}}"

      loop:                      #这里将"loop"关键字 改成 "with_items"关键字,效果是同样的!

        - A: a

          A1: a1

          A2: a2

        - B: b

          A1: b1

          A2: b2

        - C: c

          A1: c1

          A2: c2

        - D: d

          A1: d1

          A2: d2

 

执行结果:以上loop下的四个变量分别称为一块,即一个item,符号"-"为循环体块的标志,{{item.A1}}的值,即分别为a1,b1,c1,d1

[root@ss-server ~]# ansible-playbook /etc/ansible/test.yml

 

PLAY [this is test] *********************************************************************************************************************************

 

TASK [debug loop] ********************************************************************************************************************************

ok: [172.16.60.20] => (item={u'A': u'a', u'A1': u'a1', u'A2': u'a2'}) => {

    "msg""a1"

}

ok: [172.16.60.20] => (item={u'A1': u'b1', u'B': u'b', u'A2': u'b2'}) => {

    "msg""b1"

}

ok: [172.16.60.20] => (item={u'A1': u'c1', u'C': u'c', u'A2': u'c2'}) => {

    "msg""c1"

}

ok: [172.16.60.20] => (item={u'A1': u'd1', u'A2': u'd2', u'D': u'd'}) => {

    "msg""d1"

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

 

再来看一例:

[root@ss-server ~]# cat /etc/ansible/test.yml

---

- name: this is test

  hosts: test_host

  connection: local

  gather_facts: no

  vars:

    my_list:

      - a

      - b

      - c

      - 1

 

  tasks:

    - name: debug loop output

      debug:

        msg: "The {{index}} one is {{item}}"

      loop: "{{my_list}}"               # 或者使用with_items: "{{my_list}}"  或者 with_list: "{{my_list}}"

      loop_control:

        index_var: index

 

执行结果:

[root@ss-server ~]# ansible-playbook /etc/ansible/test.yml

 

PLAY [this is test] ******************************************************************************************************************************

 

TASK [debug loop output] *************************************************************************************************************************

ok: [172.16.60.20] => (item=a) => {

    "msg""The 0 one is a"

}

ok: [172.16.60.20] => (item=b) => {

    "msg""The 1 one is b"

}

ok: [172.16.60.20] => (item=c) => {

    "msg""The 2 one is c"

}

ok: [172.16.60.20] => (item=1) => {

    "msg""The 3 one is 1"

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

 

#################################################################################################################

3)字典变量

变量也能够为字典。以下示例, 用到了ansible的循环,循环关键字是"with_X", 改成loop关键字,效果是同样的!

注意:在变量中使用循环时,vars下必需要有"-",符号"-"为循环体块的标志!!

[root@ss-server ansible]# vim test.yml

---

- hosts: test_host

  gather_facts: no

  vars:

    - lists:

        list1: [1,2,3]

        list2: [4,5]

  tasks:

    - name: loop

      debug: msg="{{ item }}"

      with_items: '{{lists["list1"]}}'        #替换为 loop: '{{lists["list1"]}}', 或者 with_list: '{{lists["list1"]}}' 效果是同样的

 

执行结果:

[root@ss-server ansible]# ansible-palybook test.yml

TASK [loop] ********************************************************************

ok: [172.16.60.220] => (item=1) => {

    "item": 1,

    "msg": 1

}

ok: [localhost] => (item=2) => {

    "item": 2,

    "msg": 2

}

ok: [localhost] => (item=3) => {

    "item": 3,

    "msg": 3

}

 

接着看下面一例:

[root@ss-server ~]# cat /etc/ansible/test.yml

---

- hosts: test_host

  gather_facts: no

  vars:

    users:

        name: [xiaoming]

        address: [anhui]

        age: [28]

  tasks:

    - name: this is loop

      debug: msg="{{ item }}"

      loop: '{{users["name"]}}'       

[root@ss-server ~]# ansible-playbook /etc/ansible/test.yml

 

PLAY [test_host] *************************************************************************************************************************************

 

TASK [this is loop] **************************************************************************************************************************************

ok: [172.16.60.20] => (item=xiaoming) => {

    "msg""xiaoming"

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

 

上面的示例,若是要想打印多个字典变量,修改以下:

[root@ss-server ~]# cat /etc/ansible/test.yml

---

- hosts: test_host

  gather_facts: no

  vars:

    users:

        name: [xiaoming]

        address: [anhui]

        age: [28]

  tasks:

    - name: this is loop

      debug: msg="{{ item }}"

      loop:                         #这里用loop,with_items,with_list均可以

         '{{users["name"]}}'   

         '{{users["address"]}}'

         '{{users["age"]}}'

 

执行结果:

[root@ss-server ~]# ansible-playbook /etc/ansible/test.yml

 

PLAY [test_host] *********************************************************************************************************************************

 

TASK [this is loop] ******************************************************************************************************************************

ok: [172.16.60.20] => (item=[u'xiaoming']) => {

    "msg": [

        "xiaoming"

    ]

}

ok: [172.16.60.20] => (item=[u'anhui']) => {

    "msg": [

        "anhui"

    ]

}

ok: [172.16.60.20] => (item=[28]) => {

    "msg": [

        28

    ]

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.20                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

######   能够在一个yaml文件里放置多个hosts,将多个tasks任务一块儿执行   ########

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

[root@ss-server ansible]# cat /etc/ansible/hosts

172.16.60.237

[kevin]

172.16.60.238

[grace]

172.16.60.236

 

[root@ss-server ansible]# cat bo.yml           

---

- hosts: kevin

  remote_user: root

  gather_facts: False

  tasks:

    - name: this is test1

      shell: hostname -I

 

- hosts: 172.16.60.237

  remote_user: root

  tasks:

    - name: this is test2

      debug: msg="this server is {{ info }} "

 

- hosts: 172.16.60.238

  remote_user: root

  tasks:

    - name: this is test3

      debug: msg="this key is {{ haha }} "

 

执行结果:

[root@ss-server ansible]# ansible-playbook bo.yml -e "{'info':'my server','haha':'123123213123'}" 

 

PLAY [kevin] *************************************************************************************************************************************

 

TASK [this is test1] *****************************************************************************************************************************

changed: [172.16.60.238]

 

PLAY [172.16.60.237] *****************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.237]

 

TASK [this is test2] *****************************************************************************************************************************

ok: [172.16.60.237] => {

    "msg""this server is my server "

}

 

PLAY [172.16.60.238] *****************************************************************************************************************************

 

TASK [Gathering Facts] ***************************************************************************************************************************

ok: [172.16.60.238]

 

TASK [this is test3] *****************************************************************************************************************************

ok: [172.16.60.238] => {

    "msg""this key is 123123213123 "

}

 

PLAY RECAP ***************************************************************************************************************************************

172.16.60.237              : ok=2    changed=0    unreachable=0    failed=0  

172.16.60.238              : ok=3    changed=1    unreachable=0    failed=0

 

 

############# 再来看下面一个测试环境用过的部署脚本配置 #########################

[root@localhost ansible]# cat /opt/ansible_cfg/deploy.yml

---

- hosts: webservers

  tasks:

    - name: Installed Httpd Server

      yum: name=httpd state=present

 

    - name: Start Httpd Server

      systemd: name=httpd state=started enabled=yes

 

    - name: Start Firewalld Server

      systemd: name=firewalld state=started enabled=yes

 

    - name: Configure Firewalld Server

      firewalld: service=http immediate=yes permanent=yes state=enabled

 

- hosts: web01

  tasks:

    - name: Configure web01 Website

      copy: content='This is Web01' dest=/var/www/html/index.html

 

- hosts: web02

  tasks:

    - name: Cofnigure webi-2 weisite

      copy: content='This is Web02' dest=/var/www/html/index.html

 

- hosts: nfs01

  tasks:

    - name: Install NFS-utils Server

      yum: name=nfs-utils state=present

 

    - name: Configure Nfs-utils Server

      copy: src=./exports.j2 dest=/etc/exports owner=root group=root mode=0644

 

    - name: Create NFS Group

      group: name=www gid=666

 

    - name: Create NFS User

      user: name=www uid=666 group=www create_home=no shell=/sbin/nologin

 

    - name: Create Data Directory

      file: path=/data state=directory owner=www group=www mode=0755 recurse=yes

 

    - name: Start NFS Server

      systemd: name=nfs state=started enabled=yes

 

- hosts: nfs01

  tasks:

    - name: Mount NFS Server

      mount: path=/opt src=172.16.60.23:/data fstype=nfs opts=defaults state=mounted

######   Ansible-playbook如何正确获取ip   ######

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

[root@ansible ~]# vim /etc/ansible/hosts_all.yaml

---

- hosts: all

  tasks:      

    - name: 将原有的hosts文件备份        

      shell: mv /etc/hosts /etc/hosts_bak      

    - name: 将ansible端的hosts复制到各自机器上        

      copy: src=/root/hosts dest=/etc/ owner=root group=root mode=0644      

    - name: 在新的hosts文件后面追加各自机器内网ip和hostname        

      lineinfile: dest=/etc/hosts line="`ansible_all_ipv4_addresses`  `ansible_hostname`"

  

可是执行完ansible-playbook以后,ansible客户机器上的/etc/hosts文件里ip和主机名对应关系以下(cat /etc/hosts):

  

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4

::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

[u'172.16.60.210'] redis-fun01.kevin.cn

  

实际想要的结果是(cat /etc/hosts):

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4

::1         localhost localhost.localdomain localhost6 localhost6.localdomain6

172.16.60.210 redis-fun01.kevin.cn

  

解决办法:

调整ansible服务端的hosts_all.yaml文件中获取ip的变量

变量用 IP: "{{ ansible_eth0['ipv4']['address'] }}",而不是`ansible_all_ipv4_addresses`

  

修改后的yaml文件配置以下:

[root@ansible ~]# vim /etc/ansible/hosts_all.yaml

---

- hosts: all

  vars:      

    IP: "{{ ansible_eth0['ipv4']['address'] }}"

  tasks:      

    - name: 将原有的hosts文件备份        

      shell: mv /etc/hosts /etc/hosts_bak      

    - name: 将ansible端的hosts复制到各自机器上        

      copy: src=/root/hosts dest=/etc/ owner=root group=root mode=0644      

    - name: 在新的hosts文件后面追加各自机器内网ip和hostname        

      lineinfile: dest=/etc/hosts line="`IP`  `ansible_hostname`"

########  获取ansible清单列表里对应组的ip、指定机器执行操做 [ --list-hosts、--limit ]  ########

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

注意下面两个参数的使用:

1)获取hosts清单文件里指定组内的ip,使用"--list-hosts"

2)指定hosts清单文件里的ip执行操做,使用"--limit"

  

以下是ansible的一个清单文件:

[root@localhost ~]# cat /opt/kevin-bo.cfg

[kevin-bo_F]

172.16.60.65

  

[kevin-bo_A]

172.16.60.140

172.16.60.141

  

[kevin-bo:children]

kevin-bo_D

kevin-bo_F

kevin-bo_A

  

[kevin-bo:vars]

deploy_path=/opt/web/kevin-bo/

start_time_out=90

stop_time_out=60

module=kevin-bo

  

[kevin-bo_D]

172.16.60.195

  

如今须要获取"kevin-bo_A" 和 "kevin-bo_D" 组下的ip,--list-hosts后面加不加引号均可以。

[root@localhost ~]# ansible -i /opt/kevin-bo.cfg --list-hosts kevin-bo_A

  hosts (2):

    172.16.60.140

    172.16.60.141

[root@localhost ~]# ansible -i /opt/kevin-bo.cfg --list-hosts "kevin-bo_A"|grep -v "hosts"

    172.16.60.140

    172.16.60.141

[root@localhost ~]# ansible -i /opt/kevin-bo.cfg --list-hosts kevin-bo_D|grep -v "hosts"

    172.16.60.195

 

获取多个机器组内的ip,中间使用逗号隔开

[root@localhost ~]# ansible -i /opt/kevin-bo.cfg --list-hosts "kevin-bo_A,kevin-bo_D"

  hosts (3):

    172.16.60.140

    172.16.60.141

    172.16.60.195

 

[root@localhost ~]# ansible -i /opt/kevin-bo.cfg --list-hosts "kevin-bo_A,kevin-bo_D"|grep -v "hosts"

    172.16.60.140

    172.16.60.141

    172.16.60.195

  

在执行ansible-playbook时,能够指定单个ip或group,也能够指定多个ip或group,也能够一块儿指定ip和group,多个中间使用逗号隔开!

--limit后面加不加引号均可以。

# ansible-playbook -i 清单文件 yml文件 --limit ip

# ansible-playbook -i 清单文件 yml文件 --limit ip1,iP2,ipn

# ansible-playbook -i 清单文件 yml文件 --limit group

# ansible-playbook -i 清单文件 yml文件 --limit group1,group2,groupn

# ansible-playbook -i 清单文件 yml文件 --limit ip1,ip2,group1,groupn

还能够将制定的ip或group放在一个文件里,如ip.txt,而后--limit后面跟"@ip.txt"

# ansible-playbook -i 列表文件 yml文件 --limit @ip.txt  

# cat ip.txt

172.16.60.140

172.16.60.141

kevin-bo_F

  

如上,须要对清单文件"kevin-bo_A"组下的机器进行发布操做,因为发布过程当中涉及服务启停,为了保证发布中总体服务不中断,须要一台一台的执行,不能全部机器一块儿执行。以下:

[root@localhost ~]# vim deploy.sh

#!/bin/bash

#设置变量,传参等

BRANCH=$1

MODULE_NAME=$2

PRODUCT_PATH=$3

USER=$4

APP_NANE=${Deploy_App}

.....

  

for Next_Deploy_IP in $(ansible -i /opt/kevin-bo.cfg --list-hosts kevin-bo_A|grep -v "hosts")

do

   ansible-playbook -i /opt/kevin-bo.cfg /root/ansible/web_deploy.yml --limit "${Next_Deploy_IP}" -e "user=${USER} app_name=${APP_NANE} package_name=... ..."

   if [ $? -eq 0 ];then

      echo "[`date +%Y%m%d-%H%M%S`]++++++++++++++++++++++++${Next_Deploy_IP}部署成功!++++++++++++++++++++++++++++++"

      sleep 10

   else

      echo "[`date +%Y%m%d-%H%M%S`]++++++++++++++++++++++++${Next_Deploy_IP}部署失败!++++++++++++++++++++++++++++++"

      exit 1

   fi

done

相关文章
相关标签/搜索