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  # 执行
    复制代码

    完毕!

  • 相关阅读:
    hdu 3790 最短路径问题
    hdu 2112 HDU Today
    最短路问题 以hdu1874为例
    hdu 1690 Bus System Floyd
    hdu 2066 一个人的旅行
    hdu 2680 Choose the best route
    hdu 1596 find the safest road
    hdu 1869 六度分离
    hdu 3339 In Action
    序列化和反序列化
  • 原文地址:https://www.cnblogs.com/shetao/p/14338699.html
Copyright © 2011-2022 走看看