Slide 1

Slide 1 text

@mheap at #mwphp17 WordPress as a 12 Factor App

Slide 2

Slide 2 text

@mheap @mheap

Slide 3

Slide 3 text

@mheap Chris AKA @tweetingsherry

Slide 4

Slide 4 text

@mheap This talk is not a step by step how-to guide

Slide 5

Slide 5 text

@mheap It’s designed to show you what’s possible

Slide 6

Slide 6 text

@mheap What is a 12 Factor Application?

Slide 7

Slide 7 text

@mheap WordPress as a 12 Factor Application

Slide 8

Slide 8 text

@mheap Ready?

Slide 9

Slide 9 text

@mheap Go!

Slide 10

Slide 10 text

@mheap What is a 12 Factor Application?

Slide 11

Slide 11 text

@mheap The Twelve-Factor App https://12factor.net/

Slide 12

Slide 12 text

@mheap Codebase One codebase tracked in revision control, many deploys

Slide 13

Slide 13 text

@mheap Dependencies Explicitly declare and isolate dependencies

Slide 14

Slide 14 text

@mheap Config Store config in the environment

Slide 15

Slide 15 text

@mheap Backing Services Treat backing services as attached resources

Slide 16

Slide 16 text

@mheap Build, Release, Run Strictly separate build and run stages

Slide 17

Slide 17 text

@mheap Processes Execute the app as one or more stateless processes

Slide 18

Slide 18 text

@mheap Port Binding Export services via port binding

Slide 19

Slide 19 text

@mheap Concurrency Scale out via the process model

Slide 20

Slide 20 text

@mheap Disposability Maximize robustness with fast startup and graceful shutdown

Slide 21

Slide 21 text

@mheap Dev/Prod Parity Keep development, staging, and production as similar as possible

Slide 22

Slide 22 text

@mheap Logs Treat logs as event streams

Slide 23

Slide 23 text

@mheap Admin Processes Run admin/management tasks as one-off processes

Slide 24

Slide 24 text

@mheap 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 The Twelve-Factor App

Slide 25

Slide 25 text

@mheap Why is the Codebase important? 1 /12

Slide 26

Slide 26 text

@mheap Add to version control $ git init $ git add . $ git commit -m "Initial Commit"

Slide 27

Slide 27 text

@mheap One codebase Development Staging Production

Slide 28

Slide 28 text

@mheap No web based updates Update locally Commit to version control Build and deploy

Slide 29

Slide 29 text

@mheap Disable Automatic Updates

Slide 30

Slide 30 text

@mheap Disable Online Editor

Slide 31

Slide 31 text

@mheap Change file ownership $ chown : -R * $ chown www-data:www-data wp-content/uploads

Slide 32

Slide 32 text

@mheap

Slide 33

Slide 33 text

@mheap Why are Dependencies important? 2 /12

Slide 34

Slide 34 text

@mheap commit 599d45019f92f6cc191e39014674caeeedcd87b0 Author: Scott Taylor Date: Sat Aug 27 03:49:28 2016 +0000 Bootstrap: add `composer.lock` and `src/wp-vendor` files. Nothing is using this code yet, just going through the motions. Ignore the files in `src/wp-vendor/composer` that will explode in PHP 5.2. See #36335. Built from https://develop.svn.wordpress.org/trunk@38394 git-svn-id: http://core.svn.wordpress.org/trunk@38335 1a063a9b-81f0-0310-95a4-ce76da25c4cd WordPress’ composer.json :)

Slide 35

Slide 35 text

@mheap commit f1631f4e03303945c5c47682a36c184542cf094b Author: Scott Taylor Date: Wed Aug 31 20:36:30 2016 +0000 Bootstrap: goodnight sweet prince. See #36335. Built from https://develop.svn.wordpress.org/trunk@38480 git-svn-id: http://core.svn.wordpress.org/trunk@38421 1a063a9b-81f0-0310-95a4-ce76da25c4cd WordPress’ composer.json :(

Slide 36

