如何用Ansible管理多级环境

Ansible是一个强大的配置管理系统,用于在各种环境中设置和管理基础架构和应用程序。虽然Ansible提供易于阅读的语法,灵活的工作流程和强大的工具,管理大量的主机有重要的...

介绍

Ansible是一个强大的配置管理系统,用于在各种环境中设置和管理基础架构和应用程序。虽然Ansible提供易于阅读的语法,灵活的工作流程和强大的工具,但是当它们因部署环境和功能而异时,管理大量的主机可能会很困难。 在本指南中,我们将讨论使用Ansible来处理多级部署环境的一些策略。通常,对不同阶段的要求将导致不同数量和配置的部件。例如,开发服务器的内存需求可能不同于分段和生产的内存需求,并且重要的是明确控制表示这些需求的变量如何划分优先级。在本文中,我们将讨论一些可以提取这些差异的方法,以及Ansible提供的一些构造来鼓励配置重用。

用Ansible管理多级环境的不完全策略

虽然有很多方法可以管理Ansible中的环境,但Ansible本身并不提供有意义的解决方案。相反,它提供了许多可用于管理环境并允许用户选择的构造。 我们将在本指南中展示方法依赖于Ansible 组变量多库存 。然而,还有一些值得考虑的策略。我们将探讨下面的一些想法,以及为什么在复杂环境中实施时会出现问题。 如果你想开始使用Ansible推荐的策略,请跳到节上使用Ansible组和多个库存

仅依赖于组变量

乍看起来,组变量可能会提供Ansible需要的环境之间的所有分隔。您可以将某些服务器指定为属于您的开发环境,而其他服务器可以分配到暂存区和生产区。 Ansible使创建组和为其分配变量变得容易。 然而,组交叉带来了这个系统的严重问题。组通常用于对多个维度进行分类。例如:
  • 部署环境(本地,dev,stage,prod等)
  • 主机功能(网络服务器,数据库服务器等)
  • 数据中心区域(NYC,SFO等)
在这些情况下,主机通常每个类别在一个组中。例如,主机可以是NYC(数据中心区域)中的舞台(部署环境)上的web服务器(功能)。 如果同一个变量由一个主机的多个组设置,则Ansible无法明确指定优先级。您可能更喜欢与部署环境相关联的变量来覆盖其他值,但Ansible不提供定义此方法的方法。 相反,Ansible使用最后一个加载值 。由于Ansible按字母顺序评估组,与字典顺序中最后一个组名称相关的变量将胜出。这是可预测的行为,但从管理角度来看,明确管理组名称字母顺序并不理想。

使用组孩子建立层次结构

Ansible允许您指定使用的组其他组[ groupname :children]清单中的语法。这使您能够命名其他组的某些组成员。子组可以覆盖父组设置的变量。 通常,这用于自然分类。例如,我们可以有一组名为environments ,包括组devstageprod 。 这意味着我们可以在设置中的变量, environment组和中重写它们dev组。 你可以同样有一个名为父组functions包含组webdatabaseloadbalancer 。 此用法不能解决组交集的问题,因为子组只覆盖其父。儿童组可以在父覆盖变数,但上述组织还没有建立组类之间的关系,就像environmentsfunctions 。两个类别之间的变量优先级仍然未定义。 可能利用此系统通过设置非天然组成员身份。例如,如果要建立以下优先级,从最高优先级到最低优先级:
  • 开发环境
  • 地区
  • 功能
您可以分配组成员资格,如下所示:
示例清单
. . .
[function:children]
web
database
loadbalancer
region

[region:children]
nyc
sfo
environments

[environments:children]
dev
stage
prod
我们已经建立了这里层级结构,区域变量替代职能变量,因为该region组是一个子function组。 同样,在设置变量environments组可以覆盖任何其他人。 这意味着,如果我们设置相同的变量在不同的值devnyc ,和web组,属于每个这些的主机将使用该变量从dev 。 这实现了期望的结果并且也是可预测的。然而,这是不直观的,它混淆了真正的孩子和孩子之间的区别,需要建立等级。 Ansible的设计使其配置清晰,易于跟踪,即使对于新用户。这种类型的工作损害了这一目标。

使用允许显式加载顺序的Ansible构造

