Deploying a PHP App to Cloud Foundry
Deploying PHP apps to Cloud Foundry is simple, but fairly involved. Here are the steps to use Cloud Foundry or Bluemix's CLIs for the task.
Join the DZone community and get the full member experience.
Join For FreeI recently had a requirement to deploy a Slim application somewhere. As I already have a Bluemix account, it seemed sensible to deploy it to their Application Runtimes, service which is an installation of the Open Source Cloud Foundry project.
This turned out to be quite easy, but there are a number of steps involved, so I'm documenting it here.
Set Up the CLI tools
I'm a command line person, so did it all via the command line. There's a Cloud Foundry CLI, and also there's the Bluemix CLI tool too.
If you have bx installed, then you can use bx cf to run Cloud Foundry commands. This appears to proxy to the cf client. Regardless, the same commands seem to work in both tools. As I tend to prefer the open source option when I can, I used the cf tool. If you're using the Bluemix CLI, just prefix all my commands with bx and you should be fine.
On Mac, I used Homebrew to install cf:
$ brew install cloudfoundry/tap/cf-cli
Follow the relevant instructions for your operating system.
Prepare the PHP Application
There are a number of things we need to do to set up our PHP application for deployment. In my case, I'm deploying a Slim application, but practically, these steps work for any PHP app.
1. Select the PHP Version
CF uses buildpacks which control the environment. In our case, we'll use the PHP buildpack which comes with a variety of PHP versions. To select the one that we will use, we use the standard Composer require statement.
I want to use PHP 7.1, need to add "php" : "7.1.*" to the required section of composer.json like this:
composer.json:
...
"require": {
"php" : "7.1.*"
"slim/slim": "^3.0",
...
2. Create the Manifest File
Your Cloud Foundry environment is controlled by the manifest file, manifest.yml which must be in the root directory of your application.
manifest.yml:
---
applications:
- name: slim-bookshelf
buildpack: php_buildpack
memory: 64M
instances: 1
host: slim-bookshelf
Every CF app needs a name, and this is a minimum requirement for a valid manifest file. Note that the app name may be used on the command line, so it's easier if it doesn't have a space in it. Every other option is used to override the defaults and I find it useful to ensure that I know what will be configured.
I've set up:
- buildpack: Which build pack to use. This can be a name from cf buildpacks or a GitHub URL. I've picked the PHP buildpack that's supplied with Bluemix.
- memory: Memory limit for the application. Memory is expensive in cloud apps, so keep this as low as you can.
- instances: The number of instances to initially start.
- host: The subdomain name for this application.
That's all we need. However, the full list of options is in the docs should you need them.
3. Set Buildpack Options
The PHP buildpack can be configured using the .bp-config/options.json file. Weirdly this is a JSON file rather than YAML, but whatever.
In this file, we can set which directory to use as the public root of our project. Slim Bookshelf is a standard Slim application, so it's public root directory is public, so we need to set this. We can also enable PHP extensions here.
.bp-config/options.json:
{
"WEBDIR": "public",
"PHP_EXTENSIONS": ["gd", "pdo", "pgsql", "pdo_pgsql"]
}
There are other options available; check the docs.
4. Setup Rewrite Rules
The PHP buildpack runs Apache by default, so can you create a public/.htacces file to configure rewriting of URLs to index.php. For example:
public/.htaccess:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteCond %{REQUEST_URI}::$1 ^(/.+)(.+)::\2$
RewriteRule ^(.*) - [E=BASE:%1]
RewriteRule ^(.*)$ %{ENV:BASE}index.php [NC,L]
</IfModule>
That's it with configuring our application. The additional files we've created can be commited to git and we're good to go.
Deploy our CF Application
To deploy our Cloud Foundry application we need to log into Cloud Foundry and then push our application.
Log Into the CF CLI
We log in using cf login -a {api url}, -o {organisation} -s {space} which will ask us for our username and password.
You can get the API endpoint you need from bx regions if you're using Bluemix. For the UK, it's https://api.eu-gb.bluemix.net, my organization is 19FT and I'm using my demo space:
$ cf login -a https://api.eu-gb.bluemix.net -o 19FT -s demo
It will ask you for your username and password and then print out some summary information.
Deploy Our Application
Deployment is trivially simple:
$ cf push
You'll see it create the app and a route and then bind the route to the app. Then it uploads our files and starts the app. This involves downloading a lot of components and then it runs composer for us. When it finishes you'll get some status information like this:
0 of 1 instances running, 1 starting
1 of 1 instances running
App started
OK
App slim-bokshelf was started using this command `$HOME/.bp/bin/start`
Showing health and status for app slim-bookshelf in org 19FT / space demo as rob@19ft.com...
OK
requested state: started
instances: 1/1
usage: 64M x 1 instances
urls: slim-bookshelf.eu-gb.mybluemix.net
last uploaded: Tue Aug 29 16:06:21 UTC 2017
stack: cflinuxfs2
buildpack: php 4.3.27
state since cpu memory disk details
#0 running 2017-08-29 05:07:45 PM 0.0% 0 of 64M 0 of 1G
At this point, your public/index.php file is being served on the URL it has created, http://slim-bookshelf.eu-gb.mybluemix.net in my case.
If you need to make any changes to your app, just cf push again.
Viewing Logs
To view the logs, use cf logs {app name}. This will tail the logs, so run the command and then hit refresh to find out what went wrong:
$ cf logs slim-bookshelf
Retrieving logs for app slim-bookshelf in org 19FT / space demo as rob@19ft.com...
2017-08-30T21:56:02.47+0100 [RTR/3] OUT slim-bookshelf.eu-gb.mybluemix.net - [2017-08-30T20:56:02.466+0000] "GET / HTTP/1.1" 500 0 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.101 Safari/537.36" "5.10.124.132:48703" "169.50.91.74:61062" x_forwarded_for:"80.100.100.100" x_forwarded_proto:"http" vcap_request_id:"15e43a48-f327-4ccb-5300-cade5bb3d5bd" response_time:0.008793145 app_id:"bbfdacfb-2a5f-4041-b426-01f6a8619011" app_index:"0" x_global_transaction_id:"2263314295" x_b3_traceid:"867d2c41fc8b278a" x_b3_spanid:"867d2c41fc8b278a" x_b3_parentspanid:"-"
2017-08-30T21:56:02.47+0100 [RTR/3] OUT
2017-08-30T21:56:02.51+0100 [APP/PROC/WEB/0] OUT 20:56:02 httpd | 159.122.215.170 - - [30/Aug/2017:20:56:02 +0000] "GET / HTTP/1.1" 500 - vcap_request_id=15e43a48-f327-4ccb-5300-cade5bb3d5bd peer_addr=159.122.215.170
2017-08-30T21:56:02.51+0100 [APP/PROC/WEB/0] OUT 20:56:02 httpd | [Wed Aug 30 20:56:02.475171 2017] [proxy_fcgi:error] [pid 47:tid 140551289833216] [client 159.122.215.170:59576] AH01071: Got error 'PHP message: PHP Parse error: syntax error, unexpected ''view'' (T_CONSTANT_ENCAPSED_STRING), expecting ']' in /home/vcap/app/app/settings.php on line 27\n'
Next Steps
As you may have noticed, in our buildpack options file, we enabled the PostgreSQL PHP extension. Next up is to configure and use a PostgreSQL database with our app and also change that domain name to something more personal.
I'll cover these points in separate articles.
Published at DZone with permission of Rob Allen, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments