Automated Single-Node Application Deployment with Morpheus

This document provides a complete step-by-step guide to automating the configuration, installation, and deployment of the open source CRM application SuiteCRM using Morpheus. In this guide, we will create a custom Instance Type for SuiteCRM which can then be selected during provisioning. Once configured, the provisioning process is completely automated and results in SuiteCRM and a database installed on a single node. There is also an accompanying guide which automates the process for deployed SuiteCRM as a multi-tiered application consisting of a MySQL database on one node and the SuiteCRM application on a second node.

In this guide, we’ll use the following Morpheus constructs to fully automate the provisioning process of a single-node application:

  • Instance Types

  • Layouts

  • Node Types

  • Cypher

  • Archive

  • Inputs

  • File Templates

  • Tasks

  • Provisioning Workflows

Each of these constructs can be explored more deeply in their own specific sections of Morpheus docs but this guide will illustrate how these pieces can be pulled together to automate deployment, ensure consistency and security, and enable self-service. This could be used to create a provisionable Instance Type on any Morpheus-supported Cloud type and it’s intentionally left open-ended to be useful for any environment. As I’m building the example, I’ll show screenshots targeting a build for VMware vCenter Clouds. Despite the screenshots, this guide is useful for any environment.

Create a Morpheus Archive for Install Files

Morpheus Archives allow you to store files which can then be made available for download in scripts or by users. Archives are backed by buckets or file shares which must exist prior to creating the Archive. Buckets could be backed by Amazon S3, for example. File Shares could be backed by an NFS file share or even point directly to a local folder on the appliance itself. In this example, we’ll use an S3-backed bucket. With an Amazon AWS Cloud already integrated with Morpheus, we can even create the S3 bucket itself without leaving Morpheus UI.

To create a new bucket, navigate to Infrastructure > Storage. From the Buckets tab, click + ADD and then select “AWS S3 Bucket”. The example bucket configuration is shown below. Bear in mind if you make any changes you may need to carefully confirm Task configurations and calls to Cypher or Archive to ensure they match any changes you’ve made.

  • NAME: Automation Training S3 Bucket (this is simply a friendly name for the bucket within Morpheus)

  • Storage Service: Select your pre-existing AWS Cloud

  • BUCKET NAME: Enter a unique name for the bucket (this much conform to AWS bucket naming rules, consult AWS documentation if needed)

  • CREATE BUCKET: Checked

  • REGION: The AWS region to create the bucket in

  • ACTIVE: Checked (this makes it available for use in Morpheus)

../../_images/newBucket.png

With the bucket created, we can now create the Archive. Start by going to Tools > Archives and clicking + ADD. In the new Archive, we need to configure the following:

  • NAME: Software Archive

  • BUCKET: Select the bucket we just created

  • PUBLIC URL: Checked (this automatically creates a public download URL when files are added to the Archive)

Note

If you don’t name your Archive “Software Archive” as indicated here, you will have to make manual changes to Task config later in this guide.

At this point, you should go ahead and download the installation ZIP file for SuiteCRM. You can access version 7.14.3 here. This guide is designed for version 7.14.3. If you opt to download a different version please note that changes might be needed to the automation scripts to account for any changes to the installation or configuration processes for that version.

Click on the newly created Archive and note there are no files contained in it. Under the Files tab, click + ADD. Slide the installation ZIP file onto the modal and wait for the file to be successfully uploaded. Click DONE. We’ve now added the installation ZIP file and it is visible in the list of files on the Files tab.

Click on the name of the newly added file to access the File detail page. While here, click on the Scripts tab and you’ll see syntax examples for how this and other files might be accessed in your automation scripts. You’ll see this syntax used later in this example as we access the ZIP file directly from this Archive and automate the installation process. Generated links can be viewed from the Links tab and a record of it will be visible on the History tab.

../../_images/fileDetail.png

Create Cypher

Cypher is a secure key/value store in Morpheus. Using Cypher, we can securely store passwords and other secret values (such as API keys) which can then be called into automation Tasks and templates. Here we will store the MariaDB root user password as a Cypher entry. In the Morpheus UI, go to Tools > Cypher and click + ADD.

There are a number of different types of Cypher keys, which are useful in different contexts. Here’s we’ll use the “secret” type which allows us to enter some known value which can be securely accessed later. Enter the following:

  • KEY: secret/dba/mariadb_root

  • VALUE: Password123?

  • LEASE: 0 (Lease time is given in seconds, with “0” being unlimited)

Click SAVE CHANGES

../../_images/cypherMaria.png

Create Inputs

Inputs are custom input fields which can be added to Layouts, Instance Types, and other constructs in Morpheus. The input can be consumed as variables within templates and scripts. We’ll create three inputs in this case for the database name, the database username, and the database user password.

