Responsible with Ansible

Slides & Repo

What's a provisioning framework?

  • Automated setup of servers
  • Configuration as code

Examples

  • Create users
  • Generate config files
  • Install software
  • Start/stop/restart processes
  • Set up dependencies between operations

Describe what to do


#!/bin/bash

if $( command -v vim >/dev/null 2>&1 ); then
  echo "vim is already installed."
else
  apt-get install vim
fi

if $( grep -Fxq "filetype indent off" /etc/vim/vimrc ); then
  echo "set filetype indent off is already in /etc/vim/vimrc."
else
  echo "filetype indent off" >> /etc/vim/vimrc
  # TODO: Do not continue if this fails.
fi

# TODO: Rollback if something fails.
          

Describe state


- name: ensure installed vim
  apt: pkg={{ item }} state=installed

- name: add a string to the new file
  lineinfile:
    dest=/etc/vim/vimrc
    line='filetype indent off'
    state=present

          

Ansible

  • SSH-based
  • Client only (no server)
  • YAML configuration
  • Push
  • Supports more than setup and provisioning:
    • Application deployment
    • Remote command execution

Installation and setup (1 of 3)


# Map the ip addresses of the VMs in your /etc/hosts
192.168.101.10 db.local db
192.168.101.11 app1.local app1
192.168.101.12 app2.local app2
192.168.101.13 proxy.local proxy
            

Installation and setup (2 of 3)


#Prevent StrictHostKeyChecking by adding the following to ~/.ssh/config
Host db.local
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
User vagrant
LogLevel QUIET

Host app1.local
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
User vagrant
LogLevel QUIET

Host app2.local
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
User vagrant
LogLevel QUIET

Host proxy.local
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
User vagrant
LogLevel QUIET
            

Installation and setup (3 of 3)


git clone https://github.com/steinim/responsible-with-ansible.git
git checkout start
            
Install: Vagrant, Virtualbox and Ansible

vagrant up
            

Layout


├── ansible.cfg
├── hosts
├── site.yml
├── group_vars
│   └── <group name>
├── host_vars
│   └── <host name>
├── roles
│   ├── <role>
│   │   ├── files
│   │       └── <file>
│   │   └── templates
│   │       └── <template>.j2
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
            

Play!


ansible-playbook --private-key=~/.vagrant.d/insecure_private_key -u vagrant site.yml
            

Facts

  • Ansible by default gathers “facts” about the machines under management.
  • These facts can be accessed in Playbooks and in templates.

ansible -m setup --private-key=~/.vagrant.d/insecure_private_key -u vagrant app1.local
            

The task

  • An app user 'devops', with:
    • Password: 'devops123'
    • Home directory: /home/devops
    • ssh-key
  • A MySql database.
  • Nginx with a reverse proxy using example configuration.
  • An init script installed as a service.
  • Deploy an application that uses the provisioned infrastructure.

Help!

http://docs.ansible.com/list_of_all_modules.html

Task1: Install and configure software


git checkout start
ansible-playbook -i hosts --private-key=~/.vagrant.d/insecure_private_key -u vagrant site.yml
            
  • Modify roles/common/tasks/apt.yml.
  • Install Vim.
  • Insert the line 'filetype indent off' in /etc/vim/vimrc
Help:
http://docs.ansible.com/apt_module.html
http://docs.ansible.com/lineinfile_module.html
            

Task1: Solution


git diff task1
            

Variables

Task2: Create an application user


git checkout task1 # or keep your own solution
            
  • Create roles/users/tasks/{main.yml,users.yml}
  • Password: 'devops123'
  • Home directory: /home/devops
  • ssh-key
  • Use variables! (group_vars)
Help:
http://docs.ansible.com/group_module.html
http://docs.ansible.com/user_module.html
http://docs.ansible.com/file_module.html (copy ssh-key)
http://docs.ansible.com/lineinfile_module.html (.ssh/authorized_keys)
http://docs.ansible.com/playbooks_best_practices.html#group-and-host-variables
            
ProTip: Use '--tags', '--skip-tags', '--limit'  and/or 'gather_facts: False'
to reduce execution time.

Task2: Solution


ssh devops@app1.local
git diff task2
            

Task3: Install and configure MySql


git checkout task2 # or keep your own solution
            

roles/mysql
├── handlers
│   └── main.yml
├── tasks
│   ├── configure_mysql.yml
│   ├── install_mysql.yml
│   └── main.yml
└── templates
    └── my.cnf.j2
            
Use variables (host_vars/db.local).
Use handler to restart mysql upon notification
Template: git checkout master -- roles/mysql/templates/my.cnf.j2
MySql and deps: git checkout master -- roles/mysql/tasks/install_mysql.yml
Help:
http://docs.ansible.com/template_module.html (my.cnf.j2)
http://docs.ansible.com/mysql_user_module.html
http://docs.ansible.com/mysql_db_module.html
http://docs.ansible.com/playbooks_intro.html#handlers-running-operations-on-change
http://docs.ansible.com/playbooks_best_practices.html#group-and-host-variables
            

Task3: Solution


vagrant ssh db
mysql -u devops -p
git diff task3
            

Task4: Deploy!


git checkout task3 # or keep your own solution
git checkout task4_help # we have a lot to do!
            

roles/app
├── files
│   └── init.sh
├── handlers
│   └── main.yml
├── tasks
│   ├── deploy.yml
│   └── main.yml
└── templates
    └── config.properties.j2
            
NB! Use variables (./hosts).
Set 'serial: 1' for appservers in site.yml.
Help:
http://docs.ansible.com/service_module.html
http://docs.ansible.com/stat_module.html
            

Task4: Solution

Browse to http://app1.local:1234/

git diff task4
            

Task5: Deploy database


git checkout task4 # or keep your own solution
            

roles/db
├── files
│   └── migrate_db.sql
└── tasks
    ├── main.yml
    └── migrate_db.yml
            
Help: git checkout master -- roles/db/files/migrate_db.sql
Help:
http://docs.ansible.com/shell_module.html
"cat /tmp/migrate_db.sql | mysql -u{{ mysql_user }} \
-p{{ mysql_user_password }} -hlocalhost {{ mysql_user }}"
            

Task5: Solution

Browse to http://app1.local:1234/

git diff task5
            

Task6: Set up proxy


git checkout task5 # or keep your own solution
git checkout task6 # we will have a walk through instead of hands-on
            

roles/nginx
├── handlers
│   └── main.yml
├── tasks
│   ├── config_nginx.yml
│   ├── install_nginx.yml
│   └── main.yml
└── templates
    └── devops.conf.j2
            
Help:
http://wsgiarea.pocoo.org/jinja/docs/loops.html
            

Task6: Solution

Browse to http://proxy.local/ # refresh me many times

git diff task6
            

Play time :-)

  • Suggestions:
    • Stop one of the appservers.
    • Change database table name from HELLO to MESSAGES and deploy a new version without downtime.

Thank you!

@steinim

stein.inge.morisbak@BEKK.no