Create Multi-VM LAMP Stack on Oracle Virtualization

1
0
Send lab feedback

Create Multi-VM LAMP Stack on Oracle Virtualization

Introduction

At the core of the Oracle Virtualization solution is the Oracle Linux KVM host. On top of this hypervisor you can run many virtual machines - each running one of the supported operating systems including Oracle Linux, RHEL, Windows, Ubuntu, Solaris and others. This virtualization solution is managed through the Oracle Linux Virtualization Manager which offers a single interface to keep things organized. In addition to multi-host/multi-VM management, Oracle Linux Virtualization Manager enables key features of the Oracle Virtualization solution. For example, Oracle Linux Virtualization Manager provides automatic high availability with VM failover, live migration of VMs between hosts with zero downtime, role-based access control and audit logging, and simplified backup and disaster recovery workflows. These enterprise features transform Oracle Linux KVM from individual hosts into a true enterprise virtualization platform.

In this tutorial, we'll explore the core hypervisor technology that powers Oracle Virtualization. Kernel-based Virtual Machine (KVM) is an open-source type-1 (bare-metal) hypervisor. This functionality permits a host system, such as Oracle Linux, to host multiple virtual machines (VMs) or guests when running on supported hardware.

This tutorial will deploy Oracle Linux KVM to create virtual machines configured with LAMP stack applications, enabling you to host complete web development environments with Linux, Apache, MySQL, and PHP components across multiple VMs.

Important: The two application codes in this lab are for educational purposes only. They are designed to help developers learn and practice application development skills with the LAMP stack. These codes are not intended for production environments and should not be used as-is in a live setting.

Objectives

  • Setup OCI, Luna, or On-premise server
  • Deploy Oracle Linux KVM
  • Create Virtual Machine using Oracle Cloud Images
  • Install MySQL server
  • Install Web server with Apache and PHP

Prerequisites

Any Oracle Linux system with the following configurations:

  • a non-root user with sudo permissions

Step 1: Deploy Oracle Linux

Note: If running in your own tenancy, read the linux-virt-labs GitHub project README.md and complete the prerequisites before deploying the lab environment.

  1. Open a terminal on the Luna Desktop.

  2. Clone the linux-virt-labs GitHub project.

    git clone https://github.com/oracle-devrel/linux-virt-labs.git
  3. Change into the working directory.

    cd linux-virt-labs/ol
  4. Install the required collections.

    ansible-galaxy collection install -r requirements.yml
  5. Deploy the lab environment.

    ansible-playbook create_instance.yml -e localhost_python_interpreter="/usr/bin/python3.6" -e instance_ocpus="4" -e instance_memory="64"

    The free lab environment requires the extra variable local_python_interpreter, which sets ansible_python_interpreter for plays running on localhost. This variable is needed because the environment installs the RPM package for the Oracle Cloud Infrastructure SDK for Python, located under the python3.6 modules.

    The default deployment shape uses the AMD CPU and Oracle Linux 8. To use an Intel CPU add -e instance_shape="VM.Standard3.Flex"

    Important: Wait for the playbook to run successfully and reach the pause task. At this stage of the playbook, the installation of Oracle Linux is complete, and the instances are ready. Take note of the previous play, which prints the public and private IP addresses of the nodes it deploys and any other deployment information needed while running the lab.

Step 2: Validate Environment Supports Virtualization

  1. Open a terminal and connect via SSH to the ol-node-01 instance.

    ssh opc@<ip_address_of_instance>
  2. Run the following command to determine your CPU type.

    grep -e 'vendor_id' /proc/cpuinfo | uniq

    The vendor_id reports either AuthenticAMD for an AMD CPU or GenuinIntel for an Intel CPU.

  3. Check if the hardware supports virtualization.

    Run the command that matches your CPU type.

    1. Verify the AMD V CPU extensions exist.
    grep -w -o 'svm' /proc/cpuinfo | uniq
    1. Verify the Intel VT CPU extensions exist.
    grep -w -o 'vmx' /proc/cpuinfo | uniq

    The existence of one of these flags in the command output indicates this system supports virtualization. You can also use the lscpu command and look for the Virtualization entry in the output.

  4. Check for the loaded KVM modules.

    lsmod | grep kvm

    The output displays the KVM kernel modules after installing virtualization packages and starting the libvirtd service. On cloud systems like OCI, these modules load automatically when libvirtd starts, not during package installation. The loading sequence is: install packages → start libvirtd service → modules appear in lsmod output.

