A multi-tier  Web Application Deployment

A multi-tier Web Application Deployment

Setting up the entire stack locally using multiple VMs for each services Vagrant|VBox|Tomcat|Nginx|RabbitMQ|MySQL|Memcached|Maven

Play this article

Project Overview

In this project, we'll be hosting a web application which is a social site developed by developers, and the application is based on Java.

The user can access the application using an IP address from his/her browser(as we are setting up the project locally for now).

The Load Balancer will provide this IP as shown below in the image.

We'll be using Nginx as the reverse proxy to create the Load balancing experience. As soon as the request comes from the users, Nginx will route the request to Apache Tomcat Service.

Apache Tomcat is a Java Web Application service. When the application is written in Java, it will be hosted on Apache Tomcat.

RabbitMQ is connected to Tomcat which is a Message Broker or Queueing Agent. To connect 2 applications, you can stream the data from this.

Memcached is a Database cashing service, it will be connected to the MySQL server. When the user logs in for the first time, it will be stored in MySQL DB and cached in Memcached so, the next time when the same user sends a request, it will be retrieved from the Memcached service.

Prerequisites

Tools Required

  • Hypervisor: Oracle VM Virtual Box

  • Automation: Vagrant

  • CLI: Git Bash

  • IDE: VS Code/Sublime Text/Notepad++

Services to be Implemented

  • Nginx

  • Tomcat

  • RabitMQ

  • Memcached

  • MySql

Flow of Execution

  1. Setting up the tools explained in the Prerequisite section

  2. Clone the Source code from the Version control system(Git)

  3. cd into the Vagrant Directory and bring up the VMs

  4. Setup all the services such as:

    • MySQL

    • Memcached

    • RabbitMQ

    • Tomcat

    • Nginx

  5. App build and Deploy

  6. Accessing the application from the browser

Setting up the VMs

Previously we have been using AWS EC2 instances in all our projects. However, here I have tried a new approach. In this project, we'll be firing up the VMs in our Local system for each service listed above.

Here we'll be using Oracle Virtual Box to lunch VMs with Vagrant to automate the lunch of these VMs.

Writing a Vagrant File

A vagrant file is nothing but a piece of configuration that will automate the lunch of multiple VMs locally through Oracle Virtual Box which is written in Ruby.

NB: Before writing and proceeding with VM setup we have to install the Hostmanager plugin by $ vagrant plugin install vagrant-hostmanager command.

Vagrant.configure("2") do |config|
  config.hostmanager.enabled = true 
  config.hostmanager.manage_host = true

### Nginx VM ###
  config.vm.define "web01" do |web01|
    web01.vm.box = "ubuntu/bionic64"
    web01.vm.hostname = "web01"
    web01.vm.network "private_network", ip: "192.168.56.11"
  end

### tomcat vm ###
   config.vm.define "app01" do |app01|
    app01.vm.box = "geerlingguy/centos7"
    app01.vm.hostname = "app01"
    app01.vm.network "private_network", ip: "192.168.56.12"
    app01.vm.provider "virtualbox" do |vb|
     vb.memory = "1024"
     end
   end

### RabbitMQ vm  ####
  config.vm.define "rmq01" do |rmq01|
    rmq01.vm.box = "geerlingguy/centos7"
    rmq01.vm.hostname = "rmq01"
    rmq01.vm.network "private_network", ip: "192.168.56.16"
  end

### Memcache vm  #### 
  config.vm.define "mc01" do |mc01|
    mc01.vm.box = "geerlingguy/centos7"
    mc01.vm.hostname = "mc01"
    mc01.vm.network "private_network", ip: "192.168.56.14"
  end

### DB vm  ####
  config.vm.define "db01" do |db01|
    db01.vm.box = "geerlingguy/centos7"
    db01.vm.hostname = "db01"
    db01.vm.network "private_network", ip: "192.168.56.15"
  end
end

In the above code, we have configured 5 VMs for each service such as Nginx, Tomcat, RabbitMQ, Memcache, and MySQL DB respectively.

