Models of Configuration Management

by Joseph D. Purcell

at DrupalCon Global

July 15, 2020

Who am I?

  • PHP developer since 2004
  • Lead Architect at Bounteous

Who are you?

Did anyone else do this?

application/config/mysql_history.sql


    -- --------------------------------------------------------
    -- Add simple_id
    -- December 23, 2012

    ALTER TABLE `transactions` ADD `simple_id` VARCHAR(255) AFTER `modified`;
            

With Config Management we're all dbadmins.


  $ drush updb
  ---------------- --------------------------------- --------------- -------------------------------------------------------------------------------
   Module           Update ID                         Type            Description
  ---------------- --------------------------------- --------------- -------------------------------------------------------------------------------
   system           8901                              hook_update_n   Update the stored schema data for entity identifier fields.
   layout_builder   override_entity_form_controller   post-update     Clear caches due to addition of service decorator for entity form controller.
  ---------------- --------------------------------- --------------- -------------------------------------------------------------------------------
  ...

  $ drush cex sync
  Differences of the active config to the export directory:
  +------------+-----------------------------------------------------+-----------+
  | Collection | Config                                              | Operation |
  +------------+-----------------------------------------------------+-----------+
  |            | system.all_the_things                               | Update    |
  |            | layout.all_the_things                               | Update    |
  +------------+-----------------------------------------------------+-----------+
  The .yml files in your export directory (../config/sync) will be deleted and replaced with the active config. (yes/no) [yes]:
  >
            

Takeaways:

  1. There are 4 Config Synchronization models.
  2. There are 4 Config Split models.
    • And, there are 5 ways a config entity can be split
  3. There are guidelines for how to choose the right model.

Overview

  1. Principles of Config Management
  2. Config Synchronization Models
  3. Config Split Models
  4. Guidelines for Modeling

I. Principles of Config Management

Principle 1: Manage your config.

Always version your database.
— K. Scott Allen

This means use the config management system, which could be at the site level, install profile level, or core/contrib level.

What is configuration?

Configuration is...

  • Site configurations (site name, performance settings)
  • Schema (content types, fields, etc)
  • Plugin configs (payment methods, SOLR)
  • Content (page manager, block placement)

... it’s a little squishy.

Why does it need managed??

What happens when you don't...

  1. Have you ever made schema changes manually on PROD because you didn’t have a good way to script them?
  2. Have you worked with Magento, WordPress, Oro, or pretty much any framework without an automated config manager?
  3. Have you used Drupal 7 features?

Welcome to the future:
Drupal Configuration Management

Principle 2: Always have clean configuration.

What is clean configuration?

By default, all configuration is managed.


  $ drush cim sync
  $ drush cex sync
            

But, you can make it unmanaged.

Managed vs Unmanaged Configuration

  • Managed: Config that is under version control and deployed, it is imported and exported. (default)
  • Unmanaged: Config that is treated as state in the database, it is ignored by import/export.

Make configuration unmanaged by...

  1. Add the config to config ignore (requires config_ignore)
  2. Add the config to config export ignore (requires a custom config split OR just use config_export_ignore)
  3. Add the config to the allow list (if using config_readonly)
  4. Add default configurations to your install profile, as needed (this is tricky!)
  5. Change role permissions to allow editing that config

Properly managed vs unmanaged settings mean you always have clean configuration.

Clean configuration means: The managed configuration in the database exactly matches that in version control.

GOOD:

  $ drush config-status
   [notice] No differences between DB and sync directory.
            
BAD:

  $ drush config-status
   ----------------------------------------------------- -----------
    Name                                                  State
   ----------------------------------------------------- -----------
    system.site                                           Different
   ----------------------------------------------------- -----------
            

Config that changes needs to be unmanaged

Some examples:

  • Block placement (block.block.*)
  • Modules that are using config instead of state (key/value), e.g. Acquia's Connector which was recently fixed
  • Config you want a site admin to edit live (webform.*, tb_megamenu.menu_config.*)

Principle 3: The default config set is for what is common to all sites.

What is the default config set?

Simply put, it is:


  $settings['config_sync_directory'] = '../config/sync';
            

There is only 1 per site.

By default, all config exports to and imports from here.

Principle 4: Split sets of configuration off the default set per use-case.

A split configuration set might be...

  • An enviornment (e.g. DEV)
  • A site (e.g. in a multisite scenario)
  • An install profile
  • A grouping of functionality (e.g. a module)

Principle 5: Programmatically disable all splits, then enable.

Example: environment splits should be disabled, then enabled:


  $config['config_split.config_split.dev']['status'] = FALSE;
  $config['config_split.config_split.stage']['status'] = FALSE;
  $config['config_split.config_split.prod']['status'] = FALSE;
  $config['config_split.config_split.' . $env_name]['status'] = TRUE;
            

Principle 6: Config flows from local to production.

Your primary development branch is the canonical source of configuration.

All changes branch off the canonical and are merged back into it, just like any other code changes.

Reset your local config to the canonical before making changes.

Consider a "reset" script that is run every time you change branches:

  • Run composer install
  • Copy canonical database into your local
  • Run database updates (drush updb)
  • Run config import, twice (drush cim sync)
  • Now, you are ready to make changes

