====== Ansible ======
**General Information**
Ansible is a tool for performing remote tasks on systems. (either ad-hoc or via "playbooks")
You will need to use ansible as a user that has ssh keys setup on systems so you are not prompted for passwords during parallel command operations.
\\
If you already have Ansible installed/configured, [[linux_wiki:ansible_playbook_downloads|playbook downloads can be found here]].
**Checklist**
* Distro(s): Any
----
====== Install ======
Ansible comes in many distributions repos already.
CentOS 7
yum install ansible
----
====== Configure ======
Main Ansible config file
* /etc/ansible/ansible.cfg
* Edit this file to point Ansible to your inventory files.
===== Repo Controlled =====
It is highly recommended to put Ansible playbooks, roles, and inventory into version control. (Example: git or svn)
One suggested directory structure/workflow is:
* Shared, read-only/production use at:
* /ansible/
* Each system administrator would then clone a copy of the repo into their home directory for local changes/testing before committing working modifications to the repo.
* Have an automated job sync the shared location every so often.
* Example: Have cron perform a git pull for /ansible/ every 30 mins.
\\
Model content tree under /ansible/ after [[http://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#alternative-directory-layout|Ansible's best practices alternative structure]].
----
===== Inventory =====
Inventory setup is the most important configure task.
\\
In order for Ansible to send commands to systems, they must be listed in inventory.
\\
Suggested directory structure (after [[http://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#alternative-directory-layout|Ansible's best practices alternative structure]])
* Production Inventory: /ansible/inventories/production/hosts
* Systest Inventory: /ansible/inventories/systest/hosts
* Development Inventory: /ansible/inventories/development/hosts
==== Auto Generated Inventory ====
You will not want to introduce a manual inventory process.
Suggested workflow for auto generating your inventory files:
* Cron Job to execute inventory generation script: /etc/cron.d/ansible-generate-inventory
* Example: Executes every 30 minutes. (*/30 * * * *)
* Script that generates inventory files: /ansible/scripts/inventory-file-gen.py
* Source: The script should contact some sort of system via APIs that all newly deployed systems automatically register to. (Such as Spacewalk, Foreman/Katello, etc)
* Target directory for auto generated inventory files: /root/repos/ansible/inventories/
* Files are generated here and any changes committed to the repo (svn/git).
* Example: If there were committed changes, a repo sync job will pick them up and place them in /ansible/inventories/ at the top of every hour. (0 *)
* Example User Accounts Involved
* autorepo -> Repo user account with read/write access to an ansible repo for inventory file changes.
* autoadmin -> API user account for contacting the inventory source.
----
====== Ansible Commands ======
Examples of Ansible commands.
**Note: All host-patterns check the inventory files for matches ONLY. If a system is not in the inventory file(s), Ansible can't send a command to it.**
General Ansible command syntaxansible [-m module-name] [-a arguments] [options]
* see 'man ansible' for more details
----
===== List Hosts =====
Listing hosts matched by the given pattern and do nothing else.
\\
List hosts in the webservers_nginx group from dev inventoryansible webservers_nginx -i /ansible/inventories/development/hosts --list-hosts
\\
List all hosts from dev inventoryansible all -i /ansible/inventories/development/hosts --list-hosts
\\
List all hosts in the "webservers_nginx" group (**from any inventory**)ansible webservers_nginx --list-hosts
\\
List all hosts matching "web*" pattern (**from any inventory**)ansible "web*" --list-hosts
----
===== Test Connection =====
The module 'ping' is **not an ICMP echo command**; it tests a remote login (ssh) to the system and verifies a working remote python environment.
\\
Test connection to webservers_nginx in dev inventory onlyansible webservers_nginx -i /ansible/inventories/development/hosts -m ping
\\
Test connection to all systems in dev inventoryansible all -i /ansible/inventories/development/hosts -m ping
\\
Test connection to **all** webservers_nginx (**from any inventory**)ansible webservers_nginx -m ping
\\
Test connection to all systems in the "webservers_nginx" group (**from any inventory**)ansible webservers_nginx -m ping
\\
Test connection to systems matching a pattern (**from any inventory**)ansible "web*" -m ping
\\
Test connection to all systems (**from any inventory**)ansible all -m ping
----
===== Ad-Hoc Commands =====
Ad-hoc commands are for one off commands that are not saved in a playbook.
* Ad-hoc Intro: http://docs.ansible.com/ansible/intro_adhoc.html
* Module Index: http://docs.ansible.com/ansible/latest/modules_by_category.html
----
==== Modules: Command and Shell ====
If no module is specified, the "command" module is used.
* The command module can execute basic commands, **but cannot do shell specific functions** such as piping and redirects
* If you need that type of shell functionality, **specify the "shell" module**
\\
Check uptime of the group 'webservers_nginx' from dev onlyansible webservers_nginx -i /ansible/inventories/development/hosts -a 'uptime'
\\
Check uptime of all systems in devansible all -i /ansible/inventories/development/hosts -a 'uptime'
\\
Check uptime of the group 'webservers_nginx' (**from any inventory**)ansible webservers_nginx -a 'uptime'
\\
Check the last 10 lines in /var/log/messages (using sudo)ansible "web*" -a 'tail /var/log/messages' -b
* -b => or 'become', uses the default privilege escalation, which is sudo on Linux systems.
Equivalent command as the aboveansible "web*" -a 'sudo tail /var/log/messages'
\\
Piping example; the shell module must be specifiedansible "web*" -m shell -a 'cat /var/log/messages | grep -i error' -b
----
==== Modules: Copy and File ====
Transferring files over scp using Ansible to multiple servers at once.
\\
Copy a local file (src=) to all systems in the 'webservers_nginx' group (dest=)ansible webservers_nginx -m copy -a "src=/etc/yum.conf dest=/tmp/yum.conf"
\\
Set a file's ownership and permissionsansible webservers_nginx -m file -a "dest=/tmp/yum.conf mode=750 owner=root group=root"
\\
Remove a fileansible webservers_nginx -m file -a "dest=/tmp/yum.conf state=absent"
* This same command will recursively delete if a directory is the target
----
==== Modules: Packages ====
Managing packages with Ansible.
\\
Ensure a package is installed, do not update the package if it is installedansible my_group -m yum -a "name=dstat state=present"
\\
Ensure package is the latest version (update if not)ansible my_group -m yum -a "name=dstat state=latest"
\\
Ensure package is not installed (remove if it is)ansible my_group -m yum -a "name=dstat state=absent"
----
==== Modules: Services ====
Managing system services with Ansible.
Compatible with SysV and Systemd.
* **Note**: For systemd specific commands such as "mask", you will need to use the [[http://docs.ansible.com/ansible/latest/systemd_module.html|systemd Ansible module]] instead.
\\
Ensure httpd is started (start if not)ansible my_group -m service -a "name=httpd state=started"
\\
Restart a serviceansible my_group -m service -a "name=httpd state=restarted"
\\
Ensure a service is stoppedansible my_group -m service -a "name=httpd state=stopped"
----
====== Ansible Playbooks ======
"Playbooks are Ansible’s configuration, deployment, and orchestration language. They can describe a policy you want your remote systems to enforce, or a set of steps in a general IT process."
More Details: http://docs.ansible.com/ansible/playbooks.html
----
===== Playbook Directory Structure =====
Playbooks should be repo controlled.
Following the examples on this page:
* /ansible/playbooks
\\
**Playbooks map ansible groups to roles**
* Example playbook# File: webservers_nginx.yml
# Description: Nginx Webservers
# Last Updated: 2018-04-08
# Recent Changes:-Initial release
# hosts: group_name or 'all'
- hosts: webservers_nginx
# roles: located in ../roles/
roles:
# role: role to assign to hosts, tags: tag(s) to give entire role
- { role: webservers-nginx, tags: webservers-nginx }
# Gather host facts for this playbook
gather_facts: yes
* All systems in the ansible group "webservers_nginx" are given the roles:
* webservers-nginx
* When a playbook is executed, all tasks in the assigned roles are run (unless only specific tasks/actions are selected using tags and/or limits).
\\
**Gather a subset of facts**
If you do need to gather facts, consider gathering a subset of facts instead of everything in order to keep the fact collection fast.
* Example: Collect only the ansible_distribution facts# Gather host facts for this playbook
gather_facts: yes
# Gather only ansible_distribution info (OS attributes)
gather_subset:
- '!all'
- '!min'
- 'distribution'
* Facts returned by the above subset"ansible_distribution": "CentOS",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.5.1804",
"ansible_os_family": "RedHat",
* You can test your subset commands like this
* ad-hocansible -m setup -a 'gather_subset=!all,!min,distribution' localhost
**Available Fact Subsets**:
* all
* min
* hardware
* network
* virtual
* ohai
* facter
\\
**See the Roles section** for what happens next.
----
===== Roles Directory Structure =====
Roles contain all of the tasks that will be run when a playbook is executed against it.
\\
Roles should be repo controlled. Top level directory example is:
* /ansible/roles
An example role called "webservers-nginx" is located:
* /ansible/roles/webservers-nginx
The contents of a role directory are:
* files
* Files to be used with the 'copy' or 'script' resource. Files located in this directory can be referred to by just the filename without directory path in task yml files.
* handlers
* Actions that are only executed when certain tasks report changes. Requires 'main.yml' to execute.
* meta
* Role dependencies. Requires 'main.yml' to execute.
* **tasks** -> The main section to work with
* Tasks/actions to take when the role is executed via a playbook. Requires 'main.yml' to execute.
* templates
* Files to be used with the 'template' resource. Templates end in '.j2' (jinja2)
* vars
* Variables associated with the role. Requires 'main.yml' to execute.
----
===== Playbook/Role Creation =====
How to create a new playbook and role.
* Playbook: Maps Ansible group(s) to role(s)
* Role: Defines tasks to complete against the hosts
External References
* Intro to Playbooks: http://docs.ansible.com/ansible/playbooks_intro.html
* Intro to modules: http://docs.ansible.com/ansible/modules_intro.html
* All modules index: http://docs.ansible.com/ansible/list_of_all_modules.html
- Navigate to your local copy of the version controlled ansible repo. Example:cd ${HOME}/repos/ansible/
- Update your local copy of the version controlled ansible repo to the latest version#git
git pull
#svn
svn update
- **New Role**
- Navigate to the roles directory, then copy your role template directory to a new namecd roles/
cp -R template-role/ my-new-role
- Modify the role's files as needed to create tasks, files, handlers, etc.
- Download zip archive of an {{ :linux_wiki:role-template.zip |example role template}}.
- **New Playbook**
- Navigate to the playbooks directorycd ${HOME}/repos/ansible/playbooks/
- Copy your playbook template to a new playbook yaml file.cp TEMPLATE_PLAYBOOK.yml my_new_playbook.yml
- Playbook Template# File: TEMPLATE_PLAYBOOK.yml
# Description: PLAYBOOK DESCRIPTION HERE
# Last Updated: 2018-03-15
# Recent Changes:-Initial release
# hosts: group_name or 'all'
- hosts:
- group_name_here
# roles: located in ../roles/
roles:
# role: role to assign to hosts, tags: tag(s) to give entire role
- { role: role-name, tags: tag-name }
# Do not gather host facts for this playbook (comment out/remove if you need facts)
gather_facts: no
- Edit the new playbook (vim ansible/playbooks/my_new_playbook.yml)
- hosts: my_ansible_group
roles:
- { role: my-new-role, tags: my-new-role }
- In the above example, the playbook "my_new_playbook" states that the group "my_ansible_group" has the role of "my-new-role", and all tasks in the role "my-new-role" has the tag "my-new-role"
- The tag can be anything, but keeping it the same as the role name is useful if you want to limit the execution of a playbook to a specific role using the "tags" command line argument to ansible-playbook
- Tags are inherited at all tasks below it.
- When the playbook is executed, the tasks defined in the role will be executed against the group
- **Test Playbook**
- See the next section for details on testing the playbook before committing changes to a repo.
----
==== Playbook Testing ====
Test your playbook before committing it to a repo.
* Add these functions to your shell's config#bash = ~/.bashrc
#zsh = ~/.zshrc
# Enable Ansible test environment
ansible_local_enable(){
export ANSIBLE_INVENTORY="${HOME}/repos/ansible/inventories"
export ANSIBLE_ROLES_PATH="${HOME}/repos/ansible/roles"
echo -e "Ansible environmental variables set to:"
env | grep ANSIBLE
}
# Disable Ansible test environment
ansible_local_disable(){
unset ANSIBLE_INVENTORY
unset ANSIBLE_ROLES_PATH
echo -e "Ansible environmental variables have been unset. There should be no variable results after this line."
env | grep ANSIBLE
}
* Source the file#bash
source ~/.bashrc
#zsh
source ~/.zshrc
* Enable local variablesansible_local_enable
* Test playbook locally
* Syntax checkansible-playbook --syntax-check ${HOME}/repos/ansible/playbooks/my_new_playbook.yml
* List tasksansible-playbook -b -i ${HOME}/repos/ansible/inventories/development/dev ${HOME}/repos/ansible/playbooks/my_new_playbook.yml --list-tasks
* Run against a test systemansible-playbook -b -i ${HOME}/repos/ansible/inventories/development/dev ${HOME}/repos/ansible/playbooks/my_new_playbook.yml --limit mytestsystem
* Tests successful, disable local variablesansible_local_disable
* Commit playbook/role to the repo
----
===== Playbook Commands =====
Different methods to run playbooks.
\\
**WARNING**: If you do **NOT** specify an inventory file with "-i PATH", the playbook will run against **ALL HOSTS** in the group, which is probably not what you want.
\\
**NOTE**: If you need to use group_vars per inventory type (dev/test/prod), the full path to the inventory file needs to be used. (Example: /ansible/inventories/development/hosts )
----
==== Playbook Commands: Syntax Check ====
After creating a playbook, it is useful to check the syntax before running it to catch obvious errors.
Run a syntax check (will NOT execute the playbook)ansible-playbook --syntax-check /ansible/playbooks/my_playbook.yml
----
==== Playbook Commands: Aliases ====
Playbook commands can get rather long, some useful aliases to shorten them.
Put in your ~/.bashrc or ~/.zshrc file
# Ansible aliases
alias apd='ansible-playbook -b -i /ansible/inventories/development/hosts'
alias apt='ansible-playbook -b -i /ansible/inventories/systest/hosts'
alias app='ansible-playbook -b -i /ansible/inventories/production/hosts'
\\
Additionally, create a symlink to playbooks
ln -s /ansible/playbooks /playbooks
\\
Now, your playbook commands can look like this
# Dev inventory
apd /playbooks/myplaybook.yml
# Test inventory
apt /playbooks/myplaybook.yml
# Prod inventory
app /playbooks/myplaybook.yml
* limits, tags, etc can also be appended as normal.
----
==== Playbook Commands: List ====
Preparation/sanity check commands to do before running a playbook.
\\
**List** what hosts the playbook will run against (**from dev inventory**)ansible-playbook -i /ansible/inventories/development/hosts /ansible/playbooks/my_playbook.yml --list-hosts
* -i or --inventory -> Path to the inventory (alternative is a comma separated list of hosts or single hostname with a trailing comma)
\\
**List** what tasks the playbook will execute (**from dev inventory**)ansible-playbook -i /ansible/inventories/development/hosts /ansible/playbooks/my_playbook.yml --list-tasks
----
==== Playbook Commands: Run ====
Commands to actually run a playbook. You SHOULD do the list commands first to make sure what you are about to run is expected.
* The list commands (--list-hosts and --list-tasks) can be appended to any of the following commands to check them first before running.
\\
**Run playbook (dev env; all in group)** against all system groups defined in playbook **from dev inventory** using sudo for privilege escalationansible-playbook -b -i /ansible/inventories/development/hosts /ansible/playbooks/my_playbook.yml
* -b or --become -> Use privilege escalation (default of sudo)
\\
**Run playbook (dev env; all in group; only configure)** against all groups defined in playbook **from dev inventory** using sudo for privilege escalation, only execute actions with the matched tags "configure"ansible-playbook -b -i /ansible/inventories/development/hosts /ansible/playbooks/my_playbook.yml --tags configure
* --tags configure -> Only execute tasks in the playbook that have been tagged "configure"
* roles, import_tasks, or individual tasks can be tagged
\\
**Run playbook (dev env; range of systems)** against all groups defined in playbook **from dev inventory** using sudo for privilege escalation, further limit to hosts web01-05"ansible-playbook -b -i /ansible/inventories/development/hosts /ansible/playbooks/my_playbook.yml --limit "$(echo web{01..05})"
* --limit "$(echo web{01..05})" -> Filter results of host match to only include these systems
\\
**Run playbook (dev env; one system)** against all groups defined in playbook **from dev inventory**, limit to a single hostname (MYHOSTNAME)ansible-playbook -i /ansible/inventories/development/hosts /ansible/playbooks/my_playbook.yml --limit MYHOSTNAME
----