In this third post in my CloudFoundryFun series, I will explain the concepts of Cloud Foundry apps, services, and service bindings. To illustrate this in a fun way, we will deploy our own personal Wordpress instance and extend it with Microsoft Azure Cloud Services.
Create a Blog on SAP Cloud Platform
Cloud Foundry Apps vs. Services
But before we start with the fun part, we need to learn some Cloud Foundry concepts. You might have heard that Cloud Foundry applications consist of two types of components:
apps and services.
An app is basically the written code when it has been deployed and runs.
An app must not have any hard-coded dependencies to another app or to services such as a database. Those dependencies need to be modeled as a (backing) service.
A backing service, on the other hand,
provides consumable functionality to apps. Those services have their own lifecycle and are loosely coupled to the apps. This allows you to scale your apps rapidly when needed. So aspects such as logging, messaging or persistency are backing services by definition.
One of the many advantages that come with this architecture, is that you can simply "plug" services into your application when need. Cloud Foundry will then inject the required credentials of the backing service in your app at runtime.
In some situations like debugging, you might want to bind a local app to the backing services. This can be achieved with
service keys. Service keys are copies of the credentials that will be injected into your app at runtime.
Let's see this in action when we build our own blog on SAP Cloud Platform!
Deploy your own Wordpress Blog
For demonstration purposes, I want to show how to modify a well-known standard application like WordPress to run on Cloud Foundry. I recently found a post by Daniel Mikusa in which he explains how to
deploy Wordpress to a Cloud Foundry environment. He says that the Wordpress application requires two types of storage for:
- Structured Data
- This type of storage is needed for structured data as users, posts, comments, and metadata. A relational database is well suited for this kind of data.
- Unstructured Data
- This type, on the other hand, is needed for media files. Content creators want to enrich their posts with images, files and possibly also videos. It wouldn't make sense to store these kinds of data in a traditional database. This is why WordPress stores them by default on the file system.
At first, I thought: Great, writing this blog post will be child's play to me since the instructions are already out there. Then I realized that Wordpress requires a MySQL database (Postgres won't work) and a network file system (NFS) volume service. Unfortunately, neither one of those services is being offered in the default SAP Cloud Foundry marketplace.
But thanks to the Open Service Broker API (OSBAPI) that's not an issue at all! This spinoff of the Cloud Foundry project allows you to connect backing services from various vendors and sources to your app running in SAP Cloud Platform.
Most hyperscalers offer a service broker (implementing the OSBAPI) to provision, connect and deprovision managed services. In other words, we can create required persistency services in other datacenters, create access keys and inject those keys in our WordPress application. All those things can be done with
the exact same flow as if you were creating native services from the SAP Cloud Platform
In this post, I want to leverage
Microsoft's service broker to create the needed services. You can find instructions on how to
create a service broker in the SAP Help Portal. We will use an
Azure Database for MySQL for the structured data and a
Blob Storage service to persist unstructured data. Once the services are created, we need to make the standard WordPress application aware of them.
Disclaimer: I never administered a Wordpress blog and my PHP skills are... let's say limited. So the WordPress configuration might not follow best-practices.
Me when I'm trying to do PHP
Prerequisites
Deploy Wordpress to SAP Cloud Platform
Download the WordPress project
Download the latest version of WordPress on your local machine and unpack it in the current directory:
curl https://wordpress.org/latest.tar.gz | tar xvz
Create a MySQL database in Azure
Please make sure to install the Microsoft Azure service broker before you continue.
This command will create a new Cloud Foundry service named
AzureMySqlDB. In the background, the creation of a MySQL database (service name: azure-mysql-5-7, plan: basic) will be triggered in an Azure datacenter in
North Europe. This database will be assigned to my existing resource group "IObertRG". Resource groups are logical units that bundle different resources in Azure.
It's important to configure the firewall to allow traffic from the Internet. In productive scenarios, you might want to choose another configuration.
cf create-service azure-mysql-5-7 basic AzureMySqlDB -c '{
"location": "northeurope",
"resourceGroup": "IObertRG",
"firewallRules" : [{
"name": "AllowAll",
"startIPAddress": "0.0.0.0",
"endIPAddress" : "255.255.255.255"
}]
}'
By default the database only accepts incoming HTTPS traffic, we'll need to make sure we use HTTPS in WordPress later.
Create a Blob Store in Azure
A blob storage account can be created in the same way. We simply chose a different service and specify the corresponding plan. The name of the CF service is AzureBlobStore.
cf create-service azure-storage-blob-storage-account-and-container \
all-in-one AzureBlobStore -c '{
"location": "northeurope",
"resourceGroup": "IObertRG"
}'
Make sure both services have been created successfully before you continue. You can check the current state with:
cf services
Create the manifest of the application
Create a new file named
manifest.yaml in the WordPress root folder. This file contains information about the runtime environment and the bound services. Make sure the file looks as follows
applications:
- name: wordpress
memory: 128M
random-route: true
path: .
buildpack: php_buildpack
services:
- AzureMySqlDB
- AzureBlobStore
Define the PHP runtime
We also need to define the PHP version and extensions we want to use.
Create a new folder called .bp-config in the project root which stores the
buildpack configuration. Define the following configuration in the
options.json file within the created folder:
{
"WEBDIR": "wordpress",
"PHP_VERSION": "{PHP_73_LATEST}"
}
Specify the following PHP extensions in a new file
.bp-config/php
/php.ini.d/wp-extensions.ini
extension=mbstring.so
extension=mysqli.so
extension=gd.so
extension=zip.so
extension=openssl.so
extension=sockets.so
Rename the sample configuration file to
wp-config.php
mv wp-config-sample.php wp-config.php
Configure the connection to the MySQL Database
Replace the database configuration in wp-config.php with the following content.
// ** Read MySQL service properties from _ENV['VCAP_SERVICES']
$services = json_decode($_ENV['VCAP_SERVICES'], true);
$service = $services['azure-mysql-5-7'][0]; // pick the first MySQL service
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', $service['credentials']['database']);
/** MySQL database username */
define('DB_USER', $service['credentials']['username']);
/** MySQL database password */
define('DB_PASSWORD', $service['credentials']['password']);
/** MySQL hostname */
define('DB_HOST', $service['credentials']['host'].':'.$service['credentials']['port']);
/** Database Charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8' );
/** The Database Collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
define('DB_SSL', true);
define('FS_METHOD', 'direct');
Cloud Foundry will inject the credentials of the MySQL DB into the environment variable VCAP_SERVICES for us. So we only need to read them here. If you, later on, decide to switch the underlying DB, you can simply change the service binding and restart your application.
This is how loose coupling should look!
As mentioned earlier, Azure DBs only accept HTTPS traffic by default. So we need to define the public certificate for the SSL connection.
Only add the first line above the existing if statement in
wp-includes/wp-db.php:
// Just add this line
mysqli_ssl_set($this->dbh, NULL, NULL, ABSPATH . 'BaltimoreCyberTrustRoot.crt.pem', NULL, NULL);
if ( WP_DEBUG ) {
mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
} else {
@mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
}
Download the public certification and place it in the root of your project:
curl https://www.digicert.com/CACerts/BaltimoreCyberTrustRoot.crt.pem > BaltimoreCyberTrustRoot.crt.pem
Install the Blob Storage Plugin
By default, WordPress wants to saved unstructured data to its local file system or to a remote NFS. Luckily, there's a plugin that can handle Azure's Blob Storage as well.
Download the
Azure Blob Storage plugin and unzip its content to
wp-content/plugins/.
Set the default values for the Blob Storage
Replace the content of the following function in the plugin file
wp-content/plugins/windows-azure-storage/windows-azure-storage-settings.php.
function windows_azure_storage_plugin_settings_section() {
?>
<p><?php echo __( 'If you do not have Microsoft Azure Storage Account, please <a href="http://go.microsoft.com/fwlink/?LinkID=129453">register </a>for Microsoft Azure Services.', 'windows-azure-storage' ); ?></p>
<?php
// ** Read MySQL service properties from _ENV['VCAP_SERVICES']
$services = json_decode($_ENV['VCAP_SERVICES'], true);
$service = $services['azure-storage-blob-storage-account-and-container'][0];
update_option( 'azure_storage_account_name', $service['credentials']['storageAccountName']);
update_option( 'azure_storage_account_primary_access_key', $service['credentials']['accessKey']);
}
This will read the credentials of the blob storage service and set them as default values in the plugin settings. This way you won't need to access them manually. In a production scenario, you want to hide those credentials from end users.
Deploy Wordpress
Deploying Cloud Foundry apps is as easy as:
cf push
Activate and configure the plugin
Once your application has been deployed, go to
https://wordpress-<unique-route>-cfapps.eu10.hana.ondemand.com/wp-admin/install.php and enter your preferred language and choose the admin credentials.
In case you see a Timeout Error, just refresh the page to continue.
In the admin view, click on plugins in the left sidebar and
activate the Azure plugin.
After the successful activation, you should find a settings page for the plugin. Navigate there to note that there are default values now.
Create a
new Container to store the uploaded data. Next, select the
Use for default upload checkbox and click
save changes.
Write a sample blog
Write your first blog post about a topic of your choice by click on the
+New in the upper toolbar. Make sure to
add a media file which we can inspect later. Click
Publish... to release the post.
Have you ever had a Bavarian Breakfast? If no, please stop reading this post and find out where you can buy Weißwurst near you.
Inspect the Persisted Data
Let's see if the data has actually been persisted in our Azure services!
As mentioned before, we can create service keys locally. These keys contain the same kind of information that will be injected into your running apps. It's important to note, that it won't be the same credentials! You can revoke the keys of one app without disrupting other apps using the same service.
Create and view service keys for the MySQL database with the following commands. The second command should print your credentials to the console.
cf create-service-key AzureMySqlDB sqlkey
cf service-key AzureMySqlDB sqlkey
Use the MySQL client of your choice (e.g. Sequel Pro) to connect to the database. Don't forget that Azure blocks insecure HTTP traffic. Therefore you need to specify the
public certificate again.
Now you have access to the database and you can inspect what WordPress saved when you created the blog post. Awesome!
Lastly, we want to inspect the data saved in the blob store. Same as before, we want to create and view a service key for this service.
cf create-service-key AzureBlobStore blobkey
cf service-key AzureBlobStore blobkey
Navigate to the container you just created and follow the folder hierarchy to find the media files you uploaded. Can you find all your files in there?
You might notice that WordPress created three copies of your image (in various resolutions).
Summary
In this edition you have learned:
- What apps, services, and service keys are
- How to use a new service broker
- How to provision backing services from Azure
- How to deploy stateless applications with backing services to Cloud Foundry
- How to modify Wordpress to consume the bound services
- How to create service keys
- How to use service keys in a local setup
Service brokers of the hyperscalers:
About this series
This was the third blog post of my monthly new series #CloudFoundryFun. The name already says all there is to it, this series won’t be about building enterprise apps on Cloud Foundry. I think there are already plenty of great posts about those aspects out there. This series rather thinks outside the box and demonstrates unconventional Cloud Foundry use-cases. And sometimes it might be pure entertainment.?. |
CloudFoundryFun #4 – Fetch (football) scores periodically