zoukankan      html  css  js  c++  java
  • Ansible playbook 编程

    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
    6 echo "yun  ALL=(ALL)       NOPASSWD: ALL" >>  /etc/sudoers
    7 chmod 755 /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]
     6 172.16.1.180:22
     7 
     8 [proxyservers]
     9 172.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 26 10: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] *******************************************************************************************
    45 ok: [web01]
    46 ok: [web02]
    47 ok: [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]
    54 skipping: [web01]
    55 skipping: [web02]
    56 skipping: [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]
    62 skipping: [web01]
    63 skipping: [web02]
    64 skipping: [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]
    71 changed: [web02]
    72 changed: [web01]
    73 changed: [172.16.1.180]
    74 changed: [web03]
    75 
    76 PLAY RECAP *******************************************************************************************************
    77 172.16.1.180               : ok=2    changed=1    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0
    78 172.16.1.181               : ok=2    changed=1    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0
    79 172.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 23 22: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 23 22: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 26 16:03 file
     6 -rw-rw-r-- 1 yun yun 1205 Oct 26 16:02 test_loop_hash.yml
     7 [yun@ansi-manager object04]$ cat file/config_test.conf.j2 
     8 111
     9 [yun@ansi-manager object04]$ cat file/yml_test_j2.yml 
    10 222
    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 }}"
    20         groups: "{{ item.groups }}"
    21       loop:
    22         - { user: "testuser1", groups: "root" }
    23         - { user: "testuser2", groups: "root,yun" }
    24 
    25     - name: "Create multiple file or dir"
    26       file:
    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 26 16:03 file
     6 -rw-rw-r-- 1 yun yun 1205 Oct 26 16:02 test_with_items_hash.yml
     7 [yun@ansi-manager object04]$ cat file/config_test.conf.j2 
     8 111
     9 [yun@ansi-manager object04]$ cat file/yml_test_j2.yml 
    10 222
    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 }}"
    20         groups: "{{ item.groups }}"
    21       with_items:
    22         - { user: "testuser1", groups: "root" }
    23         - { user: "testuser2", groups: "root,yun" }
    24 
    25     - name: "Create multiple file or dir"
    26       file:
    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 26 16: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 26 16: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 26 17: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"
    13       yum:
    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 24 11:41 file
     6 -rw-rw-r-- 1 yun yun 1029 Aug 24 11:57 test_handlers.yml
     7 [yun@ansi-manager object05]$ ll file/  # 涉及配置文件
     8 total 20
     9 -rw-r--r-- 1 yun yun 11767 Aug 24 11: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 ###### 端口改为变量
    17 Listen {{ 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"
    31       yum:
    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 26 18:07 file
     6 -rw-rw-r-- 1 yun yun 1004 Oct 26 19: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"
    17       yum:
    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"
    47       file:
    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 
     5 playbook: 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 
    16 playbook: 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 24 19:51 file_yml
     6 -rw-rw-r-- 1 yun yun  518 Aug 24 19:56 test_include.yml
     7 [yun@ansi-manager object05]$ ll file_yml/
     8 total 16
     9 -rw-rw-r-- 1 yun yun 136 Aug 24 19:51 httpd_config.yml
    10 -rw-rw-r-- 1 yun yun 133 Aug 24 19:41 httpd_install.yml
    11 -rw-rw-r-- 1 yun yun  80 Aug 24 19:42 httpd_restart.yml
    12 -rw-rw-r-- 1 yun yun  93 Aug 24 19:41 httpd_start.yml
    13 ## 每个小 yml 文件的具体内容
    14 [yun@ansi-manager object05]$ cat file_yml/httpd_install.yml 
    15 - name: "Install httpd"
    16   yum:
    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 26 09: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"
    13       yum:
    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"
    27       file:
    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 29 16: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 24 14:28 file
     6 -rw-rw-r-- 1 yun yun  909 Aug 29 12: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"
    19       yum:
    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"
    44       file:
    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 29 14: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  # 执行
    复制代码

    完毕!

  • 相关阅读:
    代码检查工具介绍
    Eclipse利用代理快速安装插件
    toString结果
    Eclipse查看jdk源码
    java语言基础特性
    TODO、FIXME和XXX转载
    java泛型
    不良代码总结
    mockServer学习
    akka
  • 原文地址:https://www.cnblogs.com/shetao/p/14338699.html
Copyright © 2011-2022 走看看