Write 12-Factor PHP Apps - And Be Loved By DevOps

Today we want to focus on the app, not on the operations involved by running a zero-downtime, scalable, resilient (web) application. DevOps should help us creating a culture where Developers and Operations work together to get the applications deployed. As a Developer, it all starts by developing applications using the correct principles to make the app easily deployable, scalable, and resilient. If you are a PHP developer, use the following 12-factor principles and you'll be loved by your DevOps team.

1. Codebase

"One codebase tracked in revision control, many deploys". This is the principle everyone should already be doing. You need to make sure you have one single source of truth for your codebase, which means using a version control repository like git.

2. Dependencies

"Explicitly declare and isolate dependencies". To achieve this, you will need to apply dependency management. Your code should be deployed together with all the dependencies it needs. It's bad practice to include a copy of the dependencies in your version control, so installing dependencies should really happen during deployment. In PHP you can use composer, which basically allows you to create a list of dependencies that needs to be downloaded and installed during the deployment of the application.

3. Config

"Store config in the environment". You often see developers storing configs and credentials in the codebase in version control, which means that just before the application they just might have to change a few configuration variables. To avoid this, configure your configuration variables in the environment, and in your PHP config, use the getenv() function to read config settings and credentials.

4. Backing Services

"Treat backing services as attached resources". It shouldn't make a difference for the app whether the database is local or remote. If operations wants to change the instance where the database is running, it should be seamless. In practice, make sure you use URLs (e.g. mysql://user@pass:host/db) to connect to your underlying resources, don't connect locally over a Unix Socket.

5. Build, Release, Run

"Strictly separate build and run stages". To build your application, you can use Composer. To Release and Run you app, you should have a platform in place. A decent Platform will allow you to push your code straight to a pool of dev/staging/production servers. PaaS Providers like Heroku, Amazon Elastic Beanstalk, or software like Deis (Dockerbased) allow you to use their command line utilities or git push to send your code to the server and switch the current running app with the newest version. This also allows for quick rollback and zero-downtime deployments. See also my other article about Dokku.

6. Processes

"Execute the app as one or more stateless processes". Your application needs to be stateless, isolated, and independent from other processes. They cannot share anything. This way you can horizontally scale your processes independently from each other. You will have to make sure that a visitor can hit any webserver in the pool, so it's best practice to save your session data in a persistent store, outside the application. This can be Memcached/Redis or even MySQL.

7. Port Binding

"Export services via port binding". In general this will be done by nginx or Apache httpd, which will have a php module to execute your code. This is how it has been done for years. If you want to use PHP and have the port binding in your application layer, you can take a look at ReactPHP.

8. Concurrency

"Scale out via the process model". To do this, we can add different processes to do different tasks. Let's say you want to send e-mails, run a recurring job, or work with triggers. You don't want to do this on your web process, but on a separate worker process. If you then want to run backend processes, you will push a message to a queue system like RabbitMQ, PHP Resque or Amazon SQS. One of your worker process will pick up this message and process it. You can scale your worker processes the same way you scale your web processes. When demand is high, you (automatically) add extra instances.

9. Disposability

"Maximize robustness with fast startup and graceful shutdown". This is important when you want to scale-out, or you are deploying a new version of your application. You should strive to minimal startup time of your web application. If you are not doing anything strange, this should be already the case. Keep also in mind that hardware and software can fail, so you should build your application in a way to handle unexpected, non-graceful terminations (i.e. using message queues).

10. Dev/Prod Paritity

"Keep development, staging, and production as similar as possible". There are a lot of solutions nowadays that can help you to keep dev and prod environments as identical as possible. Take a look at Docker to create a local environment that mirrors the production environment. In some platforms you can now deploy your local Docker container to staging and production. Instead of shipping your code, you ship the whole binary.

11. Logs

"Treat logs as event streams". Rather than writing your log files to the local disk, treat it as a stream of events. You can use PHP Stream, which is implemented in the popular frameworks, like Zend Log Writers.

12. Admin Processes

"Run admin/management tasks as one-off processes". The best way is to create a scripts/ folder in your application repository to keep all your custom one-off processes. For database migrations, it's better to use a tool. Phinx is one example of a tool that can do this for you.

Conclusion

If you develop your (web) app using these principles, it will be a lot easier to maintain the infrastructure for your applications. DevOps people will love you for doing this. Your application can now be easily deployed to the Cloud or an on-premise platform like Deis or Cloudify.

Edward Viaene is the co-founder of in4it.io. We tell all our customers to use the 12-Factor principles to be able to run the app on a resilient, zero-downtime, scalable infrastructure.

Edward Viaene
Published on August 12, 2015