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

相關文章
相關標籤/搜索