还在为如何使用Ansible管理大项目苦恼?不如摸鱼的时候点进来看看

1. 利用主机模式选择主机

1.1 引用清单主机

主机模式用于指定要作为play或临时命令的目标的主机。在最简单的形式中,清单中受管主机或主机组的名称就是指定该主机或主机组的主机模式。

play中,hosts指定要针对其运行play的受管主机。对于临时命令,以命令行参数形式将主机模式提供给ansible命令。

本节中将通篇使用以下示例清单来演示主机模式。

[root@jlin ~]# cat myinventory 
web
php

[host]
host1
host2

[test]
test1
test2

[data1]
host1
test1

[data2]
host2
test2

[datacenter:children]
data1
data2

[new]
192.168.23.127
192.168.23.128

要演示如何解析主机模式,我们将执行Ansible Playbook的test.yml,使用不同的主机模式来以此示例清单中受管主机的不同子集作为目标。

1.2 受管主机

最基本的主机模式是单一受管主机名称列在清单中。这将指定该主机是清单中ansible命令要执行操作的唯一主机。

在该playbook运行时,第一个Gathering Facts任务应在与主机模式匹配的所有受管主机上运行。此任务期间的故障可能导致受管主机从play中移除。

如果清单中明确列出了IP地址,而不是主机名,则可以将其用作主机模式。如果IP地址未列在清单中,我们就无法用它来指定主机,即使该IP地址会在DNS中解析到这个主机名。

以下示例演示了如何使用主机模式来引用清单中包含的IP地址。

[root@jlin ~]# vim test.yml
---
- hosts: 192.168.23.127


[root@jlin ~]# ansible-playbook test.yml 
PLAY [192.168.23.127] ***************************************************************

TASK [Gathering Facts] **************************************************************
ok: [192.168.23.127]

PLAY RECAP **************************************************************************
192.168.23.127             : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

注意:
通过IP地址引用受管主机存在一个问题,就是难以记住play或临时命令所针对的主机使用了哪个IP地址。如果没有可解析的主机名,必须按IP地址指定主机以进行连接

可以通过设置ansible_host主机变量,在清单中将某一别名指向特定的IP地址

ansible_host: 192.168.23.127

1.3 使用组指定主机

当组名称用作主机模式时,它指定Ansible将对属于该组的成员的主机执行操作。

---
- hosts: host

all的特别组,匹配清单中的所有受管主机。

---
- hosts: all

ungrouped的特别组,包括清单中不属于任何其他组的所有受管主机:

---
- hosts: ungrouped

1.4 使用通配符匹配多个主机

使用*通配符,它将匹配任意字符串,带引号的星号匹清单中的所有主机

---
- hosts: '*'

重要

一些在主机模式中使用的字符对shell也有意义。通过ansible使用主机模式从命令行运行临时命令时,这可能会有问题。建议大家在命令行中使用单引号括起使用的主机模式,防止它们被shell意外扩展。
类似的,如果在Ansible Playbook中使用了任何特殊通配符或列表字符,必须将主机模式放在单引号里,确保能够正确解析主机模式。

---
- hosts: '!test1,development'

也可使用 * 字符匹配包含特定子字符串的受管主机或组。
匹配 * 结尾的所有清单名称:

---
- hosts: '*'

匹配开头为 192.168.23. 网段的的主机或主机组的名称:

---
- hosts: '192.168.23.*'

以下示例使用通配符主机模式来匹配开头为datacenter的主机或主机组的名称。

---
- hosts: 'datacenter*'

重要

通配符主机模式匹配所有清单名称、主机和主机组。它们不区别名称是DNS名、IP地址还是组,这可能会导致一些意外的匹配。
例如,根据示例清单,比较上一示例中指定datacenter主机模式的结果和data主机模式的结果:

---
- hosts: 'data*'

1.5 列表

通过逻辑列表来引用清单中的多个条目。逗号分隔列表匹配符合任何这些主机模式的所有主机

所有这些受管主机都将是目标:

---
- hosts: host1,test2,192.168.23.117

