Ansibleplaybook编程

编程

 

Ansible playbook 编程详解与各种小案例

 

主机规划

 

添加用户账号

说明:

1、 运维人员使用的登录账号;

2、 所有的业务都放在 /app/ 下「yun用户的家目录」,避免业务数据乱放;

3、 该用户也被 ansible 使用,因为几乎所有的生产环境都是禁止 root 远程登录的(因此该 yun 用户也进行了 sudo 提权)。

1# 使用一个专门的用户,避免直接使用root用户

2# 添加用户、指定家目录并指定用户密码

3# sudo提权

4# 让其它普通用户可以进入该目录查看信息

5 useradd -u 1050 -d /app yun && echo"123456" | /usr/bin/passwd --stdin yun

6echo"yun ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

7chmod755 /app/

 

Ansible 配置清单Inventory

之后文章都是如下主机配置清单

 1 [yun@ansi-manager ansible_info]$ pwd

2 /app/ansible_info

3 [yun@ansi-manager ansible_info]$ cat hosts_key

4 # 方式1、主机 + 端口 + 密钥

5[manageservers]

6172.16.1.180:22

7

8[proxyservers]

9172.16.1.18[1:2]:22

10

11 # 方式2:别名 + 主机 + 端口 + 密码

12[webservers]

13 web01 ansible_ssh_host=172.16.1.183 ansible_ssh_port=22

14 web02 ansible_ssh_host=172.16.1.184 ansible_ssh_port=22

15 web03 ansible_ssh_host=172.16.1.185 ansible_ssh_port=22

 

条件判断-when

when 判断在 ansible 任务中的使用频率非常高。

例如判断主机是否已经安装指定的软件包;对机器的操作系统进行判断然后再根据不同的方法「yum或apt等」进行软件包安装;根据操作系统的版本判断进行软件包的安装「是安装MySQL还是Mariadb」等。

示例:根据主机名的不同,下载不同的文件

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 4

5 -rw-rw-r-- 1 yun yun 950 Oct 2610:22 test_when.yml

6 [yun@ansi-manager object04]$ cat test_when.yml

7 ---

8 # 根据 hostname 的不同下载不同的图片

9# 特殊组 all,对所有机器有效

10 - hosts: all

11

12 tasks:

13 - name: "download picture jvm-01-01.png"

14 get_url:

15 url: http://www.zhangblog.com/uploads/jvm/jvm-01-01.png

16 dest: /tmp/

17 when: ansible_hostname == "ansi-haproxy01"

18

19 - name: "download picture jvm-01-02.png"

20 get_url:

21 url: http://www.zhangblog.com/uploads/jvm/jvm-01-02.png

22 dest: /tmp/

23 when: ansible_hostname == "ansi-haproxy02"

24

25 - name: "other download picture jvm-01-03.png"

26 get_url:

27 url: http://www.zhangblog.com/uploads/jvm/jvm-01-03.png

28 dest: /tmp/

29 # 从 facts 中获取的变量,ansible_facts["ansible_hostname"] != "ansi-haproxy01" 错误写法;ansible_hostname != "ansi-haproxy01" 正确写法

30 #when: (ansible_hostname != "ansi-haproxy01") and (ansible_hostname != "ansi-haproxy02") # 写法一

31 #或者如下3行 列表之间关系是 (and 与) 等同于上一行

32 #when:

33 # - ansible_hostname != "ansi-haproxy01"

34 # - ansible_hostname != "ansi-haproxy02"

35 #when: ansible_hostname is not match "ansi-haproxy0*" # 写法二

36 when: (ansible_hostname is match "ansi-manager") or (ansible_hostname is match "ansi-web*") # 写法三

37

38 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_when.yml # 语法检测

39 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_when.yml # 预执行,测试执行

40 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_when.yml # 执行

41

42 PLAY [all] *******************************************************************************************************

43

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

45ok: [web01]

46ok: [web02]

47ok: [web03]

48 ok: [172.16.1.180]

