vagrant and ansible

vagrant and ansible

putting vagrant on steroids

First, set up vagrant to create a group of guest virtual machines (see previous posts). We will assume your Vagrantfile is configured to build/start 3 nodes (node1, node2, node3). If these are bare builds you will want to personalize or customize each of them.

Chances are you will want to give each of them a common base of applications and configuration. As a significant example, downloaded images are set for universal time; not what you want. It is simple to just edit the /etc/timezone file or write a script to change it on multiple machines. But if you have lots of machines or tear these machines down and stand them back up frequently then exercises like this will get very tedious. Additionally there are and handful of packages you typically want one every machine.

The provision tool named ansible was designed by the author to be “a tool that I could not use for 6 months, come back later, and still remember how it worked”. The advantage for me is that it leverages ssh and sudo, tools you use everyday. It uses YAML files for configuration Wikipedia YAML which, once you understand the syntax, is easy to read and manage.

Using vagrant is a great way to consistently build virtual nodes. Add ansible to the mix and you have a great way to build and maintain many usable nodes. The vagrant tool uses ansible without any additional work other than properly calling it within your default config file (Vagrantfile). Throw a few lines in to have the ansible-playbook tool call a playbook.yml file and the fun begins.

eg: Within your Vagrantfile (see earlier post on vagrant-lxc)

  config.vm.provision :ansible do |ansible|
    ansible.playbook = "playbook.yml"
  end

The other half of the story is ansible and the playbook.yml config file. Install ansible (a python based tool) with this (assumes a Debian family OS):

sudo apt-get install ansible

Now lets write the playbook.yml file and put it right where your Vagrantfile is.

A quick word about ansible. DevOps is the buzzword of recent IT deployment trend. The driving focus is rolling continuous (frequent) deployments and upgrades. The underlying theory is that any weaknesses in your deployment strategy is exposed early and it keeps human hands off the controls. Here, we will take advantage of that perspective. The ansible suite comes with half dozen tools which might throw you off initially. The only one you concern yourself with (early in the relatively smooth learning curve) is ansible-playbook - forget about the others for now (ie ansible, ansible-doc, ansible-galaxy, ansible-pull, ansible-tools, ansible-vault). The tool ansible-playbook is designed to read a YAML (with the yml extension) playbook file (it can be called anything as long as it is a .yml file). It absorbs and executes the tasks and plays out these commands against specified hosts or host groups. That was a over simplification because it conceals the depth and feature rich possibilities of ansible playbooks. That is for another time perhaps.

Here is a quick-n-dirty playbook.yml to call from a Vagrantfile: There are a lot of commented lines of code ready for you to explore on your own.

Note: ansible YAML (xxx.yml) playbook files start with three dashes - hence --- at the beginning. One critical syntax element to know is that left alignment is essential for YAML to know the subordinate level for processing.

---
################
# NOTE: assumes:
#       This all resides in
#       $HOME/vagrant
#################

- hosts: all
  vars:
    - docroot: /var/www/html
    - domain: my.lab
    - ntp_timezone: America/New_York
    - user_password: "$6$SomeSalt$bUGZDQdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx65N/BhPuCfeg8eE1zqc8VNRFYB9sfX1"
        # python -c ' import crypt; print crypt.crypt("This is my Password", "$6$SomeSalt$") '


  sudo: true
  tasks:
    - name: Visually show host basics
      debug: msg='host [ {{ ansible_hostname }} ] {{ ansible_all_ipv4_addresses }} arch [ {{ ansible_architecture }} ]'

    - name: install required packages for apt upgrade
      apt: name={{ item }} state=latest update_cache=true
      with_items:
        - python-apt
        - aptitude

    - name: apt upgrade
      apt: upgrade=yes update_cache=yes dpkg_options='force-confold,force-confdef'

    - name: install required packages
      apt: name={{ item }} state=latest update_cache=true
      with_items:
        - vim
        - lynx
        - screen
        - git
        - ufw
        - rsync
        - chkrootkit
        - curl
        - alpine
