Ansible

Introduction to Ansible

Mattias Gees / @MattiasGees

What is Ansible?

  • Started in February 2012
  • By Michael DeHaan
  • More than 600 Contributors
  • Orchestration Engine
    • Configuration Management
    • Application Deployment
    • Continuous Delivery

Online Resources

Website

Website

Documentation

Documentation

Mailing lists

  • ansible-announce
  • ansible-project
  • ansible-devel

IRC

#ansible

Github

https://github.com/ansible/ansible

Benefits

No agent required

SSH

Easy to install


# EPEL repo
yum install ansible

# Available through a PPA
apt-get install ansible

pip install ansible
					

Requirements

  • Control machine: Python 2.6
  • Managed node: Python 2.4
  • python-simplejson
  • libselinux-python

YAML Syntax


---
- yum: name= state=installed
  with_items:
     - app_server
     - acme_software

- service: name=app_server state=running enabled=yes

- template: src=/opt/code/templates/foo.j2 dest=/etc/foo.conf
  notify:  
     - restart app server
					

Scalable

Customizable

Commands

  • ansible
  • ansible-playbook
  • ansible-pull
  • ansible-doc
  • ansible-galaxy

Modules

  • Run on remote host
  • Control system resources, executing system commands
  • Notification
  • Easy to write new modules

Modules

  • Cloud
  • Commands
  • Database
  • Files
  • Internal
  • Inventory
  • Messaging
  • Monitoring
  • Net Infrastructure
  • Network
  • Notification
  • Packaging
  • Source Control
  • System
  • Utilities
  • Web Infrastructure

Inventory

  • Contains all the managed hosts
  • Can contain variables
  • Flat file(s) or script (dynamic inventory)
  • Can interact with your own CMDB
  • Multiple inventory sources

Inventory


mail.example.com

[webservers]
foo.example.com
bar.example.com

[dbservers]
one.example.com
two.example.com
three.example.com

[servers:children]
webservers
dbservers
						

Inventory


jumper ansible_ssh_port=5555 ansible_ssh_host=192.168.1.

[webservers]
www[01:50].example.com

[webserver:vars]
port=80
						

Ansible

  • Basic tasks
  • Information from system(s)
  • Execute one module

Usage: ansible host-pattern [options]
						

Ansible


ansible all -m ping -o
ansible demo -m setup
ansible foo.example.com -a “/usr/sbin/reboot”

ansible demo -m file -a "dest=/srv/foo/a.txt mode=600" -o
ansible demo-one -m yum -a "name=httpd state=installed"
ansible demo-one -m service -a "name=httpd state=started" 
						

Playbooks

  • Execution of tasks
  • One task is one module
  • Variables
  • Handlers
  • Idempotent

Ansible


---
- hosts: http
  remote_user: user
  sudo: yes
  vars:
   in_ports:
   - 80
   tasks:
   - name: install httpd
     action: yum name=httpd state=latest

   - name: copy httpd.conf
     action: template
        src=httpd.conf.j2
        dest=/etc/httpd/conf/httpd.conf
        owner=root
        group=root
        mode=0644
        seuser="system_u"
        setype="httpd_config_t"
        backup=yes
     notify:
     - restart httpd
						

Roles

  • Reusable list of tasks
  • Has one goal (eg deploy apache)
  • Reusable

---
- hosts: demo
  gather_facts: False
  connection: local
  serial: 1
  vars:
   in_ports:
   - 80
  roles:
  - httpd
  - mysql
  - iptables
						

Templates

  • Jinja2 templating engine
  • Use of variables in files
  • Loops, Conditionals, Filters, ...

< Proxy balancer://{{ balancer_name }}>
{% for host in groups['demo-web'] %}
        BalancerMember http://{{ hostvars[host].ansible_eth1.ipv4.address }}
{% endfor %}
        Order allow,deny
        Allow from all
< /Proxy>
						

Ansible-playbook

  • Execute a playbook
  • Set-up a whole environment / host(s)

Usage: ansible-playbook playbook.yml -i inventory -l limit to host / group
						

Extra features

Accelerated mode


---
- hosts: all
  accelerate: true
  # default port is 5099
  accelerate_port: 10000
						

Asynchronous actions and polling