49 ok: [172.16.1.181]

50 ok: [172.16.1.182]

51

52 TASK [download picture jvm-01-01.png] ****************************************************************************

53 skipping: [172.16.1.180]

54skipping: [web01]

55skipping: [web02]

56skipping: [web03]

57 skipping: [172.16.1.182]

58 changed: [172.16.1.181]

59

60 TASK [download picture jvm-01-02.png] ****************************************************************************

61 skipping: [172.16.1.180]

62skipping: [web01]

63skipping: [web02]

64skipping: [web03]

65 skipping: [172.16.1.181]

66 changed: [172.16.1.182]

67

68 TASK [other download picture jvm-01-03.png] **********************************************************************

69 skipping: [172.16.1.181]

70 skipping: [172.16.1.182]

71changed: [web02]

72changed: [web01]

73 changed: [172.16.1.180]

74changed: [web03]

75

76 PLAY RECAP *******************************************************************************************************

77172.16.1.180 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

78172.16.1.181 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

79172.16.1.182 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

80 web01 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

81 web02 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

82 web03 : ok=2 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

 

标准循环

注意:

1、循环语法有两种:loop 和 with_。

2、loop 是在ansible 2.5 添加的,with_ 是一直存在的,推荐使用 loop。在未来 with_ 可能被弃用。

简单列表循环

如果我们需要在 playbook 中启动多个服务,或者下载多个文件;按照之前所学的,那么我们需要写多个 task。但这样会使得 playbook 变得臃肿,因此这时我们就需要引进循环了。

示例:一次启动多个服务,下载多个文件

使用 loop 方式【推荐】

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 20

5 -rw-rw-r-- 1 yun yun 594 Aug 2322:10 test_loop.yml

6 [yun@ansi-manager object04]$ cat test_loop.yml

7 ---

8# 启动多个服务 和下载多个文件

9 - hosts: proxyservers

10

11 tasks:

12 - name: "start httpd, rpcbind, network server"

13 service:

14 name: "{{ item }}" # 需要用引号引起来

15 state: started

16 loop:

17 - httpd

18 - rpcbind

19 - network

20

21 - name: "download multiple file"

22 get_url:

23 url: "{{ item }}" # 需要用引号引起来

24 dest: /tmp/

25 loop:

26 - http://www.zhangblog.com/uploads/jvm/jvm-01-01.png

27 - http://www.zhangblog.com/uploads/jvm/jvm-01-02.png

28 - http://www.zhangblog.com/uploads/jvm/jvm-01-03.png

29

30 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_loop.yml # 语法检测

31 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_loop.yml # 预执行,测试执行

32 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_loop.yml # 执行

 

备注:以上方法可用在 yum 模块中。

使用 with_items 方式

其中 playbook 文件中仅把 loop 变为了 with_items。

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 20

5 -rw-rw-r-- 1 yun yun 594 Aug 2322:10 test_with_items.yml

6 [yun@ansi-manager object04]$ cat test_with_items.yml

7 ---

8# 启动多个服务 和下载多个文件

9 - hosts: proxyservers

10

11 tasks:

12 - name: "start httpd, rpcbind, network server"

13 service:

14 name: "{{ item }}" # 需要用引号引起来

15 state: started

16 with_items:

17 - httpd

18 - rpcbind

19 - network

20

21 - name: "download multiple file"

22 get_url:

23 url: "{{ item }}" # 需要用引号引起来

24 dest: /tmp/

25 with_items:

26 - http://www.zhangblog.com/uploads/jvm/jvm-01-01.png

27 - http://www.zhangblog.com/uploads/jvm/jvm-01-02.png

28 - http://www.zhangblog.com/uploads/jvm/jvm-01-03.png

29

30 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_with_items.yml # 语法检测

31 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_with_items.yml # 预执行,测试执行

32 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_with_items.yml # 执行

 

如果用在 yum 模块中则会报如下弃用告警,因此该方法不适用于 yum 模块。

 