In Morpheus UI, navigate to Library > Options > Inputs. Click + ADD. Complete the following fields:

  • NAME: SuiteCRM DB Name (The name for the Input object in Morpheus)

  • LABEL: SUITECRM (Labels are a categorizing feature in Morpheus)

  • FIELD NAME: databaseNameSCRM (The internal property which the input value is assigned to)

  • SHOW ON EDIT: Checked (By checking this box, we can view this Input value when editing the Instance after provisioning)

  • DISPLAY VALUE ON DETAILS: Checked (By checking this box, we will see the value of this Input on the detail page for the provsioned Instance)

  • TYPE: Text (The input type, in this case an open text field for the user)

  • LABEL: SuiteCRM DB Name (The label the user will see next to the field at provsion time)

  • REQUIRED: Checked (By checking this box, the Input will be required at provision time)

  • Database Name Input

    ../../_images/dbNameInput.png

Click SAVE CHANGES. Then, create two additional Inputs:

  • NAME: SuiteCRM DB User

  • LABEL: SUITECRM

  • FIELD NAME: databaseUserSCRM

  • SHOW ON EDIT: Checked

  • DISPLAY VALUE ON DETAILS: Checked

  • TYPE: Text

  • LABEL: SuiteCRM DB User

  • REQUIRED: Checked

  • Database Username Input

    ../../_images/dbUserInput.png
  • NAME: SuiteCRM DB Password

  • LABEL: SUITECRM

  • FIELD NAME: databasePassSCRM

  • SHOW ON EDIT: Checked

  • DISPLAY VALUE ON DETAILS: Checked

  • TYPE: Password (Password type Inputs are masked on screen when entered by the user)

  • LABEL: SuiteCRM DB Password

  • REQUIRED: Checked

  • Database Password Input

    ../../_images/dbPassInput.png

Create File Templates

For our SuiteCRM application, we’ll need to create an Apache config file. We can create a File Template in Morpheus and the config file will be generated dynamically at provision time with the appropriate values. Navigate to Library > Templates > File Templates and click + ADD. Enter the following:

  • NAME: suitecrm - conf

  • LABELS: SUITECRM

  • FILE NAME: suitecrm.conf

  • FILE PATH: /etc/apache2/sites-available

  • PHASE: Provision

  • TEMPLATE: See below for the complete template, note how we’re able to dynamically resolve Morpheus variables within the template

  • FILE OWNER: root

  • SETTING NAME: suitecrm

  • SETTING CATEGORY: App

<VirtualHost *:80>
   ServerAdmin admin@localhost
   ServerAlias "<%=server.externalIp%>"
   DocumentRoot /var/www/html/suitecrm

   <Directory /var/www/html/suitecrm/>
        Options FollowSymlinks
        AllowOverride All
        Require all granted
   </Directory>

   ErrorLog ${APACHE_LOG_DIR}/error.log
   CustomLog ${APACHE_LOG_DIR}/access.log combined

   <Directory /var/www/html/suitecrm/>
          RewriteEngine on
          RewriteBase /
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteRule ^(.*) index.php [PT,L]
  </Directory>
</VirtualHost>
../../_images/filetemplate.png

Create Tasks

At this point, we need to create three automation Tasks. One will set the Apache config file we just created, another will be a Bash script Task to actually install and configure SuiteCRM on the box, and the third will be another Bash script Task which will restart the Apache service.

To create a Library Template Task, navigate to Library > Automation > Tasks. Click + ADD. Enter the following:

  • NAME: suitecrm file template

  • CODE: suitecrmfiletemplate

  • LABELS: SUITECRM

  • TYPE: Library Template (The proper fields will appear once the Type is set)

  • TEMPLATE: suitecrm - conf (Select the File Template we already created from this dropdown menu)

  • EXECUTE TARGET: Resource

../../_images/libtemtask.png

Now create the first Bash Task which will install and configure SuiteCRM on a newly-provisioned box:

  • NAME: suitecrm - single node

  • LABELS: SUITECRM

  • TYPE: Shell Script (The proper fields will appear once the Type is set)

  • RESULT TYPE: None

  • SUDO: Checked

  • SOURCE: Local (We will enter the script locally in this case but if version control repositories are integrated, such as Github, script content can be dynamically pulled from the repository at the time the Task is invoked. This ensures the code is always current without ever manually updating Tasks)

  • CONTENT: Expand the section below to see the script content. Note how Cypher secrets and custom option (Input) values are invoked in this script

  • EXECUTE TARGET: Resource

Install Task Content

RPass="<%=cypher.read('secret/dba/mariadb_root')%>"
SCRMDb="<%=customOptions.databaseNameSCRM%>"
SCRMUser="<%=customOptions.databaseUserSCRM%>"
SCRMPass="<%=customOptions.databasePassSCRM%>"
PHP_VERSION="8.1"
MARIADB_VERSION="mariadb-10.11"

