mirror of https://github.com/ansible/ansible.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
509 lines
19 KiB
ReStructuredText
509 lines
19 KiB
ReStructuredText
13 years ago
|
Best Practices
|
||
|
==============
|
||
|
|
||
10 years ago
|
Here are some tips for making the most of Ansible and Ansible playbooks.
|
||
13 years ago
|
|
||
11 years ago
|
You can find some example playbooks illustrating these best practices in our `ansible-examples repository <https://github.com/ansible/ansible-examples>`_. (NOTE: These may not use all of the features in the latest release, but are still an excellent reference!).
|
||
12 years ago
|
|
||
11 years ago
|
.. contents:: Topics
|
||
|
|
||
11 years ago
|
.. _content_organization:
|
||
|
|
||
12 years ago
|
Content Organization
|
||
|
++++++++++++++++++++++
|
||
|
|
||
10 years ago
|
The following section shows one of many possible ways to organize playbook content.
|
||
12 years ago
|
|
||
10 years ago
|
Your usage of Ansible should fit your needs, however, not ours, so feel free to modify this approach and organize as you see fit.
|
||
|
|
||
8 years ago
|
One crucial way to organize your playbook content is Ansible's "roles" organization feature, which is documented as part
|
||
|
of the main playbooks page. You should take the time to read and understand the roles documentation which is available here: :doc:`playbooks_reuse_roles`.
|
||
12 years ago
|
|
||
11 years ago
|
.. _directory_layout:
|
||
|
|
||
12 years ago
|
Directory Layout
|
||
|
````````````````
|
||
|
|
||
|
The top level of the directory would contain files and directories like so::
|
||
|
|
||
8 years ago
|
production # inventory file for production servers
|
||
|
staging # inventory file for staging environment
|
||
12 years ago
|
|
||
|
group_vars/
|
||
12 years ago
|
group1 # here we assign variables to particular groups
|
||
|
group2 # ""
|
||
12 years ago
|
host_vars/
|
||
12 years ago
|
hostname1 # if systems need specific variables, put them here
|
||
|
hostname2 # ""
|
||
|
|
||
10 years ago
|
library/ # if any custom modules, put them here (optional)
|
||
7 years ago
|
module_utils/ # if any custom module_utils to support modules, put them here (optional)
|
||
10 years ago
|
filter_plugins/ # if any custom filter plugins, put them here (optional)
|
||
|
|
||
12 years ago
|
site.yml # master playbook
|
||
|
webservers.yml # playbook for webserver tier
|
||
|
dbservers.yml # playbook for dbserver tier
|
||
|
|
||
|
roles/
|
||
|
common/ # this hierarchy represents a "role"
|
||
|
tasks/ #
|
||
|
main.yml # <-- tasks file can include smaller files if warranted
|
||
|
handlers/ #
|
||
|
main.yml # <-- handlers file
|
||
|
templates/ # <-- files for use with the template resource
|
||
|
ntp.conf.j2 # <------- templates end in .j2
|
||
|
files/ #
|
||
|
bar.txt # <-- files for use with the copy resource
|
||
12 years ago
|
foo.sh # <-- script files for use with the script resource
|
||
11 years ago
|
vars/ #
|
||
|
main.yml # <-- variables associated with this role
|
||
10 years ago
|
defaults/ #
|
||
|
main.yml # <-- default lower priority variables for this role
|
||
11 years ago
|
meta/ #
|
||
|
main.yml # <-- role dependencies
|
||
8 years ago
|
library/ # roles can also include custom modules
|
||
7 years ago
|
module_utils/ # roles can also include custom module_utils
|
||
8 years ago
|
lookup_plugins/ # or other types of plugins, like lookup in this case
|
||
12 years ago
|
|
||
|
webtier/ # same kind of structure as "common" was above, done for the webtier role
|
||
|
monitoring/ # ""
|
||
|
fooapp/ # ""
|
||
12 years ago
|
|
||
10 years ago
|
.. note: If you find yourself having too many top level playbooks (for instance you have a playbook you wrote for a specific hotfix, etc), it may make sense to have a playbooks/ directory instead. This can be a good idea as you get larger. If you do this, configure your roles_path in ansible.cfg to find your roles location.
|
||
10 years ago
|
|
||
8 years ago
|
.. _alternative_directory_layout:
|
||
|
|
||
|
Alternative Directory Layout
|
||
8 years ago
|
````````````````````````````
|
||
8 years ago
|
|
||
|
Alternatively you can put each inventory file with its ``group_vars``/``host_vars`` in a separate directory. This is particularly useful if your ``group_vars``/``host_vars`` don't have that much in common in different environments. The layout could look something like this::
|
||
|
|
||
|
inventories/
|
||
|
production/
|
||
8 years ago
|
hosts # inventory file for production servers
|
||
8 years ago
|
group_vars/
|
||
|
group1 # here we assign variables to particular groups
|
||
|
group2 # ""
|
||
|
host_vars/
|
||
|
hostname1 # if systems need specific variables, put them here
|
||
|
hostname2 # ""
|
||
|
|
||
|
staging/
|
||
8 years ago
|
hosts # inventory file for staging environment
|
||
8 years ago
|
group_vars/
|
||
|
group1 # here we assign variables to particular groups
|
||
|
group2 # ""
|
||
|
host_vars/
|
||
|
stagehost1 # if systems need specific variables, put them here
|
||
|
stagehost2 # ""
|
||
|
|
||
|
library/
|
||
7 years ago
|
module_utils/
|
||
8 years ago
|
filter_plugins/
|
||
|
|
||
|
site.yml
|
||
|
webservers.yml
|
||
|
dbservers.yml
|
||
|
|
||
|
roles/
|
||
|
common/
|
||
|
webtier/
|
||
|
monitoring/
|
||
|
fooapp/
|
||
|
|
||
|
This layout gives you more flexibility for larger environments, as well as a total separation of inventory variables between different environments. The downside is that it is harder to maintain, because there are more files.
|
||
|
|
||
10 years ago
|
.. _use_dynamic_inventory_with_clouds:
|
||
|
|
||
|
Use Dynamic Inventory With Clouds
|
||
|
`````````````````````````````````
|
||
|
|
||
|
If you are using a cloud provider, you should not be managing your inventory in a static file. See :doc:`intro_dynamic_inventory`.
|
||
|
|
||
10 years ago
|
This does not just apply to clouds -- If you have another system maintaining a canonical list of systems
|
||
10 years ago
|
in your infrastructure, usage of dynamic inventory is a great idea in general.
|
||
|
|
||
10 years ago
|
.. _staging_vs_prod:
|
||
11 years ago
|
|
||
10 years ago
|
How to Differentiate Staging vs Production
|
||
|
``````````````````````````````````````````
|
||
10 years ago
|
|
||
|
If managing static inventory, it is frequently asked how to differentiate different types of environments. The following example
|
||
|
shows a good way to do this. Similar methods of grouping could be adapted to dynamic inventory (for instance, consider applying the AWS
|
||
|
tag "environment:production", and you'll get a group of systems automatically discovered named "ec2_tag_environment_production".
|
||
12 years ago
|
|
||
10 years ago
|
Let's show a static inventory example though. Below, the *production* file contains the inventory of all of your production hosts.
|
||
11 years ago
|
|
||
|
It is suggested that you define groups based on purpose of the host (roles) and also geography or datacenter location (if applicable)::
|
||
12 years ago
|
|
||
|
# file: production
|
||
|
|
||
|
[atlanta-webservers]
|
||
|
www-atl-1.example.com
|
||
|
www-atl-2.example.com
|
||
|
|
||
|
[boston-webservers]
|
||
|
www-bos-1.example.com
|
||
|
www-bos-2.example.com
|
||
|
|
||
|
[atlanta-dbservers]
|
||
|
db-atl-1.example.com
|
||
|
db-atl-2.example.com
|
||
|
|
||
|
[boston-dbservers]
|
||
|
db-bos-1.example.com
|
||
|
|
||
|
# webservers in all geos
|
||
|
[webservers:children]
|
||
|
atlanta-webservers
|
||
|
boston-webservers
|
||
|
|
||
|
# dbservers in all geos
|
||
|
[dbservers:children]
|
||
|
atlanta-dbservers
|
||
|
boston-dbservers
|
||
|
|
||
|
# everything in the atlanta geo
|
||
|
[atlanta:children]
|
||
|
atlanta-webservers
|
||
|
atlanta-dbservers
|
||
|
|
||
|
# everything in the boston geo
|
||
|
[boston:children]
|
||
|
boston-webservers
|
||
|
boston-dbservers
|
||
|
|
||
11 years ago
|
.. _groups_and_hosts:
|
||
|
|
||
12 years ago
|
Group And Host Variables
|
||
|
````````````````````````
|
||
|
|
||
10 years ago
|
This section extends on the previous example.
|
||
|
|
||
|
Groups are nice for organization, but that's not all groups are good for. You can also assign variables to them! For instance, atlanta has its own NTP servers, so when setting up ntp.conf, we should use them. Let's set those now::
|
||
12 years ago
|
|
||
|
---
|
||
|
# file: group_vars/atlanta
|
||
|
ntp: ntp-atlanta.example.com
|
||
|
backup: backup-atlanta.example.com
|
||
|
|
||
11 years ago
|
Variables aren't just for geographic information either! Maybe the webservers have some configuration that doesn't make sense for the database servers::
|
||
12 years ago
|
|
||
|
---
|
||
|
# file: group_vars/webservers
|
||
|
apacheMaxRequestsPerChild: 3000
|
||
|
apacheMaxClients: 900
|
||
|
|
||
|
If we had any default values, or values that were universally true, we would put them in a file called group_vars/all::
|
||
|
|
||
|
---
|
||
|
# file: group_vars/all
|
||
|
ntp: ntp-boston.example.com
|
||
|
backup: backup-boston.example.com
|
||
|
|
||
|
We can define specific hardware variance in systems in a host_vars file, but avoid doing this unless you need to::
|
||
|
|
||
|
---
|
||
|
# file: host_vars/db-bos-1.example.com
|
||
|
foo_agent_port: 86
|
||
|
bar_agent_port: 99
|
||
|
|
||
10 years ago
|
Again, if we are using dynamic inventory sources, many dynamic groups are automatically created. So a tag like "class:webserver" would load in
|
||
|
variables from the file "group_vars/ec2_tag_class_webserver" automatically.
|
||
|
|
||
11 years ago
|
.. _split_by_role:
|
||
|
|
||
12 years ago
|
Top Level Playbooks Are Separated By Role
|
||
12 years ago
|
`````````````````````````````````````````
|
||
|
|
||
7 years ago
|
In site.yml, we import a playbook that defines our entire infrastructure. This is a very short example, because it's just importing
|
||
|
some other playbooks::
|
||
12 years ago
|
|
||
|
---
|
||
|
# file: site.yml
|
||
7 years ago
|
- import_playbook: webservers.yml
|
||
|
- import_playbook: dbservers.yml
|
||
12 years ago
|
|
||
7 years ago
|
In a file like webservers.yml (also at the top level), we map the configuration of the webservers group to the roles performed by the webservers group::
|
||
12 years ago
|
|
||
|
---
|
||
|
# file: webservers.yml
|
||
|
- hosts: webservers
|
||
12 years ago
|
roles:
|
||
|
- common
|
||
|
- webtier
|
||
12 years ago
|
|
||
10 years ago
|
The idea here is that we can choose to configure our whole infrastructure by "running" site.yml or we could just choose to run a subset by running
|
||
|
webservers.yml. This is analogous to the "--limit" parameter to ansible but a little more explicit::
|
||
|
|
||
|
ansible-playbook site.yml --limit webservers
|
||
|
ansible-playbook webservers.yml
|
||
|
|
||
11 years ago
|
.. _role_organization:
|
||
|
|
||
12 years ago
|
Task And Handler Organization For A Role
|
||
|
````````````````````````````````````````
|
||
|
|
||
11 years ago
|
Below is an example tasks file that explains how a role works. Our common role here just sets up NTP, but it could do more if we wanted::
|
||
12 years ago
|
|
||
|
---
|
||
12 years ago
|
# file: roles/common/tasks/main.yml
|
||
12 years ago
|
|
||
|
- name: be sure ntp is installed
|
||
7 years ago
|
yum:
|
||
|
name: ntp
|
||
|
state: installed
|
||
12 years ago
|
tags: ntp
|
||
|
|
||
|
- name: be sure ntp is configured
|
||
7 years ago
|
template:
|
||
|
src: ntp.conf.j2
|
||
|
dest: /etc/ntp.conf
|
||
12 years ago
|
notify:
|
||
|
- restart ntpd
|
||
|
tags: ntp
|
||
12 years ago
|
|
||
12 years ago
|
- name: be sure ntpd is running and enabled
|
||
7 years ago
|
service:
|
||
|
name: ntpd
|
||
|
state: started
|
||
|
enabled: yes
|
||
12 years ago
|
tags: ntp
|
||
|
|
||
|
Here is an example handlers file. As a review, handlers are only fired when certain tasks report changes, and are run at the end
|
||
|
of each play::
|
||
|
|
||
|
---
|
||
12 years ago
|
# file: roles/common/handlers/main.yml
|
||
12 years ago
|
- name: restart ntpd
|
||
7 years ago
|
service:
|
||
|
name: ntpd
|
||
|
state: restarted
|
||
12 years ago
|
|
||
8 years ago
|
See :doc:`playbooks_reuse_roles` for more information.
|
||
11 years ago
|
|
||
|
|
||
11 years ago
|
.. _organization_examples:
|
||
|
|
||
12 years ago
|
What This Organization Enables (Examples)
|
||
|
`````````````````````````````````````````
|
||
|
|
||
11 years ago
|
Above we've shared our basic organizational structure.
|
||
12 years ago
|
|
||
|
Now what sort of use cases does this layout enable? Lots! If I want to reconfigure my whole infrastructure, it's just::
|
||
|
|
||
|
ansible-playbook -i production site.yml
|
||
|
|
||
7 years ago
|
To reconfigure NTP on everything::
|
||
12 years ago
|
|
||
|
ansible-playbook -i production site.yml --tags ntp
|
||
|
|
||
7 years ago
|
To reconfigure just my webservers::
|
||
12 years ago
|
|
||
|
ansible-playbook -i production webservers.yml
|
||
|
|
||
7 years ago
|
For just my webservers in Boston::
|
||
12 years ago
|
|
||
|
ansible-playbook -i production webservers.yml --limit boston
|
||
|
|
||
7 years ago
|
For just the first 10, and then the next 10::
|
||
12 years ago
|
|
||
7 years ago
|
ansible-playbook -i production webservers.yml --limit boston[0:9]
|
||
|
ansible-playbook -i production webservers.yml --limit boston[10:19]
|
||
12 years ago
|
|
||
7 years ago
|
And of course just basic ad-hoc stuff is also possible::
|
||
12 years ago
|
|
||
11 years ago
|
ansible boston -i production -m ping
|
||
|
ansible boston -i production -m command -a '/sbin/reboot'
|
||
12 years ago
|
|
||
7 years ago
|
And there are some useful commands to know::
|
||
12 years ago
|
|
||
|
# confirm what task names would be run if I ran this command and said "just ntp tasks"
|
||
|
ansible-playbook -i production webservers.yml --tags ntp --list-tasks
|
||
|
|
||
|
# confirm what hostnames might be communicated with if I said "limit to boston"
|
||
|
ansible-playbook -i production webservers.yml --limit boston --list-hosts
|
||
|
|
||
11 years ago
|
.. _dep_vs_config:
|
||
|
|
||
12 years ago
|
Deployment vs Configuration Organization
|
||
|
````````````````````````````````````````
|
||
|
|
||
11 years ago
|
The above setup models a typical configuration topology. When doing multi-tier deployments, there are going
|
||
12 years ago
|
to be some additional playbooks that hop between tiers to roll out an application. In this case, 'site.yml'
|
||
|
may be augmented by playbooks like 'deploy_exampledotcom.yml' but the general concepts can still apply.
|
||
|
|
||
11 years ago
|
Consider "playbooks" as a sports metaphor -- you don't have to just have one set of plays to use against your infrastructure
|
||
|
all the time -- you can have situational plays that you use at different times and for different purposes.
|
||
|
|
||
12 years ago
|
Ansible allows you to deploy and configure using the same tool, so you would likely reuse groups and just
|
||
12 years ago
|
keep the OS configuration in separate playbooks from the app deployment.
|
||
12 years ago
|
|
||
10 years ago
|
.. _staging_vs_production:
|
||
11 years ago
|
|
||
10 years ago
|
Staging vs Production
|
||
9 years ago
|
+++++++++++++++++++++
|
||
12 years ago
|
|
||
10 years ago
|
As also mentioned above, a good way to keep your staging (or testing) and production environments separate is to use a separate inventory file for staging and production. This way you pick with -i what you are targeting. Keeping them all in one file can lead to surprises!
|
||
12 years ago
|
|
||
10 years ago
|
Testing things in a staging environment before trying in production is always a great idea. Your environments need not be the same
|
||
12 years ago
|
size and you can use group variables to control the differences between those environments.
|
||
|
|
||
11 years ago
|
.. _rolling_update:
|
||
|
|
||
12 years ago
|
Rolling Updates
|
||
|
+++++++++++++++
|
||
|
|
||
|
Understand the 'serial' keyword. If updating a webserver farm you really want to use it to control how many machines you are
|
||
|
updating at once in the batch.
|
||
|
|
||
11 years ago
|
See :doc:`playbooks_delegation`.
|
||
|
|
||
11 years ago
|
.. _mention_the_state:
|
||
|
|
||
12 years ago
|
Always Mention The State
|
||
|
++++++++++++++++++++++++
|
||
|
|
||
|
The 'state' parameter is optional to a lot of modules. Whether 'state=present' or 'state=absent', it's always best to leave that
|
||
|
parameter in your playbooks to make it clear, especially as some modules support additional states.
|
||
12 years ago
|
|
||
11 years ago
|
.. _group_by_roles:
|
||
|
|
||
13 years ago
|
Group By Roles
|
||
|
++++++++++++++
|
||
|
|
||
10 years ago
|
We're somewhat repeating ourselves with this tip, but it's worth repeating. A system can be in multiple groups. See :doc:`intro_inventory` and :doc:`intro_patterns`. Having groups named after things like
|
||
12 years ago
|
*webservers* and *dbservers* is repeated in the examples because it's a very powerful concept.
|
||
13 years ago
|
|
||
|
This allows playbooks to target machines based on role, as well as to assign role specific variables
|
||
|
using the group variable system.
|
||
|
|
||
8 years ago
|
See :doc:`playbooks_reuse_roles`.
|
||
11 years ago
|
|
||
11 years ago
|
.. _os_variance:
|
||
|
|
||
12 years ago
|
Operating System and Distribution Variance
|
||
|
++++++++++++++++++++++++++++++++++++++++++
|
||
|
|
||
10 years ago
|
When dealing with a parameter that is different between two different operating systems, a great way to handle this is
|
||
12 years ago
|
by using the group_by module.
|
||
|
|
||
|
This makes a dynamic group of hosts matching certain criteria, even if that group is not defined in the inventory file::
|
||
|
|
||
|
---
|
||
|
|
||
7 years ago
|
# talk to all hosts just so we can learn about them
|
||
|
- hosts: all
|
||
|
tasks:
|
||
|
- group_by:
|
||
|
key: os_{{ ansible_distribution }}
|
||
12 years ago
|
|
||
7 years ago
|
# now just on the CentOS hosts...
|
||
13 years ago
|
|
||
7 years ago
|
- hosts: os_CentOS
|
||
|
gather_facts: False
|
||
|
tasks:
|
||
12 years ago
|
- # tasks that only happen on CentOS go here
|
||
|
|
||
10 years ago
|
This will throw all systems into a dynamic group based on the operating system name.
|
||
|
|
||
11 years ago
|
If group-specific settings are needed, this can also be done. For example::
|
||
13 years ago
|
|
||
12 years ago
|
---
|
||
12 years ago
|
# file: group_vars/all
|
||
|
asdf: 10
|
||
13 years ago
|
|
||
12 years ago
|
---
|
||
10 years ago
|
# file: group_vars/os_CentOS
|
||
12 years ago
|
asdf: 42
|
||
13 years ago
|
|
||
11 years ago
|
In the above example, CentOS machines get the value of '42' for asdf, but other machines get '10'.
|
||
10 years ago
|
This can be used not only to set variables, but also to apply certain roles to only certain systems.
|
||
|
|
||
10 years ago
|
Alternatively, if only variables are needed::
|
||
10 years ago
|
|
||
|
- hosts: all
|
||
|
tasks:
|
||
|
- include_vars: "os_{{ ansible_distribution }}.yml"
|
||
7 years ago
|
- debug:
|
||
|
var: asdf
|
||
10 years ago
|
|
||
|
This will pull in variables based on the OS name.
|
||
13 years ago
|
|
||
11 years ago
|
.. _ship_modules_with_playbooks:
|
||
13 years ago
|
|
||
13 years ago
|
Bundling Ansible Modules With Playbooks
|
||
|
+++++++++++++++++++++++++++++++++++++++
|
||
|
|
||
7 years ago
|
If a playbook has a :file:`./library` directory relative to its YAML file, this directory can be used to add ansible modules that will
|
||
10 years ago
|
automatically be in the ansible module path. This is a great way to keep modules that go with a playbook together. This is shown
|
||
|
in the directory structure example at the start of this section.
|
||
12 years ago
|
|
||
11 years ago
|
.. _whitespace:
|
||
|
|
||
12 years ago
|
Whitespace and Comments
|
||
|
+++++++++++++++++++++++
|
||
13 years ago
|
|
||
12 years ago
|
Generous use of whitespace to break things up, and use of comments (which start with '#'), is encouraged.
|
||
|
|
||
11 years ago
|
.. _name_tasks:
|
||
|
|
||
12 years ago
|
Always Name Tasks
|
||
|
+++++++++++++++++
|
||
|
|
||
|
It is possible to leave off the 'name' for a given task, though it is recommended to provide a description
|
||
|
about why something is being done instead. This name is shown when the playbook is run.
|
||
|
|
||
11 years ago
|
.. _keep_it_simple:
|
||
|
|
||
12 years ago
|
Keep It Simple
|
||
|
++++++++++++++
|
||
13 years ago
|
|
||
12 years ago
|
When you can do something simply, do something simply. Do not reach
|
||
|
to use every feature of Ansible together, all at once. Use what works
|
||
11 years ago
|
for you. For example, you will probably not need ``vars``,
|
||
|
``vars_files``, ``vars_prompt`` and ``--extra-vars`` all at once,
|
||
12 years ago
|
while also using an external inventory file.
|
||
|
|
||
10 years ago
|
If something feels complicated, it probably is, and may be a good opportunity to simplify things.
|
||
10 years ago
|
|
||
11 years ago
|
.. _version_control:
|
||
|
|
||
12 years ago
|
Version Control
|
||
|
+++++++++++++++
|
||
12 years ago
|
|
||
|
Use version control. Keep your playbooks and inventory file in git
|
||
|
(or another version control system), and commit when you make changes
|
||
|
to them. This way you have an audit trail describing when and why you
|
||
11 years ago
|
changed the rules that are automating your infrastructure.
|
||
12 years ago
|
|
||
9 years ago
|
.. _best_practices_for_variables_and_vaults:
|
||
|
|
||
|
Variables and Vaults
|
||
|
++++++++++++++++++++++++++++++++++++++++
|
||
|
|
||
|
For general maintenance, it is often easier to use ``grep``, or similar tools, to find variables in your Ansible setup. Since vaults obscure these variables, it is best to work with a layer of indirection. When running a playbook, Ansible finds the variables in the unencrypted file and all sensitive variables come from the encrypted file.
|
||
|
|
||
7 years ago
|
A best practice approach for this is to start with a ``group_vars/`` subdirectory named after the group. Inside of this subdirectory, create two files named ``vars`` and ``vault``. Inside of the ``vars`` file, define all of the variables needed, including any sensitive ones. Next, copy all of the sensitive variables over to the ``vault`` file and prefix these variables with ``vault_``. You should adjust the variables in the ``vars`` file to point to the matching ``vault_`` variables using jinja2 syntax, and ensure that the ``vault`` file is vault encrypted.
|
||
9 years ago
|
|
||
|
This best practice has no limit on the amount of variable and vault files or their names.
|
||
|
|
||
|
|
||
13 years ago
|
.. seealso::
|
||
|
|
||
|
:doc:`YAMLSyntax`
|
||
|
Learn about YAML syntax
|
||
|
:doc:`playbooks`
|
||
|
Review the basic playbook features
|
||
|
:doc:`modules`
|
||
|
Learn about available modules
|
||
8 years ago
|
:doc:`dev_guide/developing_modules`
|
||
13 years ago
|
Learn how to extend Ansible by writing your own modules
|
||
11 years ago
|
:doc:`intro_patterns`
|
||
13 years ago
|
Learn about how to select hosts
|
||
8 years ago
|
`GitHub examples directory <https://github.com/ansible/ansible-examples>`_
|
||
13 years ago
|
Complete playbook files from the github project source
|
||
|
`Mailing List <http://groups.google.com/group/ansible-project>`_
|
||
|
Questions? Help? Ideas? Stop by the list on Google Groups
|
||
10 years ago
|
|