Slide 36 text

@mheap @mheap

Slide 37

Slide 37 text

@mheap Do it yourself!

Slide 38

Slide 38 text

@mheap { "packages": { "mheap/wordpress": { "v4.7.3": { "name": "mheap/wordpress", "dist" : { "url" : "http://wordpress.org/wordpress-4.7.3.zip", "type": "zip" }, "source" : { "url" : "https://github.com/WordPress/WordPress", "type" : "git", "reference": "4.7.3" }, "type": "package", "version": "4.7.3" } } } }

Slide 39

Slide 39 text

@mheap { "config": { "secure-http": false }, "repositories" : [ { "type" : "composer", "url" : "http://example.com" } ], "require" : { "mheap/wordpress" : ">=4.7.3" } }

Slide 40

Slide 40 text

@mheap . ├── composer.json ├── composer.lock └── vendor ├── autoload.php ├── composer │ ├── ClassLoader.php │ ├── LICENSE │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_real.php │ ├── autoload_static.php │ └── installed.json └── mheap └── wordpress ├── └── wp-config.php

Slide 41

Slide 41 text

@mheap Do it yourself! (Take Two)

Slide 42

Slide 42 text

@mheap https://getcomposer.org/doc/articles/custom-installers.md

Slide 43

Slide 43 text

@mheap { "packages": { "mheap/wordpress": { "v4.7.3": { "name": "mheap/wordpress", "dist" : { "url" : "http://wordpress.org/wordpress-4.7.3.zip", "type": "zip" }, "source" : { "url" : "https://github.com/WordPress/WordPress", "type" : "git", "reference": "4.7.3" }, "type": "wordpress-core", "version": "4.7.3", "require": { "johnpbloch/wordpress-core-installer": "~0.1" } } } } }

Slide 44

Slide 44 text

@mheap . ├── composer.json ├── composer.lock ├── vendor │ ├── autoload.php │ ├── composer │ └── johnpbloch └── wordpress ├── └── wp-config.php

Slide 45

Slide 45 text

@mheap Do it yourself! (Take Three, the real way)

Slide 46

Slide 46 text

@mheap { "require": { "johnpbloch/wordpress": ">=4.7.3" } }

Slide 47

Slide 47 text

@mheap . ├── composer.json ├── composer.lock ├── vendor │ ├── autoload.php │ ├── composer │ └── johnpbloch └── wordpress ├── └── wp-config.php

Slide 48

Slide 48 text

@mheap http://example.com/wordpress @mheap

Slide 49

Slide 49 text

@mheap Remove /wordpress/ mkdir web mv wordpress/index.php web mv wordpress/wp-config.php .

Slide 50

Slide 50 text

@mheap . ├── composer.json ├── composer.lock ├── vendor ├── web │ └── index.php ├── wordpress └── wp-config.php

Slide 51

Slide 51 text

@mheap Edit wp-config.php /* That's all, stop editing! Happy blogging. */ /** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/'); /** Sets up WordPress vars and included files. */ require_once(ABSPATH . 'wp-settings.php');

Slide 52

Slide 52 text

@mheap Edit wp-config.php /* That's all, stop editing! Happy blogging. */ /** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/../wordpress'); /** Sets up WordPress vars and included files. */ require_once(ABSPATH . 'wp-settings.php');

Slide 53

Slide 53 text

@mheap Edit index.php define('WP_USE_THEMES', true); /** Loads the WordPress Environment and Template */ require( dirname( __FILE__ ) . '/wp-blog-header.php' );

Slide 54

Slide 54 text

@mheap Edit index.php define('WP_USE_THEMES', true); /** Loads the WordPress Environment and Template */ require( dirname( __FILE__ ) . '/../wordpress/wp-blog- header.php' );

Slide 55

Slide 55 text

@mheap Control wp-content mv wordpress/wp-content web

Slide 56

Slide 56 text