#        - python3-pip
#        - inxi
#        - virtualbox-guest-utils

    - name: Install postfix
      apt: name=postfix state=latest
      register: postfix_installed
                      
    - name: Add inet_protocols = ipv4 line to main.cf
      lineinfile: dest=/etc/postfix/main.cf line='inet_protocols = ipv4'
              
    - name: Install ntp
      apt: name=ntp state=installed
      when: ansible_os_family == 'Debian'
                  
    - name: Ensure proper timezone
      file: src=/usr/share/zoneinfo/{{ ntp_timezone }} dest=/etc/localtime state=link force=yes

#    - name: Install admin packages
#      apt: name={{ item }} state=present
#      with_items:
#        - nmap
#        - lsof
#        - make
#
#    - name: Install MySQL client server and related libraries
#      apt: name={{ item }} state=latest
#      with_items:
#        - mysql-client
#        - mysql-server
#      notify:
#        - Start mysql server
#
#    - name: Install PHP and its modules
#      apt: pkg={{ item }} state=latest
#      with_items:
#        - php5
#        - php5-cli
#        - php5-curl
#        - php5-gd
#        - php5-imagick
#        - php5-mysql
#        - php5-xmlrpc
#
#    - name: Install Apache and its module9(s)
#      apt: pkg={{ item }} state=latest
#      with_items:
#        - apache2
#        - libapache2-mod-php5
#      register: apacheinstalled
#
##    - name: Activate mod_rewrite
##      apache2_module: name=rewrite state=present
#
#      notify:
#        - Start apache server
#
#    - name: Create web root
#      when: apacheinstalled|success
#      file: dest=/var/www/html mode=775 state=directory owner=www-data group=www-data 
#      notify: 
#        - Reload apache
#
    # make sure admin group exists
    - name: assure admin group
      group: name=admin state=present

    # Add the user 'wocos'
    - name: Add user wocos
      user: name=wocos groups=sudo,admin
        shell=/bin/bash 
        generate_ssh_key=yes 
        ssh_key_file=.ssh/id_rsa 
        createhome=yes state=present
        password="{{user_password }}"
        # created with:
        # python -c ' import crypt; print crypt.crypt("This is my Password", "$6$SomeSalt$") '
        # the var user_password is defined above in the vars section
   
        # another interactive way to add a password
        # vars_prompt:
        # - name: "user_password"
        #   prompt: "Enter a password for the user: "
        #   private: yes
        #   encrypt: "md5_crypt" # needs python-passlib installed
        #   confirm: yes
        #   salt_size: 7
        # password="{{ user_password }}"

#
#  handlers:
#    - name: Start mysql server
#      service: name=mysql state=started enabled=yes
#
#    - name: Start apache
#      service: name=apache2 state=restarted enabled=yes
#
#    - name: Reload apache
#      service: name=apache2 state=reloaded
######## EOF ##########

Call this from within your Vagrantfile as noted above (please see previous post on vagrant-lxc). Then (assuming the ansible playbook call within Vagrantfile is uncommented and active) run

vagrant up

It will take a bit longer because you have asked it to do much more… so get a cup of coffee… but when you are finished your vagrant/lxc nodes will be much more usable.

Now, take a risk, destroy one of the nodes and then run vagrant up again.

vagrant status # hopefully you see your nodes running (eg node1, node2, node3)
# or sudo lxc-ls --fancy
vagrant destroy node3
# or sudo lxc-stop -n node3; sudo lxc-destroy -n node3
vagrant status # just to see that node3 has disappeared
vangrant up # yes, even though some are running and one is destroyed...
# this last command should rebuild *and provision with ansible* your lost node3
vagrant status

Have a nice day, enjoy,

-g-

Geoff McNamara

“Do not meddle in the affairs of wizards, for they are subtle and quick to anger.” J.R.R Tolkien

blah Elizabeth City, NC https://www.companionway.net