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

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

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

Presentation given at Symfony Live Berlin 2014 in Berlin, Germany.

D6ccd6409910643d05ddaea3b2cd6f13?s=128

David Zuelke

October 30, 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, with

    the same configuration as on Heroku, instead of your good old VirtualHost based solution)
  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. YET ANOTHER THING...

  41. GET A FREE HEROKU T-SHIRT!

  42. The End

  43. THE TWELVE-FACTOR APP Thanks for listening! Contact: @dzuelke & dz@heroku.com