逗号分隔列表,属于任何这些组的所有主机都将是目标:

---
- hosts: host,data1

也可以混合使用受管主机、主机组和通配符,如下所示:

---
- hosts: 'host,data*,192.168.23.117'

注意

匹配host组中属于data1组的计算机:

---
- hosts: host,&data1

匹配datacenter组中定义的所有主机,但test2除外

---
- hosts: datacenter,!test2

匹配所有主机,data1组中的受管主机除外。

---
- hosts: all,!data1

2. 管理动态清单

2.1 动态生成清单

大多数大型IT环境中没有系统来跟踪可用的主机以及它们的组织方式。例如,可能有外部目录服务通过Zabbix等监控系统维护,或者位于FreeIPA或Active Directory服务器上。Cobbler等安装服务器或红帽卫星等管理服务可能跟踪部署的裸机系统。类似地,Amazon Web ServicesEC2或OpenStack部署等云服务,或者基于Vmware或红帽虚拟化的虚拟机基础架构可能是有关那些更替的实例和虚拟机的信息来源。

Ansible支持动态清单脚本,这些脚本在每当Ansible执行时从这些类型的来源检索当前的信息,使清单能够实时得到更新。这些脚本是可以执行的程序,能够从一些外部来源收集信息,并以JSON格式输出清单。

动态清单脚本的使用方式与静态清单文本文件一样。清单的位置可以直接在当前的ansible.cfg文件中指定,或者通过**-i**选项指定。如果清单文件可以执行,则它将被视为动态清单程序,Ansible会尝试运行它来生成清单。如果文件不可执行,则它将被视为静态清单。

清单位置可以在ansible.cfg配置文件中通过inventory参数进行配置。默认情况下,它被配置为**/etc/ansible/hosts**。

2.2 开源社区脚本

开源社区向Ansible项目贡献了大量现有的动态清单脚本。它们没有包含在ansible软件包中。这些脚本可从Ansible GigHub网站

https://github.com/ansible/ansible/tree/devel/examples

2.3 编写动态清单程序

可以使用任何编程语言编写自定义程序,但传递适当的选项时必须以JSON格式返回清单信息。

ansible-inventory命令是学习如何以JSON格式编写Ansible清单的有用工具。

要以JSON格式显示清单文件的内容,请运行ansible-inventory --list命令。可以使用**-i**选项指定要处理的清单文件的位置,或仅使用当前Ansible配置设置的默认清单。

以下示例演示了如何使用ansible-inventory命令来处理INI样式的清单文件并以JSON格式输出。

[root@jlin ~]# cat inventory
workstation1.host

[webservers]
web1.host
web2.host

[databases]
db1.host
db2.host


[root@jlin ~]# ansible-inventory -i inventory --list

如果要自己编写动态清单脚本,可以通过部署动态清单来源

https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html