Step 3: Install and Start KVM

  1. Check the running version of Oracle Linux.

    hostnamectl | grep 'Operating System'
  2. Install the associated software packages for Oracle Linux virtualization.

    This commands install the virtualization packages, which include libvirt, and other dependencies on Oracle Linux. The libvirt package provides a software library and API to manage KVM virtual machines and includes the libvirtd daemon that runs in the background to handle the actual VM management.

    sudo dnf module install -y virt
  3. Install virt-install - tool for creating and configuring virtual machines (VMs) using KVM (Kernel-based Virtual Machine) hypervisor.

    sudo dnf install -y virt-install
  4. Validate the host machine is ready and set up to run libvirt VMs.

    virt-host-validate

    If all checks pass, the system is prepared for creating VMs. If any checks fail, follow the instructions to correct the problem. If any check returns the value of WARN, consider following the instructions to improve the virtualization capabilities.

  5. Start the Systemd services, enabling them to start automatically on each boot.

    sudo systemctl enable --now libvirtd.service
  6. Check the services status to confirm they are up and running.

    sudo systemctl status libvirtd.service

    Output shows the service as enabled and running. If needed enter the letter 'q' to exit the output mode

Step 4: Create two Virtual Machines using Oracle Cloud Images

  1. Change to the KVM image storage location.

    cd /var/lib/libvirt/images
  2. Download the Oracle Linux VM template.

    sudo curl -O https://yum.oracle.com/templates/OracleLinux/OL8/u10/x86_64/OL8U10_x86_64-kvm-b237.qcow2

    Create VM-01 (Database)

  3. Create a meta-data file.

    cat << 'EOF' | sudo tee ~/meta-data > /dev/null
    instance-id: iid-local01
    local-hostname: vm-01
    EOF
  4. Create a user-data file.

    cat << 'EOF' | sudo tee ~/user-data > /dev/null
    #cloud-config
    
    system_info:
      default_user:
        name: opc
    
    ssh_authorized_keys:
      - <paste_public_key_here>
    EOF
  5. Generate an SSH key pair for secure connection to the VM

    ssh-keygen -t rsa -b 4096

    Hit Enter to accept each of the defaults. The command writes the key pair to the .ssh directory in the user's home.

  6. Extract the generated public SSH key

    SSHKEY=$(cat ~/.ssh/id_rsa.pub)
  7. Update the user-data file with the generated public SSH key

    sed -i "s|<paste_public_key_here>|${SSHKEY}|g" ~/user-data
  8. Generate an ISO image containing the user-data and meta-data files

    sudo genisoimage -output /var/lib/libvirt/images/vm-01.iso -volid cidata -joliet -rock ~/user-data ~/meta-data
  9. Find the OS variant that matches the downloaded image

    osinfo-query os | grep ol8
  10. Copy the Oracle Linux image to a new disk image for vm-01

    sudo cp /var/lib/libvirt/images/OL8U10_x86_64-kvm-b237.qcow2 /var/lib/libvirt/images/vm-01.qcow
  11. Create a new virtual machine named vm-01 with specified resources and configuration

    sudo virt-install --name vm-01 \
    --memory 2048 \
    --vcpus 2 \
    --disk /var/lib/libvirt/images/vm-01.qcow,device=disk,bus=virtio \
    --disk /var/lib/libvirt/images/vm-01.iso,device=cdrom \
    --os-type linux --os-variant ol8.10 \
    --virt-type kvm --graphics none \
    --network network=default,model=virtio \
    --noautoconsole \
    --import
  12. List all running virtual machines

    sudo virsh list
  13. Retrieve the IP address of the vm-01 virtual machine.

    sudo virsh net-dhcp-leases --network default
  14. Verify the virtual machine works by connecting with ssh.

    ssh opc@<ip_address_of_vm-01>
  15. Exit the vm-01 server to continue to the next step

    exit

    You can verify the version and get additional details about the OS within the virtual machine by running hostnamectl.

    Create VM-02 (Web Server)

  16. Create a meta-data file for vm-02

    cat << 'EOF' | sudo tee ~/meta-data > /dev/null
    instance-id: iid-local02
    local-hostname: vm-02
    EOF
  17. Generate an ISO image for vm-02

    sudo genisoimage -output /var/lib/libvirt/images/vm-02.iso -volid cidata -joliet -rock ~/user-data ~/meta-data
  18. Copy the Oracle Linux image to a new disk image for vm-02

    sudo cp /var/lib/libvirt/images/OL8U10_x86_64-kvm-b237.qcow2 /var/lib/libvirt/images/vm-02.qcow
  19. Create a new virtual machine named vm-02 with specified resources and configuration

    sudo virt-install --name vm-02 \
    --memory 2048 \
    --vcpus 2 \
    --disk /var/lib/libvirt/images/vm-02.qcow,device=disk,bus=virtio \
    --disk /var/lib/libvirt/images/vm-02.iso,device=cdrom \
    --os-type linux --os-variant ol8.10 \
    --virt-type kvm --graphics none \
    --network network=default,model=virtio \
    --noautoconsole \
    --import
  20. List all running virtual machines

    sudo virsh list
  21. Retrieve the IP address of the vm-02 virtual machine.

    sudo virsh net-dhcp-leases --network default
  22. Verify the virtual machine works by connecting with ssh.

    ssh opc@<ip_address_of_vm-02>
  23. Exit the vm-01 server to continue to the next step

    exit
  24. You can verify the version and get additional details about the OS within the virtual machine by running hostnamectl.

    hostnamectl

    Example Output:

    [oracle@ol-node01 images]$ ssh opc@192.168.122.46
    The authenticity of host '192.168.122.46 (192.168.122.46)' can't be established.
    ECDSA key fingerprint is SHA256:xcuVfQdoFDCC72i7plD0OfqDTSBG6QWhOm5ti4HIKEs.
    Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
    Warning: Permanently added '192.168.122.46' (ECDSA) to the list of known hosts.
    
    [opc@vm-01 ~]$ hostnamectl
       Static hostname: vm-01
             Icon name: computer-vm
               Chassis: vm
            Machine ID: 30c9345b511448b681aafb3371de9792
               Boot ID: c2d5586b094f4d299a4ba6c05086d004
        Virtualization: kvm
      Operating System: Oracle Linux Server 8.10
           CPE OS Name: cpe:/o:oracle:linux:8:10:server
                Kernel: Linux 5.15.0-206.153.7.1.el8uek.x86_64
          Architecture: x86-64
  25. Extract the IP address of vm-01

    VM01_IP=$(sudo virsh net-dhcp-leases --network default | grep vm-01 | tail -1 | awk '{print $5}' | cut -d'/' -f1)
  26. Extract the IP address of vm-02

    VM02_IP=$(sudo virsh net-dhcp-leases --network default | grep vm-02 | tail -1 | awk '{print $5}' | cut -d'/' -f1)
  27. Save the VMs IP address for later use:

    echo "VM-01 (Web): $VM01_IP"
    echo "VM-02 (Web): $VM02_IP"
  28. Test the SSH command for the VMs

    ssh -o ConnectTimeout=10 opc@$VM01_IP "echo 'VM-01 OK'"
    ssh -o ConnectTimeout=10 opc@$VM02_IP "echo 'VM-02 OK'"

