copyright | lastupdated | ||
---|---|---|---|
|
2018-01-11 |
{:shortdesc: .shortdesc} {:new_window: target="_blank"} {:codeblock: .codeblock} {:screen: .screen} {:tip: .tip} {:pre: .pre}
This tutorial walks you through the creation of a load balancer, two application servers running on Ubuntu with NGINX and PHP installed, one MySQL database server, and durable file storage to store application files and backups.
- Provision one server for the database
- Install and configure MySQL
- Create a file storage for database backups
- Provision two servers for the PHP application
- Create a file storage to share files between the application servers
- Install and configure the PHP application on the application servers
- Provision one load balancer in front of the application servers
{: #products}
This tutorial uses the following products:
![Architecture diagram](images/solution14/Architecture.png)
- The user connects to the application.
- The Load Balancer selects one of the healthy servers to handle the request.
- The elected server accesses the application files stored on a shared file storage.
- The server also pulls information from the database and finally renders the page to the user.
- At a regular interval, the database content is backed up. A stand-by database is server is available in case the master fails.
{: #prereqs}
In this tutorial, the load balancer is the front door for the application users. The virtual servers do not need to be visible on the public Internet. Thus they will be provisioned with only a private IP address and you will use your SoftLayer VPN connection to work on the servers.
-
Ensure your VPN Access is enabled.
You should be a Master User to enable VPN access or contact master user for access. {:tip}
-
Obtain your VPN Access credentials in your profile page.
-
Log in to the VPN through the web interface or use a VPN client for Linux, macOS or Windows.
You can choose to skip this step and make all your servers visible on the public Internet (although keeping them private provide an additional level of security). To make them public, select Public and Private Network Uplink when provisioning virtual servers. {: tip}
Contact your Infrastructure master user to get the following permissions:
- Network so that you can create virtual servers with Public and Private Network Uplink (this permission is not required if you use the VPN to connect to the servers)
{: #database_server}
-
Go to the catalog in the {{site.data.keyword.Bluemix}} console, and select the Virtual Server service from the Infrastructure section.
-
Select Public Virtual Server and then click Create.
-
Configure the server with the following:
-
Set Name to db1
-
Select a location where to provision the server. All other servers and resources created in this tutorial will need to be created in the same location.
-
Select the Ubuntu Minima image
-
Keep the default compute flavor. The tutorial has been tested with the smallest flavor but should work with any flavor.
-
Under Attached Storage Disks, select the 25GB boot disk.
-
Under Network Interface, select the 100Mbps Private Network Uplink option.
If you did not configure the VPN Access, select the 100Mbps Public and Private Network Uplink option. {: tip}
-
Review the other configuration options and click Provision to provision the server.
Note: The provisioning process can take 2 to 5 minutes for the server to be ready for use. After the server is created, you'll find the server credentials in the server detail page under Devices > Device list. To SSH into the server, you need the server user name, password, and private or public IP address (Click the arrow next to the device name). {: tip}
-
{: #mysql}
-
Connect to the server by using SSH:
ssh root@<Private-OR-Public-IP-Address>
Remember to connect to the VPN client with the right site address based on the Location of your virtual-server. {:tip}
-
Install MySQL:
apt-get update apt-get -y install mysql-server
You may be prompted for a password. Read through the instructions on the console shown. {:tip}
-
Run the following script to help secure MySQL database:
mysql_secure_installation
You may be prompted with couple of options. Choose wisely based on your requirements. {:tip}
-
Login to MySQL and create a database called
wordpress
:mysql -u root -p CREATE DATABASE wordpress;
-
Grant access to the database, replace database-username and database-password with what you have set earlier.
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,ALTER ON wordpress.* TO database-username@'%' IDENTIFIED BY 'database-password';
FLUSH PRIVILEGES;
-
Check if database created by using:
show databases;
-
Exit from the database using:
exit
-
Make note of the database name, user and password. You will need them when configuring the application servers.
By default MySQL only listens on the local interface. The application servers will need to connect to the database so the MySQL configuration needs to be changed to listen on the private network interfaces.
-
Edit the my.cnf file using
nano /etc/mysql/my.cnf
and add these lines:[mysqld] bind-address = 0.0.0.0
-
Exit and save the file using Ctrl+X.
-
Restart MySQL:
systemctl restart mysql
-
Confirm MySQL is listening on all interfaces by running the following command:
netstat --listen --numeric-ports | grep 3306
{: database_backup}
There are many ways in which backups can be done and stored when it comes to MySQL. This tutorial uses a crontab entry to dump the database content to disk. The backup files will be stored in a file storage. Obviously, this is a simple backup mechanism. If you plan to manage your own MySQL database server in a production environment, you will want to implement one of the backup strategies described in MySQL documentation.
- Go to the catalog in the {{site.data.keyword.Bluemix}} console, and select File Storage
- Click Create
- Configure the service with the following:
- Set Storage Type to Endurance
- Select the same Location as the one where you created the database server
- Select a billing method
- Under Storage Packages, select 0.25 IOPS/GB
- Under Storage Size, select 20GB
- Keep the Snapshot Space Size to 0GB
- Click continue to create the service.
Before a virtual server can mount a File Storage, it needs to be authorized.
- Select the newly created File Storage from the list of existing items.
- Under Authorized Hosts, click Authorize Host and select the virtual(database) server (Choose Devices > Virtual Server as Device Type > Type the name of the server).
The File Storage can be mounted as an NFS drive into the virtual server.
-
Install the NFS client libraries:
apt-get -y install nfs-common
-
Create a file called
/etc/systemd/system/mnt-database.mount
by running the following commandtouch /etc/systemd/system/mnt-database.mount
-
Edit the mnt-database.mount by using:
nano /etc/systemd/system/mnt-database.mount
-
Add the content below to the mnt-database.mount file and replace
CHANGE_ME_TO_FILE_STORAGE_MOUNT_POINT
ofWhat
with the Mount Point of the file storage (e.g fsf-lon0601a-fz.adn.networklayer.com:/IBM01SEV12345_100/data01). You can get the Mount Point url under the file storage service created.[Unit] Description = Mount for Container Storage [Mount] What=CHANGE_ME_TO_FILE_STORAGE_MOUNT_POINT Where=/mnt/database Type=nfs Options=vers=3,sec=sys,noauto [Install] WantedBy = multi-user.target
Use Ctrl+X to save and exit the nano window {: tip}
-
Create the mount point
mkdir /mnt/database
-
Mount the storage
systemctl enable --now /etc/systemd/system/mnt-database.mount
-
Check if the mount was successfully done
mount
The last lines should list the File Storage mount. If this is not the case, use
journalctl -xe
to debug the mount operation. {: tip}
- Create
/root/dbbackup.sh
shell script (usetouch
andnano
) with the following commands by replacingCHANGE_ME
with the database password you specified earlier:#!/bin/bash mysqldump -u root -p CHANGE_ME --all-databases --routines | gzip > /mnt/datamysql/backup-`date '+%m-%d-%Y-%H-%M-%S'`.sql.gz
- Make sure the file is executable
chmod 700 /root/dbbackup.sh
- Edit the crontab
crontab -e
- To have the backup performed every day at 11pm, set the content to the following, save the file and close the editor
0 23 * * * /root/dbbackup.sh
{: app_servers}
- Go to the catalog in the {{site.data.keyword.Bluemix}} console, and select the Virtual Server service from the Infrastructure section.
- Select Public Virtual Server and then click Create.
- Configure the server with the following:
-
Set Name to app1
-
Select the same location where you provisioned the database server
-
Select the Ubuntu Minima image
-
Keep the default compute flavor.
-
Under Attached Storage Disks, select 25GB as your boot disk.
-
Under Network Interface, select the 100Mbps Private Network Uplink option.
If you did not configure the VPN Access, select the 100Mbps Public and Private Network Uplink option. {: tip}
-
Review the other configuration options and click Provision to provision the server. Configure virtual server
-
- Repeat steps 1-3 to provision another virtual server named app2
{: shared_storage}
This file storage is used to share the application files between app1 and app2 servers.
- Go to the catalog in the {{site.data.keyword.Bluemix}} console, and select File Storage
- Click Create
- Configure the service with the following:
- Set Storage Type to Endurance
- Select the same Location as the one where you created the application servers
- Select a billing method
- Under Storage Packages, select 2 IOPS/GB
- Under Storage Size, select 20GB
- Under Snapshot Space Size, select 20GB
- Click continue to create the service.
Snapshots give you a convenient option to protect your data with no performance impact. Additionally, you can replicate snapshots to another data center.
- Select the File Storage from the list of existing items
- Under Snapshot Schedules, edit the snapshot schedule. The schedule could be defined as follow:
- Under Authorized Hosts, click Authorize Host to authorize the application servers(app1 and app2) to use this file storage.
Repeat the following steps on each application server(app1 and app2):
- Install the NFS client libraries
apt-get update apt-get -y install nfs-common
- Create a file using
touch /etc/systemd/system/mnt-www.mount
and edit usingnano /etc/systemd/system/mnt-www.mount
with the following content by replacingCHANGE_ME_TO_FILE_STORAGE_MOUNT_POINT
ofWhat
with the Mount Point for the file storage (e.g fsf-lon0601a-fz.adn.networklayer.com:/IBM01SEV12345_100/data01). You can find the mount points under list of file storage volumes[Unit] Description = Mount for Container Storage [Mount] What=CHANGE_ME_TO_FILE_STORAGE_MOUNT_POINT Where=/mnt/www Type=nfs Options=vers=3,sec=sys,noauto [Install] WantedBy = multi-user.target
- Create the mount point
mkdir /mnt/www
- Mount the storage
systemctl enable --now /etc/systemd/system/mnt-www.mount
- Check if the mount was successfully done
The last lines should list the File Storage mount. If this is not the case, use
mount
journalctl -xe
to debug the mount operation. {: tip}
Eventually all steps related to the configuration of the servers could be automated using a provisioning script or by capturing an image. {: tip}
{: php_application}
This tutorial sets up a Wordpress blog. All Wordpress files will be installed on the shared file storage so that both application servers can access them. Before installing Wordpress, a web server and a PHP runtime need to be configured.
Repeat the following steps on each application server:
- Install nginx
apt-get -y install nginx
- Install PHP and mysql client
apt-get -y install php-fpm php-mysql
- Stop PHP service and nginx
systemctl stop php7.0-fpm systemctl stop nginx
- Replace the content using
nano /etc/nginx/sites-available/default
with the following:server { listen 80 default_server; listen [::]:80 default_server; root /mnt/www/html; index index.php; server_name _; location = /favicon.ico { log_not_found off; access_log off; } location = /robots.txt { allow all; log_not_found off; access_log off; } location / { # following https://codex.wordpress.org/Nginx try_files $uri $uri/ /index.php?$args; } # pass the PHP scripts to the local FastCGI server location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.0-fpm.sock; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires max; log_not_found off; } # deny access to .htaccess files, if Apache's document root # concurs with nginx's one location ~ /\.ht { deny all; } }
- Create a
www
folder inside the/mnt/www
usingmkdir /mnt/www/html
As Wordpress will be installed on the File Storage mount, you only need to do the following steps on one of the servers. Let's pick app1.
-
Retrieve Wordpress installation files
If your application server has a public network link, you can directly download the Wordpress files from within the virtual server:
apt-get install curl cd /tmp curl -O https://wordpress.org/latest.tar.gz tar xzvf latest.tar.gz
If the virtual server has only a private network link, you will need to retrieve the installation files from another machine with Internet access and to copy them to the virtual server. Assuming you have retrieved the Wordpress installation files from https://wordpress.org/latest.tar.gz, you can copy it to the virtual server with
scp
:scp latest.tar.gz root@PRIVATE_IP_ADDRESS_OF_THE_SERVER:/tmp
Replace
latest
with the filename you downloaded from wordpress website. {: tip}then ssh to the virtual server and change to the
tmp
directorycd /tmp
-
Extract the installation files
tar xzvf latest.tar.gz
-
Prepare the Wordpress files
cp /tmp/wordpress/wp-config-sample.php /tmp/wordpress/wp-config.php mkdir /tmp/wordpress/wp-content/upgrade
-
Copy the files to the shared file storage
rsync -av -P /tmp/wordpress/. /mnt/www/html
-
Set permissions
chown -R www-data:www-data /mnt/www/html find /mnt/www/html -type d -exec chmod g+s {} \; chmod g+w /mnt/www/html/wp-content chmod -R g+w /mnt/www/html/wp-content/themes chmod -R g+w /mnt/www/html/wp-content/plugins
-
Call the following web service and inject the result into
/mnt/www/html/wp-config.php
usingnano
curl -s https://api.wordpress.org/secret-key/1.1/salt/
If your virtual server has no public network link, you can simply open https://api.wordpress.org/secret-key/1.1/salt/ from your web browser.
-
Set the database credentials using
nano /mnt/www/html/wp-config.php
, update the database credentials:define('DB_NAME', 'wordpress'); define('DB_USER', 'database-username'); define('DB_PASSWORD', 'database-password'); define('DB_HOST', 'database-server-ip-address');
Wordpress is configured. To complete the installation, you need to access the Wordpress user interface.
On both application servers, start the web server and the PHP runtime: 7. Start the service by running the following commands
systemctl start php7.0-fpm
systemctl start nginx
Access the Wordpress installation at http://YourAppServerIPAddress/
using either the private IP address (if you are going through the SoftLayer VPN connection) or the public IP address of app1 or app2.
If you configured the application servers with only a private network link, you will not be able to install Wordpress plugins, themes or upgrades directly from the Wordpress admin console. You will need to upload the files through the Wordpress user interface. {: tip}
{: load_balancer}
At this point, we have two application servers with separate IP addresses. They might even not be visible on the public Internet if you choose to only provision Private Network Uplink. Adding a Load Balancer in front of these servers will make the application public. The load balancer will also hide the underlying infrastructure to the users. The Load Balancer will monitor the health of the application servers and dispatch incoming requests to healthly servers.
- Go to the catalog to create a IBM Cloud Load Balancer
- In the Plan step, select the same data center as app1 and app2
- In Network Settings,
- Select the same subnet as the one where app1 and app2 where provisioned
- Use the default IBM system pool for the load balancer public IP.
- In Basic,
- Name the load balancer, e.g. app-lb-1
- Keep the default protocol configuration - by default the load balancer is configured for HTTP. SSL protocol is supported with your own certificates. Refer to Import your SSL certificates in the load balancer {: tip}
- In Server Instances, add app1 and app2 servers
- Review and Create to complete the wizard.
The Wordpress configuration needs to be changed to use the Load Balancer address. Indeed, Wordpress keeps a reference to the blog URL and injects this location in the pages. If you don't change this setting, Wordpress will redirect the users to the backend servers directly, thus bypassing the Load Balancer or not working at all if the servers only have a private IP address.
-
Find the Load Balancer address in its detail page. You can find the Load Balancer you created under Network / Load Balancing / Local.
You can also use your own domain name with the Load Balancer by adding a CNAME record pointing to the Load Balancer address in your DNS configuration. {: tip}
-
Log as administrator in the Wordpress blog via app1 or app2 URL
-
In Settings / General, set both the Wordpress Address (URL) and Site Address (URL) to the Load Balancer address
-
Save the settings. Wordpress should redirect to the Load Balancer address It may take some time before the Load Balancer address becomes active due to DNS propagation. {: tip}
The Load Balancer is configured to check the health of the servers and to redirect users only to healthy servers. To understand how the Load Balancer is working, you can
-
Watch the nginx logs on both app1 and app2 with:
tail -f /var/log/nginx/*.log
You should already see the regular pings from the Load Balancer to check the server health. {: tip}
-
Access Wordpress through the Load Balancer address and make sure to force a hard reload of the page. Notice in the nginx logs both app1 and app2 are serving content for the page. The Load Balancer is redirecting traffic to both servers as expected.
-
Stop nginx on app1
systemctl nginx stop
-
After a short while reload the Wordpress page, notice all hits are going to app2.
-
Stop nginx on app2.
-
Reload the Wordpress page. The Load Balancer will return an error as there is no healthy server.
-
Restart nginx on app1
systemctl nginx start
-
Once the Load Balancer detects app1 as healthy, it will redirect traffic to this server.
- Delete the Load Balancer
- Cancel db1, app1 and app2
- Delete the two File Storage services
- Static content served by your application may benefit from a Content Delivery Network in front of the Load Balancer to reduce the load on your backend servers. Refer to Accelerate delivery of static files using a CDN - Object Storage for a tutorial implementing a Content Delivery Network.
- In this tutorial we provision two servers, more servers could be added automatically to handle additional load. SoftLayer Auto Scale provides you with the ability to automate the manual scaling process associated with adding or removing virtual servers to support your business applications.
- To increase availability and disaster recovery options, File Storage can be configured to perform automatic regular snapshots of the content and replication to another data center.