跳至内容

Ansible - 大规模基础设施

在本章中,您将学习如何扩展您的配置管理系统。


**目标**: 在本章中,您将学习如何

✔ 为大型基础设施组织您的代码;
✔ 将所有或部分配置管理应用到一组节点;

🏁 **ansible**, **配置管理**, **扩展**

**知识**: ⭐ ⭐ ⭐
**复杂度**: ⭐ ⭐ ⭐ ⭐

**阅读时间**: 30 分钟


我们在前面的章节中已经了解了如何以角色的形式组织我们的代码,以及如何使用一些角色来管理更新(补丁管理)或部署代码。

那么配置管理呢?如何使用 Ansible 管理数十、数百甚至数千台虚拟机呢?

云的出现改变了传统方法。VM 在部署时被配置。如果它的配置不再符合要求,则会将其销毁并用新的 VM 替换。

本章介绍的配置管理系统组织将满足这两种 IT 使用方式:“一次性”使用或定期“重新配置”服务器池。

但是,请注意:使用 Ansible 来确保服务器池符合要求需要改变工作习惯。如果在下次运行 Ansible 时没有看到这些修改被覆盖,则不可能手动修改服务管理器的配置。

注意

我们将在下面设置的内容并不是 Ansible 最擅长的领域。Puppet 或 Salt 等技术将做得更好。请记住,Ansible 是一个自动化工具箱,并且是无代理的,这解释了性能上的差异。

注意

更多信息可以在 此处找到

变量存储

首先我们要讨论的是数据与 Ansible 代码之间的分离。

随着代码越来越大越来越复杂,修改它包含的变量将变得越来越复杂。

为了确保网站的维护,最重要的是正确地将变量与 Ansible 代码分离。

我们还没有在这里讨论过,但您应该知道 Ansible 可以根据被管理节点的清单名称或其成员组,自动加载它在特定文件夹中找到的变量。

Ansible 文档建议我们如下组织代码

inventories/
   production/
      hosts               # inventory file for production servers
      group_vars/
         group1.yml       # here we assign variables to particular groups
         group2.yml
      host_vars/
         hostname1.yml    # here we assign variables to particular systems
         hostname2.yml

如果目标节点是group1hostname1,则包含在 hostname1.ymlgroup1.yml 文件中的变量将被自动加载。这是一种将所有角色的所有数据存储在同一个位置的好方法。

通过这种方式,您的服务器的清单文件成为它的身份证明。它包含与您的服务器的默认变量不同的所有变量。

从变量集中化的角度来看,必须通过添加前缀(例如角色名称)来组织角色中的变量命名。还建议使用扁平变量名称而不是字典。

例如,如果您想将 sshd_config 文件中的 PermitRootLogin 值设置为变量,一个好的变量名称可以是 sshd_config_permitrootlogin(而不是 sshd.config.permitrootlogin,它可能也是一个好的变量名称)。

关于 Ansible 标签

使用 Ansible 标签可以执行或跳过代码中的部分任务。

注意

更多信息可以在这里找到

例如,让我们修改用户创建任务

- name: add users
  user:
    name: "{{ item }}"
    state: present
    groups: "users"
  loop:
     - antoine
     - patrick
     - steven
     - xavier
  tags: users

现在,您可以使用 ansible-playbook 选项 --tags 仅运行带有 users 标签的任务。

ansible-playbook -i inventories/production/hosts --tags users site.yml

您也可以使用 --skip-tags 选项。

关于目录布局

让我们关注一个关于组织 CMS (内容管理系统) 正确运行所需文件和目录的提案。

我们的起点将是 site.yml 文件。这个文件有点像 CMS 的指挥家,因为它只会根据需要包含目标节点所需的 角色。

---
- name: "Config Management for {{ target }}"
  hosts: "{{ target }}"

  roles:

    - role: roles/functionality1

    - role: roles/functionality2

当然,这些角色必须在与 site.yml 文件同级目录的 roles 目录下创建。

我喜欢在我的 vars/global_vars.yml 中管理我的全局变量,即使我可以将它们存储在 inventories/production/group_vars/all.yml 中的文件中。

