Skip to content

Added a new article about applications with multiple kernels #6840

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Dec 15, 2016
149 changes: 149 additions & 0 deletions request/multiple_kernels.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
.. index::
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be in the configuration/ directory?

single: kernel, performance

How To Create Symfony Applications with Multiple Kernels
========================================================

In most Symfony applications, incoming requests are processed by the
``web/app.php`` front controller, which instantiates the ``app/AppKernel.php``
class to create the application kernel that loads the bundles and generates the
response.

This single kernel approach is a convenient default provided by the Symfony
Standard edition, but Symfony applications can define any number of kernels.
Whereas :doc:`environments </configuration/environments>` execute the same
application with different configurations, kernels can execute different parts
of the same application.

These are some of the common use cases for creating multiple kernels:

* An application that defines an API could define two kernels for performance
reasons. The first kernel would serve the regular application and the second
one would only respond to the API requests, loading less bundles and enabling
less features;
* A highly sensitive application could define two kernels. The first one would
only load the routes that match the parts of the application exposed to the
public. The second kernel would load the rest of the application and its
access would be protected by the web server;
* An application that uses a bundle which doesn't allow multiple instances could
Copy link
Contributor

@ogizanagi ogizanagi Aug 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure about this one.
It is presented as a solution to bundles registering a single service instead of allowing the creation of multiple instances through configuration. But creating new kernels has way too much impact to be considered for this use-case.
Once again, a kernel environment is probably more appropriate to define a different bundle configuration. But anyway, none of the 2 solutions would allow to make the different bundle configurations cohabit within the very same request. In my opinion, the sentence is misleading regarding this 😕.
The only solution for this use case is to not use the bundle/bundle configuration, and register services yourself.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. I'm probably going to remove this use case. I added because the other day one person asked me if EasyAdmin supported defining two different backends in the same app. The bundle itself doesn't support that ... but with this multi-kernel trick, everything is easily solved.

Can anyone think of other use cases or do we just leave the first two proposed ones? Thanks.

Copy link
Contributor

@ogizanagi ogizanagi Aug 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about micro-services oriented apps ? You can split your services in multiple optimized modules, allowing to enable/disable a group of micro services on a server instance, by simply exposing or not a kernel instance.
It avoids dealing with multiple git repositories and allow to share code/configuration more easily.
However, it's very close to the mentioned API use-case, but with more advanced partitioning.

Copy link
Member Author

@javiereguiluz javiereguiluz Aug 4, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's nice! I've added that use case. Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe the most common use case is the front-end/back-end sceneries, a big e-commerce application, for example ?

define two identical kernels to define a different bundle configuration for
each of them.

Adding a new Kernel to the Application
--------------------------------------

Creating a new kernel in a Symfony application is a three-step process:

1. Create a new front controller to load the new kernel;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is another way to do this (which is done on a BIG Symfony site I know of): keeping app.php and app_dev.php and using some URL matching to load different kernels. For example, if the URL starts with /admin, then load the AdminKernel, else AppKernel. I think it's worth mentioning both. So, what about:

A) Making step (1) actually step (3) (I think creating the kernel and hooking up the configuration makes sense to have first, then finally show how you can instantiate the now-created kernel)

B) Rename this step to Step 3) Executing the kernel from a front controller

C) Mention the if statement approach above (it could be mentioned first or second).

2. Create the new kernel class;
3. Define the configuration loaded by the new kernel.

The following example shows how to create a new kernel for the API of a given
Symfony application.

Step 1) Create a new Front Controller
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Instead of creating the new front controller from scratch, it's recommended to
duplicate the existing ``web/app_dev.php`` and ``web/app.php`` files. For
example, you can create ``web/api_dev.php`` and ``web/api.php`` (or
``web/api/app_dev.php`` and ``web/api/app.php`` depending on your server
configuration).

Then, update the code of the new front controllers to instantiate the new kernel
class instead of the usual ``AppKernel`` class::

// web/api.php
// ...
$kernel = new ApiKernel('prod', false);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you don't put a require call to load the file defining it, you already need to show the update of the autoload config

// ...

// web/api_dev.php
// ...
$kernel = new ApiKernel('dev', true);
// ...

Step 2) Create the new Kernel Class
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Now you need to define the ``ApiKernel`` class used by the new front controller.
The recommendation again is to duplicate the existing ``app/AppKernel.php`` file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The easiest way to do this is by duplicating the existing...

and make the needed changes.

In this example, the changes of the new ``ApiKernel`` would be to load less
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this example, the ApiKernel will load less bundles than AppKernel. Be sure to also change
the location of the cache, logs and config files so they don't collide with the files
from AppKernel

bundles than ``AppKernel`` and to change the location of the cache, logs and
config files to not mess with the regular application::

// app/ApiKernel.php
<?php
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We usually don't have the <?php. If you do want it for some specific reason, the filename should probably be moved inside of it, so that the comment is in PHP. But probably, we should just remove <?php


use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class ApiKernel extends Kernel
{
public function registerBundles()
{
// load only the bundles strictly needed for the API...
}

public function getCacheDir()
{
return dirname(__DIR__).'/var/cache/api/'.$this->getEnvironment();
}

public function getLogDir()
{
return dirname(__DIR__).'/var/logs/api';
}

public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load($this->getRootDir().'/config/api/config_'.$this->getEnvironment().'.yml');
}
}

Step 3) Define the Kernel Configuration
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Finally, define the configuration used by the application when it executes the
new API kernel. According to the previous code, this config must be defined in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finally, define the configuration files that the new ApiKernel will load. According to the
above code, this config will live in the...

the ``app/config/api/`` directory.

The new configuration can be created from scratch when you load just a few
bundles, because it will be very simple. Otherwise, duplicate the existing
config files or better, import them and override the needed options:

.. code-block:: yaml

# app/config/api/config_dev.yml
imports:
- { resource: ../config_dev.yml }

# override option values ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another option is to share some configuration files, especially if both kernels use some of the same bundles that you want configured in the same ways. I'm haven't done this enough to settle on the best organization for this... but we could at least mention it. Perhaps a app/config/shared.yml file where we show just a little bit of config and mention how you could import this from the config.yml file of both kernels.

Adding more Kernels to the Application
--------------------------------------

If your application is very complex and you create several kernels, it's better
to store them on their own directories instead of messing with lots of files in
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

store them in their...

the default ``app/`` directory:

.. code-block:: text

project/
├─ app/
│ ├─ ...
│ ├─ config/
│ └─ AppKernel.php
├─ api/
│ ├─ ...
│ ├─ config/
│ └─ ApiKernel.php
├─ ...
└─ web/
├─ ...
├─ app.php
├─ app_dev.php
├─ api.php
└─ api_dev.php