遍历哈希列表

如果我们需要创建多个用户并且每个用户都有指定的附加组;或者要创建多个文件,每个文件属主、属组、权限不一样;或者需要拷贝文件,但是每个文件的位置不一样,且属主、属组、权限不一样等等;那之前所学的简单循环就不能满足我们的需求了。这时「哈希列表循环」就闪亮登场了。

示例:

使用 loop 方式【推荐】

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 16

5 drwxrwxr-x 2 yun yun 56 Oct 2616:03file

6 -rw-rw-r-- 1 yun yun 1205 Oct 2616:02 test_loop_hash.yml

7 [yun@ansi-manager object04]$ catfile/config_test.conf.j2

8111

9 [yun@ansi-manager object04]$ catfile/yml_test_j2.yml

10222

11 [yun@ansi-manager object04]$ cat test_loop_hash.yml

12 ---

13# 使用循环字典创建多个用户,创建多个文件,拷贝多个文件

14 - hosts: proxyservers

15

16 tasks:

17 - name: "Create multiple user"

18 user:

19 name: "{{ item.user }}"

20groups: "{{ item.groups }}"

21 loop:

22 - { user: "testuser1", groups: "root" }

23 - { user: "testuser2", groups: "root,yun" }

24

25 - name: "Create multiple file or dir"

26file:

27 path: "{{ item.path }}"

28 owner: "{{ item.owner }}"

29 group: "{{ item.group }}"

30 mode: "{{ item.mode }}"

31 state: "{{ item.state }}"

32 loop:

33 - { path: "/tmp/with_items_testdir", owner: "yun", group: "root", mode: "755", state: "directory" }

34 - { path: "/tmp/with_items_testfile", owner: "bin", group: "bin", mode: "644", state: "touch" }

35

36 - name: "copy multiple file"

37 copy:

38 src: "{{ item.src }}"

39 dest: "{{ item.dest }}"

40 owner: "{{ item.owner }}"

41 group: "{{ item.group }}"

42 loop:

43 - { src: "./file/config_test.conf.j2", dest: "/tmp/with_items_testdir/", owner: "yun", group: "root" }

44 - { src: "./file/yml_test_j2.yml", dest: "/tmp/yml_test.yml", owner: "yun", group: "yun" }

45

46 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_loop_hash.yml # 语法检测

47 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_loop_hash.yml # 预执行,测试执行

48 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_loop_hash.yml # 执行

 

使用 with_items 方式

其中 playbook 文件中仅把 loop 变为了 with_items。

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 16

5 drwxrwxr-x 2 yun yun 56 Oct 2616:03file

6 -rw-rw-r-- 1 yun yun 1205 Oct 2616:02 test_with_items_hash.yml

7 [yun@ansi-manager object04]$ catfile/config_test.conf.j2

8111

9 [yun@ansi-manager object04]$ catfile/yml_test_j2.yml

10222

11 [yun@ansi-manager object04]$ cat test_with_items_hash.yml

12 ---

13# 使用循环字典创建多个用户,创建多个文件,拷贝多个文件

14 - hosts: proxyservers

15

16 tasks:

17 - name: "Create multiple user"

18 user:

19 name: "{{ item.user }}"

20groups: "{{ item.groups }}"

21 with_items:

22 - { user: "testuser1", groups: "root" }

23 - { user: "testuser2", groups: "root,yun" }

24

25 - name: "Create multiple file or dir"

26file:

27 path: "{{ item.path }}"

28 owner: "{{ item.owner }}"

29 group: "{{ item.group }}"

30 mode: "{{ item.mode }}"

31 state: "{{ item.state }}"

32 with_items:

33 - { path: "/tmp/with_items_testdir", owner: "yun", group: "root", mode: "755", state: "directory" }

34 - { path: "/tmp/with_items_testfile", owner: "bin", group: "bin", mode: "644", state: "touch" }

35

36 - name: "copy multiple file"

37 copy:

