How to parallelize loops with an inculde in ansible
Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.
This slowed down the whole cluster deploy time by a factor of the members on it.
To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.
The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.
Using "Parallel task execution in Ansible" as reference, I ended up having something like:
- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0
- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"
However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.
- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20
This does seem to work just fine, running one ping to each item and then moving on to the next action.
Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?
asynchronous ansible
add a comment |
Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.
This slowed down the whole cluster deploy time by a factor of the members on it.
To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.
The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.
Using "Parallel task execution in Ansible" as reference, I ended up having something like:
- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0
- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"
However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.
- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20
This does seem to work just fine, running one ping to each item and then moving on to the next action.
Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?
asynchronous ansible
Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00
add a comment |
Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.
This slowed down the whole cluster deploy time by a factor of the members on it.
To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.
The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.
Using "Parallel task execution in Ansible" as reference, I ended up having something like:
- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0
- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"
However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.
- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20
This does seem to work just fine, running one ping to each item and then moving on to the next action.
Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?
asynchronous ansible
Recently I came across a bottleneck in our ansible playbooks' code. We were deploying our clusters (e.g. a mongoDB Replica Set) sequentially - i.e. one VM after another, each waiting for the previous to be up and running.
This slowed down the whole cluster deploy time by a factor of the members on it.
To solve this, I started digging on ansible's async actions and pooling and found out a few examples on parallel loops and "fire-and-forget" strategies for scenarios like ours.
The particular thing is, we have defined our own "customize the VM and spawn it" ansible task (create_instance.yml) that gets included and receives the different customization variables from the playbook and abstracts the whole process by running different KVM/shell commands.
Using "Parallel task execution in Ansible" as reference, I ended up having something like:
- name: Generate VMs for DB
hosts: hypervisor_fe
tags: platform,mongodb
tasks:
- include: tasks/create_instance.yml
vars:
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
register: mongo_instances
async: 7200
poll: 0
- name: Wait for instance creation to complete
async_status: jid={{ item.ansible_job_id }}
register: mongo_jobs
until: mongo_jobs.finished
retries: 300
with_items: "{{ mongo_instances.results }}"
However, this setup does seem to ignore all the new async code and keeps the old, sequential behavior. I'm guessing this has to do with the no. and granularity of plays inside the imported task. If I instead replace the include for a single, explicit long-running task - let's say, e.g.
- name: Test async operation
shell: ping -c1 {{ item.hostname }} && sleep 20
This does seem to work just fine, running one ping to each item and then moving on to the next action.
Is this assumption right? Does someone has experience with include and async loops in ansible? Do I need to move the async declaration to a single play inside the imported code?
asynchronous ansible
asynchronous ansible
edited Nov 12 '18 at 14:56
asked Nov 12 '18 at 14:22
Alfageme
1,24011120
1,24011120
Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00
add a comment |
Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00
Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00
Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00
add a comment |
1 Answer
1
active
oldest
votes
I advice you to rethink your playbook design in the following way:
- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
- hosts: new_vms
tasks:
- include: create_instance.yml
And inside create_instance.yml use delegate_to: hypervisor_fe.
This gives you native Ansible host loop for every vm with concurrent execution of each task.
Won't this fail with "unreachable" when trying to gather the facts ofnew_vms(not yet created)? Is there a way to apply thedelegate_toto all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33
1
You can disable it withgather_facts: noand collect them later withsetupmodule. You can applydelegate_to: localhosttoincludestatement or addblockinto your task file and applydelegate_toto the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53264168%2fhow-to-parallelize-loops-with-an-inculde-in-ansible%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
I advice you to rethink your playbook design in the following way:
- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
- hosts: new_vms
tasks:
- include: create_instance.yml
And inside create_instance.yml use delegate_to: hypervisor_fe.
This gives you native Ansible host loop for every vm with concurrent execution of each task.
Won't this fail with "unreachable" when trying to gather the facts ofnew_vms(not yet created)? Is there a way to apply thedelegate_toto all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33
1
You can disable it withgather_facts: noand collect them later withsetupmodule. You can applydelegate_to: localhosttoincludestatement or addblockinto your task file and applydelegate_toto the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41
add a comment |
I advice you to rethink your playbook design in the following way:
- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
- hosts: new_vms
tasks:
- include: create_instance.yml
And inside create_instance.yml use delegate_to: hypervisor_fe.
This gives you native Ansible host loop for every vm with concurrent execution of each task.
Won't this fail with "unreachable" when trying to gather the facts ofnew_vms(not yet created)? Is there a way to apply thedelegate_toto all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33
1
You can disable it withgather_facts: noand collect them later withsetupmodule. You can applydelegate_to: localhosttoincludestatement or addblockinto your task file and applydelegate_toto the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41
add a comment |
I advice you to rethink your playbook design in the following way:
- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
- hosts: new_vms
tasks:
- include: create_instance.yml
And inside create_instance.yml use delegate_to: hypervisor_fe.
This gives you native Ansible host loop for every vm with concurrent execution of each task.
I advice you to rethink your playbook design in the following way:
- hosts: localhost
tasks:
- add_host:
name: "{{ item.name }}"
groups: new_vms
vm: "{{ item }}"
with_items: "{{ mongodb.vms }}"
- hosts: new_vms
tasks:
- include: create_instance.yml
And inside create_instance.yml use delegate_to: hypervisor_fe.
This gives you native Ansible host loop for every vm with concurrent execution of each task.
answered Nov 12 '18 at 19:38
Konstantin Suvorov
36.1k44081
36.1k44081
Won't this fail with "unreachable" when trying to gather the facts ofnew_vms(not yet created)? Is there a way to apply thedelegate_toto all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33
1
You can disable it withgather_facts: noand collect them later withsetupmodule. You can applydelegate_to: localhosttoincludestatement or addblockinto your task file and applydelegate_toto the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41
add a comment |
Won't this fail with "unreachable" when trying to gather the facts ofnew_vms(not yet created)? Is there a way to apply thedelegate_toto all tasks on the include? (~30)
– Alfageme
Nov 13 '18 at 10:33
1
You can disable it withgather_facts: noand collect them later withsetupmodule. You can applydelegate_to: localhosttoincludestatement or addblockinto your task file and applydelegate_toto the block.
– Konstantin Suvorov
Nov 13 '18 at 10:41
Won't this fail with "unreachable" when trying to gather the facts of
new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)– Alfageme
Nov 13 '18 at 10:33
Won't this fail with "unreachable" when trying to gather the facts of
new_vms (not yet created)? Is there a way to apply the delegate_to to all tasks on the include? (~30)– Alfageme
Nov 13 '18 at 10:33
1
1
You can disable it with
gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.– Konstantin Suvorov
Nov 13 '18 at 10:41
You can disable it with
gather_facts: no and collect them later with setup module. You can apply delegate_to: localhost to include statement or add block into your task file and apply delegate_to to the block.– Konstantin Suvorov
Nov 13 '18 at 10:41
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53264168%2fhow-to-parallelize-loops-with-an-inculde-in-ansible%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Based on what I read in stackoverflow.com/a/39207589/2172072 by @konstantin-suvorov: "include can't use async keyword" - thus, this seems not to be an option right now. Digging on ansible's GH found out this FR: github.com/ansible/ansible/issues/22716
– Alfageme
Nov 12 '18 at 16:00