@mheap Edit wp-config.php /** Absolute path to the WordPress directory. */ if ( !defined('ABSPATH') ) define('ABSPATH', dirname(__FILE__) . '/wordpress'); define('WP_HOME', 'http://example.com'); define('CONTENT_DIR', '/wp-content'); define('WP_CONTENT_DIR', __DIR__ . '/web' . CONTENT_DIR); define('WP_CONTENT_URL', WP_HOME . CONTENT_DIR); /** Sets up WordPress vars and included files. */ require_once(ABSPATH . 'wp-settings.php');

Slide 57

Slide 57 text

@mheap Create .gitignore vendor wordpress

Slide 58

Slide 58 text

@mheap . ├── composer.json ├── composer.lock ├── vendor ├── web │ ├── index.php │ └── wp-content │ ├── plugins │ ├── themes │ └── uploads ├── wordpress └── wp-config.php

Slide 59

Slide 59 text

@mheap . ├── composer.json ├── composer.lock ├── web │ ├── index.php │ └── wp-content │ ├── plugins │ ├── themes │ └── uploads └── wp-config.php

Slide 60

Slide 60 text

@mheap . ├── composer.json ├── composer.lock ├── web │ ├── index.php │ └── wp-content │ ├── plugins │ ├── themes │ └── uploads └── wp-config.php

Slide 61

Slide 61 text

@mheap @mheap

Slide 62

Slide 62 text

@mheap { "repositories":[ { "type":"composer", "url":"https://wpackagist.org" } ], "require": { "johnpbloch/wordpress": ">=4.7.3" } }

Slide 63

Slide 63 text

@mheap { "repositories":[ { "type":"composer", "url":"https://wpackagist.org" } ], "require": { "johnpbloch/wordpress": ">=4.7.3", "wpackagist-plugin/captcha":">=3.9", "wpackagist-theme/hueman":">=3.3.7" } }

Slide 64

Slide 64 text

