Skip to main content

Command Palette

Search for a command to run...

Automate Deploying a LAMP Stack Application using Ansible

Updated
6 min read
Automate Deploying a LAMP Stack Application using Ansible
H

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 root privileges
  • 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-controller host is configured with the IP addresses of the targets as below example

image.png

  • 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 files sub-folder and move into it:

    mkdir files
    
  • Create MySQL Configuration file my.cnf under files folder:

    vi files/my.cnf
    
  • Paste the below lines inside my.cnf and 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.sql on the controller host under files folder:
    vi files/db-load-script.sql
    
  • Paste below lines inside db-load-script.sql file 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.php file on controller host under files folder
    vi files/index.php
    
    • Paste below code inside index.php file and make sure to replace <YOUR-DB-HOST-IP> with your specific DB Host IP address before saving it:
<!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 host value <YOUR-WEB-HOST-IP> in Create Application DB User task 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!

More from this blog

Hamza Noweder's Blog

8 posts

A Cloud Enthusiast