如何在Ansible中针对单主机执行特定任务?含角色场景及示例
Great question! Let's break down your two scenarios and fix up that playbook example you shared—there are definitely cleaner, more reliable ways to handle this, and I'll walk you through them step by step.
First, let's address the critical issue in your original example: you can't use the hosts field inside a task (like you tried in the killing the container task). The hosts parameter is only valid at the play level, not within individual tasks. That's a common gotcha, so let's fix that first with a proper, Ansible-compliant implementation.
Fixed Playbook & Role Example
Here's a corrected version of your setup that works as intended, using Ansible's standard patterns for cross-host task execution:
Your main playbook (your_playbook.yml)
- hosts: swarm_manager roles: - custom_role
roles/custom_role/tasks/main.yml
- name: Get the node running our target service shell: > docker service ps service --filter "desired-state=running" --format "{{.Node}}" | head -n1 register: target_node changed_when: false # Mark this as non-changing since it's just info gathering - name: Kill the service's container on the target node shell: > docker kill $(docker ps --filter "name=service" --format "{{.ID}}") delegate_to: "{{ target_node.stdout }}" become: true # Add this if you need sudo privileges for docker commands
Key improvements here:
- Used Docker's built-in
--formatflag instead ofgrep/awkfor parsing output—it's far more reliable if Docker's output format ever changes - Used
delegate_toto send the kill task directly to the target node (this is the correct way to run tasks on a different host within a play) - Added
changed_when: falseto the info-gathering task so Ansible doesn't mark it as a "change" every time
Scenario 1: Trigger tasks for specific hosts via an Ansible Role
You have two solid, scalable options here depending on your needs:
Option 1: Delegate individual tasks
Like the example above, use delegate_to to send specific tasks from your role to the target host. This is perfect for one-off or small sets of tasks that need to run on a different host than the play's target.
Option 2: Dynamically add hosts to a temporary group
If you need to run multiple plays or tasks against the target host, you can add it to a temporary group mid-play and reference that group later:
# Inside your role's tasks - name: Add target node to a temporary group add_host: name: "{{ target_node.stdout }}" groups: target_container_host # Then, in a subsequent play (can be in the same playbook or role) - hosts: target_container_host tasks: - name: Stop and remove the container cleanly docker_container: name: service state: absent become: true
(Bonus: Using the docker_container module instead of raw shell commands makes your playbook idempotent and easier to maintain!)
Scenario 2: Run specific tasks for a single host in a Playbook
If you just need to target a single host for certain tasks, here are four flexible approaches:
Directly specify the host in the play:
- hosts: my_single_host tasks: - name: Run a task only on this host command: echo "Hello from single host!"Use the
--limitflag when running the playbook:
No need to modify your playbook—just restrict execution to one host at runtime:ansible-playbook your_playbook.yml --limit my_single_hostUse a
whencondition to filter tasks:
If your play targets multiple hosts but you want a task to run only on one:- hosts: all tasks: - name: Run only on my_single_host command: echo "Hello from specific host!" when: inventory_hostname == "my_single_host"Delegate the task to the single host:
Similar to scenario 1, you can send a task to a single host even if your play is targeting other hosts:- hosts: swarm_manager tasks: - name: Run a task on my_single_host command: echo "Hello from delegated host!" delegate_to: my_single_host
内容的提问来源于stack exchange,提问作者Rajesh Rajendran

