Automate Deploying a LAMP Stack Application using Ansible

A Cloud Enthusiast
What is Ansible?
Ansible is a software tool that provides simple but powerful automation for cross-platform computer support. It is primarily intended for IT professionals, who use it for application deployment, updates on workstations and servers, cloud provisioning, configuration management, intra-service orchestration, and nearly anything a systems administrator does on a weekly or daily basis. Ansible doesn't depend on agent software and has no additional security infrastructure, so it's easy to deploy.
In this project, we will use Ansible to deploy a LAMP stack web application on multi-node setup.
Pre-requisites
- User with
rootprivileges 3 CentOS hosts on the same network. One will act the Ansible controller, and the other two will acts as target hosts. The hostnames should be configured as below to follow along:
- ansible-controller
- lamp-db
- lamp-web
Ansible installed on ansible-controller host
- /etc/hosts/ on
ansible-controllerhost is configured with the IP addresses of the targets as below example

- SSH Password-less login enabled between the ansible-controller host and the two target hosts
Steps
Step1: Create the project folder and access it by running below commands:
mkdir lamp-stack-playbooks
cd lamp-stack-playbooks
Step 2: Configure the inventory file
- Create an inventory file
vi inventory - Copy below lines and paste them in the inventory file. Also, make sure to replace and with your proper DB and Web hosts' IP addresses. In addition you need to specify the user and SSH private key path for both DB and WEB.
[db_servers]
lamp-db ansible_host=<YOUR-DB-HOST-IP> ansible_user=<DB_USER> ansible_ssh_private_key_file=<PATH_TO_DB_SSH_PRIVATE_KEY> mysqlservice=mysqld mysql_port=3306 dbname=ecomdb dbuser=ecomuser dbpassword=ecompassword
[web_servers]
lamp-web ansible_host=<YOUR-WEB-HOST-IP> ansible_user=<WEB_USER> ansible_ssh_private_key_file=<PATH_TO_WEB_SSH_PRIVATE_KEY> httpd_port=80 repository=https://github.com/noweder/lamp-app-ecommerce.git
Step 3: Prepare the configuration files
Create
filessub-folder and move into it:mkdir filesCreate MySQL Configuration file
my.cnfunderfilesfolder:vi files/my.cnf- Paste the below lines inside
my.cnfand save it:[mysqld] innodb-buffer-pool-size=5242880 # datadir=/var/lib/mysql # socket=/var/lib/mysql/mysql.sock user=mysql # Disabling symbolic-links is recommended to prevent assorted security risks symbolic-links=0 port=3306 - Create another file named
db-load-script.sqlon the controller host underfilesfolder:vi files/db-load-script.sql - Paste below lines inside
db-load-script.sqlfile and save it:
USE ecomdb;
CREATE TABLE products (id mediumint(8) unsigned NOT NULL auto_increment,Name varchar(255) default NULL,Price varchar(255) default NULL, ImageUrl varchar(255) default NULL,PRIMARY KEY (id)) AUTO_INCREMENT=1;
INSERT INTO products (Name,Price,ImageUrl) VALUES ("Laptop","100","c-1.png"),("Drone","200","c-2.png"),("VR","300","c-3.png"),("Tablet","50","c-5.png"),("Watch","90","c-6.png"),("Phone Covers","20","c-7.png"),("Phone","80","c-8.png"),("Laptop","150","c-4.png");
- Create
index.phpfile on controller host underfilesfoldervi files/index.php- Paste below code inside
index.phpfile and make sure to replace<YOUR-DB-HOST-IP>with your specific DB Host IP address before saving it:
- Paste below code inside
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>E-Commerce Website</title>
<!-- Favicon -->
<link rel="icon" href="img/favicon.png" type="image/png" />
<!-- Bootstrap CSS -->
<link href="css/bootstrap.min.css" rel="stylesheet">
<!-- Icon CSS-->
<link rel="stylesheet" href="vendors/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="vendors/linearicons/linearicons-1.0.0.css">
<!-- Animations CSS-->
<link rel="stylesheet" href="vendors/wow-js/animate.css">
<!-- owl_carousel-->
<link rel="stylesheet" href="vendors/owl_carousel/owl.carousel.css">
<!-- Theme style CSS -->
<link href="css/style.css" rel="stylesheet">
<!-- <link href="css/responsive.css" rel="stylesheet"> -->
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!--==========Main Header==========-->
<header class="main_header_area">
<nav class="navbar navbar-default navbar-fixed-top" id="main_navbar">
<div class="container-fluid searchForm">
<form action="#" class="row">
<div class="input-group">
<span class="input-group-addon"><i class="lnr lnr-magnifier"></i></span>
<input type="search" name="search" class="form-control" placeholder="Type & Hit Enter">
<span class="input-group-addon form_hide"><i class="lnr lnr-cross"></i></span>
</div>
</form>
</div>
<div class="container">
<div class="row">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="col-md-2 p0">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="index.html">
<img src="img/logo.png" alt="">
<img src="img/logo-2.png" alt="">
</a>
</div>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<div class="col-md-9 p0">
<ul class="nav navbar-nav main_nav">
<li><a href="#">Laptops</a></li>
<li><a href="#">Drones</a></li>
<li><a href="#">Gadgets</a></li>
<li><a href="#">Phones</a></li>
<li><a href="#">VR</a></li>
<li><a href="#">Contact us</a></li>
</ul>
</div>
<div class="col-md-1 p0">
<ul class="nav navbar-nav navbar-right">
<li><a href="#" class="nav_searchFrom"><i class="lnr lnr-magnifier"></i></a></li>
</ul>
</div>
</div><!-- /.navbar-collapse -->
</div>
</div><!-- /.container-fluid -->
</nav>
</header>
<!--==========Main Header==========-->
<!--==========Slider area==========-->
<section class="slider_area row m0">
<div class="slider_inner">
<div class="camera_caption">
<h2 class="wow fadeInUp animated">Make Your Shopping Easy</h2>
<h5 class="wow fadeIn animated" data-wow-delay="0.3s">Find everything accordingly</h5>
<a class="learn_mor wow fadeInU" data-wow-delay="0.6s" href="#product-list">Show Now!</a>
</div>
</div>
</section>
<!--==========End Slider area==========-->
<section class="best_business_area row">
<div class="check_tittle wow fadeInUp" data-wow-delay="0.7s" id="product-list">
<h2>Product List</h2>
</div>
<div class="row it_works">
<?php
$link = mysqli_connect('<YOUR_DB_HOST_IP>', 'ecomuser', 'ecompassword', 'ecomdb');
if ($link) {
$res = mysqli_query($link, "select * from products;");
while ($row = mysqli_fetch_assoc($res)) { ?>
<div class="col-md-3 col-sm-6 business_content">
<?php echo '<img src="img/' . $row['ImageUrl'] . '" alt="">' ?>
<div class="media">
<div class="media-left">
</div>
<div class="media-body">
<a href="#"><?php echo $row['Name'] ?></a>
<p>Purchase <?php echo $row['Name'] ?> at the lowest price <span><?php echo $row['Price'] ?>$</span></p>
</div>
</div>
</div>
<?php
}
}
else {
?>
<div style="width: 100%">
<div class="error-content">
<h1>Database connection error</h1>
<p>
<?php
echo mysqli_connect_errno() . ":" . mysqli_connect_error();
?>
</p>
</div>
</div>
<?php
}
?>
</div>
</section>
<footer class="footer_area row">
<div class="container custom-container">
<div class="copy_right_area">
<h4 class="copy_right">© Copyright 2019 Ecommerce Website | All Rights Reserved</h4>
</div>
</div>
</footer>
<!-- jQuery -->
<script src="js/jquery-1.12.4.min.js"></script>
<!-- Bootstrap -->
<script src="js/bootstrap.min.js"></script>
<!-- Wow js -->
<script src="vendors/wow-js/wow.min.js"></script>
<!-- Wow js -->
<script src="vendors/Counter-Up/waypoints.min.js"></script>
<script src="vendors/Counter-Up/jquery.counterup.min.js"></script>
<!-- Stellar js -->
<script src="vendors/stellar/jquery.stellar.js"></script>
<!-- owl_carousel js -->
<script src="vendors/owl_carousel/owl.carousel.min.js"></script>
<!-- Theme js -->
<script src="js/theme.js"></script>
</body>
</html>
Step 3: Create a deploy-lamp-stack.yml playbook file under lamp-stack-playbooks and paste below code:
---
- name: Deploy lamp stack application
hosts: all
become: yes
tasks:
- name: Install common dependencies
yum:
name:
- libselinux-python
- libsemanage-python
- firewalld
state: installed
# Install and Configure Database
- name: Deploy DB of the application
hosts: lamp-db
become: yes
tasks:
- name: Install MariaDB package
yum:
name:
- mariadb-server
- MySQL-python
state: installed
- name: Create Mysql configuration file
copy: src=files/my.cnf dest=/etc/my.cnf
- name: Start MariaDB Service
service: name=mariadb state=started enabled=yes
- name: Start firewalld
service: name=firewalld state=started enabled=yes
- name: insert firewalld rule
firewalld: port={{ mysql_port }}/tcp permanent=true state=enabled immediate=yes
- name: Create Application Database
mysql_db: name={{ dbname }} state=present
- name: Create Application DB User
mysql_user: name={{ dbuser }} password={{ dbpassword }} priv=*.*:ALL host='<YOUR_WEB_HOST_IP>' state=present
- name: Move db-load-script to db host
copy:
src: files/db-load-script.sql
dest: /tmp/db-load-script.sql
- name: Load Inventory Data
shell: mysql -f < /tmp/db-load-script.sql
- name: Deploy web application
hosts: lamp-web
become: yes
tasks:
- name: Install httpd and php
yum:
name:
- httpd
- php
- php-mysql
state: present
- name: Install web role specific dependencies
yum: name=git state=installed
- name: Start firewalld
service: name=firewalld state=started enabled=yes
- name: insert firewalld rule for httpd
firewalld: port={{ httpd_port }}/tcp permanent=true state=enabled immediate=yes
- name: Set index.php as the default page
tags: "Set index.php as the default page"
replace:
path: /etc/httpd/conf/httpd.conf
regexp: 'DirectoryIndex index.html'
replace: 'DirectoryIndex index.php'
- name: http service state
service: name=httpd state=started enabled=yes
- name: Copy the code from repository
git: repo={{ repository }} dest=/var/www/html/ force=yes
- name: Create the index.php file
copy: src=files/index.php dest=/var/www/html/index.php
- Make sure to replace
<YOUR_WEB_HOST_IP>with your specific Web Host IP address before saving the file.
Step 4: Run the playbook with below command
ansible-playbook -i inventory deploy-lamp-stack.yml
- Make sure to replace the
hostvalue<YOUR-WEB-HOST-IP>inCreate Application DB Usertask with your specific web host IP address.
Step 5: Access the web application
- Run the below command to access the web application from CLI:
curl <YOUR-WEB-HOST-IP> - Or, copy
<YOUR-WEB-HOST-IP>and paste it into a web browser.
Thank you for reading!


