Microservices Design Using Sidecar Pattern

What is Sidecar Pattern?

 
The sidecar pattern is used to promote separation of concerns in micorservices architecture. This pattern allows us to offload processing of some kind to a separate module that gets deployed along with the main service component. The sidecar pattern is sometimes referred as decomposition pattern.
 

Why it useful in Microservices architecture?

 
Generally, in a microservices architecture, things like logging, monitoring, messaging, tracing, encrypting and decrypting, configuration, and exceptions handling are common modules which we need to implement into each service and due to time constraints we may repeating the same code again and again across services. This is considered to be a bad practice and the overall complexity of application will increase.
 
By using sidecar pattern, we can eliminate this kind of problem by removing redundant code across services and create separate components or services and make it generic enough so that it can be reusable.
 
 

The Solution Approach

 
The details of design are actually very straightforward. The key here is that you need to write the module specific enough for your immediate needs, while being generic enough for other parts of your system.
 
It is not necessary that a sidecar module/service is part of your main application, but is connected to it. It goes wherever the parent application goes and it can use a similar runtime as like mocroservies.
 
Once we deploy it, the functionality should just appear and it works like a kind of plug and plays with main service application. If that piece of functionality needs somewhere else, we simply add reference of the sidecar with the service and it will inherit the  required functionality.
 
With the sidecar pattern, we can deploy the sidecar as a module associated with every applicable service.
 
 
Let’s consider, we have three microservices. We added our first sidecar called logging to each service. We are uploading it as part of the parent service when we do the deployment. So all of these run within a single process but they are very distinct modules. And we are getting the benefits of the sidecar everywhere while not writing code in each service.
 
Similarly, we're added another sidecar called configuration and are applying it to each service. But messaging sidecar applied for two of our services. That is the power of sidecar.
 
The benefit of this approach is that you pick sidecar and choose where you want to apply the functionality and simply apply it. As long as your sidecar is written generically enough, you can apply it anywhere and that service will automatically inherit that functionality through a single process. As a result, it’s reducing complexity and redundancy in code by abstracting the common infrastructure-related functionalities to a different layer.
 

Sample Implementation of Sidecar Pattern in ASP.NET Core based Microservices

 
I created 3 microservices project called Students, Courses and Payments in ASP.NET Core. I also created a class library as a common project and added the  required NuGet packages. Here, we will be reading application configuration values from Azure Key Vault into each services, just to demonstrate how sidecar patterns works.
 
 
The below implementation is for extension method of IWebHostBuilder in SidecarExtensions.cs. This is a generic method for configuration which will be used in each service.
  1. using Microsoft.AspNetCore.Hosting;  
  2. using Microsoft.Extensions.Configuration;  
  3. using Microsoft.Extensions.DependencyInjection;  
  4.   
  5. namespace Common  
  6. {  
  7.     public static class SidecarExtensions  
  8.     {  
  9.         public static IWebHostBuilder UseKVConfiguration(this IWebHostBuilder webHostBuilder)  
  10.         {  
  11.             webHostBuilder.ConfigureServices(services => {  
  12.                 IConfigurationRoot configuration = LoadKeyVaultSettings();  
  13.                 services.AddSingleton<IConfiguration>(configuration);  
  14.             });  
  15.   
  16.             return webHostBuilder;  
  17.         }  
  18.   
  19.         public static IConfigurationRoot LoadKeyVaultSettings()  
  20.         {  
  21.             var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true)  
  22.                .AddEnvironmentVariables()  
  23.                .Build();  
  24.   
  25.             var sc = new ServiceConfiguration();  
  26.             configuration.Bind(sc);  
  27.   
  28.             var configBuilder = new ConfigurationBuilder();  
  29.             if (sc.KeyVault != null && !string.IsNullOrEmpty(sc.KeyVault.Uri))  
  30.             {  
  31.                 if (!string.IsNullOrEmpty(sc.KeyVault.ClientId) && !string.IsNullOrEmpty(sc.KeyVault.Secret))  
  32.                 {  
  33.                     configBuilder.AddAzureKeyVault(sc.KeyVault.Uri, sc.KeyVault.ClientId, sc.KeyVault.Secret);  
  34.                 }  
  35.             }  
  36.   
  37.             return configBuilder  
  38.                .AddJsonFile("appsettings.json", optional: true)  
  39.                .AddEnvironmentVariables()  
  40.                .Build();  
  41.         }  
  42.         public class ServiceConfiguration  
  43.         {  
  44.             public KeyVaultInfo KeyVault { getset; }  
  45.         }  
  46.         public class KeyVaultInfo  
  47.         {  
  48.             public string Uri { getset; }  
  49.   
  50.             public string ClientId { getset; }  
  51.   
  52.             public string Secret { getset; }  
  53.         }  
  54.     }  
  55. }  
Added UseKVConfiguration in ConfigureHostBuilder on Program.cs into one of the services along with common project reference.
 
 
I modified appsettings.json and added Azure Key Vault configuration values into the service.
 
 
Now we can able to access the configuration value wherever need into the service through configuration DI as like below.
 
 
Similarly, we can add this configuration to other services.
 
Excellent! Now we have a clear understanding of the sidecar pattern with sample examples of implementation. It will help us to build a decomposition system between the main application and the underlying platform.
 
Hope you find this information useful!