Deploy LAMP with Vagrant and Fabric


Introduction

Lets automate every thing using python and ssh. Fabric is python library and command-line tool, which use SSH for application deployment in remote servers.
Install Fabric
By default in all unix like machine Python is available. We can install fabric library by using utility 'pip'

Create basic Vagrant file

To start with fabric lets start our vagrant guest first. Please refer Vagrant Quickstart for more details on vagrant. Create directory ch2 and create basic Vagrantfile.

Write first Fabric code

Firstly, create a fabfile.py and place it in the same directory where you have your Vagrantfile.
Import fabric library and create function to for Guest Box SSH access details
from fabric.api import env, local, run

def vagrant():
    # change from the default user to 'vagrant'
    env.user = 'vagrant'
    # connect to the port-forwarded ssh
    env.hosts = ['127.0.0.1:2222']

    # use vagrant ssh key
    result = local('vagrant ssh-config | grep IdentityFile', capture=True)
    env.key_filename = result.split()[1][1:-1]
Now add function to call any command which we want to run in Guest OS
def uname():
    run('uname -a')
So final fabfile.py file will be look like:-
$ cat fabfile.py
from fabric.api import env, local, run

def vagrant():
    # change from the default user to 'vagrant'
    env.user = 'vagrant'
    # connect to the port-forwarded ssh
    env.hosts = ['127.0.0.1:2222']

    # use vagrant ssh key
    result = local('vagrant ssh-config | grep IdentityFile', capture=True)
    env.key_filename = result.split()[1][1:-1]
def uname():
    run('uname -a')
Let execute script and check result
$ fab vagrant uname
[localhost] local: vagrant ssh-config | grep IdentityFile
[127.0.0.1:2222] Executing task 'uname'
[127.0.0.1:2222] run: uname -a
[127.0.0.1:2222] out: Linux localhost.localdomain 2.6.32-573.el6.x86_64 ...
[127.0.0.1:2222] out:


Done.
Disconnecting from 127.0.0.1:2222... done.

Here our first basic version of fabric script is ready to perform remote operations.

Update Fabric code

In previous version of script we hard coded Guest OS IP address and ssh port. But depend upon Vagrantfile configuration, IP address can be different also. So let detect dynamically Guest OS IP.
Now we need to import vagrant library for python, rename function 'vagrant' with 'start' and modify 'host' and 'key' settings
$ cat fabfile.py
import vagrant
from fabric.api import env, local, run

def start():
    ## Initialise
    v = vagrant.Vagrant()

    ## make sure vagrant is up
    v.up()

    env.hosts = [v.user_hostname_port()]
    env.key_filename = v.keyfile()
    env.disable_known_hosts = True # useful for when the vagrant box ip changes.

    # change from the default user to 'vagrant'
    env.user = 'vagrant'

def uname():
    run('uname -a')
When we execute modified script then result output will be same. Only difference is this time we didn't provided Guest OS IP
$ fab start uname

Deploy LAMP stack with fabric

In LAMP stack we will install Apache, Mysql and PHP appliactions. Algorithm flow will be,
  • Install App,
  • Allow in iptable,
  • Start app,
  • Enable to start at boot
  • Configure APP (If require)
Lets write method to deploy mysql server, apache and php in same 'fabfile.py' file

Mysql Server

def deploy_mysql():
    ## Install Mysql-Server
    run('sudo yum -y install mysql-server')

    ## Add iptable rules
    run('sudo iptables -I INPUT -p tcp --dport 3306 -m state --state NEW,ESTABLISHED -j ACCEPT')
    run('sudo iptables -I OUTPUT -p tcp --sport 3306 -m state --state ESTABLISHED -j ACCEPT')
    run('sudo service iptables save')

    ##Start Application
    run('sudo /sbin/service mysqld start')

    ## Launch at reboot
    run('sudo chkconfig mysqld on')

    ## Set Mysql password
    mysqlPassword = 'fabricDeploy'

    ## Check condietion for for 2nd attempt of script, in case password already reset in first attempt
    result = run("mysql -u root -p%s <<< 'show databases'" % mysqlPassword,warn_only=True)
    if result.failed:
        run("/usr/bin/mysqladmin -u root password '%s'" % mysqlPassword)
        run("/usr/bin/mysqladmin -u root --password='%s' -h %s password '%s'" % (mysqlPassword,env.hostname,mysqlPassword))

Apache

def deploy_apache():
    ## Install Apache
    run("sudo yum -y install httpd  mod_ssl")

    ## Add IPtable rules
    run("sudo iptables -I INPUT -p tcp --dport 80 -j ACCEPT")
    run(" sudo service iptables save")

    ## Start Apache
    run("sudo service httpd start")

    ## Launch at boot
    run(" sudo /sbin/chkconfig httpd on")

PHP

def deploy_php():
    ## Insatll PHP
    run("sudo yum -y install php php-devel php-mysql")
    run("sudo service httpd restart")
So now our functions to deploy Mysql,Apache and PHP are ready. We can deploy calling functions one by one 3 times, Like
$ fab start deploy_mysql
$ fab start deploy_apache
$ fab start deploy_php
Or since we have to deploy all together, so lets create another function to deploy all app together
def deploy_lamp_stack():
    execute(deploy_mysql)
    execute(deploy_apache)
    execute(deploy_php)
Now lets deploy all together
$ fab start deploy_lamp_stack

Create Box

Installing all application every time require network bandwidth. So to work offline and decrease deployment time, lets create local vagrant box
## Create vagarnt box from curent guest os and name as 'centos-lamp-6.7'
$ vagrant package --output centos-lamp-6.7

## Check created box
$ ls 
## Expected output 'Vagrantfile, fabfile.py and centos-lamp-6.7'

## Add box in local box repository
$ vagrant box add --name centos-lamp-6.7  ./centos-lamp-6.7

## Confirm Box added
$ vagrant box list

## Delete box file
$ rm centos-lamp-6.7

Run PHP Code

Since now our clean Guest OS is saved as box, Lets play with our current Guest OS.
Create new function to write php script with phpinfo function inside apache DocumentRoot
def deploy_project():
    ##Deploy Dummy Project
    run("echo '' | sudo tee /var/www/html/index.php")
Deploy demo php code
$ fab start deploy_project

## Open Url http://127.0.0.1:8080/ in your local web browser
## Expecting Output of phpinfo function

Conclusion

So now our local LAMP box is ready. So next time for any new php project then edit "config.vm.box=centos-lamp-6.7" in Vagrantfile
If we have local yum repository available in LAN then no need to create new box, Just deploy LAMP stack using fabric in default vm box.

References:-

Comments

Popular posts from this blog

Mysql to CSV

Secure server with Firewalld

Setup K8s cluster via kubeadm