38 src: "{{ item.src }}"

39 dest: "{{ item.dest }}"

40 owner: "{{ item.owner }}"

41 group: "{{ item.group }}"

42 with_items:

43 - { src: "./file/config_test.conf.j2", dest: "/tmp/with_items_testdir/", owner: "yun", group: "root" }

44 - { src: "./file/yml_test_j2.yml", dest: "/tmp/yml_test.yml", owner: "yun", group: "yun" }

45

46 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_with_items_hash.yml # 语法检测

47 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_with_items_hash.yml # 预执行,测试执行

48 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_with_items_hash.yml # 执行

 

遍历字典

示例:

使用 loop 方式【推荐】

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 28

5 -rw-rw-r-- 1 yun yun 452 Oct 2616:46 test_loop_dict.yml

6 [yun@ansi-manager object04]$ cat test_loop_dict.yml

7 ---

8# 打印信息

9 - hosts: manageservers

10 vars:

11 users:

12 alice:

13 name: Alice Appleworth

14 telephone: 123-456-7890

15 bob:

16 name: Bob Bananarama

17 telephone: 987-654-3210

18

19 tasks:

20 - name: "print user info"

21 debug:

22 msg: "User {{ item.key }}, userfullname: {{ item.value.name }} ({{ item.value.telephone }})"

23 # 将字典转换为适合循环的项表 第一种方式推荐

24 loop: "{{ users|dict2items }}"

25 #loop: "{{ lookup("dict", users) }}"

26

27 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_loop_dict.yml # 语法检测

28 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_loop_dict.yml # 预执行,测试执行

29 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_loop_dict.yml # 执行

 

使用 with_items 方式

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 28

5 -rw-rw-r-- 1 yun yun 458 Oct 2616:47 test_with_items_dict.yml

6 [yun@ansi-manager object04]$ cat test_with_items_dict.yml

7 ---

8# 打印信息

9 - hosts: manageservers

10 vars:

11 users:

12 alice:

13 name: Alice Appleworth

14 telephone: 123-456-7890

15 bob:

16 name: Bob Bananarama

17 telephone: 987-654-3210

18

19 tasks:

20 - name: "print user info"

21 debug:

22 msg: "User {{ item.key }}, userfullname: {{ item.value.name }} ({{ item.value.telephone }})"

23 # with_dict 会直接解析字典

24 with_dict: "{{ users }}"

25

26 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_with_items_dict.yml # 语法检测

27 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_with_items_dict.yml # 预执行,测试执行

28 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_with_items_dict.yml # 执行

 

变量循环-vars

针对yum 安装多个包很有用,其他则会报出警告。

 1 [yun@ansi-manager object04]$ pwd

2 /app/ansible_info/object04

3 [yun@ansi-manager object04]$ ll

4 total 36

5 -rw-rw-r-- 1 yun yun 252 Oct 2617:46 test_cycle_vars.yml

6 [yun@ansi-manager object04]$ cat test_cycle_vars.yml

7 ---

8# 批量包安装

9 - hosts: proxyservers

10

11 tasks:

12 - name: "Install multiple packages"

13yum:

14 name: "{{ multi_package }}"

15 state: present

16 vars:

17 multi_package:

18 - tree

19 - nc

20 - tcpdump

21

22 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key --syntax-check test_cycle_vars.yml # 语法检测

23 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key -C test_cycle_vars.yml # 预执行,测试执行

24 [yun@ansi-manager object04]$ ansible-playbook -b -i ../hosts_key test_cycle_vars.yml # 执行

 

该方法不一定适用于其他模块

 

 

触发器-handlers

当我们修改了服务的配置文件时,这时我们需要去重启服务,那么 handlers 就可以派上用场了。

注意事项:

1、无论多少个 task 通知了相同的 handlers,handlers 仅会在所有 tasks 结束后运行一次。

2、只有 task 发生改变了才会通知 handlers,没有改变则不会通知和触发 handlers。

3、不能用 handlers 替代 task 。

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 24

