$30 off During Our Annual Pro Sale. View Details »

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.

David Zuelke

October 30, 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. View Slide

  4. View Slide

  5. @dzuelke

    View Slide

  6. “The Twelve-Factor App”

    !
    !
    !

    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. 12factor.net

    View Slide

  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");

    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. TIME FOR A DEPLOY!
    It's as easy as pie.

    View Slide

  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

    View Slide

  18. what happened there?

    View Slide

  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.

    View Slide

  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.

    View Slide

  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.

    View Slide

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

    View Slide

  23. XII. ADMIN PROCESSES
    Management tasks like DB migrations are one-off processes.
    The same release,

    the same config,

    the same code!

    View Slide

  24. DEMO TIME!

    View Slide

  25. http://start.heroku.com/php

    &

    http://devcenter.heroku.com/categories/php

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

  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!

    View Slide

  30. DEV/PROD PARITY

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  35. PHP needs a dedicated web server

    View Slide

  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

    View Slide

  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)

    View Slide

  38. ONE MORE THING...

    View Slide

  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

    View Slide

  40. YET ANOTHER THING...

    View Slide

  41. GET A FREE HEROKU T-SHIRT!

    View Slide

  42. The End

    View Slide

  43. THE TWELVE-FACTOR APP
    Thanks for listening! Contact: @dzuelke & [email protected]

    View Slide