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
Table of contents
- Project Overview
- Prerequisites
- Flow of Execution
- Setting up the VMs
- VMs up & Running(vagrant up )
- Setting up Services
- Code Build & Deploy Artifacts
- Nginx Setup(ReverseProxy/Web SVC)
- Accessing App from Browser
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
Setting up the tools explained in the Prerequisite section
Clone the Source code from the Version control system(Git)
cd into the Vagrant Directory and bring up the VMs
Setup all the services such as:
MySQL
Memcached
RabbitMQ
Tomcat
Nginx
App build and Deploy
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
The
Vagrant.configure("2") do |config|
block initializes the Vagrant configuration.config.hostmanager.enabled = true
enables the Vagrant Hostmanager plugin, which manages the hosts file on the host machine.config.hostmanager.manage_host = true
allows Vagrant to manage the host entries for the VMs.The
web01
VM definition starts withconfig.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.The
app01
VM definition starts withconfig.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.The
rmq01
VM definition starts withconfig.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.The
mc01
VM definition starts withconfig.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.The
db01
VM definition starts withconfig.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 privilegeyum 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 DBsystemctl 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: