Operational
Learning Outcomes
Installation
http://docs.ansible.com/intro_getting_started.html
http://docs.ansible.com/intro_installation.html
Whiteboard time!
STATIC INI
Create an INI inventory file based off of instructor provided servers, specifying a human readable name and a connection IP address or hostname
web1 ansible_ssh_host=10.10.10.10
web2 ansible_ssh_host=20.20.20.20
STATIC INI
Groups
Create a web group in the inventory file
[web]
web1 ansible_ssh_host=10.10.10.10
web2 ansible_ssh_host=20.20.20.20
GroupsUse Cases for Dynamic Inventory Scripts
Dynamic Inventory Demo
Lab: Configure Inventory File
Objective: Identify the nodes that Ansible will manage
Targeting Hosts
Executing a Task
ad-hoc commands are single-task executions which leverage modules
Modules
Modules are code that is executed on the remote host
Ansible provided core modules:
Module Documentation
ansible-doc -l
ansible-doc setup
ansible-doc copy
Examples
Rebooting all servers
ansible all -m command -a "/sbin/reboot"
Setting fork level to 10
ansible webservers -f 10 -m setup
Copy a file from the local host to inventory hosts
ansible dbservers -m copy -a "src=/path/to/file dest=/path/to/dest"
Install nginx and add a user
ansible all -m apt -a "pkg=nginx state=present"
ansible all -m user -a "name=bob state=present"
Cloning a git repo to a path
ansible appservers -m git -a "repo=https://github.com/ansible/ansible dest=/home/user/ansible"
Ensure httpd is started
ansible -m service -a "name=httpd state=started"
Backgrounding tasks, with optional polling every 60 seconds
ansible all -B 3600 -a "/usr/bin/long_running_operation --do-stuff"
ansible all -B 1800 -P 60 -a "/usr/bin/long_running_operation --do-stuff"
Running setup module to gather and display all facts about a machine known to Ansible
ansible web1.example.com -m setup
COWSAY
Lab: AD-HOC Commands
Objective: Configure your CentOS node via command line Ansible interactions
A Review of Ansible Plays and Playbooks
Plays
An ordered series of tasks executed on a selection of hosts
with controls over how the tasks operate.
- 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
Playbooks
Ansible-playbook is the tool used to select
Playbook Execution
$ ansible-playbook play.yaml -i pre-prod -e "cache_dir=/srv/cache/" -f 30 -l dfw
Lab: Playbook
Write a playbook that performs the tasks from the prior lab.
At this time your work should be completed targeting only your CentOS node
Objective: Expand your Playbook to include previous AdHoc commands
Content Organization
Magic happens when you put your files in the right locations
Understand the basics of variables, where they come from, how they get set, and how to evaluate and manipulate them
Host Variables
Host variables are "facts" about a server that contains info such as:
Host Variables
Where do they come from?
Group Variables
"Facts" that apply to a grouping of servers
Group Variables
Where do they come from?
The name of the files in the group_vars directory line up with the group name being targeted. "all" is a special keyword to apply facts to all hosts.
Variable Precedence
Using Variables in YAML
Ansible uses "mustache" like variable expansion
Group_vars/all
---
apache2_version: 2.2.22-1ubuntu1
Tasks
- apt: name="apache2={{ apache2_version }}" state=present
Register
A special keyword "register" exists for all tasks, that will assign the output from a module to the variable of the specified name, for later manipulation or evaluation in use with other tasks
- git: repo=git://github.com/ansible/ansible.git dest=/tmp/ansible
register: ansible_git
Inspecting Variables
Different modules produce different data structures. The 'debug' module will help you inspect that data structure.
- debug: var=ansible_git
Output Sample
ok: [someserver] => {
"ansible_git": {
"after": "1b4ba5431b1070c63b9069d310f42e16f302db10",
"before": "69b2d82be6ffe20f04070cddf11b7629aa8420e5",
"changed": true,
"invocation": {
"module_args": "repo=git://github.com/ansible/ansible.git dest=/tmp/ansible",
"module_name": "git"
}
}
}
Module Output Structure
All modules should return a key titled "changed" with a boolean value of "true" or "false" defining whether the module made a change
Additionally, under a failure scenario, a module would set a key of "failed" with a boolean value of "true"
Dynamically Adding Host Facts
During runtime you can run add additional host vars using the "set_fact" module
- local_action:
module: wait_for
host: "{{ ansible_default_ipv4.address }}"
port: 22
delay: 1
timeout: 1
register: port_test
failed_when: False
- set_fact: ansible_ssh_port=2222
when: port_test|failed
Magical Variables
There are several standard variables that are created and exposed by ansible
How to properly use include_vars and vars_files to include variables in your playbooks
vars_files
vars_files is used in playbooks to include a file of variables outside of the usual variable locations
include_vars
The include_vars module is similar to vars_files and allows for dynamic inclusion of variables within the context of a role.
YAML list syntax:
---
Foods:
- Apple
- Orange
- Strawberry
- Mango
Lab: Variables
Objective: Populate a set of group variables
Loops
with_items: Loops over a list, one task per item
Standard Loops
To save some typing, repeated tasks can be written in short-hand like so:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
Standard Loops
If you have defined a YAML list in a variables file, or the ‘vars’ section, you can also do:
- name: add several users
user: name={{ item }} state=present groups=wheel
with_items: users
Lab: Loops
Create four web directories from list of domains defined in group_vars/all
Note: Example location for these directories: /var/www/domain.com "one per site"
Objective: Create content directories for each of the domains in your list
Conditionals
Useful for
Platform Variance in Playbooks
Task Conditionals
- name: install nginx
yum: name=nginx state=present
when: ansible_distribution == 'CentOS'
- name: install nginx
apt: pkg=nginx state=present
when: ansible_distribution == 'Debian'
Platform Variance in playbooks
group_by
Create dyanmic groups matching certain criteria
- name: grouping play
hosts: all
tasks:
- name: create distro groups
group_by: key={{ ansible_distribution }}
- name: CentOS play
hosts: CentOS
gather_facts: False
tasks:
- # tasks that only happen on CentOS go here
Lab: Conditionals
Objective: Alter your existing playbook to add management for the ubuntu node
Status Control
Local Action
Delegation
Run a task on another server, on behalf of the server we are currently operating on.
Templates
Ansible can easily transfer files to remote systems, but often it is desirable to substitute variables in other files. Variables may come from the inventory file, Host Vars, Group Vars, or Facts. Templates use the Jinja2 template engine and can also include logical constructs like loops and if statements.
Templates
# Example from Ansible Playbooks
- template: src=/mytemplates/foo.j2 dest=/etc/file.conf owner=bin group=wheel mode=0644
# Copy a new "sudoers file into place, after passing validation with visudo
- action: template src=/mine/sudoers dest=/etc/sudoers validate='visudo -cf %s'
Templates
Example
Example: nginx.conf
server {
listen 80;
server_name domain.com;
access_log /var/log/nginx/domain.com-access.log;
error_log /var/log/nginx/domain.com-error.log;
location / {
root /var/www/html;
index index.html index.htm;
}
}
Example of Templating
So this...
server_name domain.com;
Becomes...
server_name {{ item }};
Lab: Templates
Objective: Build a reusable skeletal configuration
Handlers
Handlers are just like regular tasks in an Ansible playbook , but are only run if the Task contains a “notify” directive and also indicates that it changed something. For example, if a config file is changed then the task referencing the config file templating operation may notify a service restart handler. This means services can be bounced only if they need to be restarted. Handlers can be used for things other than service restarts, but service restarts are the most common usage.
---
# this might be in a file like handlers/handlers.yml
- name: restart apache
service: name=apacheII state=restarted
Handlers
In this example, if you wanted to define how to restart apache, you would only have to do that once for all of your playbooks. You might make a handlers.yml that looks like:
handlers:
- include: handlers/handlers.yml
Handlers
And in your main playbook file, just include it like so, at the bottom of a play:
- name: Update the Apache config
action: copy src=httpd.conf dest=/etc/httpd/httpd.conf
notify: restart apache
Handlers
This will call the "Restart Apache" handler whenever 'copy' alters the remote httpd.conf.
- name: Update our app's configuration
action: copy src=myapp.conf dest=/etc/myapp/production.conf
notify:
- restart apache
- restart redis
Handlers
Here's how to specify more than one handler
---
- hosts: webservers
remote_user: root
- name: This is a play that adds a conf file and restarts Apache
tasks:
- name: ensure apache is at the latest version
yum: pkg=httpd state=latest
- name: write the apache config file
template: src=/srv/httpd.j2 dest=/etc/httpd.conf
notify:
- restart apache
- name: ensure apache is running
service: name=httpd state=started
handlers:
- name: restart apache
service: name=httpd state=restarted
Handlers
You can mix in includes along with your regular non-included tasks and handlers.
Includes can also be used to import one playbook file into another. This allows you to define a top-level playbook that is composed of other playbooks.
For Example:
- name: this is a play at the top level of a file
hosts: all
remote_user: root
tasks:
- name: say hi
tags: foo
shell: echo "hi..."
- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
Lab: Handlers
Objective: Triggers service restarts within your playbook
Version Control
Version control and Ansible go hand in hand. This topic will walk through many of the benefits of storing your ansible content in SCM and why this is itself a best practice.
Version Control
Galaxy, Git, and You!
Vault
RBAC and execution model
Centralized
RBAC and execution model
Distributed
Proper naming of plays, tasks, and handlers
Names have significance
$ ansible-playbook play.yaml --start-at-task="a good task"
- name: a good task
file: path=/etc/foobar state=absent
notify: bounce foo service
handlers:
- name: bounce foo service
service: name=foo state=restarted
Playbook formatting
whitespace, YAML, line lengths, oh my!
Playbook formatting
whitespace, line lengths, continuations
tasks:
- name: one task
command: echo
- name: lots of arguments
rax_dns_record: credentials=/path/to/my/creds type=A
data=4.2.2.2 name=www.nodomain.not
Playbook formatting
order and style of playbook directives
- name: Generate env/cell specific content
hosts: localhost
connection: local
gather_facts: false
tags:
- localprep
vars:
- cachedir: cache/
tasks:
- name: stuff
Playbook formatting
to quote or not to quote
- name: "My name has a : in it"
command: "{{ variable_here }}"
when: "'some_string' in varaible_here"
hosts: "*-webs"
Playbook formatting
variable referencing
- name: name here
command: echo {{ variable here }}
register: output
when: variable != "derp"
failed_when: output.stderr == "FAILURE"
Playbook formatting
YAML gotchas
A massive thanks to the content dev team...
Chris Caillouet
Chris Old
David Federlein
Jesse Keating
Justin Phelps
Matt Martz
Mike Martin
Paul Durivage
Peter Isburgh
Tim Gerla