5 drwxrwxr-x 2 yun yun 129 Aug 2411:41file

6 -rw-rw-r-- 1 yun yun 1029 Aug 2411:57 test_handlers.yml

7 [yun@ansi-manager object05]$ ll file/ # 涉及配置文件

8 total 20

9 -rw-r--r-- 1 yun yun 11767 Aug 2411:41 httpd.conf.j2

10 [yun@ansi-manager object05]$ vim file/httpd.conf.j2 # 配置文件修改的地方

11…………

12# Change this to Listen on specific IP addresses as shown below to

13# prevent Apache from glomming onto all bound IP addresses.

14#

15 #Listen 12.34.56.78:80

16###### 端口改为变量

17Listen {{ httpd_port }}

18

19…………

20 [yun@ansi-manager object05]$ cat test_handlers.yml # yml 文件

21 ---

22# 比如安装配置启动 httpd。当我们修改配置文件,重启 httpd 服务

23# 要求:修改配置,重启一个或多个服务

24 - hosts: proxyservers

25 # 这里为了演示方便,因此变量直接就写在了该文件中

26 vars:

27 - httpd_port: 8081

28

29 tasks:

30 - name: "Install httpd"

31yum:

32 name: "{{ packages }}"

33 state: present

34 vars:

35 packages:

36 - httpd

37 - httpd-tools

38

39 - name: "Httpd config"

40 template:

41 src: ./file/httpd.conf.j2

42 dest: /etc/httpd/conf/httpd.conf

43 # 一个通知

44 # notify: "Restart httpd server"

45 # 多个通知

46 notify:

47 - "Restart httpd server"

48 - "Restart crond server"

49

50 - name: "Start httpd server"

51 systemd:

52 name: httpd

53 state: started

54 enabled: yes

55

56 handlers:

57 - name: "Restart httpd server"

58 systemd:

59 name: httpd

60 state: restarted

61

62 - name: "Restart crond server"

63 systemd:

64 name: crond

65 state: restarted

66

67 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_handlers.yml # 语法检测

68 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_handlers.yml # 预执行,测试执行

69 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_handlers.yml # 执行

 

任务标签-tags

默认情况下,当我们执行一个 playbook 时,会执行该 playbook 中所有的任务。如果只想执行一个 task 或者部分 task 用于调试或者需求就是执行部分 task。那么可以使用 ansible 的标签(tags)功能给单独 task 或者全部 task 打上标签。之后利用这些标签来指定要运行哪些 playbook 任务,或不运行哪些 playbook 任务。

打标签方式

对一个 task 打一个标签;

对一个 task 打多个标签;

对多个 task 打一个标签

标签如何运用

-t TAGS, --tags=TAGS:执行指定的 tag 标签任务;多个标签使用逗号分开

--skip-tags=SKIP_TAGS:跳过指定标签不执行,执行指定外的 task「标签作用于 task 上,即使该task还有其他标签,这个 task 也不会被执行」;多个标签使用逗号分开

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 8

5 drwxrwxr-x 2 yun yun 27 Oct 2618:07file

6 -rw-rw-r-- 1 yun yun 1004 Oct 2619:21 test_tags.yml

7 [yun@ansi-manager object05]$ cat test_tags.yml

8 ---

9# tags 标签测试

10 - hosts: proxyservers

11 # 这里为了演示方便,因此变量直接就写在了该文件中

12 vars:

13 - httpd_port: 8081

14

15 tasks:

16 - name: "Install httpd"

17yum:

18 name: "{{ packages }}"

19 state: present

20 vars:

21 packages:

22 - httpd

23 - httpd-tools

24 tags:

25 - httpd_server

26 - httpd_install

27

28 - name: "Httpd config"

29 template:

30 src: ./file/httpd.conf.j2

31 dest: /etc/httpd/conf/httpd.conf

32 notify: "Restart httpd server"

33 tags:

34 - httpd_server

35 - httpd_config

36