境内有Ansible几个结构,允许明确的变负荷排序,即vars_filesinclude_vars 。 这些可用于内Ansible起着在文件中定义的命令明确加载其他变量。 该vars_files指令是一出戏的范围内有效,而include_vars模块可以在任务中使用。 总的想法是设置在只有基本的识别变量group_vars ,然后利用这些加载与所需变量的其余部分正确的变量文件。 例如,少数的group_vars文件可能是这样的:
group_vars / dev
---
env: dev
group_vars / stage
---
env: stage
group_vars / web
---
function: web
group_vars / database
---
function: database
然后我们将有一个单独的vars文件,它定义每个组的重要变量。这些通常保持在一个单独的vars为了清楚目录。 不像group_vars文件,以打交道时include_vars ,文件必须包括.yml文件扩展名。 让我们假设我们需要的设置server_memory_size变量在每一个不同的值vars文件。您的开发服务器可能会小于生产服务器。此外,您的Web服务器和数据库服务器可能有不同的内存要求:
vars / dev.yml
---
server_memory_size: 512mb
vars / prod.yml
---
server_memory_size: 4gb
vars / web.yml
---
server_memory_size: 1gb
vars / database.yml
---
server_memory_size: 2gb
然后,我们可以创建一个明确加载正确的一个剧本vars根据分配给来自主机的值文件group_vars文件。加载的文件的顺序将决定优先顺序,并且最后一个值胜出。 随着vars_files ,一个例子戏是这样的:
example_play.yml
---
- name: variable precedence test
  hosts: all
  vars_files:
    - "vars/{{ env }}.yml"
    - "vars/{{ function }}.yml"
  tasks:
    - debug: var=server_memory_size
由于这些官能团最后加载, server_memory_size值将从取var/web.ymlvar/database.yml文件:
ansible-playbook -i inventory example_play.yml
. . .
TASK [debug] *******************************************************************
ok: [host1] => {
    "server_memory_size": "1gb"      # value from vars/web.yml
}
ok: [host2] => {
    "server_memory_size": "1gb"      # value from vars/web.yml
}
ok: [host3] => {
    "server_memory_size": "2gb"      # value from vars/database.yml
}
ok: [host4] => {
    "server_memory_size": "2gb"      # value from vars/database.yml
}
. . .
如果我们切换要加载的文件的顺序,我们可以使部署环境变量更高的优先级:
example_play.yml
---
- name: variable precedence test
  hosts: all
  vars_files:
    - "vars/{{ function }}.yml"
    - "vars/{{ env }}.yml"
  tasks:
    - debug: var=server_memory_size
再次运行操作手册显示部署环境文件中应用的值:
ansible-playbook -i inventory example_play.yml
. . .
TASK [debug] *******************************************************************
ok: [host1] => {
    "server_memory_size": "512mb"      # value from vars/dev.yml
}
ok: [host2] => {
    "server_memory_size": "4gb"        # value from vars/prod.yml
}
ok: [host3] => {
    "server_memory_size": "512mb"      # value from vars/dev.yml
}
ok: [host4] => {
    "server_memory_size": "4gb"        # value from vars/prod.yml
}
. . .
等效剧本使用include_vars ,经营作为一个任务,看起来像:
---
- name: variable precedence test
  hosts: localhost
  tasks:
    - include_vars:
        file: "{{ item }}"
      with_items:
        - "vars/{{ function }}.yml"
        - "vars/{{ env }}.yml"
    - debug: var=server_memory_size
这是Ansible允许显式排序的一个区域,这是非常有用的。然而,与前面的实施例一样,存在一些显着的缺点。 首先,使用vars_filesinclude_vars需要你地方紧密绑群体在不同的位置的变量。 该group_vars位置成为位于实际变量存根vars目录。 这再次增加了复杂性并降低了清晰度。 用户必须正确的变量文件匹配到主机,这恐怕是Ansible使用时会自动group_vars 。 更重要的是,依靠这些技术使它们成为强制性的。每个剧本都需要一个部分,以正确的顺序显式加载正确的变量文件。没有这个的游戏将无法使用关联的变量。此外,运行ansible的即席任务命令将是任何依赖变量几乎完全是不可能的。 到目前为止,我们已经研究了管理多级环境的一些策略,并讨论了为什么它们可能不是一个完整的解决方案。然而,Ansible项目确实提供了一些关于如何最好地在环境中抽象基础结构的建议。 推荐的方法是通过完全分离每个操作环境来与多级环境一起工作。不是在单个清单文件中维护所有主机,而是为每个单独的环境维护一个清单。独立group_vars目录也保持。 基本目录结构看起来像这样:
.
├── ansible.cfg
├── environments/         # Parent directory for our environment-specific directories
│   │
│   ├── dev/              # Contains all files specific to the dev environment
│   │   ├── group_vars/   # dev specific group_vars files
│   │   │   ├── all
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts         # Contains only the hosts in the dev environment
│   │
│   ├── prod/             # Contains all files specific to the prod environment
│   │   ├── group_vars/   # prod specific group_vars files
│   │   │   ├── all
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts         # Contains only the hosts in the prod environment
│   │
│   └── stage/            # Contains all files specific to the stage environment
│       ├── group_vars/   # stage specific group_vars files
│       │   ├── all
│       │   ├── db
│       │   └── web
│       └── hosts         # Contains only the hosts in the stage environment
│
├── playbook.yml
│
└── . . .
正如你所看到的,每个环境是不同的和分隔的。环境目录中包含一个清单文件(任意命名的hosts )和一个独立group_vars目录。 目录树中有一些明显的重复。有webdb文件为每个环境。 在这种情况下,需要重复。 通过首先在一个环境中修改变量,并在测试后将它们移动到下一个,可以跨环境推出变量更改,就像对代码或配置更改一样。 该group_vars变量跟踪每个环境的当前默认值。 一个限制是无法根据跨环境的功能选择所有主机。幸运的是,这与上面的可变重复问题属于同一类别。尽管为某个任务选择所有Web服务器有时很有用,但是您几乎总是希望逐个推出所有环境中的更改。这有助于防止错误影响您的生产环境。