Principle 7: Import config twice on deploy.


  drush cim sync -y || drush cim sync -y
  drush cim sync -y 
            

Line 1: Import but allow it to fail using the || trick
(there are caching issues when modules are enabled)

Line 2 Import to reflect changes in how config is imported (config split)

I've not seen any indication this will change.

Get ready for the main event!

Drumroll, please...

via GIPHY

Two categories of config models:

  • Synchronization Models: for your site's entire set of config.
  • Split Models: for splitting out differences on a module or config-entity level (e.g. per-environment split of dblog).

Pick 1 synchronization model, layer on split models as you like.

Configuration Synchronization Models

Config Synchronization Models

  1. Globally Shared Management (default): All sites share the config set.
  2. Profile Shared Management: All sites of the same profile share the config set.
  3. Separate Management: All sites have their own config set.
  4. Unmanaged: No configurations are managed in code.

Model 1: Globally Shared Management (default)


  $settings['config_sync_directory'] = '../config/sync';
            

Model 2: Profile Shared Management


  $settings['config_sync_directory'] = "../docroot/profiles/custom/{$profile_name}/config/sync";
            

This is a symlink to ../config/{$profile_name}/sync

Model 3: Separate Management


  $settings['config_sync_directory'] = "../config/{$site_name}/sync";
            

Model 4: Unmanaged

Config Split Models

  1. Environment Splits: Allows DEV to have different config than PRD.
  2. Site Splits: Allows sites to have different config than what is in synchronization.
  3. Profile Splits: Allows all sites of a given profile to have different config than what is in synchronization.
  4. Module Splits: Allows sites with a given module to have different config than what is in synchronization.

Let's look at 4 examples...

1: Environment Splits with Globally Shared Management

2: Profile Splits with Globally Shared Management

3: Site Splits with Globally Shared Management

4: Site Splits with Profile Shared Management

You can't talk about config split models without getting into split types...

5 ways a config entity can be split.

With each of the split examples, on a per-module or per-config entity basis you choose between these options:

  1. No Split (default): The config entity is always in synchronization, it never splits.
  2. Complete Module Split: The module is only enabled when that split is active, and all of its config entities only exist when the split is active.
  3. Complete Entity Split: The entity is never in synchronization, it only exists when the split is active.
  4. Conditional Entity Split: The entity is always in synchronization, it only splits if its different than synchronization.
  5. Unmanaged: The config entity is never in synchronization or splits, it only exists in the database.

Look at examples with Profile Shared Management and Site Splits

No Split (default)

All config imports and exports to synchronization directory.

Complete Module Split

Complete Entity Split

Conditional Entity Split

Unmanaged

III. Guidelines for Modeling

Which Synchronization Model should you use?

80% of a default config set should be shared by all sites.

Example: 12 content types, 10 are managed, 2 are unmanaged.

At least 8 should be in your default config set (synchronization directory).

Math: 8 / (12 - 2) = 80%

(This proxy guideline for how difficult it will be to manage the application.)

Managed config does not scale well with # of sites.

1 site: > 90% managed config ("Collectible" sites)

2-5 sites: 80% managed config

6-20 sites: 40% managed config

20+ sites: < 20% managed config ("Commodity" sites)

Which Split Model(s) should you use?

Synchronization Models and Split Models Work Together

  Env Splits Site Splits Profile Splits Module Splits
Globally Shared
Profile Shared 🚫
Separate 🚫
Unmanaged 🚫 🚫 🚫 🚫
Scenario Use Case # Sites % Managed
Globally Shared with Site Splits Same functionality, minor per-site differences <10 100%
Globally Shared with Profile Splits Same functionality, minor per-install-profile differences 20+ 80%
Profile Shared with Site Splits Same functionality by install profile, minor per-site differences 20+ 80%
Unmanaged Same base functionality, large differences per-site 70+ 0%

Environment splits and module splits can be used with any managed setup.

How do you choose whether to make a config managed, unmanaged, or split?

Recap

4 Config Synchronization Models

  1. Globally Shared Management (default): All sites share the config set.
  2. Profile Shared Management: All sites of the same profile share the config set.
  3. Separate Management: All sites have their own config set.
  4. Unmanaged: No configurations are managed in code.

4 Config Split Models

  1. Environment Splits: Allows DEV to have different config than PRD.
  2. Site Splits: Allows sites to have different config than what is in synchronization.
  3. Profile Splits: Allows all sites of a given profile to have different config than what is in synchronization.
  4. Module Splits: Allows sites with a given module to have different config than what is in synchronization.

5 ways a config entity can be split.

With each of the split examples, on a per-module or per-config entity basis you choose between these options:

  1. No Split (default): The config entity is always in synchronization, it never splits. (default)
  2. Complete Module Split: The module is only enabled when that split is active, and all of its config entities only exist when the split is active.
  3. Complete Entity Split: The entity is never in synchronization, it only exists when the split is active.
  4. Conditional Entity Split: The entity is always in synchronization, it only splits if its different than synchronization.
  5. Unmanaged: The config entity is never in synchronization or splits, it only exists in the database.

Refer back to our decision aids...

Thank you!

Please provide feedback:
events.drupal.org/global2020/sessions/models-configuration-management


Slides are available:
github.com/josephdpurcell

Let's talk! @josephdpurcell

Further Reading