Step 5: Setup MySQL on VM-01

Install MySQL

  1. From the ol-node-01 instance SSH establish an SSH connection to VM-01
    ssh opc@$VM01_IP
  2. Download MySQL repository configuration
    sudo yum -y install https://dev.mysql.com/get/mysql84-community-release-el8-1.noarch.rpm
  3. Disable default MySQL module to avoid conflicts
    sudo yum -y module disable mysql
  4. Install MySQL server and client
    sudo yum install -y mysql mysql-server
  5. Start MySQL service
    sudo systemctl start mysqld
  6. Enable MySQL service to start at boot
    sudo systemctl enable mysqld
  7. Allow incoming MySQL traffic through the firewall
    sudo firewall-cmd --permanent --add-service=mysql
  8. Reload firewall configuration to apply changes
    sudo firewall-cmd --reload

Configure MySQL

  1. Extract temporary root password from MySQL log
    TEMP_PASS=$(sudo grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}')
  2. Login to MySQL with temporary root password
    mysql -uroot -p$TEMP_PASS --connect-expired-password
  3. Change root password to a secure value
    ALTER USER 'root'@'localhost' IDENTIFIED BY 'Welcome#123';
  4. Create 'admin' user with a secure password
    CREATE USER 'admin'@'%' IDENTIFIED BY 'Welcome#123';
  5. Grant all privileges to 'admin' user
    GRANT ALL PRIVILEGES ON *.* TO 'admin'@'%' WITH GRANT OPTION;
  6. Create 'empuser' user with a secure password
    CREATE USER 'empuser'@'%' IDENTIFIED BY 'Welcome#123';
  7. Grant all privileges to 'empuser'
    GRANT ALL PRIVILEGES ON *.* TO 'empuser'@'%' WITH GRANT OPTION;
  8. Reload privilege tables to apply changes
    FLUSH PRIVILEGES;
  9. Quit MySQL shell
    \q
  10. Exit SSH session from VM-01
    exit