#Wait until any apt-get processes have finished
if [ `ps -ef | grep [a]pt-get | wc -l` = !0 ]
then
    sleep 120
fi

#Install apache, start service and enable on boot
apt-get install apache2 -y
systemctl stop apache2.service
systemctl start apache2.service
systemctl enable apache2.service

#Install MariaDB, start service and enable on boot
curl -LsS https://r.mariadb.com/downloads/mariadb_repo_setup | \
sudo bash -s ----mariadb-server-version="$MARIADB_VERSION"
apt update
apt-get install mariadb-server mariadb-client -y
systemctl stop mariadb.service
systemctl start mariadb.service
systemctl enablemariadb.service

#The following commands are from the mysql secure installation guidance
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '$RPass';"
mysql -u root -p$RPass-e "FLUSH PRIVILEGES;"
mysql -u root -p$RPass-e "DELETE FROM mysql.user WHERE User='';"
mysql -u root -p$RPass-e "DELETE FROM mysql.user WHERE User='root' \
AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
mysql -u root -p$RPass-e "DROP DATABASE IF EXISTS test;"
mysql -u root -p$RPass-e "DELETE FROM mysql.db WHERE Db='test' \
OR Db='test\_%';"
mysql -u root -p$RPass-e "FLUSH PRIVILEGES;"

#Create the SuiteCRM User
mysql -u root -p$RPass-e "CREATE User '$SCRMUser'@'localhost' \
IDENTIFIED BY '$SCRMPass';"

#Create the SuiteCRM database
mysql -u root -p$RPass -e "CREATE DATABASE $SCRMDb;"
mysql -u root -p$RPass -e "GRANT ALL ON $SCRMDb.* TO \
$SCRMUser@localhost IDENTIFIED BY '$SCRMPass';"
mysql -u root -p$RPass -e "FLUSH PRIVILEGES;"

#Install required software for SuiteCRM
add-apt-repository ppa:ondrej/php -y
apt-get update
apt-get install php$PHP_VERSIONlibapache2-mod-php$PHP_VERSION \
php$PHP_VERSION-common php$PHP_VERSION-mysql php$PHP_VERSION-gmp \
php$PHP_VERSION-curl php$PHP_VERSION-intl php$PHP_VERSION-mbstring \
php$PHP_VERSION-xmlrpc php$PHP_VERSION-gd php$PHP_VERSION-bcmath \
php$PHP_VERSION-imap php$PHP_VERSION-xml php$PHP_VERSION-cli \
php$PHP_VERSION-zip -y

#Update php.ini file with required settings
short_open_tag=On
memory_limit=256M
upload_max_filesize=100M
max_execution_time=360

for key in short_open_tag memory_limit upload_max_filesize max_execution_time
do
  sed -i "s/^\($key\).*/\1 $(eval echo = \${$key})/" \
/etc/php/$PHP_VERSION/apache2/php.ini
done

#Restart apache
systemctl restart apache2.service

#Test file created for debugging
echo "<?php phpinfo( ); ?>" | sudo tee /var/www/html/phpinfo.php

#Download and install latest SuiteCRM. Composer v2 does not work with Suitecrm.
file_url="<%= archives.link('Software Archive', 'SuiteCRM-7.14.3.zip',1200) %>"
wget $file_url-O "./SuiteCRM-7.14.3.zip"--no-check-certificate
apt-get install unzip -y
unzip SuiteCRM-7.14.3.zip -d /var/www/html
mv /var/www/html/SuiteCRM-7.14.3/ /var/www/html/suitecrm
cd/var/www/html/suitecrm
chown -R www-data:www-data /var/www/html/suitecrm/
chmod -R 755 /var/www/html/suitecrm/
../../_images/installtask.png

Finally, we’ll add the Apache restart Task. Configure a new Task as shown below:

  • NAME: suitecrm apache restart

  • LABELS: SUITECRM

  • TYPE: Shell Script (The proper fields will appear once the Type is set)

  • RESULT TYPE: None

  • SUDO: Checked

  • SOURCE: Local

  • CONTENT: Expand the section below to see the script content

  • EXECUTE TARGET: Resource

Restart Task Content

a2ensite suitecrm.conf
a2enmod rewrite
systemctl restart apache2.service
../../_images/restarttask.png

Create the Provisioning Workflow