脚本以适当的解释器行(例如,#!/usr/bin/python)开头并且可以执行,以便Ansible能够运行它。

在传递–list选项时,脚本必须显示清单中所有主机和组的JSON编码散列/字典。

在最简单的形式中,组可以是一个受管主机列表。在这个清单脚本的JSON编码输出示例中,webservers是一个主机组,该组内含web1.host和web2.host受管主机。databases主机组的成员有db1.host和db2.host主机。

[root@jlin ~]# ./inventoryscript --list
{
    "web": ["web1","web2"],
    "databases": ["db1","db2"]
}

每个组的值可以是JSON散列/字典,含有由每一受管主机、任何子组和可能设置的任何组变量组成的列表。下一示例显示了一个比较复杂的动态清单的JSON编码输出。boston组具有两个子组(backup和ipa)、自己的三个受管主机,以及一个组变量集合(example_host: false)。

{
    "web": [
        "web1",
        "web2"
    ],
    "boston": {
        "children": [
            "backup",
            "ipa"
        ],
        "vars": {
            "example_host": false
        },
        "hosts": [
            "server1",
            "server2",
            "server3",
        ]
    },
    "backup": [
        "server4"
    ],
    "ipa": [
        "server5"
    ],
    "_meta": {
        "hostvars": {
            "server5": {
                "ntpserver": "ntp",
                "dnsserver": "dns"
            }
        }
    }
}

该脚本也支持–host managed-host选项。此选项必须显示由与该主机关联的变量组成的JSON散列/字典,或者空白的JSON散列/字典。

[root@jlin ~]# ./inventoryscript --host server5.demo
{
    "ntpserver": "ntp",
    "dnsserver": "dns"
}

注意
通过–host hostname选项调用时,该脚本必须显示指定主机的变量的JSON散列/字典。如果不提供任何变量,则可能显示空白的JSON散列或字典。

另外,如果–list选项返回名为_meta的顶级元素,则可以在一次脚本调用中返回所有主机变量,从而提升脚本性能。此时,不会进行–host调用。

部署动态清单来源

https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html

脚本示例:

[root@jlin ~]# vim inventory.py
#!/usr/bin/env python

'''
Example custom dynamic inventory script for Ansible, in Python.
'''

import os
import sys
import argparse

try:
    import json
except ImportError:
    import simplejson as json

class ExampleInventory(object):

    def __init__(self):
        self.inventory = {}
        self.read_cli_args()

        # Called with `--list`.
        if self.args.list:
            self.inventory = self.example_inventory()
        # Called with `--host [hostname]`.
        elif self.args.host:
            # Not implemented, since we return _meta info `--list`.
            self.inventory = self.empty_inventory()
        # If no groups or vars are present, return empty inventory.
        else:
            self.inventory = self.empty_inventory()

        print json.dumps(self.inventory);

    # Example inventory for testing.
    def example_inventory(self):
        return {
            'group': {
                'hosts': ['192.168.23.127', '192.168.23.128'],
                'vars': {
                    'ansible_ssh_user': 'root',
                    'ansible_ssh_pass': '123456',
                    'example_variable': 'value'
                }
            },
            '_meta': {
                'hostvars': {
                    '192.168.23.127': {
                        'host_specific_var': 'foo'
                    },
                    '192.168.23.128': {
                        'host_specific_var': 'bar'
                    }
                }
            }
        }

    # Empty inventory for testing.
    def empty_inventory(self):
        return {'_meta': {'hostvars': {}}}

    # Read the command line args passed to the script.
    def read_cli_args(self):
        parser = argparse.ArgumentParser()
        parser.add_argument('--list', action = 'store_true')
        parser.add_argument('--host', action = 'store')
        self.args = parser.parse_args()

# Get the inventory.
ExampleInventory()

如何使用这个脚本呢?

chmod +x inventory.py
./inventory.py --list
./inventory.py --host 192.168.23.127

ansible使用这个动态清单来管理主机:

ansible all -i inventory.py -m ping
ansible 192.168.23.127 -i inventory.py -m ping

2.4 管理多个清单

Ansible支持在同一运行中使用多个清单。如果清单的位置是一个目录(不论是由**-i选项设置的、是inventory**参数的值,还是以某种其他方式设置的),将组合该目录中包含的所有清单文件(不论是静态还是动态)来确定清单。该目录中的可执行文件将用于检索动态清单,其他文件则被用作静态清单。

清单文件不应依赖于其他清单文件或脚本来解析。例如,如果静态清单文件指定某一个组应当是另一个组的子级,则它也需要具有该组的占位符条目,即使该组的所有成员都来自动态清单。

[test]

[servers]
test.demo

[servers:children]
cloud-east

这可以确保不论清单文件以什么顺序解析,它们在内部都一致。

注意
清单文件的解析顺序不是由文档指定的。如果存在多个清单文件,它们会按照字母顺序进行解析。务必要确保所有文件都自相一致,从而避免意外的错误

Ansible会忽略清单目录中以特定后缀结尾的文件。这可以通过在Ansible配置文件中的inventory_ignore_extensions指令来控制

使用动态清单

https://docs.ansible.com/ansible/latest/user_guide/intro_dynamic_inventory.html

开发动态清单

https://docs.ansible.com/ansible/latest/dev_guide/developing_inventory.html

3. 配置并行

3.1 使用分叉在ansible中配置并行

当Ansible处理playbook时,会按顺序运行每个play。确定play的主机列表之后,Ansible将按顺序运行每个任务

Ansible可以同时连接到play中的所有主机以执行每项任务。适用于小型主机列表

Ansible所进行的最大同时连接数由Ansible配置文件中的forks参数控制。默认情况下设为5

[root@jlin ~]# grep forks /etc/ansible/ansible.cfg 
#forks          = 5

[root@jlin ~]# ansible-config dump|grep -i forks
DEFAULT_FORKS(default) = 5

[root@jlin ~]# ansible-config list|grep -i forks
DEFAULT_FORKS:
  description: Maximum number of forks Ansible will use to execute tasks on target
  - {name: ANSIBLE_FORKS}
  - {key: forks, section: defaults}
  name: Number of task forks

例如,假设Ansible控制节点配置了5个forks的默认值,并且play具有10个受管主机。Ansible将在前5个受管主机上执行play中的第一个任务,然后在其他5个受管主机上对第一个任务执行第二轮。在所有受管主机上执行第一个任务后,Ansible将继续一次在5受管主机的组中的所有受管主机上执行下一个任务。Ansible将依次对每个任务执行此操作,直到play结束。

forks的默认值设置得非常保守。如果你的控制节点正在管理Linux主机,则大多数任务将在受管主机上运行,并且控制节点的负载较少。在这种情况下,通常可以将forks的值设置得更高,可能接近100,然后性能就会提高。

如果playbook在控制节点上运行很多代码,则应明智地提高forks限值。如果使用Ansible管理网络路由器和交换机,则大多数模块在控制节点上运行而不是在网络设备上运行。由于这会增加控制节点上的负载,因此其支持forks数量增加的能力将显著低于仅管理Linux主机的控制节点。

可以从命令行覆盖Ansible配置文件中forks的默认设置。ansible和ansible-playbook命令均提供-f或–forks选项以指定要使用的forks数量。

3.2 管理滚动更新

Ansible运行play时,会确保所有受管主机在启动任何主机进行下一个任务之前已完成每个任务。所有受管主机完成所有任务后,将运行任何通知的处理程序。

所有主机上运行所有任务可能会导致意外行为。如果play更新负载均衡Web服务器集群,可能需要在进行更新时让每个Web服务器停止服务。如果所有服务器都在同一个play中更新,则它们可能全部同时停止服务。

避免此问题的一种方法是使用serial关键字,通过play批量运行主机。在下一批次启动之前,每批主机将在整个play中运行。

Ansible一次在两个受管主机上执行play,直至所有受管主机都已更新。Ansible首先在前两个受管主机上执行play中的任务。如果这两个主机中的任何一个或两个都通知了处理程序,则Ansible将根据这两个主机的需要运行处理程序。在这两个受管主机上执行完play时,Ansible会在接下来的两个受管主机上重复该过程。Ansible继续以这种方式运行play,直到所有受管主机都已更新。

---
- name: test
  hosts: webservers
  serial: 2
  tasks:
  - name: latest apache httpd package is installed
    yum:
      name: httpd
      state: latest
    notify: restart apache
    
  handlers:
  - name: restart apache
    service:
      name: httpd
      state: restarted

重要
出于某些目的,每批主机算作在主机子集上运行的完整play。这意味着,如果整个批处理失败,play就会失败,这将导致整个playbook运行失败。

在设置了serial: 2的上一个场景中,如果出现问题并且处理的前2个主机的play失败,则playbook将中止,其余3个主机将不会通过play运行。这是一个有用的功能,因为只有一部分服务器会不可用,使服务降级而不是中断。

serial关键字也可以指定为百分比。此百分比应用于play中的主机总数,以确定滚动更新批处理大小。无论百分比为何,每一工序的主机数始终为1或以上。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汉只只

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值