37 - name: "Start httpd server"

38 systemd:

39 name: httpd

40 state: started

41 enabled: yes

42 tags:

43 - httpd_server

44 - httpd_start

45

46 - name: "Create dir"

47file:

48 path: /tmp/with_items_testdir

49 state: directory

50 tags: create_dir

51

52 handlers:

53 - name: "Restart httpd server"

54 systemd:

55 name: httpd

56 state: restarted

 

playbook 标签查看

 1 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_tags.yml  # 语法检测

2## 查看 playbook 中的任务和标签

3 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --list-tasks

4

5playbook: test_tags.yml

6

7 play #1 (proxyservers): proxyservers TAGS: []

8 tasks:

9 Install httpd TAGS: [httpd_install, httpd_server]

10 Httpd config TAGS: [httpd_config, httpd_server]

11 Start httpd server TAGS: [httpd_server, httpd_start]

12 Create dir TAGS: [create_dir]

13## 查看 playbook 中的标签

14 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --list-tags

15

16playbook: test_tags.yml

17

18 play #1 (proxyservers): proxyservers TAGS: []

19 TASK TAGS: [create_dir, httpd_config, httpd_install, httpd_server, httpd_start]

 

playbook 执行

 1## 单个标签执行

2 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml -t httpd_install

3 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml -t httpd_server

4## 多个标签执行

5 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml -t httpd_install,httpd_config,httpd_start

6## 跳过哪些标签不执行「标签作用于 task 上,即使该 task 还有其他标签,这个 task 也不会被执行」

7 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --skip-tags httpd_server

8 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml --skip-tags httpd_install,create_dir

9## 执行整个 playbook

10 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_tags.yml

 

文件引用/复用-include与import

在实际应用中,是不可能将所有 task 写在一个 playbook 中的,需要进行拆分,方便后期重复使用。这样后面写其他 playbook 的时候,如果有重复的,那么直接引用之前写的即可。

Includes 与 Imports

1、include 和 import 虽然功能相近,但是 ansible 执行引擎对他们的处理却截然不同。

2、所有 import* 语句都会在解析 playbook 时进行预处理。「提前准备好工具」

3、所有 include* 语句都是在执行 playbook 时遇到再处理。「需要什么工具,再拿什么工具」

PS:include 模块:这个模块还将支持一段时间,但在不久的将来可能会弃用「最好不要使用这个模块」。

示例

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 32

5 drwxrwxr-x 2 yun yun 103 Aug 2419:51 file_yml

6 -rw-rw-r-- 1 yun yun 518 Aug 2419:56 test_include.yml

7 [yun@ansi-manager object05]$ ll file_yml/

8 total 16

9 -rw-rw-r-- 1 yun yun 136 Aug 2419:51 httpd_config.yml

10 -rw-rw-r-- 1 yun yun 133 Aug 2419:41 httpd_install.yml

11 -rw-rw-r-- 1 yun yun 80 Aug 2419:42 httpd_restart.yml

12 -rw-rw-r-- 1 yun yun 93 Aug 2419:41 httpd_start.yml

13## 每个小 yml 文件的具体内容

14 [yun@ansi-manager object05]$ cat file_yml/httpd_install.yml

15 - name: "Install httpd"

16yum:

17 name: "{{ packages }}"

18 state: present

19 vars:

20 packages:

21 - httpd

22 - httpd-tools

23

24 [yun@ansi-manager object05]$ cat file_yml/httpd_config.yml

25 - name: "Httpd config"

26 template:

27 src: ./file/httpd.conf.j2

28 dest: /etc/httpd/conf/httpd.conf

29 notify: "Restart httpd server"

30

31 [yun@ansi-manager object05]$ cat file_yml/httpd_start.yml

32 - name: "Start httpd server"

33 systemd:

34 name: httpd

35 state: started

36 enabled: yes

37

38 [yun@ansi-manager object05]$ cat file_yml/httpd_restart.yml