Code Explanation

  1. The Vagrant.configure("2") do |config| block initializes the Vagrant configuration.

  2. config.hostmanager.enabled = true enables the Vagrant Hostmanager plugin, which manages the hosts file on the host machine.

  3. config.hostmanager.manage_host = true allows Vagrant to manage the host entries for the VMs.

  4. The web01 VM definition starts with config.vm.define "web01" do |web01|. This VM is using the "ubuntu/bionic64" box, has the hostname "web01," and is assigned the IP address "192.168.56.11" on a private network.

  5. The app01 VM definition starts with config.vm.define "app01" do |app01|. This VM is using the "geerlingguy/centos7" box, has the hostname "app01," and is assigned the IP address "192.168.56.12" on a private network. It also sets the memory allocation for the VM to 1024 MB using the VirtualBox provider.

  6. The rmq01 VM definition starts with config.vm.define "rmq01" do |rmq01|. This VM is using the "geerlingguy/centos7" box, has the hostname "rmq01," and is assigned the IP address "192.168.56.16" on a private network.

  7. The mc01 VM definition starts with config.vm.define "mc01" do |mc01|. This VM is using the "geerlingguy/centos7" box, has the hostname "mc01," and is assigned the IP address "192.168.56.14" on a private network.

  8. The db01 VM definition starts with config.vm.define "db01" do |db01|. This VM is using the "geerlingguy/centos7" box, has the hostname "db01," and is assigned the IP address "192.168.56.15" on a private network.

VMs up & Running(vagrant up )

Now after preparing the Vagrant file, we'll start the VMs using vagrant up command in the same directory where the Vagrant file is present.

Currently, on my Virtual Box, there are no VMs available:

Once we do vagrant up , it will start firing up VMs as below:

Once the entire setup is completed, we can see all the VMs listed in VBox

Validating the Connection among Servers

It is necessary to validate these servers because the Nginx server == will connect to ==> Tomcat.

Tomcat == to ==> Db and all other services accordingly.

We can validate by doing SSH to each server and making a simple ping to each service.

NB: Until now these are just empty servers(VMs), going forward we will set up all the services in their respective VMs.

1) web01(For Nginx service)

vagrant ssh web01 will allow us to ssh into the Nginx VM

$ cat /etc/hosts will show the hosts below where all the services are listed that it will interact with:

2) app01(For Tomcat service)

Setting up Services

1) Setup MySQL(Database SVC)

  • Updating the Server:

    vagrant ssh db01 will allow us to ssh into the DB server.

    sudo -i get the root privilege

    yum update -y to update the server

  • Setting up the password for DB:

    vi /etc/profile : This file typically contains system-wide environment variables and startup configurations for all users.

    source /etc/profile : using this command you persist the password as an environment variable.

  • Installing EPL repository:

    yum install epel-release -y : The term "epl-release" typically refers to the "Extra Packages for Enterprise Linux (EPEL) release." EPEL is a repository project that provides additional software packages for Red Hat Enterprise Linux (RHEL), CentOS, and other compatible Linux distributions.

  • Installing Maria DB and Git:

    yum install git mariadb-server -y : This will install maria db server and git as well.

    • Starting up and enabling maria DB:

      systemctl start mariadb : this command will start the DB

      systemctl enable mariadb : it will enable the db service to up and run automatically when system reboots.

      systemctl status mariadb : this will check the status of the DB

  • Setting up Root Password for Maria DB:

    mysql_secure_installation : is a shell script that enables you to improve the security of your MySQL installation.

Logging in to SQL DB:

mysql -u root -p : using this command followed by the password we can login to the DB.

Cloning the Project Source code

We'll be cloning the VProfile project code to the DB server to run the SQL queries written in the project to make the DB ready to work with other services. To do so we have to clone the project to the DB server by:

git clone -b local-setup https://github.com/rkn1999/vprofile-project.git : this will clone the entire project to the server.

Once we cloned the project, we can see that we have a file named db_backup.sql which will help us to initialize the database.

Before that we have to create a database.

Creating a database in DB server

mysql -u root -p"$DATABASE_PASS" -e "create database accounts" : this will create a database named accounts.

mysql -u root -p"$DATABASE_PASS" -e "grant all privileges on accounts.* To 'admin'@'app01' identified by 'admin123' " : this will add a user in MySQL named admin. admin user from the database can be accessed from app01 server and it'll have full privileges on accounts database.

Running the db_backup.sql

mysql -u root -p"$DATABASE_PASS" accounts < src/main/resources/db_backup.sql

The above command will get into accounts database and run the db_backup.sql

mysql -u root -p"$DATABASE_PASS" -e "FLUSH PRIVILEGES"

The above command executes a SQL statement that reloads the grant tables in the MySQL server, making any changes to user accounts or privileges effective immediately.

Database setup completed

Now, after flushing the PRIVILEGES a database named accounts has been created in the MySQL

This is all done by the db_backup.sql query.

2) Setup Memcache(DB Caching SVC)

vagrant ssh mc01 will allow us to ssh into the Memcache server.

sudo -i get the root privilege

yum update -y to update the server