@mheap Edit .gitignore vendor wordpress wp-content/* !wp-content/uploads/

Slide 65

Slide 65 text

@mheap │ ├── customize.php │ ├── edit-comments.php │ ├── edit-form-advanced.php │ ├── edit-form-comment.php │ ├── edit-link-form.php │ ├── edit-tag-form.php │ ├── edit-tags.php │ ├── edit.php │ ├── export.php │ ├── freedoms.php │ ├── images │ │ ├── align-center-2x.png │ │ ├── align-center.png │ │ ├── align-left-2x.png │ │ ├── align-left.png │ │ ├── align-none-2x.png │ │ ├── align-none.png │ │ ├── align-right-2x.png │ │ ├── align-right.png │ │ ├── arrows-2x.png │ │ ├── arrows.png │ │ ├── browser-rtl.png │ │ ├── browser.png │ │ ├── bubble_bg-2x.gif │ │ ├── bubble_bg.gif │ │ ├── comment-grey-bubble-2x.png │ │ ├── comment-grey-bubble.png │ │ ├── date-button-2x.gif │ │ ├── date-button.gif │ │ ├── generic.png │ │ ├── icons32-2x.png │ │ ├── icons32-vs-2x.png │ │ ├── icons32-vs.png │ │ ├── icons32.png │ │ ├── imgedit-icons-2x.png │ │ ├── imgedit-icons.png │ │ ├── list-2x.png │ │ ├── list.png │ │ ├── loading.gif │ │ ├── marker.png │ │ ├── mask.png │ │ ├── media-button-2x.png │ │ ├── media-button-image.gif │ │ ├── media-button-music.gif │ │ ├── media-button-other.gif │ │ ├── media-button-video.gif │ │ ├── media-button.png │ │ ├── menu-2x.png │ │ ├── menu-vs-2x.png │ │ ├── menu-vs.png │ │ ├── menu.png │ │ ├── no.png │ │ ├── post-formats-vs.png │ │ ├── post-formats.png │ │ ├── post-formats32-vs.png │ │ ├── post-formats32.png │ │ ├── resize-2x.gif │ │ ├── resize-rtl-2x.gif │ │ ├── resize-rtl.gif │ │ ├── resize.gif │ │ ├── se.png │ │ ├── sort-2x.gif │ │ ├── sort.gif │ │ ├── spinner-2x.gif │ │ ├── spinner.gif │ │ ├── stars-2x.png │ │ ├── stars.png │ │ ├── w-logo-blue.png │ │ ├── w-logo-white.png │ │ ├── wheel.png │ │ ├── wordpress-logo-white.svg │ │ ├── wordpress-logo.png │ │ ├── wordpress-logo.svg │ │ ├── wpspin_light-2x.gif │ │ ├── wpspin_light.gif │ │ ├── xit-2x.gif │ │ ├── xit.gif │ │ └── yes.png │ ├── import.php │ ├── includes │ │ ├── admin-filters.php │ │ ├── admin.php │ │ ├── ajax-actions.php │ │ ├── bookmark.php │ │ ├── class-automatic-upgrader-skin.php │ │ ├── class-bulk-plugin-upgrader-skin.php │ │ ├── class-bulk-theme-upgrader-skin.php │ │ ├── class-bulk-upgrader-skin.php │ │ ├── class-core-upgrader.php │ │ ├── class-file-upload-upgrader.php │ │ ├── class-ftp-pure.php │ │ ├── class-ftp-sockets.php │ │ ├── class-ftp.php │ │ ├── class-language-pack-upgrader-skin.php │ │ ├── class-language-pack-upgrader.php │ │ ├── class-pclzip.php │ │ ├── class-plugin-installer-skin.php │ │ ├── class-plugin-upgrader-skin.php │ │ ├── class-plugin-upgrader.php │ │ ├── class-theme-installer-skin.php │ │ ├── class-theme-upgrader-skin.php │ │ ├── class-theme-upgrader.php │ │ ├── class-walker-category-checklist.php │ │ ├── class-walker-nav-menu-checklist.php │ │ ├── class-walker-nav-menu-edit.php │ │ ├── class-wp-ajax-upgrader-skin.php │ │ ├── class-wp-automatic-updater.php │ │ ├── class-wp-comments-list-table.php │ │ ├── class-wp-filesystem-base.php │ │ ├── class-wp-filesystem-direct.php │ │ ├── class-wp-filesystem-ftpext.php │ │ ├── class-wp-filesystem-ftpsockets.php │ │ ├── class-wp-filesystem-ssh2.php │ │ ├── class-wp-importer.php │ │ ├── class-wp-internal-pointers.php │ │ ├── class-wp-links-list-table.php │ │ ├── class-wp-list-table-compat.php │ │ ├── class-wp-list-table.php │ │ ├── class-wp-media-list-table.php │ │ ├── class-wp-ms-sites-list-table.php │ │ ├── class-wp-ms-themes-list-table.php │ │ ├── class-wp-ms-users-list-table.php │ │ ├── class-wp-plugin-install-list-table.php │ │ ├── class-wp-plugins-list-table.php │ │ ├── class-wp-post-comments-list-table.php │ │ ├── class-wp-posts-list-table.php │ │ ├── class-wp-press-this.php │ │ ├── class-wp-screen.php │ │ ├── class-wp-site-icon.php │ │ ├── class-wp-terms-list-table.php │ │ ├── class-wp-theme-install-list-table.php │ │ ├── class-wp-themes-list-table.php │ │ ├── class-wp-upgrader-skin.php │ │ ├── class-wp-upgrader.php │ │ ├── class-wp-users-list-table.php │ │ ├── comment.php │ │ ├── continents-cities.php │ │ ├── credits.php │ │ ├── dashboard.php │ │ ├── deprecated.php │ │ ├── edit-tag-messages.php │ │ ├── export.php │ │ ├── file.php │ │ ├── image-edit.php │ │ ├── image.php │ │ ├── import.php │ │ ├── list-table.php │ │ ├── media.php │ │ ├── menu.php │ │ ├── meta-boxes.php │ │ ├── misc.php │ │ ├── ms-admin-filters.php │ │ ├── ms-deprecated.php │ │ ├── ms.php . ├── composer.json ├── composer.lock ├── web │ ├── index.php │ └── wp-content └── wp-config.php (1762 files)

Slide 66

Slide 66 text

@mheap Bedrock https://roots.io/bedrock/

Slide 67

Slide 67 text

@mheap

Slide 68

Slide 68 text

@mheap Why is Config important? 3 /12

Slide 69

Slide 69 text

@mheap wp-config.php Committed to git Hard to change between environments

Slide 70

Slide 70 text

@mheap if ($_SERVER['REMOTE_ADDR'] == '82.123.234.12') { define('DB_USER', 'prod_wp'); } else if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') { define('DB_USER', 'root'); }

Slide 71

Slide 71 text

@mheap if ($_SERVER['REMOTE_ADDR'] == '82.123.234.12') { include 'wp-config-staging.php'; } else if ($_SERVER['REMOTE_ADDR'] == '127.0.0.1') { include 'wp-config-dev.php'; }

Slide 72

Slide 72 text

@mheap composer.json { "repositories":[ { "type":"composer", "url":"https://wpackagist.org" } ], "require": { "johnpbloch/wordpress": ">=4.7.3", "wpackagist-plugin/captcha":">=3.9", "wpackagist-theme/hueman":">=3.3.7", "vlucas/phpdotenv": "^2.4" } }

Slide 73

Slide 73 text

@mheap wp-config.php require_once __DIR__.'/vendor/autoload.php'; $dotenv = new Dotenv\Dotenv(__DIR__); $dotenv->load(); /** * The base configuration for WordPress *

Slide 74

Slide 74 text

@mheap .env DB_NAME=wptest DB_USER=user DB_PASSWORD=secret DB_HOST=localhost

Slide 75

Slide 75 text

@mheap wp-config.php /** The name of the database for WordPress */ define('DB_NAME', getenv('DB_NAME')); /** MySQL database username */ define('DB_USER', getenv('DB_USER')); /** MySQL database password */ define('DB_PASSWORD', getenv('DB_PASSWORD')); /** MySQL hostname */ define('DB_HOST', getenv('DB_HOST'));

