Mastering Ansible

Mastering Ansible

November 18, 2017 CI/CD 0

Today I’d like to write a bit about a more technical topic, namely Ansible. Ansible is a ‘simple’ way to automate apps and IT infrastructure. It combines Application Deployment, Configuration Management and Continuous Delivery into one neat little package. I first started working with it at NN, during my time in the API NN Ext. Platform team. This was a very hectic time with a very high workload. This allowed me to work on many different subjects, but didn’t grant me any time to actually study any topic in-depth.

Now that’s changed. I’m no longer in that team or company and I have all the time to put a solid theoretical foundation under my existing Ansible knowledge. I want to do this by¬†building my own Ansible swarm. The eventual plan will be to creare my own CI/CD pipeline on my Windows 10 PC via Gitlab CI and automate builds and build-information via AWS Alexa. Eventually, I want to copy this set-up on my Ubuntu Laptop for extra learning. Let’s get started.

The next couple of posts are based on “”

Tools used:

  • Atom
  • Vagrant
  • Ansible
    • MySQl
    • NGINX
    • Apache2, Python
  • Virtualbox

Vagrant is a very nice tool that helps you set up a virtual network. People call it a wrapper as its wrapped around Virtualbox and handles all tasks for you automatically. For each virtual environment I’m using the Ubuntu/Trusty64 image.

The idea is to create 5 instances:

  • Control
  • Loadbalancer
  • Webserver 1
  • Webserver 2
  • Database

Control will be the main Ansible machine. The other four will work together to provide access to content on the Webserver.

The script for Vagrant is as follows:

# vi: set ft=ruby :

# Getting Started:
# 1. vagrant plugin install vagrant-hostmanager
# 2. vagrant up
# 3. vagrant ssh
# This should put you at the control host
# with access, by name, to other vms
Vagrant.configure(2) do |config|
 config.hostmanager.enabled = true = "ubuntu/trusty64"

config.vm.define "control", primary: true do |h| "private_network", ip: ""
 h.vm.provision :shell, :inline => <<'EOF'
if [ ! -f "/home/vagrant/.ssh/id_rsa" ]; then
 ssh-keygen -t rsa -N "" -f /home/vagrant/.ssh/id_rsa
cp /home/vagrant/.ssh/ /vagrant/

cat << 'SSHEOF' > /home/vagrant/.ssh/config
Host *
 StrictHostKeyChecking no

chown -R vagrant:vagrant /home/vagrant/.ssh/

config.vm.define "lb01" do |h| "private_network", ip: ""
 h.vm.provision :shell, inline: 'cat /vagrant/ >> /home/vagrant/.ssh/authorized_keys'

config.vm.define "app01" do |h| "private_network", ip: ""
 h.vm.provision :shell, inline: 'cat /vagrant/ >> /home/vagrant/.ssh/authorized_keys'

config.vm.define "app02" do |h| "private_network", ip: ""
 h.vm.provision :shell, inline: 'cat /vagrant/ >> /home/vagrant/.ssh/authorized_keys'

config.vm.define "db01" do |h| "private_network", ip: ""
 h.vm.provision :shell, inline: 'cat /vagrant/ >> /home/vagrant/.ssh/authorized_keys'

The set-up is quite simple. By adding this in a ‘Vagrantfile’ (the one you get after doing ‘vagrant init’) you can establish the entire structure by running ‘vagrant up’. The next tier will contain a MySQL DB, Loadbalancer and two Webservers. A nice detail is that the control machine has a shared folder with my Windows 10 machine. This means I can run Atom on all Ansible .yml files and edit them in the GUI I’m used to. (I hate VIM or any other linux-based text editor)

You can log in the control machine by typing ‘vagrant ssh’. Once you’re in you have to install Ansible to deal with the config management of the lower tier (LB, DB and Webserver)

For the DB, Loadbalancer and Webservers, I have to add the following to each respective .yml file

DB Script:

- hosts: database
 become: true
 - name: install tools
 apt: name={{item}} state=present update_cache=yes
 - python-mysqldb

- name: install mysql-server
 apt: name=mysql-server state=present update_cache=yes

- name: ensure mysql started
 service: name=mysql state=started enabled=yes

- name: ensure mysql listening on all ports
 lineinfile: dest=/etc/mysql/my.cnf regexp=^bind-address
 line="bind-address ="
 notify: restart mysql

- name: create demo database
 mysql_db: name=demo state=present

- name: create demo user
 mysql_user: name=demo password=demo priv=demo.*:ALL host='%' state=present

 - name: restart mysql
 service: name=mysql state=restarted


Webserver Script:

- hosts: webserver
 become: true
 - name: install items
 apt: name={{item}} state=present update_cache=yes
 - apache2
 - libapache2-mod-wsgi
 - python-pip
 - python-virtualenv
 - python-mysqldb
#Start Apache
 - name: ensure apache2 started
 service: name=apache2 state=started enabled=yes

- name: ensure mod_wsgi enabled
 apache2_module: state=present name=wsgi
 notify: restart apache2
#Copy Demo Files
 - name: copy demo app source
 copy: src=demo/app/ dest=/var/www/demo mode=0755
 notify: restart apache2
# Copy Config
 - name: copy apache virtual host config
 copy: src=demo/demo.conf dest=/etc/apache2/sites-available mode=0755
 notify: restart apache2
# Initiate Python
 - name: setup python virtualenv
 pip: requirements=/var/www/demo/requirements.txt virtualenv=/var/www/demo/.venv
 notify: restart apache2
# Stop default site and start own site
 - name: deactivate default apache site
 file: path=/etc/apache2/sites-enabled/000-default.conf state=absent
 notify: restart apache2

- name: activate demo apache site
 file: src=/etc/apache2/sites-available/demo.conf dest=/etc/apache2/sites-enabled/demo.conf state=link
 notify: restart apache2

 - name: restart apache2
 service: name=apache2 state=restarted


LB Script:

--- - hosts: loadbalancer become: true tasks: - name: install tools apt: name={{item}} state=present update_cache=yes with_items: - python-httplib2 - name: install nginx apt: name=nginx state=present update_cache=yes - name: ensure nginx started service: name=nginx state=started enabled=yes - name: configure nginx site template: src=templates/nginx.conf.j2 dest=/etc/nginx/sites-available/demo mode=0644 notify: restart nginx - name: de-activate default nginx site file: path=/etc/nginx/sites-enabled/default state=absent notify: restart nginx - name: activate nginx site file: src=/etc/nginx/sites-available/demo dest=/etc/nginx/sites-enabled/demo state=link notify: restart nginx handlers: - name: restart nginx service: name=nginx state=restarted



By adding these scripts, some custom ‘app’ files in the Ansible folder and running the playbook, we now have a single Control station with Ansible, a Database running mySQL, a Loadbalancer with NGINX and two webservers with Apache2, ready to go. Following along with the lectures, I’ve also made two playbooks called “Stack_Status.yml” and “Stack_reset.yml” in order to check what’s going on and to reboot the entire stack.

I’ll be continuing to work on this going forward. I’ll be trying to recreate this same set-up again on Monday on my Ubuntu Laptop for training. There seems to be some bugs with my versions of 1.6 Ubuntu and 1.8 Vagrant but I’ll look into that later today. (Sad that I can’t take my desktop with me to work…)