yum install Memcached -y : this will install the memcache service

systemctl enable memcached : this will enable the memcache service so that, it will automatically up and run on system reboot.

systemctl start memcached : it will start the memcache service

memcached -p 11211 -u 11111 -u memcached -d : This is the command to start the Memcached service.

  • -p 11211: This option specifies the port on which Memcached will listen. In this case, it is set to port 11211.

  • -u 11111: This option sets the user ID under which Memcached will run. In this case, it is set to user ID 11111.

  • -u memcached: This option specifies an additional user ID. It seems like you have specified the -u option twice, once with a numeric user ID (11111) and once with a username (memcached).

  • -d: This option tells Memcached to run in the background as a daemon.

We can also validate whether it's listening to the above said port by ss -tunlp | grep 11211:

Memcache setup is completed !

3) Setup RabbitMQ(Broker/Queue SVC)

vagrant ssh rmq01 will allow us to ssh into the RabbitMQ server.

sudo -i get the root privilege

yum update -y to update the server

yum install Memcached -y : this will install the memcache service

Installing dependencies for RabbitMQ

yum install wget -y

cd /tmp/ : move to tmp directory

wget http://packages.erlang-solutions.com/erlang-solutions-2.0-1.noarch.rpm : download this RPM

sudo rpm -Uvh erlang-solutions-2.0-1.noarch.rpm : installing the downloaded RPM

sudo yum -y install erlang socat : installing erlang and after completing this the dependencies installation has been completed.

Installing RabbitMQ Server

curl -s https://packagecloud.io/install/repositories/rabbitmq/rabbitmq-server/script.rpm.sh | sudo bash : Downloading RabbitMQ with a bash script which will setup the RabbitMQ repository.

sudo yum install rabbitmq-server -y : Now this will install the RabbitMQ server

Starting the Service

systemctl start rabbitmq-server : this will start the service

systemctl enable rabbitmq-server : this will enable the server

Config Changed in RabbitMQ

sudo sh -c 'echo "[{rabbit, [{loopback_users, []}]}]." > /etc/rabbitmq/rabbitmq.config' : this will pass the output of loobback_users into rabbitmq.config file.

sudo rabbitmqctl add_user test test : it will add a user test with password test

sudo rabbitmqctl set_user_tags test administrator : this will give administrator prevelege to the user test.

Restarting RabbitMQ server

systemctl restart rabbitmq-server : this will restart the server and persist the config changes.

4) Tomcat Setup(Application SVC)

Tomcat is the service where our application will be hosted.

vagrant ssh app01 will allow us to ssh into the Tomcat VM where it will be installed.

sudo -i get the root privilege

yum update -y to update the server

Tomcat Dependancies

yum install java-1.8.0-openjdk -y : Tomcat requires open JDK 1.8.0 to be installed.

yum install git maven wget -y : we also need git, maven and wget to be installed as part of dependencies for our project.

Tomcat Installation

cd /tmp/ : move to tmp directory

Download Tomcat package :

wget https://archive.apache.org/dist/tomcat/tomcat-8/v8.5.37/bin/apache-tomcat-8.5.37.tar.gz

Extracting the package:

tar xzvf apache-tomcat-8.5.37.tar.gz

After extracting we can see the tomcat directory:

Adding Tomcat user

useradd --home-dir /usr/local/tomcat8 --shell /sbin/nologin tomcat

Copying data to Tomcat home directory

