What is Ansible?
Ansible is simple, fast, complete, effecient and secure
Ansible is...
Application Deployment
Multi-Tier Orchestration
Configuration Management
1. Ansible is a powerful automation engine.
2. It's several tools in one: Application deployment, multi-Tier orchestration, configuration management and even provisioning.
Simple
Easy to write, read, maintain and evolve- without writing scripts or custom code
Ansibles automation language is easy to write, read, maintain and evolve because you to have to write scripots or use custom code.
This allows sysadmins, developers, and IT managers to complete automation projects in hours, not weeks.
FAST to learn and setup
1. Ansible is fast to learn.If you are a system admin or a developer, you can be automating in under 30 minutes.You can forget how it works and focus on what you want to do.
2. Setup is also fast because you don't have to install agents to manage machines. It relies on SSH. As long as SSH is installed, you are ready to automate.
Efficient
Doesn't require a custom agent or software to install.
Ansible runs on OpenSSH.
1. With no additional software infrastructure, you don't have to
worry about managing the management tool.
2. That means anywhere SSH goes, Ansible goes.
3. It doesn't suck memory or CPU resources when it is not in use.
4. Designed from day one to automate no-downtime rolling updates
and multi-tier orchestration.
Secure
No agent
SSH transport
Ansible plays can be read by anyone
1. It doesn't need additional ports or root level daemons.
2. It uses built-in OS authentication for better security - login
as who you are, sudo if you want to sudo.
3. You can work with tools like Kerberos, LDAP, and sssd.
4. OpenSSH is the most peer-reviewed security component around.
5. This makes it auditable. You know what you're automating,
and bugs have nowhere to hide.
Inventory
Ansible works against multiple systems in your infrastructure at the same time. It does this by selecting portions of systems listed in Ansible’s inventory file, which defaults to being saved in the location /etc/ansible/hosts.
Hosts
A host is simply a remote machine that Ansible manages. They can have individual variables assigned to them, and can also be organized in groups. All hosts have a name they can be reached at (which is either an IP address or a domain name) and optionally a port number if they are not to be accessed on the default SSH port.
Groups
A group consists of several hosts assigned to a pool that can be conveniently targeted together, and also given variables that they share in common.
Playbook
Playbooks are the language by which Ansible orchestrates, configures, administers, or deploys systems. Playbooks contain
Plays
.
Play
A play is a mapping between a set of hosts selected by a host specifier and the
tasks
which run on those hosts to define the role that those systems will perform. There can be one or many plays in a playbook.
Tasks
Tasks combine an action with a name and optionally some other keywords (like looping directives). Tasks call
modules
.
Modules
Modules are the units of work that Ansible ships out to remote machines. Modules can be implemented in any language. Modules just have to return JSON or simple key=value pairs. Once modules are executed on remote machines, they are removed, so no long running daemons are used. Ansible refers to the collection of available modules as a ‘
library
’.
Library
A collection of modules made available to /usr/bin/ansible or an Ansible playbook.
Example
Ansible Architecture
Remote Execution
Replacement for traditional systems administration tasks
Checking system responsiveness and uptime
Gathering information about a collection of systems
Replace one off rsync scripts, fabric, or terminal multiplexing
Ansible provides a command-line tool and framework capable of
executing over a large number of hosts, eliminating the need for
systems administrators to multiplex terminal sessions via SSH to
execute concurrent tasks across multiple hosts. What may have
been done in bash scripts, rsync scripts, etc. can be done via
ad-hoc one-liners in the shell.
Remote Execution
ansible -m user -a "name=bob state=present" webservers
ansible -m apt -a "pkg=apache2 state=present" webservers
Example 1 is adding a user to all the systems defined in the
webservers group. Example 2 is installing the apache2 package
on all systems defined in the webservers group.
Config Management
Lengthy system configuration, to include adding users, ssh keys, installing and configuring services, and bootstrapping systems to a given state.
"Configuration remediation" Consistent server configuration. Removes manual configuration errors.
Servers need to be configured; Ansible configures servers.
Using a combination of imperative and declarative syntax
[described in detail--maybe using the GPS analogy], using
concepts such as tasks, roles, plays, and playbooks, complex
machine configurations are being assembled and converged by
the Ansible toolchain rather than manually by administrators.
Configuration is either set manually by the author or dynamically at runtime by Ansible, resulting in consistent configuration across large server sets.
Application Deployment and Orchestration
Ansible can be used to replace various deployment and orchestration tools.
Deploy your custom application.
Replacement for Capistrano and Fabric (i.e., git deployments)
Good for large, complex environments
Application Development: Two Schools of Thought
Rolling Release
Remove node from production, update components, and put back into rotation.
Fresh Start
Deploy entirely new infrastructure and replace current environment wholesale.
Provisioning Infrastructure Dynamically
Infrastructure is Data.
You can provision to various clouds.
Dynamic Inventory plugins for various providers (Rackspace, Amazon, Digital Ocean, OpenStack, Eucalyptus, etc.)
Cover the various ways that infrastructure can be provisioned
using Ansible. Mention that there are modules that provide
he ability to deploy to various clouds. Include a high level
overview of the dynamic inventory plugin system. (Creating
Infrastructure is the same as Configuring Infrastructure.)
What is your team currently using for:
Application Deployment
Multi-Tier Orchestration
Configuration Management
Have the class search the ansible documention and come up
with something that Ansible does. Be that a specific module,
or a high level concept.
System Requirements
Control machine:
Linux, BSD, OS X (Not Windows!)
Python 2.6 or 2.7
Target machines:
Linux, BSD, OS X, Windows
Python 2.4 or greater (2.5 or greater recommended)
Installation
CentOS 7:
Must configure EPEL (if not already setup)
$ sudo yum install ansible
Ubuntu:
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible
Mac:Use pip
$ sudo pip install ansible
Ansible Key Components
What makes Ansible tick!
Let's delve into the concepts that drive Ansible.
Key components of Ansible
Inventory
Modules/Tasks
Plays
Playbooks
These are some very key components you'll need to understand for using Ansible.
Inventory
Ansible works against multiple systems in your infrastructure
at the same time. It does this by selecting portions of systems
listed in Ansible's inventory.
Inventory concepts
Hosts
Groupings
Inventory-specific data
Static or Dynamic sources
Breaking down by topic, we'll cover four parts (Note the listed)
Inventory: Hosts
Hosts can have Ansible specific attributes such as:
Connection IP addresses and ports
Remote user and sudo user
Connection types (Paramiko, OpenSSH, local, etc.)
Further limit targeted hosts using --limit
You have a lot of flexibility when you specify hosts in Inventory. You can
set variables to determine connection types, host ip addresses and fully-qualified
domain names, remote users and sudo users as well as any other variable you may
come up with to use when interacting with your hosts, such as "apache_port" or
"mysql ports".
Inventory: Hosts
This is an example of a host entry in an inventory file:
web1.example.com ansible_ssh_port=5555 ansible_ssh_host=192.168.1.50
As you can see, we have a host name, a specified SSH port and IP Address.
Inventory:
Host Entries Using Ranges
You can have ranges of machine names or letters like this:
www[01:50].example.com ansible_ssh_port=5555
db-[a-f].example.com ansible_ssh_port=5555
Here we see that we can bracket a range of alpha-numeric characters to shorten our entries in the file.
Inventory: Groups
Inventory Host Organization: Groups
Allow targeted operations against different types of hosts.
Can have variables that apply to all hosts within them.
Limit allows you to specify only certain groups to act against.
Hosts can exist in more than one group at once.
We can also act against groups of hosts in a similar manner to single hosts.
This allows you to also have standard settings for lots of similar hosts, such
as a standard set of ports for apache on all web servers. You can limit the execution of
Ansible jobs just as you can single hosts with the "--limit" option. Hosts can exist
in more than one group at once, letting you do interesting operations on the intersections
of groups. For example, target all of the east coast web servers.
Inventory: Groups
Groups are represented in brackets above host lists in the inventory file.
[webservers]
www[01:50].example.com ansible_ssh_port=5555
[databases]
db-[a-f].example.com ansible_ssh_port=5555
This is an example of a range of hosts specified via the bracket nomenclature.
Dynamic Inventory : Ansible and the Cloud
Inventory can also be gathered on demand from other sources dynamically. Those sources include:
Cloud API (Rackspace, Amazon, Digital Ocean, OpenStack, Eucalyptus , etc.)
Cobbler
Create your own for fun and profit!
So we can also take inventory from a wide variety of sources on the fly. We can touch Rackspace,
Openstack, Amazon EC2, Digital Ocean, and other provisioning systems like Cobbler. You can also
create your own inventory module to interface with any custom CMDB systems you may have.
Inventory: Ansible and the Cloud
Dynamic inventories also respect groups and other details.
Groups are auto-determined by instance tags, regions and other attributes.
Dynamic Inventories can be used alongside Static Inventories for a hybrid cloud approach.
Tagged instances automatically are put in a group based on that tag. Other attributes also
become groups, such as regions deployed to, or other custom attributes.
Tasks
A task is a discrete action that is a declaration about the state of a system.
Example Tasks:
Directory should exist
Package should be installed
Service should be running
Cloud Instance should exist
These are examples of declarative tasks where the beginning state is disregarded in favor of ensuring end-state.
Tasks: Examples
Ansible can execute single tasks on sets of hosts to full-fill an ad-hoc declarations
$ ansible web-hosts -m file -a "path=/opt/cache state=directory"
$ ansible web-hosts -m yum -a "name=nginx state=present"
$ ansible web-hosts -m service -a "name=nginx enabled=yes state=started"
in the first we make sure opt/cache exists, the second we install nginx, third we make
sure nginx is installed, chkconfig'ed on and the service is started.
Tasks: Sources
Code for tasks can come from:
Existing modules
Custom modules
Raw ssh commands
Tasks use modules or commands to create their actions to apply to remote systems.
You can create your own modules, use any of the over 200 included modules, or use the output from commands.
LAB
Add a User using an Ansible ad-hoc command
Modules
Modules are the bits of code copied to the target system to be executed to satisfy the task declaration.
Code need not exist on remote host -- ansible copies it over
Many modules come with Ansible -- "batteries included"
Custom modules can be developed easily
Command/shell modules exists for simple commands
Script module exists for using existing code
Raw module exists for executing raw commands over ssh
Modules essentially create python code out of the descriptions given via the tasks that are then sent to the
remote machine and interpreted/executed by that host. Once executed, Ansible then cleans up after itself and
removes the module and output from the remote system.
Module Interactions
Module listing and documentation via ansible-doc
$ ansible-doc -l
acl Sets and retrieves file ACL information.
apt Manages apt-packages
$ ansible-doc acl
> ACL
Sets and retrieves file ACL information.
Options (= is mandatory):
- entry
The acl to set or remove. This must always be quoted in the [...]
Modules and tasks represent the core function of ansible. Modules are capable of idempotence --
can be ran successively and understand change vs no change. In these examples we see how to use
the command "ansible-doc" to review informtaion about specific modules that are included.
Module Interactions in Tasks
A series of tasks
- name: add cache dir
file: path=/opt/cache state=directory
- name: install nginx
yum: name=nginx state=present
- name: start nginx
service: name=nginx enabled=yes state=started
An ordered series of tasks can be described to form plays. Tasks utilize modules to act upon remote hosts.
Plays
Plays are ordered sets of tasks to execute against host selections from your inventory.
Play Naming
- name: This is a Play
General best practices are to name tasks in a way that shows what they do.
Plays: Hosts Selection
- name: This is a Play
hosts: web-servers
This is how we specify in a play/plabook what hosts we will act upon based on group.
Play Arguments
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
Furthermore, we can specify other variables as arguments.
Such as what remote user to connect as, or whether we sudo to root to complete our task.
Play: Variables
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
vars:
http_port: 80
cache_dir: /opt/cache
We gather facts before every run from hosts we are acting on. Facts become variables that
contain information such as kernel level, host name, ip addresses and other standard information.
Play: Tasks
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
gather_facts: no
vars:
http_port: 80
cache_dir: /opt/cache
tasks:
- name: create cache dir
file: path={{ cache_dir }} state=directory
- name: install nginx
yum: name=nginx state=installed
This is a compelte example of a play within a playbook. It contains arguments, variables,
host groups to act on, two tasks and wheteher we use sudo on those tasks. It also uses the variables
specified for the cache directory. Variables are represented in the Jinja2 format with double curly braces.
Plays: Concurrency and Order of Operations
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
vars:
http_port: 80
cache_dir: /opt/cache
tasks:
- name: create cache dir
file: path={{ cache_dir }} state=directory
- name: install nginx
yum: name=nginx state=installed
You can specify number of concurrent machines to act upon via setting a number of forks. That will act upon
that number of hosts at once, however the tasks within the play complete from top to botton, in order, one at a time.
Plays: Conditionals
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
vars:
http_port: 80
cache_dir: /opt/cache
tasks:
- name: create cache dir
file: path={{ cache_dir }} state=directory
- name: install apache
yum: name=httpd state=installed
when: ansible_os_family == "RedHat"
- name: install apache
apt: pkg=apache2 state=installed
when: ansible_os_family == "Debian"
This is an example of a conditional. Conditionals allow for actions to be dependant on some fact or variable set.
In this case, we see that we install nginx via Linux-Distro specific package managers. The variable "ansible_os_family"
is a discovered fact gathered when we first run the play or playbook against hosts.
Plays: Error Handling
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
vars:
http_port: 80
cache_dir: /opt/cache
tasks:
- name: create cache dir
file: path={{ cache_dir }} state=directory
- name: install nginx
yum: name=httpd state=installed
when: ansible_os_family == "RedHat"
- name: install nginx
apt: pkg=apache2 state=installed
when: ansible_os_family == "Debian"
- name: failing command
command: /bin/fail
ignore_errors: yes
In this example we see the use of the "ignore_errors" setting, allowing users to dictate to ansible
to ignore when the return codes of ansible-initiated tasks indicate failures or errors. Another way
to do this is by using the "failed_when" options.
Plays: Inclusions
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
vars_files:
- vars/nginx.yaml
tasks:
- name: create cache dir
file: path={{ cache_dir }} state=directory
- include: tasks/install-apache.yaml
- name: failing command
command: /bin/fail
ignore_errors: yes
Take note of the "include" task: This allows us to include other playbooks at specific points in our
run allowing for complicated aspects of orchestration to be seamless based on function or type of
playbook. While this is useful, most often now you will use Roles for this functionality. We'll talk
more about those in a bit.
LAB
Write and run a play that creates the directory /opt/cache on a
targeted host machine
Playbooks
Playbooks are ordered sets of plays to execute against inventory selections.
Playbooks: Inventory Selection
$ ansible-playbook -i production play.yaml
$ ansible-playbook -i pre-prod play.yaml
$ ansible-playbook -i hosts/dfw/ play.yaml
As you can see, we can specify different inventories to run the playbook "play.yaml" against.
Playbooks: Global Variables
$ ansible-playbook -i pre-prod -e "cache_dir=/srv/cache/" play.yaml
Variables declared in this manner from the command line override other values.
Playbooks: Forks
$ ansible-playbook -f 30 -i pre-prod -e "cache_dir=/srv/cache/" play.yaml
This shows us declaring this playbook to be run against 30 hosts at a time by delcaring
"-f 30" which is the flag for "forks equals 30 at a time."
Playbooks: Inventory-Limits
$ ansible-playbook --limit dfw -f 30 -i pre-prod -e "cache_dir=/srv/cache/" play.yaml
This shows us running a playbook while declaring a limit to run only against "DFW"
which could mean a single host named DFW, or a host group DFW.
Playbooks: Inclusions
- name: This is a Play
hosts: web-servers
remote_user: fred
sudo: yes
connection: ssh
gather_facts: no
vars:
http_port: 80
cache_dir: /opt/cache
tasks:
- name: create cache dir
file: path={{ cache_dir }} state=directory
- include: playbook2.yaml
In this example we see that at the end of the playbook, we include another playbook. This allows
us to continue against other playbooks using the already discovered facts and variables declared.
Playbooks: Roles
Roles are portable units of task organization in playbooks.
Roles are units of organization in Ansible. Assigning a role to a group of hosts
(or a set of groups, or host patterns, etc.) implies that they should implement a
specific behavior. A role may include applying certain variable values, certain tasks,
and certain handlers - or just one or more of these things. Because of the file structure
associated with a role, roles become redistributable units that allow you to share
behavior among playbooks - or even with other users.
Basic Playbook Structure
In this chapter we'll cover the basic playbook structure, and write a simple playbook from scratch.
Play Header
---
- name: this is the name of a play
hosts: all
user: root
tasks: []
As we covered earlier, a playbook is a series of plays. Each play needs a "hosts" keyword, which tells Ansible to which hosts hosts this play applies. You can define a lot of other parameters at the play level, including which user to log in as, whether these tasks should be run through sudo, which connection mechanism to use, etc.
Write the tasks
---
- name: this is the name of a play
hosts: all
user: root
tasks:
- name: install nginx
yum: package=nginx state=present
Now that we have the "front matter" of the play defined, we can add the tasks, as shown. Each task can have a name that is human-readable. This isn't required, but it's recommended. Then you call the module, in this case "yum", and any arguments.
Run the playbook
Run the playbook. If you've written everything correctly, it should install nginx on the target systems, and return the results. Notice the "Gathering Facts" step that occurs at the top of the run. This is implicit, but you can turn it off with "gather_facts: no" in the play. At the end, a "host recap" will be printed out. This gives you a summary of tasks that completed successfully, tasks that changed something on the target system, any failures, or unreachable systems.
LAB
Write playbook to install nginx, start the service and enable it at
time of boot