PHP on Heroku

edpug 19/2/13

Heroku

Heroku is a Platform As A Service (PAAS)

Supports the following languages:

Many others supported through "Buildpacks"
https://devcenter.heroku.com/articles/third-party-buildpacks

facebook & heroku - September 2011.
http://developers.facebook.com/blog/post/558/

other PAAS

the Heroku way

processes (the UNIX model)

Poka-yoke (ポカヨケ) - fail-safing/mistake-proofing

"to eliminate product defects by preventing, correcting, or drawing attention to human errors as they occur"

The Twelve-Factor App

"a methodology for building software-as-a-service apps"

the 12 factors

  1. Codebase
  2. Dependencies
  3. Config
  4. Backing Services
  5. Build, release, run
  6. Processes
  7. Port binding
  8. Concurrency
  9. Disposability
  10. Dev/prod parity
  11. Logs
  12. Admin processes

Setting up heroku

Get an account & grab the heroku toolbelt from https://toolbelt.heroku.com/

                $ heroku login
                Enter your Heroku credentials.
                Email: enru@example.com
                Password:
                Could not find an existing public key.
                Would you like to generate one? [Yn]
                Generating new SSH public key.
                Uploading ssh public key /Users/enru/.ssh/id_rsa.pub
            

Once you have logged in and sent a SSH key up to heroku you can create your app with the heroku create command.

                $ cd ~/myapp
                $ heroku create
                Creating stark-fog-398... done, stack is cedar
                http://stark-fog-398.herokuapp.com/ | git@heroku.com:stark-fog-398.git
                Git remote heroku added
            

Processes & Scaling

heroku allows you to run as many processes as you like.

View your running process with heroku ps

By default, heroku provides one web process and tries to automatically identify your application type.

Commit a Procfile if you need more control over your processes.

                $ cat Procfile 
                web: sh boot.sh 
                worker: php queue_runner.php
                clock: php update_feed.php
            

Processes are scaled up ad down with heroku ps:scale web=2

Heroku Config

We can store & display environment variables in heroku using the heroku config command.

                $ heroku config:add MY_ENV_VAR=abc123
                Setting config vars and restarting pacific-cove-5430... done, v11
                MY_ENV_VAR: abc123
            

Storing the application's configuration in the environment makes it very easy to move between development, testing and production platforms.

It also reduces the risk of exposing confidential settings.

Local Development

Local dev can be done using PHP's dev server.

Foreman (part of the heroku toolbelt) can also be used for local development

A local Procfile can be used to get Foreman to run the PHP dev server

                $ cat Procfile.dev 
                web: php -S localhost:5000 -t . 
                $ foreman start -f Procfile.dev 
                21:32:27 web.1  | started with pid 25937
            

Our web app will now be available at http://localhost:5000/

dev/prod parity

Local Environment Variables

Foreman also loads up any variables declared in a .env file into its environment

                $ echo "STATUS=development" >>.env
            

There is an addon that will pull heroku config vars out into a local .env file that into can be used for local development with Foreman

https://github.com/ddollar/heroku-config

                $ cat .env 
                STATUS=development
                MY_ENV_VAR=abc123
            

Logs

heroku provides access to your application logs with heroku logs.

stdout and stderr go to logs.

Several filters to this command are available heroku logs --source app or heroku logs --ps web.

Logs can be tailed with heroku logs --tail.

Logs can be sent to syslogd on another machine.

                $ heroku drains:add syslog://host1.example.com:514
                Drain syslog://host1.example.com:514 added to myapp
            

Maintenance

Putting your app/site into maintenance mode is a simple as:

                $ heroku maintenance:on
            

Visitors are redirected to the default maintenance page or the URL contained in the MAINTENANCE_PAGE_URL env var.

404

You can set a default 404 page by adding a ERROR_PAGE_URL variable to your heroku config.

Postgres DB Addon

heroku provides Postgres as a database solution

                $ heroku addons:add heroku-postgresql:dev
                Adding heroku-postgresql:dev to pacific... done, v69 (free)
                  Attached as HEROKU_POSTGRESQL_TEAL
                Database has been created and is available
            

You can find info about your DB with heroku pg:info

heroku pg:psql will give you access to your production DB.

$ heroku pg:psql
psql (9.1.7, server 9.1.6)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

afhgf5r5y431vf=>
            

DB pull/backup

Pull/push your production DB into/from your dev DB with:

                $ heroku db:pull $DATABASE_URL
                $ heroku db:push $DATABASE_URL
            

...or dump/restore your DB using the heroku pgbackups addon:

                $ heroku pgbackups:capture
                $ curl -o latest.dump `heroku pgbackups:url`
                $ heroku pgbackups:restore DATABASE 'https://s3.amazonaws.com/me/items/3H0q/latest.dump'
            

connecting to Postgres with a DSN

heroku provide a command to get your DB's Data Source Name

$ heroku pg:credentials DATABASE
Connection info string:
   "dbname=vnb324vndgh23h host=ec2-123-45-678-910.compute-1.amazonaws.com port=6212 user=user1234 password=abcd123 sslmode=require"
            

This info is already in your environment.

https://github.com/enru/dsnfromenv

require 'enru/dsnfromenv.php';
try {
    $dsn = new enru\DsnFromEnv();
    $dbh = new PDO($dsn->parse());
} 
catch (PDOException $e) {
    print "Error!: " . $e->getMessage() . "
"; die(); }

Deploying to Heroku

Deploying to heroku is done using git. A simple push is all that is required.

                $ git push origin master
                Counting objects: 5, done.
                Delta compression using up to 2 threads.
                Compressing objects: 100% (3/3), done.
                Writing objects: 100% (3/3), 4.39 KiB, done.
                Total 3 (delta 1), reused 0 (delta 0)
                -----> PHP app detected
                -----> Bundling Apache version 2.2.22
                -----> Bundling PHP version 5.3.10
                -----> Discovering process types
                       Procfile declares types -> (none)
                       Default types for PHP   -> web
                -----> Compiled slug size: 9.6MB
                -----> Launching... done, v12
                       http://pacific-cove-5430.herokuapp.com deployed to Heroku

                To git@heroku.com:pacific-cove-5430.git
                   ba90ccb..4323b3d  master -> master
            

How does heroku know this is php?

heroku's buildpack for PHP looks for an index.php file.

If no Procfile the default process for the PHP buildpack is run, which is:
`web: sh boot.sh`

                $ cat boot.sh
                for var in `env|cut -f1 -d=`; do
                echo "PassEnv $var" >> /app/apache/conf/httpd.conf;
                done
                touch /app/apache/logs/error_log
                touch /app/apache/logs/access_log
                tail -F /app/apache/logs/error_log &
                tail -F /app/apache/logs/access_log &
                export LD_LIBRARY_PATH=/app/php/ext
                export PHP_INI_SCAN_DIR=/app/www
                echo "Launching apache"
                exec /app/apache/bin/httpd -DNO_DETACH
            

Buildpacks

using Buildpacks

How a tailor-made platform is created - choice of web-server, compiled PHP modules

                $ heroku create myapp --buildpack https://github.com/some/buildpack.git
            

Set the BUILDPACK_URL to change the buildpack in use.

                $ heroku config:add BUILDPACK_URL=https://github.com/some/buildpack.git -a myapp
            

Example buildpacks:

closing

using a PAAS allows you to focus on development

ability to scale is there if/when needed

easy to move app/sites built in this way

many free/low-cost plans = cheap to execute ideas

good engineering principles encouraged

THE END