-
-
Notifications
You must be signed in to change notification settings - Fork 5.2k
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
Changes from 6 commits
7cb2aa1
21329ec
a23d82d
d45e1f4
5c8ed87
097a73d
2c5aeb1
af4ff18
e403fd8
2613810
bc3618d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
.. index:: | ||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure about this one. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's nice! I've added that use case. Thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 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 C) Mention the |
||
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); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
and make the needed changes. | ||
|
||
In this example, the changes of the new ``ApiKernel`` would be to load less | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We usually don't have the |
||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 ... | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
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 |
There was a problem hiding this comment.
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?