cp -r /tmp/apache-tomcat-8.5.37/* /usr/local/tomcat8/

Making Tomcat user the owner of tomcat home dir

chown -R tomcat.tomcat /usr/local/tomcat8

Setting up Systemd for Tomcat

By setting up the systemd we can start and stop the Tomcat Service just by the command start tomcat and stop tomcat and to do so, we have to create a file as tomcat.service at the below given path with vi:

vi /etc/systemd/system/tomcat.service : it will create a file and the below snippet will be the content of the file to support the Tomcat service.

[Unit] Description=Tomcat After=network.target [Service] User=tomcat WorkingDirectory=/usr/local/tomcat8 Environment=JRE_HOME=/usr/lib/jvm/jre Environment=JAVA_HOME=/usr/lib/jvm/jre Environment=CATALINA_HOME=/usr/local/tomcat8 Environment=CATALINE_BASE=/usr/local/tomcat8 ExecStart=/usr/local/tomcat8/bin/catalina.sh run ExecStop=/usr/local/tomcat8/bin/shutdown.sh SyslogIdentifier=tomcat-%i [Install] WantedBy=multi-user.target

systemctl daemon-reload: Once you make changes to the Tomcat service file we have to reload it.

Starting and Enabling Tomcat Service

systemctl enable tomcat

systemctl start tomcat

systemctl status tomcat

With this, service setup is DONE !!!

Code Build & Deploy Artifacts

Cloning the Source Code

git clone -b local-setup https://github.com/rkn1999/vprofile-project.git : this will clone the project to /tmp directory and from here we'll be build the project and generate the artifact.

Updating Configuration File

However, before generating the artifact, we have to update the configuration file which will help to connect to all the backend services.

The configuration file is present in src/main/resources/application.properties which has the content as below:

#JDBC Configutation for Database Connection
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://db01:3306/accounts?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
jdbc.username=admin
jdbc.password=admin123

#Memcached Configuration For Active and StandBy Host
#For Active Host
memcached.active.host=mc01
memcached.active.port=11211
#For StandBy Host
memcached.standBy.host=127.0.0.2
memcached.standBy.port=11211

#RabbitMq Configuration
rabbitmq.address=rmq01
rabbitmq.port=5672
rabbitmq.username=test
rabbitmq.password=test

#Elasticesearch Configuration
elasticsearch.host =192.168.1.85
elasticsearch.port =9300
elasticsearch.cluster=vprofile
elasticsearch.node=vprofilenode

Here, all our configuration is correct according to our service such as DB name, user, passwords etc.. if there is any changes we have to make it in here accordingly.

Once this configuration is done we can build the artifact.

Building the Artifact using Maven build

mvm install : command will start downloading the dependencies and build the project artifact. And below you can see the packaging has been successful.

After build success we can see that vprofile-v2.war file has been created in the target folder.

This .war file is the packaged version or working software which we're going to deploy in Tomcat Server.

Deploying the Artifact to Tomcat

Before deploying our application package/artifact, bydefault there is a tomcat application present in the file location(/usr/local/tomcat8/webapps/ROOT ) where our application would be relying. So we have to remove that.

rm -rf /usr/local/tomcat8/webapps/ROOT : this command will remove the existing tomcat webapp.

cp target/vprofile-v2.war /usr/local/tomcat8/webapps/ROOT.war : now this command will copy the vprofile-v2.war from target directory to /usr/local/tomcat8/webapps directory and will be renamed from vprofile-v2.war to ROOT.war .

Now, the .war file has been copied to the desired location:

Now, restart the tomcat service by systemctl start tomcat

Once you restart the Tomcat service, it will extract the ROOT.war and make it the default application.

And from now, our Vprofile application has been set as default application for Tomcat.

Here, the application packaging and deployment has been completed to the Tomcat service.

Nginx Setup(ReverseProxy/Web SVC)

We are at the final step of our project deployment. Here we will be setting up Nginx as our reverse proxy to generate the HTTP request.

vagrant ssh web01 will allow us to ssh into the Tomcat VM where it will be installed.

sudo -i get the root privilege

apt update -y to update the server as this is a Ubuntu server.

apt upgrade to upgrade the system to latest patches

Installing Nginx

apt install nginx -y : this will simply install nginx in ubuntu system

Creating a configuration file

Here we'll be creating a configuration file which will be used to redirect the traffic from Nginx to Tomcat server on port 8080. This configuration file will be placed at /etc/nginx/sites-available/ and the name of the file will be vproapp . So, the complete path will be /etc/nginx/sites-available/vproapp . And the config file will be having the below configuration:

upstream vproapp {
server app01:8080;
}
server {
listen 80;
location / {
proxy_pass http://vproapp;
}
}

Removing the default Nginx web page

rm -rf /etc/nginx/sites-enabled/default : this will remove the default Nginx webpage from the location /etc/nginx/sites-enabled/default .

Activating the Application

Finally, we can activate the application and make it availe to use. To do so, we have to create a link between /etc/nginx/sites-available/vproapp and /etc/nginx/sites-enabled/vproapp with the command :

 ln -s /etc/nginx/sites-available/vproapp /etc/nginx/sites-enabled/vproapp

And finally restart Nginx with

systemctl restart nginx : after all the setup restart the Nginx service and make sure it's up and running .

Accessing App from Browser

Now to access the Web Site from browser we need the IP address of the server(web01) where it is hosted. If it was an EC2 instance we could simply access it from it's public IP by editing the inbound rule and exposing the IP.
However, as we have set everything in our local system we'll be needing the IP address of the hosted VM.

ifconfig : this command will give us the IP address of the VM and the highlighted IP address the one we need.

We are also able to login to the application and this login credentials are coming from MySQL: