The Twelve-Factor App: Best Practices for Modern PHP Apps

The Twelve-Factor App: Best Practices for Modern PHP Apps

Presentation given at International PHP Conference 2014 in Munich, Germany.

D6ccd6409910643d05ddaea3b2cd6f13?s=128

David Zuelke

October 28, 2014
Tweet

Transcript

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

  2. David Zuelke

  3. None
  4. dz@heroku.com

  5. @dzuelke

  6. “The Twelve-Factor App” ! ! !

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

    collection of experiences.
  8. Its goals are scalability, maintainability, portability.

  9. 12factor.net

  10. 4/12 MAIN FACTORS, CODE ACCORDINGLY I. Codebase
 From one codebase,

    perform many deploys to staging, prod, ... II. Dependencies
 Your application explicitly declares userland and platform deps. III. Configuration
 Read from $_ENV: API keys, database credentials, SMTP hosts, ... XI. Logging
 file_put_contents("php://stderr",  "Yay  log");
  11. II. DEPENDENCIES Applications have explicitly declared dependencies.

  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"          }   }
  13. III. CONFIGURATION Store config in the environment.

  14. III. CONFIGURATION Store config in the environment. Assumption: same code

    but different configuration per deployment target
  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
  16. TIME FOR A DEPLOY! It's as easy as pie.

  17. $  heroku  create   $  git  push  heroku  master  

    -­‐-­‐-­‐-­‐-­‐>  PHP  app  detected   -­‐-­‐-­‐-­‐-­‐>  Setting  up  runtime  environment...                -­‐  PHP  5.5.16                -­‐  Apache  2.4.10                -­‐  Nginx  1.6.0   -­‐-­‐-­‐-­‐-­‐>  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-­‐10-­‐28  12:36:19                Loading  composer  repositories  with  package  information                Installing  dependencies  from  lock  file                    -­‐  Installing  monolog/monolog  (1.9.1)                        Loading  from  cache                              Generating  optimized  autoload  files   -­‐-­‐-­‐-­‐-­‐>  Discovering  process  types                Procfile  declares  types  -­‐>  web   -­‐-­‐-­‐-­‐-­‐>  Compressing...  done,  57.4MB   -­‐-­‐-­‐-­‐-­‐>  Launching...  done,  v3                http://your-­‐php-­‐app.herokuapp.com/  deployed  to  Heroku
  18. what happened there?

  19. 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.
  20. 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.
  21. 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.
  22. XII. ADMIN PROCESSES Management tasks like DB migrations are one-off

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

    processes. The same release, the same config, the same code!
  24. DEMO TIME!

  25. http://start.heroku.com/php & http://devcenter.heroku.com/categories/php

  26. X. DEV/PROD PARITY Keep dev, stage and prod envs as

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

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

    similar as possible. SQLite ≠ MySQL Apache ≠ Nginx File based sessions ≠ Redis based sessions
  29. 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 on your box: Vagrant is always your friend!
  30. DEV/PROD PARITY

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

  32. heroku-­‐ruby-­‐app  $  cat  Procfile   web:  bundle  exec  unicorn  -­‐p

     $PORT  -­‐c  ./config/unicorn.rb
  33. heroku-­‐java-­‐app  $  cat  Procfile   web:  java  -­‐jar  target/dependency/jetty-­‐runner.jar  -­‐-­‐port

     $PORT   target/*.war
  34. heroku-­‐php-­‐app  $  cat  Procfile   web:  php  -­‐S  0.0.0.0:$PORT

  35. PHP needs a dedicated web server

  36. 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  (v43)          Loading  from  cache   ! Writing  lock  file   Generating  autoload  files   ! heroku-­‐php-­‐app  $  foreman  start   14:30:45  web.1  |  started  with  pid  11175   14:30:46  web.1  |  Booting  on  port  5000...   14:30:46  web.1  |  Using  PHP-­‐FPM  configuration  include  'fpm.conf'   14:30:46  web.1  |  Starting  php-­‐fpm...   14:30:46  web.1  |  Starting  nginx...   14:30:46  web.1  |  [28-­‐Oct-­‐2014  14:30:46]  NOTICE:  [pool  www]   'user'  directive  is  ignored  when  FPM  is  not  running  as  root   14:30:46  web.1  |  [28-­‐Oct-­‐2014  14:30:46]  NOTICE:  [pool  www]   'user'  directive  is  ignored  when  FPM  is  not  running  as  root
  37. (only needed if you want to run things locally)

  38. ONE MORE THING...

  39. heroku-­‐php-­‐app  $  git  rm  Procfile   heroku-­‐php-­‐app  $  hhvm  `which

     composer`  require  hhvm  ~3.2   ./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.2.0  in  composer.json.   -­‐-­‐-­‐-­‐-­‐>  Setting  up  runtime  environment...                -­‐  HHVM  3.2.0                -­‐  Apache  2.4.10                -­‐  Nginx  1.6.0   -­‐-­‐-­‐-­‐-­‐>  Building  runtime  environment...                NOTICE:  No  Procfile,  defaulting  to  'web:  vendor/bin/ heroku-­‐hhvm-­‐apache2'   -­‐-­‐-­‐-­‐-­‐>  Compressing...  done,  77.4MB   -­‐-­‐-­‐-­‐-­‐>  Launching...  done,  v3                http://your-­‐hhvm-­‐app.herokuapp.com/  deployed  to  Heroku
  40. The End

  41. THE TWELVE- FACTOR APP Thanks for listening! Contact: @dzuelke &

    dz@heroku.com. rate my talk on joind.in!