Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Twelve-Factor App (and PHP on Heroku)

The Twelve-Factor App (and PHP on Heroku)

Best practices for modern PHP apps. Presented at International PHP Conference Spring Edition 2014 in Berlin, Germany.

David Zuelke

June 03, 2014
Tweet

More Decks by David Zuelke

Other Decks in Programming

Transcript

  1. THE TWELVE-FACTOR APP
    Best Practices for Modern PHP Applications

    View Slide

  2. David Zuelke

    View Slide

  3. David Zülke

    View Slide

  4. View Slide

  5. View Slide

  6. @dzuelke

    View Slide

  7. “The Twelve-Factor App”
    is
    a manifesto,
    a methodology,
    a condensed collection of experiences.

    View Slide

  8. Its goals are
    scalability,
    maintainability,
    portability.

    View Slide

  9. I. CODEBASE
    One codebase, many deploys.

    View Slide

  10. I. CODEBASE
    One codebase, many deploys.
    Git, Mercurial, SVN, even CVS are okay.
    A samba share is never okay.
    Neither are floppy disks.

    View Slide

  11. II. DEPENDENCIES
    Applications have explicitly declared dependencies.

    View Slide

  12. II. DEPENDENCIES
    Applications have explicitly declared dependencies.
    $  cat  composer.json
    {
           "require":  {
                   "php":  ">=5.3.3",
                   "ext-­‐mcrypt":  "*",
                   "symfony/symfony":  "~2.4.6",
                   "doctrine/orm":  "~2.2,>=2.2.3",
                   "doctrine/doctrine-­‐bundle":  "~1.2",
                   "twig/extensions":  "~1.0",
                   "symfony/monolog-­‐bundle":  "~2.4"
           }
    }

    View Slide

  13. III. CONFIGURATION
    Store config in the environment.

    View Slide

  14. III. CONFIGURATION
    Store config in the environment.
    Assumption:
    same code but different configuration per deployment target

    View Slide

  15. III. CONFIGURATION
    Store config in the environment.
    $transport  =  Swift_SmtpTransport::newInstance(
           getenv('EMAIL_HOST'),  getenv('EMAIL_PORT')?:25
    )
           -­‐>setUsername(getenv('EMAIL_USERNAME'))
           -­‐>setPassword(getenv('EMAIL_PASSWORD'))
    ;
    Assumption:
    same code but different configuration per deployment target

    View Slide

  16. V. BUILD, RELEASE, RUN
    A build step vendors dependencies, prepares assets, etc.
    A release step creates a package from build and config.
    A runtime step executes, without special knowledge.

    View Slide

  17. V. BUILD, RELEASE, RUN
    A build step vendors dependencies, prepares assets, etc.
    A release step creates a package from build and config.
    A runtime step executes, without special knowledge.

    View Slide

  18. X. DEV/PROD PARITY
    Keep dev, stage and prod envs as similar as possible.

    View Slide

  19. X. DEV/PROD PARITY
    Keep dev, stage and prod envs as similar as possible.
    SQLite ≠ MySQL
    Apache ≠ Nginx
    File based sessions ≠ Redis based sessions

    View Slide

  20. X. DEV/PROD PARITY
    Keep dev, stage and prod envs as similar as possible.
    SQLite ≠ MySQL
    Apache ≠ Nginx
    File based sessions ≠ Redis based sessions
    If apt-­‐get or brew don't get the job done:
    Vagrant is always your friend!

    View Slide

  21. XI. LOGGING
    Treat your logs as a stream of events.

    View Slide

  22. XI. LOGGING
    Treat your logs as a stream of events.
    Stop rotating logs and so forth in your app.
    Let the runtime worry about it.
    Log to STDOUT/STDERR.
    Centrally archive it.

    View Slide

  23. XII. ADMIN PROCESSES
    Management tasks like DB migrations are one-off processes.

    View Slide

  24. XII. ADMIN PROCESSES
    Management tasks like DB migrations are one-off processes.
    The same release,
    the same config,
    the same code!

    View Slide

  25. PHP ON HEROKU
    Putting it all together!

    View Slide

  26. $  heroku  create
    $  git  push  heroku  master
    -­‐-­‐-­‐-­‐-­‐>  PHP  app  detected
    -­‐-­‐-­‐-­‐-­‐>  Setting  up  runtime  environment...
                 -­‐  PHP  5.5.12
                 -­‐  Apache  2.4.9
                 -­‐  Nginx  1.4.6
    -­‐-­‐-­‐-­‐-­‐>  Installing  PHP  extensions:
                 -­‐  opcache  (automatic;  bundled)
                 -­‐  memcached  (composer.json;  downloaded)
                 -­‐  intl  (composer.json;  bundled)
                 -­‐  newrelic  (add-­‐on  detected;  downloaded)
    -­‐-­‐-­‐-­‐-­‐>  Installing  dependencies...
                 Composer  version  05d991  2014-­‐04-­‐29  12:36:19
                 Loading  composer  repositories  with  package  information
                 Installing  dependencies  from  lock  file
                     -­‐  Installing  psr/log  (1.0.0)
                         Loading  from  cache
                 
                     -­‐  Installing  monolog/monolog  (1.9.1)
                         Loading  from  cache
                 
                 Generating  optimized  autoload  files

    View Slide

  27. DEMO TIME!

    View Slide

  28. DEV/PROD PARITY

    View Slide

  29. heroku-­‐python-­‐app  $  cat  Procfile
    web:  gunicorn  hello:app

    View Slide

  30. heroku-­‐ruby-­‐app  $  cat  Procfile
    web:  bundle  exec  unicorn  -­‐p  $PORT  -­‐c  ./config/unicorn.rb

    View Slide

  31. heroku-­‐java-­‐app  $  cat  Procfile
    web:  java  -­‐jar  target/dependency/jetty-­‐runner.jar  -­‐-­‐port  $PORT  
    target/*.war

    View Slide

  32. heroku-­‐php-­‐app  $  cat  Procfile
    web:  php  -­‐S  0.0.0.0:$PORT

    View Slide

  33. PHP needs a dedicated web server

    View Slide

  34. heroku-­‐php-­‐app  $  cat  Procfile
    web:  vendor/bin/heroku-­‐php-­‐nginx
    heroku-­‐php-­‐app  $  composer  require  -­‐-­‐dev  heroku/heroku-­‐
    buildpack-­‐php
    ./composer.json  has  been  updated
    Loading  composer  repositories  with  package  information
    Updating  dependencies  (including  require-­‐dev)
       -­‐  Installing  heroku/heroku-­‐buildpack-­‐php  (v15)
           Loading  from  cache
    Writing  lock  file
    Generating  autoload  files

    View Slide

  35. (only needed if you want to run things locally)

    View Slide

  36. heroku-­‐php-­‐app  $  foreman  start
    17:47:26  web.1    |  started  with  pid  70338
    17:47:26  web.1    |  Booting  on  port  5000...
    17:47:26  web.1    |  Using  PHP-­‐FPM  configuration  file  'vendor/
    heroku/heroku-­‐buildpack-­‐php/conf/php/php-­‐fpm.conf'
    17:47:26  web.1    |  Using  PHP  configuration  (php.ini)  file  
    'vendor/heroku/heroku-­‐buildpack-­‐php/conf/php/php.ini'
    17:47:26  web.1    |  Using  Nginx  server-­‐level  configuration  
    include  'vendor/heroku/heroku-­‐buildpack-­‐php/conf/nginx/
    default_include.conf'
    17:47:27  web.1    |  Using  Nginx  configuration  file  'vendor/
    heroku/heroku-­‐buildpack-­‐php/conf/nginx/heroku.conf.php'
    17:47:27  web.1    |  Interpreting  vendor/heroku/heroku-­‐buildpack-­‐
    php/conf/nginx/heroku.conf.php  to  heroku.conf
    17:47:27  web.1    |  Starting  log  redirection...
    17:47:27  web.1    |  Starting  php-­‐fpm...
    17:47:27  web.1    |  Starting  nginx...
    17:47:27  web.1    |  [29-­‐Apr-­‐2014  17:47:27]  NOTICE:  [pool  www]  
    'user'  directive  is  ignored  when  FPM  is  not  running  as  root
    17:47:27  web.1    |  [29-­‐Apr-­‐2014  17:47:27]  NOTICE:  [pool  www]  
    'user'  directive  is  ignored  when  FPM  is  not  running  as  root
    17:47:27  web.1    |  [29-­‐Apr-­‐2014  17:47:27]  NOTICE:  fpm  is  
    running,  pid  70379
    17:47:27  web.1    |  [29-­‐Apr-­‐2014  17:47:27]  NOTICE:  ready  to  
    handle  connections

    View Slide

  37. ONE MORE THING...

    View Slide

  38. heroku-­‐php-­‐app  $  git  rm  Procfile
    heroku-­‐php-­‐app  $  hhvm  `which  composer`  require  hhvm  3.0.1
    ./composer.json  has  been  updated
    Loading  composer  repositories  with  package  information
    Updating  dependencies  (including  require-­‐dev)
    Nothing  to  install  or  update
    Generating  autoload  files
    heroku-­‐php-­‐app  $  git  add  composer.*
    heroku-­‐php-­‐app  $  git  ci  -­‐m  'use  HHVM'
    heroku-­‐php-­‐app  $  git  push  heroku  master
    -­‐-­‐-­‐-­‐-­‐>  PHP  app  detected
    -­‐-­‐-­‐-­‐-­‐>  Detected  request  for  HHVM  3.0.1  in  composer.json.
    -­‐-­‐-­‐-­‐-­‐>  Setting  up  runtime  environment...
                 -­‐  HHVM  3.0.1
                 -­‐  Apache  2.4.9
                 -­‐  Nginx  1.4.6
    -­‐-­‐-­‐-­‐-­‐>  Building  runtime  environment...
                 NOTICE:  No  Procfile,  defaulting  to  'web:  vendor/bin/
    heroku-­‐hhvm-­‐apache2'

    View Slide

  39. !e End

    View Slide

  40. THE TWELVE-FACTOR APP
    Further reading:
    http://12factor.net/
    http://devcenter.heroku.com/categories/php
    I'm @dzuelke, thank you for listening :)

    View Slide