设置跨环境变量

在推荐的设置中不可能的一件事是跨环境的可变共享。有很多方法可以实现跨环境变量共享。最简单的方法之一是利用Ansible的能力来使用目录代替文件。我们可以更换all的每个中的文件group_vars与目录中all目录。 在目录中,我们可以再次在文件中设置所有特定于环境的变量。然后,我们可以创建指向包含跨环境变量的文件位置的符号链接。这两个都将应用于环境中的所有主机。 首先在层次结构中的某个位置创建一个跨环境变量文件。在这个例子中,我们将其放置在environments的目录。将所有跨环境变量放在该文件中:
cd environments
touch 000_cross_env_vars
接下来,将进入一个group_vars目录下,重命名all文件,并创建all目录。将重命名的文件移动到新目录中:
cd dev/group_vars
mv all env_specific
mkdir all
mv env_specific all/
接下来,您可以创建一个指向跨环境变量文件的符号链接:
cd all/
ln -s ../../../000_cross_env_vars .
当您为每个环境完成上述步骤后,您的目录结构将如下所示:
.
├── ansible.cfg
├── environments/
│   │
│   ├── 000_cross_env_vars
│   │
│   ├── dev/
│   │   ├── group_vars/
│   │   │   ├── all/
│       │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│   │   │   │   └── env_specific
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts
│   │
│   ├── prod/
│   │   ├── group_vars/
│   │   │   ├── all/
│   │   │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│   │   │   │   └── env_specific
│   │   │   ├── db
│   │   │   └── web
│   │   └── hosts
│   │
│   └── stage/
│       ├── group_vars/
│       │   ├── all/
│       │   │   ├── 000_cross_env_vars -> ../../../000_cross_env_vars
│       │   │   └── env_specific
│       │   ├── db
│       │   └── web
│       └── hosts
│
├── playbook.yml
│
└── . . .
内设置的变量000_cross_env_vars文件将提供给各环境的具有低优先级。

设置默认环境清单

它可以设定在一个默认清单文件ansible.cfg文件。这是一个好主意,有几个原因。 首先,它允许你离开了明确的库存标志ansibleansible-playbook 。所以不要输入:
ansible -i environments/dev -m ping
您可以通过键入以下内容访问默认广告资源:
ansible -m ping
其次,设置默认清单有助于防止意外更改意外影响登台或生产环境。默认情况下,您的开发环境中,最不重要的基础架构会受到更改的影响。推动修改新的环境则是一个明确的操作要求的-i标志。 要设置默认目录,打开你的ansible.cfg文件。 这可能是在项目的根目录下,或在/etc/ansible/ansible.cfg根据您的配置。 注:下面的例子演示编辑ansible.cfg在项目目录中的文件。 如果您使用的是/etc/ansibile/ansible.cfg进行更改文件,修改下面的编辑路径。 当使用/etc/ansible/ansible.cfg ,如果你的库存保持在外面/etc/ansible目录,确保设置时要使用绝对路径,而不是相对路径的inventory价值。
nano ansible.cfg
如上所述,建议将开发环境设置为默认清单。注意我们如何选择整个环境目录,而不是它包含的主机文件:
[defaults]
inventory = ./environments/dev
您现在应该能够使用默认的库存没有-i选项。 非默认的库存仍然需要使用-i ,这有助于保护他们免受意外更改。

结论

在本文中,我们探讨了Ansible在多个环境中管理主机的灵活性。这允许用户在主机是多个组的成员时采用许多不同的策略来处理可变优先级,但是模糊性和缺乏官方方向可能是具有挑战性的。与任何技术一样,最适合您的组织将取决于您的用例和您的要求的复杂性。找到适合您需求的策略的最佳方法是实验。在下面的评论中分享您的用例和方法。