Slide 76

Slide 76 text

@mheap

Slide 77

Slide 77 text

@mheap Why are Backing Services important? 4 /12

Slide 78

Slide 78 text

@mheap Attached Resources Local or remote Your application doesn’t care

Slide 79

Slide 79 text

@mheap Config Driven Zero code changes Scale up/down at will

Slide 80

Slide 80 text

@mheap Misbehaving Hardware Attach / detach at will No need to redeploy, config only

Slide 81

Slide 81 text

@mheap We do this by default In PHP, everything is a detached service

Slide 82

Slide 82 text

@mheap wp-config.php /** The name of the database for WordPress */ define('DB_NAME', getenv('DB_NAME')); /** MySQL database username */ define('DB_USER', getenv('DB_USER')); /** MySQL database password */ define('DB_PASSWORD', getenv('DB_PASSWORD')); /** MySQL hostname */ define('DB_HOST', getenv('DB_HOST'));

Slide 83

Slide 83 text

@mheap @mheap

Slide 84

Slide 84 text

@mheap

Slide 85

Slide 85 text

@mheap Why is Build, Release, Run important? 5 /12

Slide 86

Slide 86 text

@mheap Build $ composer install $ zip -r app.zip *

Slide 87

Slide 87 text

@mheap Release $ scp app.zip remote-host:~ $ ssh remote-host $ unzip app.zip $ cd /var/www $ mv ~/app releases/20161201 $ ln -s releases/20161201 live_new $ mv -Tf live_new live

Slide 88

Slide 88 text

@mheap Build $ composer install $ fpm -s dir -t rpm -n ${name} -v '$ {version}' .=/var/www/${name} —after- install after-install.sh --after-remove after-remove.sh

Slide 89

Slide 89 text

