VMware Hands-on Labs

HOL 3-Tier Application – Updates for PhotonOS 3

This article contains the updates required to create our 3-Tier demonstration app on PhotonOS 3 rather than v1.0 that was described in the original series from 2017.

If you are not familiar with the intent of the original post, the idea is to have a distributed but simple “application” that can be used to demonstrate a variety of scenarios in a lab environment, including micro segmentation and load balancing (you can scale the web and app tiers pretty easily and part 5 covers some ideas). I add in some SSL to make things interesting and, hopefully, a bit more realistic. While the new VMs are a little larger than their old counterparts, PhotonOS still boots lightning fast in a vSphere VM.

I think this is equally useful for home labs as our Hands-on Labs environments and many of our customers agree.We have received a lot of positive feedback on these articles and some great suggestions for tweaks. Frankly, this update is long overdue.

December 3 2020 NOTE: Apologies, but the “Preformatted” style is messed up on this site.

You can retrieve the proper Python files from my GitHub repo while I look into what I can do to make this readable once again.

For reference, the old series is available at the following links.

Changes

While my goal here is to keep things simple and flexible for the base app, some changes are required due to alterations in the packages included with the minimal PhotonOS installation that is provided, and others are modifications to make the app give a bit better “feel” and demo. Other changes are required because PhotonOS 2 and higher use Python 3.x rather than 2.x, so some syntax has to change in the script — I also cleaned up a bit of the code to make it more Pythonic.

Before we get too far into the text, a picture of the updated app.

Updated Diagram

One of the most requested changes was to move the db-01a VM from listening on port 80/tcp to something more”database-y” like, for example, 3306/tcp. This is the port that MySQL uses and some people feel that it gives the app more realism.

It is still HTTP traffic, but it looks more like a database on the network. The following updated diagram represents the configuration of this new version.

aplication diagram

 

Summary of Changes