Step 6: Setup Apache/PHP on VM-02

  1. From the ol-node-01 instance SSH establish an SSH connection to VM-02

    ssh opc@$VM02_IP
  2. Install Apache HTTP server

    sudo yum install -y httpd
  3. Install PHP 8.2 and its dependencies

    sudo dnf install -y @php:8.2
  4. Install PHP MySQL and JSON extensions

    sudo yum install -y php-mysqlnd php-json
  5. Enable and start Apache HTTP server

    sudo systemctl enable --now httpd
  6. Allow incoming HTTP traffic on port 80

    sudo firewall-cmd --permanent --add-port=80/tcp
  7. Reload firewall configuration to apply changes

    sudo firewall-cmd --reload
  8. Allow Apache to connect to network resources

    sudo setsebool -P httpd_can_network_connect 1
  9. Exit SSH session from VM-02

    exit

Step 7: Test Apache

  1. Display public IP address of VM-02 YOUR_VM_02_PUBLIC_IP:

    echo "VM-02 (Web): $VM02_IP"
  2. Open a new terminal Luna or on-prem environment and create SSH tunnel to access VM-02 web server from local machine

    ... be sure to first replace <YOUR_VM_02_PUBLIC_IP> and <YOUR_OCI_PUBLIC_IP>

    ssh -L 8081:<YOUR_VM_02_PUBLIC_IP>:80 opc@<YOUR_OCI_PUBLIC_IP>
  3. Use a browser from Luna or on-prem environment to test Apache by accessing the web server through the SSH tunnel

    http://localhost:8081

    Important: Leave the SSH tunnel and Browser open for later use