---
- hosts: all
  remote_user: root
  tasks:
  - name: simulate long running op (15 sec), wait for up to 45, poll every 5
    command: /bin/sleep 15
    async: 45
    poll: 5
						

Check mode


Usage: ansible-playbook foo.yml --check
						

---
tasks:

  - name: this task is run even in check mode
    command: /something/to/run --even-in-check-mode
    always_run: yes
						

Usage: ansible-playbook foo.yml --check --diff --limit foo.example.com
						

Rolling updates


---
- name: test play
  hosts: webservers
  serial: 3
						

Max failure percentage


---
- hosts: webservers
  max_fail_percentage: 30
  serial: 10
						

Delegation


---
- hosts: webservers
  serial: 5

  tasks:
  - name: take out of load balancer pool
    command: /usr/bin/take_out_of_pool {{ inventory_hostname }}
    delegate_to: loadbalancer.example.com

  - name: actual steps would go here
    yum: name=acme-web-stack state=latest

  - name: add back to load balancer pool
    command: /usr/bin/add_back_to_pool {{ inventory_hostname }}
    delegate_to: loadbalancer.example.com
						

Local actions/playbooks


---
# ...
  tasks:
  - name: recursively copy files from management server to target
    local_action: command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/
						

Usage: ansible-playbook playbook.yml --connection=local
						

---
- hosts: demo
  connection: local
						

Error handling / Overriding output


---
- name: this will not be counted as a failure
  command: /bin/false
  ignore_errors: yes

- name: this command prints FAILED when it fails
  command: /usr/bin/example-command -x -y -z
  register: command_result
  failed_when: "'FAILED' in command_result.stderr"

- shell: /usr/bin/billybass --mode="take me to the river"
  register: bass_result
  changed_when: "bass_result.rc != 2"
						

Lookups


---
- hosts: all

  tasks:

     - debug: msg="{{ lookup('env','HOME') }} is an environment variable"

     - debug: msg="{{ item }} is a line from the result of this command"
       with_lines:
         - cat /etc/motd

     - debug: msg="{{ lookup('pipe','date') }} is the raw result of running this command"

     - debug: msg="{{ lookup('redis_kv', 'redis://localhost:6379,somekey') }} is value in Redis for somekey"

     - debug: msg="{{ lookup('dnstxt', 'example.com') }} is a DNS TXT record for example.com"

     - debug: msg="{{ lookup('template', './some_template.j2') }} is a value from evaluation of this template"
						

Prompts


---
- hosts: all
  remote_user: root
  vars:
    from: "camelot"
  vars_prompt:
    name: "what is your name?"
    quest: "what is your quest?"
    					

  vars_prompt:
   - name: "release_version"
     prompt: "Product release version"
     default: "1.0"
						

Tags


---
tasks:

    - yum: name={{ item }} state=installed
      with_items:
         - httpd
         - memcached
      tags:
         - packages

    - template: src=templates/src.j2 dest=/etc/foo.conf
      tags:
         - configuration
						

Usage: ansible-playbook example.yml --tags "configuration,packages"
						

---
roles:
  - { role: webserver, port: 5000, tags: [ 'web', 'foo' ] }
						

---
- include: foo.yml tags=web,foo	
						

Best Practices


production                # inventory file for production servers
stage                     # inventory file for stage environment

group_vars/
   group1                 # here we assign variables to particular groups
   group2                 # ""
host_vars/
   hostname1              # if systems need specific variables, put them here
   hostname2              # ""

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
            foo.sh        #  <-- script files for use with the script resource
        vars/             #
            main.yml      #  <-- variables associated with this role

    webtier/              # same kind of structure as "common" was above, done for the webtier role
    monitoring/           # ""
    fooapp/               # ""
						

Ansible-pull

  • Host gets Ansible configuration
    • Git
    • SVN
    • NFS
    • ...
  • Runs the playbook on itself
  • No central machine needed
  • Enforcing of configuration

Usage: ansible-pull [options] playbook.yml						
						

Ansible-doc

  • View documentation of modules

Usage: ansible-doc yum -M module_path
						

Ansible-galaxy

  • Download roles
  • http://galaxy.ansible.com

Usage: ansible-galaxy install bennojoy.nginx
						

Thank you

Mattias Gees

@MattiasGees / mattias.gees@btr-services.be