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
如果目标节点是group1
的 hostname1
,则包含在 hostname1.yml
和 group1.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 文档中给出的建议,您将很快获得一个
- 易于维护的源代码,即使它包含大量角色
- 一个相对快速、可重复的合规系统,您可以部分或全部应用它
- 可以根据情况和服务器进行调整
- 您的信息系统的具体细节与代码分离,易于审计,并且集中在您的配置管理的清单文件中。