Thanks to the simplicity of the application, the number of changes required has not been excessive

  • General updates
    • PhotonOS 3, Rev 2 base OVA
      • 1 vCPU
      • 2 GB RAM
      • 16 GB disk (thin provisioned and consumes ~700 MB once configured)
    • Updated scripts (data.py and app.py) due to Python 2.x to 3.x switch
      • NOTE: The updated scripts are available on github (https://github.com/doug-baer/hol-3-tier-app)
  • Build the Template (Part 1)
    • Begin with the new OVA
    • Open firewall port for 3306/tcp
    • A small hack to make Apache start properly after a reboot
  • DB Server (Part 2)
    • Installing sqlite (it is no longer part of the base install of PhotonOS)
    • Moving the database from listening on port 80 (http) to 3306 (mysql)
    • Updated data.py script
    • Change different lines in httpd.conf (updated Apache config)
    • Specify the new port when testing/validating the setup
  • App Server (Part 3)
    • Updated app.py script (includes the change required to access db-01a on port 3306)
    • Change different lines in httpd.conf (updated Apache config)
  • Web Server (Part 4)
    • No changes needed!

The Updates

  • Build the Template
  • Create the db-01a VM
  • Create the app-01a VM
  • Create the web-01a VM

Build the Template

We start with a PhotonOS 3 base OS. This guide assumes you are using Photon3-Rev2 – photon-hw11-3.0-9355405.ova – from https://github.com/vmware/photon/wiki/Downloading-Photon-OS

(If you prefer, you can also deploy your own VM using the ISO, selecting a Minimal installation, although you may have some additional work to do.)

Deploy a copy of the OVA into your environment and follow the same instructions as in the original document.

The process is nearly identical except for the following

Network interface config script has a new name

The 10-dhcp-en.network file is named 99-dhcp-en.network now.

Open port 3306/tcp in the firewall

When you modify the /etc/systemd/scripts/iptables file on your base template, make it look like this (added the open of tcp/3306)

#Enable ping by anyone 
iptables -A INPUT -p icmp -j ACCEPT 
#Enable web and app traffic 
iptables -A INPUT -p tcp -m tcp --dport 80 -j ACCEPT 
iptables -A INPUT -p tcp -m tcp --dport 443 -j ACCEPT 
iptables -A INPUT -p tcp -m tcp --dport 3306 -j ACCEPT 
iptables -A INPUT -p tcp -m tcp --dport 8443 -j ACCEPT

A small hack to make Apache start properly on boot

This version of PhotonOS wipes out the /var/run/httpd directory at startup, which breaks Apache. To make sure the webserver can start after a reboot, add the following line at the bottom of /usr/lib/tmpfiles.d/var.conf file

d /var/run/httpd 0755 - - -

Create the db-01a VM

Install sqlite

When installing httpd, also install the sqlite package with

# tdnf install sqlite

Updated data.py script

Remembering that whitespace is very important in Python, use the following script in place of the one in the original article.

import cgi
import sqlite3

conn = sqlite3.connect('/etc/httpd/db/clients.db')
curs = conn.cursor()
print("Content-type:text/plain\n\n")
form = cgi.FieldStorage()
querystring = form.getvalue("querystring")

if querystring is not None:
    queryval = "%" + querystring + "%"
    select = "SELECT * FROM clients WHERE name LIKE '" + queryval + "'"
else:
    select = "SELECT * FROM clients"
    for row in curs.execute(select):
        if len(row) == 4:
            for item in row:
                print(item,'|')
            print("#")
conn.close()

Change different lines in /etc/http/httpd.conf

  • Instead of line 176, go to 180 and add
LoadModule cgi_module /usr/lib/httpd/modules/mod_cgi.so
  • Instead of line 379, go to 383 and add
#database directory
<Directory "/etc/httpd/db">
AllowOverride None
Options None
Require all granted
</Directory>

NEW: Change listening port 80/tcp to 3306/tcp

  • On line 52, change
Listen 80 -> Listen 3306
  • And, on line 221, change
ServerName localhost:80 -> db-01a:3306

Specify the new port when testing/validating the setup

Because we changed the listening port, we need to update the command we use to test the functionality. You must specify the new port number as part of the test URL:

# curl http://db-01a:3306/cgi-bin/data.py

Create the app-01a VM

There are fewer changes required to the app-01a VM since we are not making significant changes to the design at this layer.

Updated app.py script

Remembering that whitespace is very important in Python, use the following script in place of the one in the original article.

#!/usr/bin/env python3

# app.py - script used to process database results for presentation

import os
import cgi
import requests

webservers = {
  '192.168.120.30': 'web-01a',
  '192.168.120.31': 'web-02a',
  '192.168.120.32': 'web-03a'
 }

print("Content-type:text/html\n\n")
print("<head><title>Customer Database</title></head>\n")
print("<body>\n")
print("<h1>Customer Database Access</h1>\n")

remote = os.getenv("REMOTE_ADDR")
form = cgi.FieldStorage()
querystring = form.getvalue("querystring")

if remote in webservers:
    accessName = webservers[remote]
else:
    accessName = remote

print("Accessed via:", accessName, "\n<p>")

if querystring != None:
    url = 'http://db-01a:3306/cgi-bin/data.py?querystring=' + querystring
else:
    url = 'http://db-01a:3306/cgi-bin/data.py'
    querystring = ""

r = requests.get(url)

print('<form action="/cgi-bin/app.py">')
print(' Name Filter (blank for all records):')
print(' <input type="text" name="querystring" value="'+querystring+'">')
print(' <input type="submit" value="Apply">')
print('</form>')

print("\n<table border=1 bordercolor=black cellpadding=5 cellspacing=0>")

print("\n<th>Rank</th><th>Name</th><th>Universe</th><th>Revenue</th>")

# deal with the data coming across the wire
a = r.text.split("|\n#")
for row in a:
    if len(row) != 1:
        print("<tr>")
        splitrow = row.split("|")
        for item in splitrow:
            if item != None:
                print("<td>",item,"</td>")
        print("</tr>\n")
    print("</body></html>\n")

Change different lines in /etc/http/httpd.conf

  • Instead of line 176, go to 180 and add
LoadModule cgi_module /usr/lib/httpd/modules/mod_cgi.so
  • Instead of line 508, go to 521 and uncomment
Include conf/extra/httpd-ssl.conf

Create the web-01a VM

The web tier of this application is very simple and, other than starting with the update base template above, there are no additional changes to the process defined in the original article.

End

At this point, you should be able to use these three VMs just like the original versions, but with all of the updated PhotonOS 3.0 goodness.

Be sure to check out HOL Three-Tier Application, Part 5 – Use Cases for some ideas — just remember that the db-01a listens on 3306/tcp instead of 80/tcp now.