---
- name: "Config Management for {{ target }}"
  hosts: "{{ target }}"
  vars_files:
    - vars/global_vars.yml
  roles:

    - role: roles/functionality1

    - role: roles/functionality2

我还喜欢保留禁用功能的可能性。因此,我使用条件和默认值来包含我的角色,如下所示。

---
- name: "Config Management for {{ target }}"
  hosts: "{{ target }}"
  vars_files:
    - vars/global_vars.yml
  roles:

    - role: roles/functionality1
      when:
        - enable_functionality1|default(true)

    - role: roles/functionality2
      when:
        - enable_functionality2|default(false)

不要忘记使用标签

- name: "Config Management for {{ target }}"
  hosts: "{{ target }}"
  vars_files:
    - vars/global_vars.yml
  roles:

    - role: roles/functionality1
      when:
        - enable_functionality1|default(true)
      tags:
        - functionality1

    - role: roles/functionality2
      when:
        - enable_functionality2|default(false)
      tags:
        - functionality2

你应该得到类似的东西

$ tree cms
cms
├── inventories
│   └── production
│       ├── group_vars
│          └── plateform.yml
│       ├── hosts
│       └── host_vars
│           ├── client1.yml
│           └── client2.yml
├── roles
│   ├── functionality1
│      ├── defaults
│         └── main.yml
│      └── tasks
│          └── main.yml
│   └── functionality2
│       ├── defaults
│          └── main.yml
│       └── tasks
│           └── main.yml
├── site.yml
└── vars
    └── global_vars.yml

注意

您可以自由地在集合中开发您的角色

测试

让我们启动剧本并运行一些测试

$ ansible-playbook -i inventories/production/hosts -e "target=client1" site.yml

PLAY [Config Management for client1] ****************************************************************************

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

TASK [roles/functionality1 : Task in functionality 1] *********************************************************
ok: [client1] => {
    "msg": "You are in functionality 1"
}

TASK [roles/functionality2 : Task in functionality 2] *********************************************************
skipping: [client1]

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

如您所见,默认情况下,只运行 functionality1 角色的任务。

让我们在清单中为我们的目标节点激活 functionality2 并重新运行剧本。

$ vim inventories/production/host_vars/client1.yml
---
enable_functionality2: true
$ ansible-playbook -i inventories/production/hosts -e "target=client1" site.yml

PLAY [Config Management for client1] ****************************************************************************

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

TASK [roles/functionality1 : Task in functionality 1] *********************************************************
ok: [client1] => {
    "msg": "You are in functionality 1"
}

TASK [roles/functionality2 : Task in functionality 2] *********************************************************
ok: [client1] => {
    "msg": "You are in functionality 2"
}

PLAY RECAP ******************************************************************************************************
client1                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

尝试只应用 functionality2

$ ansible-playbook -i inventories/production/hosts -e "target=client1" --tags functionality2 site.yml

PLAY [Config Management for client1] ****************************************************************************

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

TASK [roles/functionality2 : Task in functionality 2] *********************************************************
ok: [client1] => {
    "msg": "You are in functionality 2"
}

PLAY RECAP ******************************************************************************************************
client1                    : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

让我们在整个清单上运行

$ ansible-playbook -i inventories/production/hosts -e "target=plateform" site.yml

PLAY [Config Management for plateform] **************************************************************************

TASK [Gathering Facts] ******************************************************************************************
ok: [client1]
ok: [client2]

TASK [roles/functionality1 : Task in functionality 1] *********************************************************
ok: [client1] => {
    "msg": "You are in functionality 1"
}
ok: [client2] => {
    "msg": "You are in functionality 1"
}

TASK [roles/functionality2 : Task in functionality 2] *********************************************************
ok: [client1] => {
    "msg": "You are in functionality 2"
}
skipping: [client2]

PLAY RECAP ******************************************************************************************************
client1                    : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
client2                    : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   

如您所见,functionality2 仅在 client1 上运行。

好处

通过遵循 Ansible 文档中给出的建议,您将很快获得一个

  • 易于维护的源代码,即使它包含大量角色
  • 一个相对快速、可重复的合规系统,您可以部分或全部应用它
  • 可以根据情况和服务器进行调整
  • 您的信息系统的具体细节与代码分离,易于审计,并且集中在您的配置管理的清单文件中。