Morpheus Workflows pull multiple Tasks together into a logical group. There are two types of Workflows: Operational and Provisioning. We won’t use any Operational Workflows here but these Workflows can be run on-demand as needed or set to run on a recurring time schedule (like a cronjob). Provisioning Workflows are associated with an Instance at provision time and will automatically run when the Instance reaches certain phases of its lifecycle, such as during provisioning, teardown, startup, or shutdown. In this case, we can create a Provisioning Workflow with our Tasks in the provisioning phase so that SuiteCRM will be installed, the Apache config file will be set, and the Apache service will be restarted automatically when the Instance is provisioned.

Navigate to Library > Automation > Workflows and click + ADD. Set the following configurations:

  • NAME: SuiteCRM - single node

  • LABELS: SUITECRM

  • PLATFORM: Linux

  • TASKS: Expand the Provision section and begin typing the names of our Tasks in the Search field. After adding them, they can be reordered but they should be set such that the install script is run first, the file template is set second, and the Apache restart is run last

Click SAVE CHANGES

../../_images/provworkflow.png

Create a Custom Library Item

Having created Cypher entries, Inputs, and Tasks, we’re ready to put them all together into a custom Instance Type for our Morpheus Library. We’ll create a new SuiteCRM Library entry that will be available to some or all users (depending on Role permissions) in the provisioning wizard. This will allow them to stand up single node SuiteCRM appliances with just a few clicks. In Morpheus there are three layers to such Library items: Instance Types, Layouts, and Node Types. We’ll create the Instance Type first:

Navigate to Library > Blueprints > Instance Types and click + ADD. Enter the following configurations:

  • NAME: Custom SuiteCRM

  • CODE: custSuiteCRM

  • CATEGORY: Apps

  • LABELS: SUITECRM

  • ICON: If desired, search the file system on your local computer for a SuiteCRM logo icon for easier identification of this Instance Type at provision time

../../_images/instype.png

Click SAVE CHANGES. After creating the Instance Type, click into it and then click + ADD LAYOUT from the Instance Type Detail Page. A Layout specifies the technology the Instance will run on, in this case VMware. It’s possible to have multiple Layouts associated with an Instance Type which can be selected depending on the chosen Cloud the user might be provisioning on. Configure the Layout as follows:

  • NAME: SuiteCRM - Single Node

  • VERSION: 7.14.3

  • LABELS: SUITECRM

  • CREATABLE: Checked (If unchecked, this Layout won’t be an available option at provision time)

  • TECHNOLOGY: Select the relevant technology for your environment

  • MINIMUM MEMORY: 2048 (If entered, this value will override any memory requirement set on the virtual image to ensure your Instance service will run properly)

  • WORKFLOW: Select the Workflow we’ve already created, “SuiteCRM - single node”

  • INPUTS: Search and find the three custom Inputs we created earlier

../../_images/layout.png

Once the configurations are entered, click SAVE CHANGES. After creating the Layout, we need to associate a Node Type. From the Layout Detail Page, click + ADD within the “VM Types” section. The term VM Types is sometimes used in place of Node Types in Morpheus but they refer to the same thing and are fully interchangeable. Node Types are compute images and will be relevant types for the destination Cloud technology (AMIs for provisioning on AWS or VMware virtual images for vCenter Clouds, etc.) In this case, we’re simply going to point to a default Ubuntu image in an appropriate format which is supplied by Morpheus. You can associate Node Types with your own custom virtual images as well when needed. Set the following configurations on the new Node Type:

  • NAME: Custom Ubuntu 22.04 Node

  • SHORT NAME: ubuntu2204

  • VERSION: 22.04

  • TECHNOLOGY: Select the relevant technology for your environment

  • VM IMAGE: Select the included Ubuntu 18.04 image

Click SAVE CHANGES

../../_images/nodetype.png

Provision the SuiteCRM Instance Type

At this point, the setup is finished and SuiteCRM will be available as an Instance Type option for your users. We’ll go ahead and walk through the provisioning process at this point just to take a look.

To begin provisioning, navigate to Provisioning > Instances and click + ADD. From the list of Instance Types, select the “SUITE_CRM” Instance Type we just created, click NEXT. From the Group tab, select a Group which contains a destination Cloud relevant to the Instance configuration and then select the Cloud you’d like to provision the app onto. Click NEXT. From the Configuration Tab, select the Layout we created and configure a plan, Resource Pool, and network which makes sense for your environment and the compute needs of the workload. You’ll then notice the Input fields we created where you’ll need to enter a SuiteCRM database name, Username, and Password. Click NEXT. On the Automation tab, we do not need to select a Workflow as our Workflow is already set on the Layout. Click NEXT and click COMPLETE.

../../_images/provision.png

Configure SuiteCRM

SuiteCRM is now ready for its initial setup. In a web browser, go to http://<YOUR_INSTANCE_IP>/install.php. You should see the license agreement page and can proceed with the setup steps. SuiteCRM is now up and running. Additional instances of SuiteCRM can be stood up in the future with just a few clicks!

../../_images/eula.png