您如何处理 Ansible 角色中的服务器依赖性?

How Do You Handle Server Dependencies in Ansible Roles?

我是 Ansible 新手。我的 Ansible 剧本具有以下目录结构:

$HOME/playbooks
├── project1
├── project2
└── roles

我在角色目录中收集了我常用的角色,例如我的 "nginx" 角色,然后我将通过在每个项目的 ansible.cfg 文件中添加以下行来在我的项目目录中引用这些角色:

# $HOME/playbooks/project1/ansible.cfg
[defaults]
roles_path = $HOME/playbooks/roles

当通用角色任务取决于任务在哪个服务器上时,您如何配置个人 Ansible 剧本任务和通用角色任务 运行?就我而言,我有一个用于配置我的网络服务器的 "webservers.yml" 剧本和一个用于配置我的文件服务器的 "fileservers.yml" 剧本。我的网站将 运行 在我的网络服务器上,但我的静态和媒体文件将从单独的文件服务器提供。我目前在我的 nginx 角色的 main/task.yml 文件中包含以下任务:

# $HOME/playbooks/roles/nginx/tasks/main.yml
- name: create nginx config file
  template: src=nginx.conf.j2
            dest=/etc/nginx/sites-available/{{ domain }}.conf
  notify: restart nginx
  become: True
  tags: nginx

问题是每台服务器上的 nginx 配置文件会略有不同,因为(我认为)我的网络服务器上的 nginx 进程 运行ning 需要将静态文件请求重定向到 nginx 进程运行ning 在我的文件服务器上。我是否应该将 "create nginx config file" 任务保留在我的普通 nginx 角色中,让它将一个最小模板复制到每台服务器上,然后在我的网络服务器和文件服务器剧本中再次调用该任务,并让每个人部署一个特定于服务器的配置版本文件(例如 nginx.webserver.conf.j2 与 nginx.fileserver.conf.j2)?我是否应该将创建配置文件留在我的主要角色任务之外,并在每个剧本中执行它? (这种方法对我来说似乎是错误的)或者有更强大的方法来做到这一点?

谢谢!

如果每台机器上的nginx配置不同,那么你应该有库存变量来驱动每台服务器上配置文件的生成。适当地模板化您的 nginx.conf 文件以处理您的网络服务器和文件服务器配置。如果配置完全不同,您应该考虑使用单独的角色(nginx_web 和 nginx_file)或至少为每个配置单独的 jinja 模板。

@Petro026 已经提到的库存或组变量是一种选择。在您的 nginx 角色或配置模板中,您只需检查这些变量。

但我认为在这种情况下有更好的选择,因为这些角色是在网络服务器或文件服务器剧本的上下文中明确调用的。您可以简单地引入一个影响角色工作方式的角色参数。

- role: nginx
  mode: direct

或者对于网络服务器 mode: redirect

然后您可以在任务级别进行过滤

- some: task
  when: mode == "redirect"

或者根据条件处理模板中的所有内容。

{% if mode == "redirect" %}
# I am a webserver
{% else %}
# I am a fileserver
{% endif %}

现在,结果与使用组或主机变量完全相同,但我认为查看剧本的人所发生的事情更加明显,nginx 角色支持不同的模式以及该信息的定义位置(作为角色参数)。

Should I just leave the create config file out of my main role task and just execute it in each playbook? (This approach seems wrong to me) Or is there a more robust way to do this?

这是另一种选择。事实上,将任务正确地写入剧本似乎是错误的。但是嵌套角色呢?这再次为您提供了一个干净的解决方案。

保持你的 nginx 角色不变,只删除文件服务器和网络服务器之间不同的部分。

然后您创建两个新角色。一个叫 nginx_web,一个叫 nginx_file。现在,在这两个角色中,您都设置了对 <role>/meta/main.yml:

中常见 nginx 角色的依赖
dependencies:
  - role: nginx
    tags: nginx

现在你只需要将不同的部分添加到 nginx_webnginx_filetasks/main.yml 中,看起来它只是那个单一的模板任务。您甚至可以在您的公共 nginx 角色中保留用于重新启动 nginx 的处理程序,并从其他角色调用它。

现在您在剧本中需要参考的只是 nginx_webnginx_filenginx 角色在 nginx_web/file.

中的任务之前作为依赖项自动执行

更新:描述角色参数

可以以不同的方式应用角色。作为字符串或字典。字符串示例

roles:
  - roleName

如果您希望添加其他信息,例如标签、条件或其他参数,您可以提供字典。在这种情况下,角色名称进入字典键 role:

roles:
  - role: roleName
    tags: someTag
    when: someVar is defined
    become: True
    foo: bar

所有附加数据都传递给角色内的每个任务。 Ansible 将表现得好像 tagsbecomewhen 已应用于角色内的每个任务。 Ansible 不知道的其他一切都将被视为变量。

或者您可以将字典写成 JSON,因为 YAML 支持有限的 JSON 格式。

roles:
  - {role: "roleName", tags: "someTag", when: "someVar is defined", become: True, foo: "bar"}

但我觉得那个屁股很丑,更喜欢纯 YAML 定义

后者是documentation中显示的格式:

Also, should you wish to parameterize roles, by adding variables, you can do so, like this:

---

- hosts: webservers
  roles:
    - common
    - { role: foo_app_instance, dir: '/opt/a',  app_port: 5000 }
    - { role: foo_app_instance, dir: '/opt/b',  app_port: 5001 }