Using Feature Flags and Externalized configuration .NET Core app with Flagsmith
You can use config-maps, attach volumes to containers in Docker or Kubernetes to substitute files, or you can use environment variables to extract configuration from applications. But these are dirty hacks in comparison to what you can do if you would have a service which would provide a configuration for your microservice. There are many of them on the market, but I specifically want to stop on Flagsmith (formerly Bullet Train). After certain considerations, this tool looks the most convenient for the needs of my project. In this article I’ll tell you more about why we chose it and what were our considerations.
The adhering of these two architectural patterns (feature toggles and externalized configuration) helps in three commonly known areas on CI/CD process:
- it leverages the continuous delivery process by allowing to decouple deployment and releasing
- configuration of the service and integrations between services become easier due to avoiding re-deployments
- you can extract your secretes from code base and store them in a separate protected storage
In development usage of feature toggles helps to merge easier from your long live feature branch. In addition, it helps incorporation of Trunk Based Development in your development process and make releases easier (the downside of this is the higher skill level for developers) . For example, if you’ve merged some big feature to your master, but during pre-release testing you decide that you need to add more changes, it’s easier to deploy with disabled features, than to rollback your changes from the master branch.
Flagsmith and Alternatives
The majority of tools which I investigated makes focus only on feature flags. It means you can get management and monitoring of Boolean flags, but for configuration settings you’ll need to find another solution. There were such candidates as ConfigCat, LaunchDarkly, featureflag.tech and others which you can find in this list. Most of them offer SaaS solutions, paid and limited only with toggles. In our case we wanted to host on-premise, within boundaries of our intranet. Because of these reasons I stopped on Vault Project in the beginning. It’s very nice from the perspective of security. In contrast its usage appeared not straightforward as it could be. Also UI is not really convenient to use for settings and toggles. And my final choice was for Flagsmith. Both tools are open source, but on top of this, the latter much easier to be deployed in containers. It can be integrated with existing DB clusters, such as Postgres and others, and can be deployed to Docker/Kubernetes easily, it has a lot of client libraries (e.g., for NodeJs, .NET Core) and allows easy access via shell script which is useful for CI/CD pipelines.
Flagsmith features in short
You can use the free plan of their hosted SaaS solution, or deploy an Open Source version to your infrastructure. After deployment you can create organization. For each organization you can create as many environments as you need. You can define flags or settings in any environment and they become available for all environments of the organization.
You can create users and segments to override environment settings for specific users or groups of users. It’s possible also to associate additional information about users in the key-value format.
Actually you don’t need to create users forehand. The tool will create users automatically, when you specify an identity in the client application. After that, you can define a rule in segments to group users by some value in its traits. This automatically allocates users to one or another group which may help in A/B testing. We are using users a bit differently from this which I’ll below more.
You can use settings to store any kind of data. It may be a JSON string which you would convert later in an internal object. API interface (and client libraries) allows to load several settings and flags together or individually. You can configure caching mechanisms for intensively used applications with web hooks which can update the cache when setting is used or changed.
How we use Flagsmith in our microservices
We use the .NET Core NuGet package of the client library which is version 2.1.3 on the moment of writing this article. We deploy Flagsmith in Docker on our production environment and on local machines of developers.
Wrapping and Abstracting
In their documentation Flagsmith has a simple usage example. The problem with it is that it relies on a singleton class which is not injectable. Because of that we introduced a wrapper class which retains the original usage pattern, but in addition allows injection. We packed it into the internal NuGet package which is used in every microservice where we need the remote configuration. So the interface looks as follows:
And below is the implementation class (only part of it):
On top of that we created utility classes which help register dependencies in
Startup.cs and offer a fluent interface for settings which has common usage for all microservice (for example, Kafka brokers, endpoints of certain microservices and etc.).
User = Microservice
In contrast to the suggested usage of Users in Flagsmith, we use it to identify microservices. We don’t need to have separate configuration per user, but we do need sometimes to override configuration for specific microservice. We might need this during experimenting on the Beta environment, when we need all our services to work as usual, but the service which feeds data into the system needs to stream it from production. There are multiple scenarios to use this feature of Flagsmith.
Migration from appsettings.json
Since Flagsmith allows to store string values, the migration from appsettings files is very simple. Before that we had a huge hierarchy of json-configs because we have four environments and some of our microservices could be run using different configurations on the same environment. We just put JSON text which was in json configs to remote settings. On top of that we introduced user names for different configurations of the same service. The rest has been done by Falgsmith. The service just loads the configuration which it needs. Our appsettings.json files become light and simple.
In order to not forget the purpose of settings and flags, their origin and usage, we developed a simple convention:
<type>_<scope>_<purpose> (e.g., flag_feederservice_extendedaudit)
type could be
setting which corresponds to the type of a created item. The
scope usually determines a microservice which the item belongs to. The
purpose is a short description of the item itself.
Points to Remember
In conclusion I’d like to mention points which seem to be complicated to practice, but at the same time, which are important to follow to make feature flags and externalized configuration work for you and not opposite.
- Do not reuse old items
- Enforce short life span for feature flags and track all of them which need to be removed on your Kanban/Scrum board. Remove them as soon as a feature is fully released
- Do not use combinations or hierarchy of toggles
- Use strategy pattern instead of IF and move the toggle point as close to
Startup.csfile as possible
There are two topics which I’d highly recommend to read about on the Martin Fowler’s blog :
- De-coupling decision points from decision logic
- Inversion of Decision