39 - name: "Restart httpd server"

40 systemd:

41 name: httpd

42 state: restarted

43

44###### 主调用 yml 文件内容 ######

45 [yun@ansi-manager object05]$ cat test_include.yml

46 ---

47# 调用其他 yml 文件

48 - hosts: proxyservers

49 # 这里为了演示方便,因此变量直接就写在了该文件中

50 vars:

51 - httpd_port: 8083

52

53 tasks:

54 - include_tasks: ./file_yml/httpd_install.yml

55 - include_tasks: ./file_yml/httpd_config.yml

56 - include_tasks: ./file_yml/httpd_start.yml

57

58 handlers:

59 # 使用 import 进行预处理,这样防止 notify 时,在 handlers 找不到对应的信息

60 - import_tasks: ./file_yml/httpd_restart.yml

61

62 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_include.yml # 语法检测

63 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_include.yml # 预执行,测试执行

64 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_include.yml # 执行

 

忽略错误-ignore_errors

在 playbook 执行过程中,默认情况下如果有错误发生,那么后面的 task 就不执行,并且退出当前的 playbook。

如果我们对某些 task 执行结果不关心,不管执行是否成功,后面的 task 也要继续执行。那就需要通过 ignore_errors 来忽略当前 task 的错误结果,让后面的 task 继续往下执行。

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 36

5 -rw-rw-r-- 1 yun yun 479 Aug 2609:24 test_ignore_errors.yml

6 [yun@ansi-manager object05]$ cat test_ignore_errors.yml

7 ---

8# ignore_errors 测试

9 - hosts: proxyservers

10

11 tasks:

12 - name: "Install httpd"

13yum:

14 name: "{{ packages }}"

15 state: present

16 vars:

17 packages:

18 - httpd

19 - httpd-tools

20

21 - name: "Shell false"

22 shell: /bin/false

23 # 是否忽略该 task 的错误 「打开或关闭注释,对比」

24 ignore_errors: True

25

26 - name: "Create dir"

27file:

28 path: /tmp/with_items_testdir

29 state: directory

30

31 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_ignore_errors.yml # 语法检测

32 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_ignore_errors.yml # 预执行,测试执行

33 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_ignore_errors.yml # 执行

 

默认情况

 

使用了 ignore_errors 的情况

 

自定义错误判定条件-failed_when

命令不依赖返回状态码来判定是否执行失败,而是要查看命令返回内容来决定,比如返回内容中包括 command not found 字符串,则判定为失败。

 

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 48

5 -rw-rw-r-- 1 yun yun 369 Aug 2916:12 test_custom_error.yml

6 [yun@ansi-manager object05]$ cat test_custom_error.yml

7 ---

8# 自定义错误条件

9 - hosts: proxyservers

10

11 tasks:

12 - name: "this command prints "command not found" if not find"

13 shell: "kkk -x" # 测试一

14 #shell: "/bin/kkk -x" # 测试二

15 register: shell_result

16 failed_when: ""command not found" in shell_result["stderr"]"

17

18 - name: "print shell_result info"

19 debug:

20 msg: "{{ shell_result["stderr"] }}"

21

22 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_custom_error.yml # 语法检测

23 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_custom_error.yml # 预执行,测试执行

24 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_custom_error.yml # 执行

 

强制调用触发器-force_handlers

通常情况下,当 task 执行失败后,playbook 会终止。任何在此之前已经被 task notify 的 handlers 都不会被执行。

此时,如果你在 playbook 中设置了 force_handlers: yes 参数,则被通知的 handlers 就会被强制执行(有些特殊场景可能会使用到)。

如示例,在一个 playbook 中,如果配置文件的 task 已经被执行成功,并且 notify 了 handlers,之后必须重启服务。那么我们会强制要求:即使后续的 task 执行失败,之前被通知的 handlers 也必须执行。