Step 8: Create Test Application


  1. Return to your opc@ol-node-01 ssh instance

  2. Retrieve IP address of VM-01 from DHCP leases

    VM01_IP=$(sudo virsh net-dhcp-leases --network default | grep vm-01 | tail -1 | awk '{print $5}' | cut -d'/' -f1)
  3. Retrieve IP address of VM-02 from DHCP leases

    VM02_IP=$(sudo virsh net-dhcp-leases --network default | grep vm-02 | tail -1 | awk '{print $5}' | cut -d'/' -f1)
  4. From the ol-node-01 instance SSH establish an SSH connection to VM-02

    ssh opc@$VM02_IP
  5. Create a PHP info page to display PHP configuration

    sudo tee /var/www/html/info.php > /dev/null << 'EOF'
    <?php phpinfo(); ?>
    EOF
  6. Create database connection test application

    sudo tee /var/www/html/dbtest.php > /dev/null << 'EOF'
    <?php
    echo "<h1>Multi-VM LAMP Stack Test</h1>";
    
    // Database connection details
    define('DB_SERVER', '$VM01_IP');
    define('DB_USERNAME', 'admin');
    define('DB_PASSWORD', 'Welcome#123');
    define('DB_NAME', 'mysql');
    
    echo "<p>Testing connection to MySQL at: " . DB_SERVER . "</p>";
    
    // Test network connectivity
    $fp = @fsockopen(DB_SERVER, 3306, $errno, $errstr, 5);
    if (!$fp) {
        echo "<p style='color: red;'>ERROR: Cannot reach MySQL server</p>";
        echo "<p>Error: $errstr ($errno)</p>";
    } else {
        echo "<p style='color: green;'>✓ Network connection successful</p>";
        fclose($fp);
        
        // Test MySQL connection
        $link = mysqli_connect(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
        if($link === false){
            echo "<p style='color: red;'>ERROR: Could not connect to MySQL</p>";
            echo "<p>Error: " . mysqli_connect_error() . "</p>";
        } else {
            echo "<p style='color: green;'>✓ Successfully Connected to MySQL!</p>";
            echo "<p>MySQL Version: " . mysqli_get_server_info($link) . "</p>";
            echo "<p>Host Info: " . mysqli_get_host_info($link) . "</p>";
            mysqli_close($link);
        }
    }
    ?>
    EOF
  7. Set application file permissions

    sudo chown apache:apache /var/www/html/*.php
  8. Update line define('DB_SERVER', '$VM01_IP'); by changing the $VM01_IP value with the saved IP address value

    sudo vi /var/www/html/dbtest.php

    Example Output:

    ... Code before
    define('DB_SERVER', '192.168.122.???');
    ... Code after
  9. Exit VM-02

    exit

Step 9: Access Your Webserver and Database Test application


  1. If SSH tunnel is closed then create for basic test
    ssh -L 8081:$VM02_IP:80 opc@<YOUR_OCI_PUBLIC_IP>
  2. Basic LAMP test Browse to:
     http://localhost:8081/info.php
  3. Basic Database test Demo Browse to:
    http://localhost:8081/dbtest.php

Expected Results:

  • Basic test: Green "Successfully Connected to MySQL!" message

Step 10: Create and Load Employee Database

  1. You should be in your opc@ol-node-01 ssh instance

  2. Retrieve IP address of VM-01 from DHCP leases

    VM01_IP=$(sudo virsh net-dhcp-leases --network default | grep vm-01 | tail -1 | awk '{print $5}' | cut -d'/' -f1)
  3. Retrieve IP address of VM-02 from DHCP leases

    VM02_IP=$(sudo virsh net-dhcp-leases --network default | grep vm-02 | tail -1 | awk '{print $5}' | cut -d'/' -f1)
  4. From the opc@ol-node-01 ssh instance establish an SSH connection to VM-01

    ssh opc@$VM01_IP
  5. Change to /tmp folder

    cd /tmp
  6. Download MySQL employee sample database

    curl -L -o master.zip https://github.com/datacharmer/test_db/zipball/master/
  7. Install compression tools

    sudo dnf install -y unzip
  8. Extract the database

    sudo unzip master.zip
    sudo mv datacharmer-test_db-* employees_db
    cd employees_db
  9. Load the database

    mysql -u admin -pWelcome#123 < employees.sql
  10. Verify database loaded

    mysql -u admin -pWelcome#123 -e "USE employees; SHOW TABLES; SELECT COUNT(*) FROM employees;"
  11. Exit database VM

    exit

Step 11: Create Employee Database Web Application

  1. From the ol-node-01 instance SSH establish an SSH connection to VM-02

    ssh opc@$VM02_IP
  2. Create professional employee database application

    sudo tee /var/www/html/employees.php > /dev/null << 'EOF'
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Employee Database - Multi-VM LAMP Demo</title>
        <style>
            body { 
                font-family: Arial, sans-serif; 
                max-width: 1200px; 
                margin: 0 auto; 
                padding: 20px;
                background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
            }
            .header { 
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white; 
                text-align: center; 
                padding: 30px;
                border-radius: 15px;
                margin-bottom: 20px;
                box-shadow: 0 8px 16px rgba(0,0,0,0.1);
            }
            .info-box { 
                background: rgba(255,255,255,0.9);
                padding: 25px; 
                border-radius: 12px;
                box-shadow: 0 4px 8px rgba(0,0,0,0.1);
                margin-bottom: 20px;
                backdrop-filter: blur(10px);
            }
            .success { color: #28a745; font-weight: bold; }
            .error { color: #dc3545; font-weight: bold; }
            table { 
                width: 100%; 
                border-collapse: collapse; 
                margin: 20px 0;
                background: rgba(255,255,255,0.9);
                border-radius: 12px;
                overflow: hidden;
                box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            }
            th, td { 
                padding: 15px; 
                text-align: left; 
                border-bottom: 1px solid #ddd;
            }
            th { 
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                font-weight: bold;
            }
            tr:hover { background-color: rgba(102, 126, 234, 0.1); }
            .stats { 
                display: grid; 
                grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); 
                gap: 20px; 
                margin: 20px 0; 
            }
            .stat-card { 
                background: white; 
                padding: 20px; 
                border-radius: 10px; 
                text-align: center; 
                box-shadow: 0 4px 8px rgba(0,0,0,0.1);
            }
            .stat-number { font-size: 2em; font-weight: bold; color: #667eea; }
        </style>
    </head>
    <body>
        <div class="header">
            <h1>🏢 Employee Database Demo</h1>
            <p>MySQL Employee Sample Database on Multi-VM Architecture</p>
        </div>
    
        <?php
        // Database connection details
        define('DB_SERVER', '$VM01_IP');
        define('DB_USERNAME', 'empuser');
        define('DB_PASSWORD', 'Welcome#123');
        define('DB_NAME', 'employees');
    
        try {
            // Connect to MySQL database on separate VM
            $pdo = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USERNAME, DB_PASSWORD);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            
            echo '<div class="info-box success">';
            echo '<h2>✅ Connected to Employee Database</h2>';
            echo '<p><strong>Database Server:</strong> ' . DB_SERVER . ' (vm-01)</p>';
            echo '<p><strong>Web Server:</strong> ' . gethostname() . ' (vm-02)</p>';
            echo '</div>';
            
            // Get database statistics
            $stats = [];
            
            $stmt = $pdo->query("SELECT COUNT(*) as count FROM employees");
            $stats['employees'] = $stmt->fetch()['count'];
            
            $stmt = $pdo->query("SELECT COUNT(*) as count FROM departments");
            $stats['departments'] = $stmt->fetch()['count'];
            
            $stmt = $pdo->query("SELECT COUNT(*) as count FROM salaries");
            $stats['salaries'] = $stmt->fetch()['count'];
            
            $stmt = $pdo->query("SELECT COUNT(*) as count FROM titles");
            $stats['titles'] = $stmt->fetch()['count'];
            
            echo '<div class="info-box">';
            echo '<h2>📊 Database Statistics</h2>';
            echo '<div class="stats">';
            echo '<div class="stat-card"><div class="stat-number">' . number_format($stats['employees']) . '</div><div>Employees</div></div>';
            echo '<div class="stat-card"><div class="stat-number">' . number_format($stats['departments']) . '</div><div>Departments</div></div>';
            echo '<div class="stat-card"><div class="stat-number">' . number_format($stats['salaries']) . '</div><div>Salary Records</div></div>';
            echo '<div class="stat-card"><div class="stat-number">' . number_format($stats['titles']) . '</div><div>Job Titles</div></div>';
            echo '</div>';
            echo '</div>';
            
            // Show recent employees
            echo '<div class="info-box">';
            echo '<h2>👥 Sample Employee Data</h2>';
            $stmt = $pdo->query("SELECT emp_no, first_name, last_name, gender, hire_date FROM employees ORDER BY hire_date DESC LIMIT 20");
            $employees = $stmt->fetchAll();
            
            echo '<table>';
            echo '<thead><tr><th>Employee #</th><th>First Name</th><th>Last Name</th><th>Gender</th><th>Hire Date</th></tr></thead>';
            echo '<tbody>';
            
            foreach ($employees as $emp) {
                echo '<tr>';
                echo '<td>' . htmlspecialchars($emp['emp_no']) . '</td>';
                echo '<td>' . htmlspecialchars($emp['first_name']) . '</td>';
                echo '<td>' . htmlspecialchars($emp['last_name']) . '</td>';
                echo '<td>' . htmlspecialchars($emp['gender']) . '</td>';
                echo '<td>' . htmlspecialchars($emp['hire_date']) . '</td>';
                echo '</tr>';
            }
            echo '</tbody></table>';
            echo '</div>';
            
            // Show departments
            echo '<div class="info-box">';
            echo '<h2>🏬 Departments</h2>';
            $stmt = $pdo->query("SELECT dept_no, dept_name FROM departments ORDER BY dept_name");
            $departments = $stmt->fetchAll();
            
            echo '<table>';
            echo '<thead><tr><th>Department Code</th><th>Department Name</th></tr></thead>';
            echo '<tbody>';
            
            foreach ($departments as $dept) {
                echo '<tr>';
                echo '<td>' . htmlspecialchars($dept['dept_no']) . '</td>';
                echo '<td>' . htmlspecialchars($dept['dept_name']) . '</td>';
                echo '</tr>';
            }
            echo '</tbody></table>';
            echo '</div>';
            
        } catch (PDOException $e) {
            echo '<div class="info-box error">';
            echo '<h2>❌ Database Connection Error</h2>';
            echo '<p>Error: ' . htmlspecialchars($e->getMessage()) . '</p>';
            echo '</div>';
        }
        ?>
    
        <div class="info-box">
            <h2>🏗️ Multi-VM Architecture</h2>
            <p><strong>Database VM (vm-01):</strong> MySQL Server with Employee Database</p>
            <p><strong>Web VM (vm-02):</strong> Apache + PHP Web Application</p>
            <p><strong>Data Source:</strong> MySQL Sample Employee Database</p>
            <p><strong>Records:</strong> 300,000+ employees, 400,000+ salary records</p>
        </div>
    </body>
    </html>
    EOF
  3. Set proper permissions

    sudo chown apache:apache /var/www/html/employees.php
  4. Update line define('DB_SERVER', '$VM01_IP'); by changing the $VM01_IP value with the saved IP address value

    sudo vi /var/www/html/employees.php

    Example Output:

    ... Code before
    define('DB_SERVER', '192.168.122.???');
    ... Code after
  5. Exit web server VM

    exit

Step 12: Access Employee Application

  1. If SSH tunnel is closed then create for basic test
    ssh -L 8081:$VM02_IP:80 opc@<YOUR_OCI_PUBLIC_IP>
  2. Employee Database Demo Browse to:
    http://localhost:8081/employees.php

Expected Results:

  • Basic test: Green "Successfully Connected to MySQL!" message
  • Employee demo: Professional interface with 300,000+ employee records

Applications Available:

🔧 Basic LAMP Test (http://localhost:8081/dbtest.php)

  • Simple database connectivity test
  • System information display
  • MySQL version and status

🏢 Employee Database Demo (http://localhost:8081/employees.php)

  • 300,000+ employee records
  • 400,000+ salary records
  • Professional interface with statistics
  • Real-world data for demonstrations
  • Department listings and employee details

Essential Management Commands

VM Management

  1. List running VMs and their status

    sudo virsh list
  2. Start VM-01

    sudo virsh start vm-01
  3. Shutdown VM-01

    sudo virsh shutdown vm-01
  4. Display DHCP leases for VMs on the default network

    sudo virsh net-dhcp-leases --network default

Setup For running this lab on Oracle Cloud Infrastructure

  1. Virtual Cloud Network Setup

    Navigate: Networking → Virtual Cloud Networks → Start VCN Wizard
    - Name: ol-vcn-01
    - Create VCN
    Navigate: Networking → Virtual Cloud Networks → kvm-network → Security Lists
    Add these ingress rules:
    - SSH: Source 0.0.0.0/0, TCP Port 22
    - HTTP: Source 0.0.0.0/0, TCP Port 80
  2. Compute Instance Setup:

        Navigation: Hamburger Menu  Compute  Instances  Create Instance
    
        Configuration:
        - Name: ol-node-01
        - Image: Oracle Linux 8 (Latest)
        - Shape: VM.Standard.E4.Flex (4 OCPUs, 16GB RAM)
        - Boot Volume: 100 GB
        - VCN: ol-vcn-01 
        - Subnet: Public subnet ol-vcn-01
        - Assign Public IP: Yes
        - Add SSH Key: Upload your public key
  3. Test Compute public IP with SSH

    ssh opc@<ol-vcn-01_PUBLIC_IP>
  4. Continue to Step 2: Validate Environment Supports Virtualization


Next Steps

Learn to manage hosts and vms with Oracle Linux Virtual Manager (OLVM)

SSR