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 toolansible-playbook
is designed to read a YAML (with theyml
extension) playbook file (it can be called anything as long as it is a .yml file). It absorbs and executes thetasks
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-
comments powered by Disqus