如果不强制执行就变成了,第一次执行时:配置文件修改成功,但由于之后有 task 执行失败,导致 playbook 终止,后续 handlers 没有被调用,对应服务没有重启;第二次执行时:配置文件没发生改变「因此第一次已经更新了配置文件」,因此不会通知 handlers。最终结果就是配置改变了,但是就是没有重启服务。显然不符合我们的初衷。

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 40

5 drwxrwxr-x 2 yun yun 129 Aug 2414:28file

6 -rw-rw-r-- 1 yun yun 909 Aug 2912:23 test_error_deal.yml

7 [yun@ansi-manager object05]$ cat test_error_deal.yml

8 ---

9# 即使 task 执行错误,之前已 notify 的 handlers 必须被执行

10 - hosts: proxyservers

11 # 这里为了演示方便,因此变量直接就写在了该文件中

12 vars:

13 - httpd_port: 8087

14 # 即使 task 执行错误,之前已 notify 的 handlers 必须被执行

15 force_handlers: yes

16

17 tasks:

18 - name: "Install httpd"

19yum:

20 name: "{{ packages }}"

21 state: present

22 vars:

23 packages:

24 - httpd

25 - httpd-tools

26

27 - name: "Httpd config"

28 template:

29 src: ./file/httpd.conf.j2

30 dest: /etc/httpd/conf/httpd.conf

31 notify: "Restart httpd server"

32

33 - name: "Start httpd server"

34 systemd:

35 name: httpd

36 state: started

37 enabled: yes

38

39 # /bin/false 返回状态码为1,不为0

40 - name: "Shell task"

41 shell: /bin/false

42

43 - name: "Create dir"

44file:

45 path: /tmp/with_items_testdir

46 state: directory

47

48 handlers:

49 - name: "Restart httpd server"

50 systemd:

51 name: httpd

52 state: restarted

53

54 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_error_deal.yml # 语法检测

55 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_error_deal.yml # 预执行,测试执行

56 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_error_deal.yml # 执行

 

抑制changed状态-changed_when

ansible 会自动判断模块执行状态,command、shell 及其它模块如果修改了远程主机状态则被判定为 changed 状态,不过也可以自己决定达到 changed 状态的条件。

当我们在 playbook 中使用 shell 或者 command 模块时,每次 task 执行状态都是 changed。原因是因为每次我们都去执行获取当前数据,而不是一个固化的状态。

但在实际应用中,我们可能不需要 shell 或者 command 模块执行后的 changed 状态,这时我们就需要通过 changed_when: false 来抑制这个改变。

当然上述的 changed_when: false 可以在任何模块中使用,不局限于 shell 和 command 模块,只是我们常用于这两个模块而已。

 1 [yun@ansi-manager object05]$ pwd

2 /app/ansible_info/object05

3 [yun@ansi-manager object05]$ ll

4 total 44

5 -rw-rw-r-- 1 yun yun 299 Aug 2914:47 test_changed_when.yml

6 [yun@ansi-manager object05]$ cat test_changed_when.yml

7 ---

8 # 使用 changed_when: false 抑制 changed 状态

9 - hosts: proxyservers

10

11 tasks:

12 - name: "Shell task"

13 shell: netstat -lntp | grep"httpd"

14 register: check_httpd

15 # changed_when: false # 任何时候,都不为 changed 状态

16 #### check_httpd["stdout"] 不包含 httpd 为 true,否则 false

17 changed_when: ""httpd" not in check_httpd["stdout"]" # 结果为 false

18

19 - name: "Debug output"

20 debug:

21 msg: "{{ check_httpd.stdout }}"

22

23 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key --syntax-check test_changed_when.yml # 语法检测

24 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key -C test_changed_when.yml # 预执行,测试执行

25 [yun@ansi-manager object05]$ ansible-playbook -b -i ../hosts_key test_changed_when.yml # 执行

 

完毕!


 

 

———END———
如果觉得不错就关注下呗 (-^O^-) !

 

以上是 Ansibleplaybook编程 的全部内容, 来源链接: utcz.com/z/515896.html

回到顶部