100-day Challenge #062: Running WordPress on Cloud Foundry

By: | April 9, 2016
Share

Translator’s note: This is the 14th article of the series “Cloud Foundry 100-day Challenge selection”. “#062” in the title means that it is 62nd (published on September 16, 2015) in the original Japanese series.

Original Author: Kiyohide NAGAI


The 62nd topic of “Cloud Foundry 100-Day Challenge” is the super-famous WordPress. As such, there are numerous articles that tell how to deploy it onto Cloud Foundry, so there may be no need to introduce another explanation, but please bear with us.

Basic information

The procedures are as follows:

  • 1) Retrieving source code
  • 2) Deploying application
  • 3) Checking application behavior
  • 4) Deployment using version for Cloud Foundry

1. Retrieving source code

We can use the version for Cloud Foundry, but that would be too easy, so first we will demonstrate how to deploy with the official source code.
First we download the Japanese version source code.

$ wget https://ja.wordpress.org/wordpress-4.2.4-ja.tar.gz
$ tar xzvf wordpress-4.2.4-ja.tar.gz
$ cd wordpress
$ ls
index.php        wp-blog-header.php    wp-includes        wp-settings.php
license.txt      wp-comments-post.php  wp-links-opml.php  wp-signup.php
readme.html      wp-config-sample.php  wp-load.php        wp-trackback.php
wp-activate.php  wp-content            wp-login.php       xmlrpc.php
wp-admin         wp-cron.php           wp-mail.php

2. Deploying application

For those who don’t know, WordPress can be operated by combination of PHP and MySQL. As such, the following description appears in numerous previous articles, and should look familiar to frequent readers.

2.1 Adding PHP extension module

First we go ahead to add the MySQL module.

$ mkdir .bp-config
$ vi .bp-config/options.json
$ cat .bp-config/options.json
{
    "PHP_EXTENSIONS": ["mysql"]
}

2.2 Preparing MySQL service

$ cf create-service p-mysql 100mb wpdb1

Additionally, we create ‘wp-config.php’ in order to obtain connection information for the created database from the environment variable.

$ cp wp-config-sample.php wp-config.php
$ vi wp-config.php
$ diff wp-config-sample.php wp-config.php
22a23,27
> 
> $services = getenv("VCAP_SERVICES");
> $services_json = json_decode($services,true);
> $mysql_config = $services_json["p-mysql"][0]["credentials"];
> 
24c29
< define('DB_NAME', 'database_name_here');
---
> define('DB_NAME', $mysql_config["name"]);
27c32
< define('DB_USER', 'username_here');
---
> define('DB_USER', $mysql_config["username"]);
30c35
< define('DB_PASSWORD', 'password_here');
---
> define('DB_PASSWORD', $mysql_config["password"]);
33c38
< define('DB_HOST', 'localhost');
---
> define('DB_HOST', $mysql_config["hostname"]);

2.3 Pushing application

Let’s create manifest.yml before pushing.

$ vi manifest.yml
:
$ cat manifest.yml
---
applications:
- name: wpja
  services:
  - wpdb1

.. then ‘cf push’.

$ cf push
:
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: wpja.10.244.0.34.xip.io
last uploaded: Thu Aug 6 06:48:30 UTC 2015
stack: cflinuxfs2
buildpack: PHP
 
     state     since                    cpu    memory          disk      details   
#0   running   2015-08-06 03:48:59 PM   1.6%   33.5M of 256M   0 of 1G

Done!

3. Checking application behavior

We will get the below wizard when we access the URL, so go ahead and enter what we would like to.

Let’s log in and make a test post.


However, note that you will lose your attached file if you ‘cf restart’ the application at this point.

‘cf restart’ wipes out the attachment file because a post itself is saved into the database but its attachment files are saved on the application’s local file system.
In order to rectify this situation, let us try deploying the source code tailored for Cloud Foundry.

4. Deployment using version for Cloud Foundry

(Translator’s note: This section was actually an introduction of the post by Daniel Mikusa *1 for Japanese readers. So English readers should have better refer to the Mikusa’s post, and read this section as a complement of it.)

Like the previous case, we start by downloading the source code.

$ git clone https://github.com/dmikusa-pivotal/cf-ex-worpress.git
$ cd cf-ex-wordpress
$ ls
manifest.yml  README.md  wp-config.php

There is almost no content; the repository actually does not include any source code of ‘WordPress’ itself.
Let us look and see what actually is included.

$ ls -a
.       .bp-config  .extensions .gitignore  manifest.yml
..      .cfignore   .git        README.md   wp-config.php

The important piece here is ‘.extensions/wordpress/extension.py’.
This is a file for using the options of ‘PHP-buildpack’. We haven’t had many opportunities in the past, but using it will further expand our deployment options.
Today we will utilize options to retrieve the ‘WordPress’ source code and mount disks of external servers to some of the directories of the application. The latter function will allow us to keep data that would be lost with a reboot of the application.

As for prior preparations, we first prepare MySQL.

$ cf create-service p-mysql 100mb wpdb2

We also modify ‘wp-config.php’, as the service name that is obtained from the environment variable does not match.

$ vi wp-config.php
$ git diff
diff --git a/wp-config.php b/wp-config.php
index dbbff27..b59be71 100644
--- a/wp-config.php
+++ b/wp-config.php
@@ -16,7 +16,7 @@
  
 // ** Read MySQL service properties from _ENV['VCAP_SERVICES']
 $services = json_decode($_ENV['VCAP_SERVICES'], true);
