1 of 27

Twelve Factor [Drupal]

Your Path to Cloud-Native

2 of 27

Agenda

#DCCO2019

  • Review the “why” of cloud-native applications
  • Identify limiting factors of Drupal 8 in going cloud-native
  • Introduce the Twelve-Factor App as a model for bridging the divide
  • Explore each factor as it relates to Drupal today and moving forward

3 of 27

Cloud-Native

#DCCO2019

“Cloud-native is an approach to building and running applications that exploits the advantages of the cloud computing delivery model. Cloud-native is about how applications are created and deployed, not where… Cloud-native applications conform to a framework or ‘contract’ designed to maximize resilience through predictable behaviors.”

https://pivotal.io/cloud-native

4 of 27

So...Kubernetes? Containers?

#DCCO2019

This is not a Kubernetes talk.

Containers are great but

use the infrastructure that

makes sense for you.

“Our motivation is to raise awareness of some systemic problems we’ve seen in modern application development, to provide a shared vocabulary for discussing those problems, and to offer a set of broad conceptual solutions to those problems with accompanying terminology.”

5 of 27

Is Drupal 8 Cloud-Native?

#DCCO2019

It can be (that’s why we’re here!)

Drupal is busy shedding technical debt from a legacy web application paradigm; Drupal 8 was a huge step forward.

Cloud-Native is a logical extension of that work.

6 of 27

Twelve-Factor App: A Framework

#DCCO2019

Cloud computing is full of buzz-words; The Twelve-Factor App serves as a simple guide to actionable changes, not just jargon.

Inspired by experience at Heroku.

“The twelve-factor methodology can be applied to apps written in any programming language, and which use any combination of backing services (database, queue, memory cache, etc).”

7 of 27

Factors I and II: Code & Dependencies

#DCCO2019

Factor I: One codebase tracked in revision control, many deploys. Multiple apps in a single codebase should be split into separate services.

Factor II: Explicitly declare and isolate dependencies. We’ve got Composer! (But don’t forget your theme build pipeline, too.)

8 of 27

Factor III: Config

#DCCO2019

Store config in the environment.

In Drupal: Config that changes per environment (e.g., secrets, connection specifics) is injected as environment variables or files.

“In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy.”

9 of 27

Factor III: Config

#DCCO2019

What about environment-specific groups of overrides (e.g., settings.local.php?)

Docker Compose and “Docker-Plus” (DDEV, Lando) allow a declarative option to grouped config.

“In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as ‘environments’, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.”

10 of 27

Factor IV: Backing Services

#DCCO2019

“The code for a twelve-factor app makes no distinction between local and third party services. To the app, both are attached resources, accessed via a URL or other locator/credentials stored in the config.”

“Resources can be attached to and detached from deploys at will.”

Review: How does this interact with Factor III: Config?

11 of 27

Factor IV: Backing Services

#DCCO2019

12 of 27

Factor V: Build, Release, Run

#DCCO2019

Build: Combine codebase (Factor I) and dependencies (Factor II) into an executable bundle (a.k.a., an artifact)

Release: Combine the build with configuration (Factor III)

Run: An executed release in your runtime environment (e.g., Kubernetes, serverless)

13 of 27

Factor V: Build, Release, Run

#DCCO2019

14 of 27

Factor VI: Processes

#DCCO2019

“The app is executed in the execution environment as one or more processes...Twelve-factor processes are stateless and share-nothing.”

Stateless: Any data that needs to persist must be stored in a stateful backing service, typically a database.

Share-Nothing: Each update request is satisfied by a single node (instance).

15 of 27

Factor VI: Processes: Share-Nothing

#DCCO2019

How can we make Drupal more scalable?

Out-of-the-box D8 share-nothing violations?

  • Twig cache → twig_temp
  • public stream wrapper/local filesystem
  • Where does CSS and JS get written?
  • Others?

16 of 27

Factor VI: Processes - Share-Nothing

#DCCO2019

We can use Drupal without local file storage?!

Yes! Drupal and PHP support custom stream wrapper definitions/drivers.

flysystem module +

Service-specific drivers

17 of 27

Factor VI: Processes - Share-Nothing

#DCCO2019

Attached services means accounting for latency.

Object storage is accessed over HTTP; need to account for latency, caching and invalidation.

Areas for improvement here: Image style generation can slow down initial page loads, even when generating HTML; CSS on CDNs doesn’t really work.

18 of 27

Factor VII: Port Binding

#DCCO2019

Export services via port binding.

In a web app world, this is pretty easy, BUT:

  • Consider reverse proxies/CDNs (especially when using stream wrappers)
  • Where’s your TLS termination?
  • How do you handle service discovery? (Think about Factor IV: Backing Services)

19 of 27

Factor VIII: Concurrency

#DCCO2019

Scale out via the process model.

“But I don’t need scaling” - OK, but how about cron? Background processes? Queue workers?

If we do scale, where and how does cron run?

20 of 27

Factor IX: Disposability

#DCCO2019

Maximize robustness with fast startup and graceful shutdown.

How do we handle database/schema updates? (Ideally, these are a separate process.)

Maintenance mode? Bootstrapping?

Is your app fault-tolerant?

21 of 27

Factor IX: Disposability

#DCCO2019

“In their most recent Datadog survey on container use, Datadog noted that containers are now churning 12 times faster than VMs, up from 9x just a year earlier, and 6x two years ago. As a result, the average lifetime of an orchestrated container is now just 12 hours.”

22 of 27

Factor X: Dev-Prod Parity

#DCCO2019

Keep development, staging, and production as similar as possible.

What does “similar” mean to you?

“The twelve-factor developer resists the urge to use different backing services between development and production, even when adapters theoretically abstract away any differences in backing services.”

23 of 27

Factor X: Dev-Prod Parity

#DCCO2019

How close can we get our local environment to production?

What artifact are we building? Can we build and run it locally?

Are adapters sufficient to iron out differences? Are they entirely necessary?

24 of 27

Factor X: Dev-Prod Parity

#DCCO2019

Management aside: How does running backing services locally encourage your developers to expand their skills and understanding?

25 of 27

Factor XI: Logs

#DCCO2019

Treat logs as event streams.

Let’s be honest: Who’s actively watching dblog?

How can we do better?

  • Log aggregation: monolog? stdout?
  • Where do the logs go and who’s watching?
  • Normalizing the payload to JSON?
  • What about logs from cron? Uncaught PHP errors?

26 of 27

Factor XII: Admin Processes

#DCCO2019

“One-off admin processes should be run in an identical environment as the regular long-running processes of the app. They run against a release, using the same codebase and config as any process run against that release. Admin code must ship with application code to avoid synchronization issues.”

How does Symfony Console and Drush 9 help us run one-off admin processes in an identical environment to our web runtime?

27 of 27

Conclusions: How close are we?

#DCCO2019

Drupal 8 (9!) can be cloud-native with a few key tweaks.

  • Filesystem - Can we install without local storage?
  • Ensuring core APIs natively support backing service swapping
  • Making Drupal’s request handling as stateless as possible.