PAYATHON 2026

如何通过指定 tags 在一个 role 中引入另一个 role?

排障赵师傅

apply: tags 会给引入的 role 内的任务追加标签,不能按任务原有的标签筛选任务。

要按 certificates 内部原有的标签执行任务,应移除 apply: tags,给 include_role 入口设置相应标签,再通过命令行 --tags 选择。如果不传 --tags 时也只想执行 CA 和 wildcard 任务,可以用 tasks_from 指定一个只包含这些任务的入口文件。

为什么所有任务都会匹配 ca

原配置中,两处 tags 的作用不同:

- name: Copy CA certificates to prevent MITM issues
  ansible.builtin.include_role:
    name: certificates
    apply:
      tags:
        - ca
        - wildcards
  tags:
    - ca

外层的 tags: ca 控制是否选中这条 include_role 任务。apply.tags 给 role 内的任务追加 ca、wildcards 标签,不会检查任务原来的标签是否在这个列表中。include_role 参数说明

按题目中的静态导入结构,追加标签后,各组任务的有效标签如下:

任务组原有标签追加后的标签
根 CA 证书caca, wildcards
普通密钥与证书certscerts, ca, wildcards
wildcard 证书wildcardwildcard, ca, wildcards
IDM 证书idm, neveridm, never, ca, wildcards

这些任务都带有 ca,因此执行 -t ca 时都会匹配。

示例中的 wildcards 与 role 内定义的 wildcard 是两个不同的标签,拼写需要统一。

为什么带有 never 的任务也会执行

never 表示默认跳过,但显式选择任务上的其他标签,仍可让它执行。IDM 任务继承 ca 后,就能被 --tags ca 选中。特殊标签规则

这两种运行情况需要分开看:

  • 使用 -t ca 时,原配置给 IDM 任务追加了 ca,所以它会执行。
  • 不传 -t 时,如果没有其他标签配置、标签继承或 always 标签的影响,普通的 apply.tags: [ca, wildcards] 不会让 never 任务执行。

如果不传 -t 时也出现了这个问题,应先确认看到的是任务文件被解析、加载,还是其中的任务确实执行了。文件被加载不代表所有任务都会执行。同时检查 ansible.cfg、ANSIBLE_RUN_TAGS 和上层标签设置。

按命令行标签选择:移除 apply.tags

将 os-base/tasks/main.yml 中的引入改为:

- name: Include certificate tasks
  ansible.builtin.include_role:
    name: certificates
  tags:
    - ca
    - wildcard

保留 certificates/tasks/main.yml 中各个 import_tasks 原有的标签,然后运行:

# 只选择 CA 任务
ansible-playbook playbooks/os-base.yml -e t=node1 --tags ca

# 选择 CA 和 wildcard 任务
ansible-playbook playbooks/os-base.yml -e t=node1 --tags ca,wildcard

动态 include_role 的外层标签只标记引入任务本身,不会自动传给内部任务。运行时先按标签选中入口,再按内部任务各自的标签决定是否执行。动态引入的标签规则

这里需要给入口同时添加 ca 和 wildcard。如果入口只有 ca,单独运行 --tags wildcard 时,入口会被跳过,内部的 wildcard 任务也无法执行。

也可以将入口设为:

- name: Include certificate tasks
  ansible.builtin.include_role:
    name: certificates
  tags:
    - always

这样,后续增加内部标签时通常无需修改入口。不过,使用其他标签运行时,这个入口也会被处理,内部任务仍按运行时标签筛选。

不传 --tags 时,这两种写法都会按默认规则运行 certificates 的普通任务,包括 certs,不会将默认执行范围限制为 CA 和 wildcard。

默认也只运行指定部分:使用 tasks_from

如果完整执行 os-base 时只需要 CA 和 wildcard,可以为 certificates 增加一个专用任务入口。

创建 roles/certificates/tasks/os_base.yml:

- name: Install root CA certificates
  ansible.builtin.import_tasks:
    file: _deploy_ca_certs.yml
  tags:
    - ca

- name: Install wildcard pair
  ansible.builtin.import_tasks:
    file: _deploy_wildcard.yml
  tags:
    - wildcard

在 roles/os-base/tasks/main.yml 中指定这个入口:

- name: Include certificates required by os-base
  ansible.builtin.include_role:
    name: certificates
    tasks_from: os_base
  tags:
    - ca
    - wildcard

tasks_from 指定从 role 的 tasks/ 目录加载哪个文件,替代默认的 main.yml。tasks_from 参数说明

使用这份配置后,可以这样运行:

# 完整执行 os-base,证书部分只包含专用入口中的任务
ansible-playbook playbooks/os-base.yml -e t=node1

# 只选择 CA 任务
ansible-playbook playbooks/os-base.yml -e t=node1 --tags ca

# 选择 CA 和 wildcard 任务
ansible-playbook playbooks/os-base.yml -e t=node1 --tags ca,wildcard

这会绕过 certificates/tasks/main.yml。如果摘要、初始化等任务是证书部署的前置步骤,也需要将它们加入专用入口。

摘要标签和排查时的注意事项

ansible_run_tags 表示本次运行选择的标签,不是当前任务持有的标签。未指定 --tags 且没有其他运行标签配置时,它通常是 ["all"];传入 --tags ca 时则是 ["ca"]。apply.tags 不会修改它。特殊变量说明

always_block 只是文件名,不会自动赋予任务 always 行为。如果希望按标签运行时也显示摘要,可以给这个静态导入显式添加标签:

- name: Import summary tasks
  ansible.builtin.import_role:
    name: commons
    tasks_from: always_block
  tags:
    - always

该任务仍需位于实际加载的入口中,且未被 --skip-tags 排除。

排查时还需注意:

  • --tags 对整个 playbook 生效,其他 role 中带有 ca 的任务也可能执行。如果需要独立选择,应使用更具体的标签名。
  • 检查上层 play、block 或 role 是否给所有子任务统一追加了 ca。如果有,移除这里的 apply.tags 后仍可能出现相同结果。
  • --list-tasks 和 --list-tags 无法完整展示动态引入内部的任务与标签,不能仅凭列表判断实际执行范围。预览功能的限制

备注:内容仅供参考。