-$service = $services['cleardb'][0];  // pick the first MySQL service
+$service = $services['p-mysql'][0];  // pick the first MySQL service
  
 // ** MySQL settings - You can get this info from your web host ** //
 /** The name of the database for WordPress */

.bpconfig is already prepared, so we edit manifest.yml.

diff --git a/wp-config.php b/wp-config.php
index dbbff27..b59be71 100644
--- a/wp-config.php
+++ b/wp-config.php
@@ -16,7 +16,7 @@
 
:
 applications:
-- name: mywordpress
-  memory: 128M
-  path: .
-  buildpack: https://github.com/cloudfoundry/php-buildpack
-  host: wordpress-on
+- name: cfwp
   services:
-  - mysql-db
+  - wpdb2
   env:
-    SSH_HOST: user@your-ssh-server
-    SSH_PATH: /full/or/relative/path/on/ssh/server
-    SSH_KEY_NAME: sshfs_rsa
-    SSH_OPTS: '["cache=yes", "kernel_cache", "compression=no", "large_read"]'
+    SSH_HOST: ubuntu@192.168.1.10
+    SSH_PATH: /home/ubuntu/sshfs
+    SSH_KEY_NAME: id_rsa
+    SSH_OPTS: '["cache=yes", "kernel_cache", "compression=no", "large_read", "Ciphers=arcfour"]'

Here, we input the name of the server that the application connects to via SSH, the name of the private key file, etc.

From here, we describe the preparation procedures for the SSH connection.
First, we create the directory where we save the key file, and configure administration settings for the directory.

$ mkdir .ssh
$ chmod 700 .ssh
$ ssh-keygen -t rsa -f .ssh/id_rsa
$ ls .ssh/
id_rsa  id_rsa.pub
$ cat .ssh/id_rsa.pub

After creating the key files, we register the public key (id_rsa.pub) to ‘ssh/authorized_keys’ of the SSH server that we are connecting to.

(Move to the SSH server that we are connecting to)

$ vi .ssh/authorized_keys

(Return to the original server)

We execute the following, in order to register the SSH server we are connecting to to ‘known_hosts’.

$ ssh-keyscan -t rsa 192.168.1.10 > .ssh/known_hosts

We would like to ‘cf push’ here, but as described in “Configuring Application Security Group” of #002: Running postgresql-cf-service-broker on Cloud Foundry , the connection will fail if the SSH server being connected to is a private address.
As such, as has been done in previous articles, we will conduct the creation of ‘security group’ under the ‘admin’ authority of Cloud Foundry.

$ cf login -u admin
(.. admin user ..)
$ vi sg-ssh.json
$ cat sg-ssh.json
[
  {
    "protocol": "tcp",
    "destination": "192.168.1.10",
    "ports": "22"
  }
]
$ cf create-security-group sshwp sg-ssh.json
$ cf logout
$ cf login
(.. ordinary user ..)

All that is left to do is to ‘cf push’, but we will add a finishing touch so that we can get the same results with the Japanese version we used earlier.
For this, we edit the ‘extension.py’ seen earlier.

$ vi .extensions/wordpress/extension.py
$ git diff
diff --git a/.extensions/wordpress/extension.py b/.extensions/wordpress/extension.py
index 21d6360..5a1bc91 100644
--- a/.extensions/wordpress/extension.py
+++ b/.extensions/wordpress/extension.py
@@ -13,10 +13,10 @@ _log = logging.getLogger('wordpress')
  
  
 DEFAULTS = utils.FormattedDict({
-    'WORDPRESS_VERSION': '4.1.1',  # or 'latest'
+    'WORDPRESS_VERSION': '4.2.4-ja',  # or 'latest'
     'WORDPRESS_PACKAGE': 'wordpress-{WORDPRESS_VERSION}.tar.gz',
     'WORDPRESS_HASH': '258bda90f618d7af3a2db7f22fc926d1fedb06f4',
-    'WORDPRESS_URL': 'https://wordpress.org/{WORDPRESS_PACKAGE}',
+    'WORDPRESS_URL': 'https://ja.wordpress.org/{WORDPRESS_PACKAGE}',
 })

.. and finally, ‘cf push’.

$ cf push
:
requested state: started
instances: 1/1
usage: 256M x 1 instances
urls: cfwp.10.244.0.34.xip.io
last uploaded: Thu Aug 6 07:42:47 UTC 2015
stack: cflinuxfs2
buildpack: PHP
 
     state     since                    cpu    memory          disk      details   
#0   running   2015-08-06 04:45:23 PM   1.7%   37.2M of 256M   0 of 1G      

We test the application the same way we did earlier.

Rebooting does not cause any problems either.

This is what we get when we check the directory that we mounted from the SSH server:

~/sshfs$ ls -al
total 32
drwxrwxr-x 6 ubuntu ubuntu 4096 Aug  6 07:43 .
drwxr-xr-x 5 ubuntu ubuntu 4096 Aug  6 07:12 ..
-rw------- 1 ubuntu ubuntu   28 Jan  8  2012 index.php
drwx------ 4 ubuntu ubuntu 4096 Aug  6 07:43 languages
drwx------ 4 ubuntu ubuntu 4096 Aug  6 07:43 plugins
drwx------ 5 ubuntu ubuntu 4096 Aug  6 07:43 themes
drwxrwxr-x 3 ubuntu ubuntu 4096 Aug  6 07:48 uploads
-rw------- 1 ubuntu ubuntu  276 Aug  6 07:43  WARNING_DO_NOT_EDIT_THIS_DIRECTORY

Finally, this function to save with the SSH seems a bit “old-fashioned”, but we have seen disappointing results associated with application reboots in previous articles, so I suggest you give this function a try.

Software used in this post