@mheap Release $ sudo yum upgrade my-app

Slide 90

Slide 90 text

@mheap Run PHP does this for free (Maybe restart php-fpm)

Slide 91

Slide 91 text

@mheap

Slide 92

Slide 92 text

@mheap Why are Processes important? 6 /12

Slide 93

Slide 93 text

@mheap Shared Resources Memory Disk

Slide 94

Slide 94 text

@mheap @mheap

Slide 95

Slide 95 text

@mheap Caveats It only works going forwards

Slide 96

Slide 96 text

@mheap

Slide 97

Slide 97 text

@mheap Why is Port Binding important? 7 /12

Slide 98

Slide 98 text

@mheap PHP-FPM Binds it’s own port Doesn’t talk HTTP

Slide 99

Slide 99 text

@mheap $ php -S localhost:8000 Built in server

Slide 100

Slide 100 text

@mheap ReactPHP Async PHP event loop

Slide 101

Slide 101 text

@mheap

Slide 102

Slide 102 text

@mheap Why is Concurrency important? 8 /12

Slide 103

Slide 103 text

@mheap Scale out via processes Web process Worker process Admin process

Slide 104

Slide 104 text

@mheap PHP-FPM Daemonises 12 Factor app should not write PID file Instead, rely on process manager

Slide 105

Slide 105 text

@mheap

Slide 106

Slide 106 text

@mheap Why is Disposability important? 9 /12

Slide 107

Slide 107 text

@mheap Elastic Scaling

Slide 108

Slide 108 text

@mheap Rapid Deployment

Slide 109

Slide 109 text

@mheap Config Changes

Slide 110

Slide 110 text

@mheap Fast Startup Time

Slide 111

Slide 111 text

@mheap

Slide 112

Slide 112 text

@mheap Why is Dev / Prod parity important? 10/12

Slide 113

Slide 113 text

@mheap Sync your code Follow factors one (codebase) and two (dependencies)

Slide 114

Slide 114 text

@mheap Sync your database wp-sync-db (Free) wp-migrate-db-pro (Paid)

Slide 115

Slide 115 text

@mheap Reducing the gap The time gap The personnel gap The tools gap

Slide 116

Slide 116 text

@mheap Reducing the gap Make the time gap small Make the personnel gap small Make the tools gap small

Slide 117

Slide 117 text

@mheap Releases Time: Hours People: Code Authors Tools: Identical

Slide 118

Slide 118 text

@mheap Jenkins https://jenkins.io/

Slide 119

Slide 119 text

@mheap Trellis https://roots.io/trellis/

Slide 120

Slide 120 text

@mheap Shameless Plug

Slide 121

Slide 121 text

@mheap

Slide 122

Slide 122 text

@mheap Why are Logs important? 11/12

Slide 123

Slide 123 text

@mheap Logs are streams Write to STDOUT Managed by process manager

Slide 124

Slide 124 text

@mheap WordPress can do this define( 'WP_DEBUG_LOG', true );

Slide 125

Slide 125 text

@mheap Spotting patterns Finding specific events in the past. Large-scale graphing of trends Triggering alerts

Slide 126

Slide 126 text

@mheap

Slide 127

Slide 127 text

@mheap Why are Admin processes important? 12/12

Slide 128

Slide 128 text

@mheap update_links.php Updates all posts to switch links from http://example.com to https:// example.com

Slide 129

Slide 129 text

@mheap Ship with app code Deployed in the same package Code reviews and tests

Slide 130

Slide 130 text

@mheap

Slide 131

Slide 131 text

@mheap The Twelve-Factor App https://12factor.net/

Slide 132

Slide 132 text

@mheap Bonus!

Slide 133

Slide 133 text

@mheap wp-cli Comments Menus Posts Users

Slide 134

Slide 134 text

@mheap composer.json Explorer http://composer.json.jolicode.com/

Slide 135

Slide 135 text

https://joind.in/ 20313 @mheap at #mwphp17 Michael Heap @mheap [email protected]